Package com.bbn.openmap.omGraphics

Source Code of com.bbn.openmap.omGraphics.OMGraphic

// **********************************************************************
//
// <copyright>
//
//  BBN Technologies
//  10 Moulton Street
//  Cambridge, MA 02138
//  (617) 873-8000
//
//  Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/omGraphics/OMGraphic.java,v $
// $RCSfile: OMGraphic.java,v $
// $Revision: 1.8.2.7 $
// $Date: 2006/05/19 17:52:46 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.omGraphics;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.TexturePaint;
import java.awt.geom.GeneralPath;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import com.bbn.openmap.omGraphics.geom.BasicGeometry;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;

/**
* Used to be the base class of OpenMap graphics, but now inherits
* from BasicGeometry, which now contains all the information about
* the geometry of the OMGraphic. The OMGraphic also contains
* information about how the geometry should be drawn.
* <P>
* The OMGraphics are raster and vector graphic objects that know how
* to position and render themselves on a given x-y window or lat-lon
* map projection. All you have to do is supply the location data
* (x/y, lat/lon) and drawing information (color, line width) and the
* graphic handles the rest.
* <p>
*
* This class contains parameters that are common to most types of
* graphics. If a parameter doesn't make sense for a particular
* graphic type, it is ignored.
* <p>
*
* The OMGraphics are being updated to be able to provide
* java.awt.Shape representations of themselves after they have been
* generated(). The getShape() method returns a java.awt.Shape object.
* With the Shape object, you can do some spatial analysis (object
* operations) on the projected OMGraphics.
*
* NOTES:
* <ul>
* <li>Color values cannot be set to null, but can be set to
* OMGraphic.clear. Actually, if you set them to null, they will set
* themselves to be clear.
* <li>XY Rendering: Java specifies that the origin is the top left
* of the window, x increases to the right, y increases down.
* <li>LatLon Rendering: Defined by the Projection object. The center
* of the window usually corresponds to the center of the projection.
* OMGraphics should project themselves using the appropriate
* forward() method listed in the Projection interface
* <li>Offset Rendering: same as XY, but with origin set to a
* projected LatLon point.
* </ul>
*
* @see OMBitmap
* @see OMCircle
* @see OMLine
* @see OMPoly
* @see OMRect
* @see OMRaster
* @see OMText
* @see OMGraphicList
* @see Projection
*/
public abstract class OMGraphic extends BasicGeometry implements OMGeometry,
        OMGraphicConstants, Cloneable, Serializable {

    /**
     * The Java2D Stroke. This is used for lineWidth, and dashing of
     * the lines and polygon edges.
     */
    protected transient Stroke stroke = BASIC_STROKE;

    /**
     * This color is the real foreground color of the object. It is
     * kept so that the object knows how to de-highlight itself. It
     * defaults to black.
     */
    protected Paint linePaint = Color.black;

    /**
     * This paint is used for the matting area around the edge of an
     * OMGraphic painted when the matted variable is set to true.
     */
    protected Paint mattingPaint = Color.black;

    /**
     * The color that the object is displayed with. This color changes
     * back and forth between the selectColor and the lineColor,
     * depending on the if the object is selected or not.
     */
    protected Paint displayPaint = linePaint;

    /**
     * This color is the fill color of the object. It defaults to a
     * black color that is transparent.
     */
    protected Paint fillPaint = clear;

    /**
     * This Paint object is the fill texture mask of the object. It
     * defaults to null. If this texture mask is set, the fill paint
     * will still be used to fill the OMGraphic shape, but then this
     * paint will be rendered on top. If the textureMask has
     * transparency, the fill paint still influences appearance.
     */
    protected TexturePaint textureMask = null;

    /**
     * This color is the highlight color that can be used when the
     * object is selected. The default color is black, just like the
     * line color.
     */
    protected Paint selectPaint = Color.black;

    /**
     * Flag to indicate that the object has/hasnot been put in a
     * special mode as a result of some event. Set through the
     * select()/deselect methods().
     */
    protected boolean selected = false;

    /**
     * A flag for whether an EditableOMGraphic should show it's
     * palette if the OMGraphic is modified.
     */
    protected boolean showEditablePalette = true;

    /**
     * Flag to note if the current edge color matches the fill color.
     * Can be used to save from rendering the edge if rendering the
     * filled area already takes care of it.
     */
    protected boolean edgeMatchesFill = false;

    /**
     * The renderType describes the relation of the object to the
     * window. RENDERTYPE_LATLON means the object is positioned
     * relative to lat/lon points. RENDERTYPE_XY means the object is
     * positioned relative to window pixel coordinates.
     * RENDERTYPE_OFFSET means the object is drawn at a pixel offset
     * to a lat/lon point.
     */
    protected int renderType = RENDERTYPE_UNKNOWN;

    /**
     * Decluttering is not supported by OpenMap yet. But, when it is,
     * these parameters will describe the way the object is
     * manipulated on the window relative to its neighbors.
     * DECLUTTERTYPE_NONE means the object will be drawn where its
     * attributes say it should be. DECLUTTERTYPE_SPACE indicates that
     * the window space of the object should be marked as taken, but
     * the object should not be moved. DECLUTTERTYPE_MOVE means the
     * object should be moved to the nearest open location closest to
     * the position indicated by its attributes. DECLUTTERTYPE_LINE is
     * the same as MOVE, but in addition, a line is drawn from the
     * current position to its original position.
     */
    protected int declutterType = DECLUTTERTYPE_NONE;

    /**
     * Flag for determining when the matting around the edge of an
     * OMGraphic. Matting is a line, two pixels wider than the edge,
     * painted under the edge. It makes the OMGraphic stand out on
     * busy backgrounds.
     */
    protected boolean matted = false;

    /**
     * The flag set in generate that causes the OMGraphic to look for
     * an OMLabeler attribute in render. This flag prevents an
     * unnecessary hashtable lookup every render call.
     */
    protected transient boolean hasLabel = false;

    /**
     * Checks if the Paint is clear.
     *
     * @param paint Paint or null.
     * @return true if Paint is null or is a Color with a 0 alpha
     *         value.
     */
    public static boolean isClear(Paint paint) {
        if (paint instanceof Color) {
            return ((((Color) paint).getRGB() & 0xff000000) == 0);
        } else {
            return false;
        }
    }

    // ////////////////////////////////////////////////////////

    /**
     * Construct a default OMGraphic.
     */
    protected OMGraphic() {}

    /**
     * Construct an OMGraphic. Standard simple constructor that the
     * child OMGraphics usually call. All of the other parameters get
     * set to their default values.
     *
     * @param rType render type
     * @param lType line type
     * @param dcType declutter type
     */
    protected OMGraphic(int rType, int lType, int dcType) {
        setRenderType(rType);
        setLineType(lType);
        setDeclutterType(dcType);
    }

    /**
     * Construct an OMGraphic. More complex constructor that lets you
     * set the rest of the parameters.
     *
     * @param rType render type
     * @param lType line type
     * @param dcType declutter type
     * @param lc line color
     * @param fc fill color
     * @param sc select color
     */
    public OMGraphic(int rType, int lType, int dcType, Color lc, Color fc,
            Color sc) {
        this(rType, lType, dcType);
        setLinePaint(lc);
        setSelectPaint(sc);
        setFillPaint(fc);
    }

    /**
     * Set the render type of the graphic. Accepts RENDERTYPE_LATLON,
     * RENDERTYPE_XY and RENDERTYPE_OFFSET. All weird values get set
     * to RENDERTYPE_XY. See the definition on the renderType
     * parameter.
     *
     * @param value the rendertype for the object.
     */
    public void setRenderType(int value) {
        if (renderType == value)
            return;
        setNeedToRegenerate(true); // flag dirty

        renderType = value;
    }

    /**
     * Return the render type.
     *
     * @return the rendertype of the object - RENDERTYPE_LATLON,
     *         RENDERTYPE_XY, RENDERTYPE_OFFSET and
     *         RENDERTYPE_UNKNOWN.
     */
    public int getRenderType() {
        return renderType;
    }

    /**
     * OMGraphic method for returning a simple description of the
     * OMGraphic.
     *
     * @param level used by OMGraphicLists to provide an offset, or a
     *        notion of embedding.
     */
    public String getDescription(int level) {
        if (level == 0) {
            return getDescription();
        } else {
            return "|--> " + getDescription();
        }
    }

    /**
     * OMGraphic method for returning a simple description of the
     * OMGraphic.
     */
    public String getDescription() {
        String cname = getClass().getName();
        int lastPeriod = cname.lastIndexOf('.');
        if (lastPeriod != -1) {
            cname = cname.substring(lastPeriod + 1);
        }
        return cname;
    }

    /**
     * Set the declutter setting for the graphic. Accepts
     * DECLUTTERTYPE_SPACE, DECLUTTERTYPE_MOVE, DECLUTTERTYPE_LINE,
     * and DECLUTTERTYPE_NONE. All weird values are set to
     * DECLUTTERTYPE_NONE.
     * <p>
     * Right now, this is unimplemented in OpenMap. But for
     * information, DECLUTTERTYPE_NONE means the object has no impact
     * on the placement of objects. DECLUTTERTYPE_SPACE means the
     * object shouldn't have things placed on it, but to draw it where
     * the coordinates dictate. DECLUTTERTYPE_MOVE means to put the
     * object in an open space, and DELCUTTERTYPE_LINE adds the
     * feature that if the object is not drawn where it's coordinates
     * say it should be, then a line should be drawn showing where the
     * original position is.
     * <P>
     * Decluttering of geometries is not supported. This flag is not
     * used.
     *
     * @param value the declutter type value.
     */
    public void setDeclutterType(int value) {
        if (declutterType == value)
            return;
        setNeedToRegenerate(true); // flag dirty

        declutterType = value;
    }

    /**
     * Return the declutter type.
     *
     * @return declutter type, see above.
     */
    public int getDeclutterType() {
        return declutterType;
    }

    /**
     * Given a java.awt.Graphics object, set the Stroke and Paint
     * parameters of it to match the OMGraphic's edge settings.
     *
     * @param g java.awt.Graphics
     * @see #setGraphicsColor
     */
    public void setGraphicsForEdge(Graphics g) {
        if (g instanceof Graphics2D) {
            ((Graphics2D) g).setStroke(getStroke());
        }
        setGraphicsColor(g, getDisplayPaint());
    }

    /**
     * Given a java.awt.Graphics object, set the Paint to be the
     * OMGraphic's fillPaint setting.
     *
     * @param g java.awt.Graphics
     * @see #setGraphicsColor
     */
    public void setGraphicsForFill(Graphics g) {
        if (g instanceof Graphics2D) {
            ((Graphics2D) g).setStroke(BASIC_STROKE);
        }
        setGraphicsColor(g, getFillPaint());
    }

    /**
     * Set the Paint in the given Graphics. If the Graphics is not an
     * instance of Graphics2D, then the Color of the graphics is set
     * if the Paint is an instance of Color.
     *
     * @param g java.awt.Graphics
     * @param paint java.awt.Paint
     */
    public void setGraphicsColor(Graphics g, Paint paint) {
        if (g instanceof Graphics2D) {
            ((Graphics2D) g).setPaint(paint);
        } else if (paint instanceof Color) {
            g.setColor((Color) paint);
        }
    }

    /**
     * Set the line color of the graphic object. The line color is the
     * normal display edge color of the object. This color is used as
     * the display color when the object is NOT selected
     * (hightlighted). The display color is set to the select color in
     * this method if <code>selected</code> boolean attribute is
     * false.
     *
     * @param value the real line color
     * @deprecated Use setLinePaint instead. Now taking advantage of
     *             the Java2D API.
     */
    public void setLineColor(Color value) {
        setLinePaint(value);
    }

    /**
     * Return the normal foreground color of the object.
     *
     * @return the line color. Returns null if the Paint is not a
     *         Color.
     */
    public Color getLineColor() {
        if (linePaint instanceof Color) {
            return (Color) linePaint;
        } else {
            return null;
        }
    }

    /**
     * Set the line Paint. The line Paint is the normal display edge
     * paint of the graphic. This Paint is used as the display Paint
     * when the object is NOT selected (hightlighted). The display
     * Paint is set to the select Paint in this method if
     * <code>selected</code> boolean attribute is false.
     *
     * @param paint the real line Paint
     */
    public void setLinePaint(Paint paint) {
        if (paint != null) {
            linePaint = paint;
        } else {
            linePaint = Color.black;
        }

        if (!selected) {
            displayPaint = linePaint;
        }
        setEdgeMatchesFill();
    }

    /**
     * Get the normal line Paint used for the graphic.
     *
     * @return Line Paint.
     */
    public Paint getLinePaint() {
        return linePaint;
    }

    /**
     * Set the select color of the graphic object. The selected color
     * is used as the display color when the object is selected
     * (highlighted). The display color is set to the select color in
     * this method if <code>selected</code> boolean attribute is
     * true.
     *
     * @param value the selected color.
     * @deprecated Use setSelectPaint instead. Now taking advantage of
     *             the Java2D API.
     */
    public void setSelectColor(Color value) {
        setSelectPaint(value);
    }

    /**
     * Return the selected color, which is the line or foreground
     * color used when the graphic is "selected".
     *
     * @return the selected mode line color. Returns null if the
     *         select Paint is not a Color.
     */
    public Color getSelectColor() {
        if (selectPaint instanceof Color) {
            return (Color) selectPaint;
        } else {
            return null;
        }
    }

    /**
     * Set the select Paint. The select Paint is the display edge
     * paint of the graphic. This Paint is used as the display Paint
     * when the object IS selected (hightlighted). The display Paint
     * is set to the select Paint in this method if
     * <code>selected</code> boolean attribute is true.
     *
     * @param paint the real select Paint
     */
    public void setSelectPaint(Paint paint) {
        if (paint != null) {
            selectPaint = paint;
        } else {
            selectPaint = Color.black;
        }

        if (selected) {
            displayPaint = selectPaint;
        }
        setEdgeMatchesFill();
    }

    /**
     * Get the normal select Paint used for the graphic.
     *
     * @return Select Paint.
     */
    public Paint getSelectPaint() {
        return selectPaint;
    }

    /**
     * Return the color that should be used for display. This color
     * changes, depending on whether the object is selected or not.
     * The display color is also set when the line color or the select
     * color is set, depending on the statue of the
     * <code>selected</code> boolean attribute.
     *
     * @return the color used as the edge color or foreground color,
     *         in the present selected state. If the displayPaint is
     *         not a Color, this method returns null.
     */
    public Color getDisplayColor() {
        if (displayPaint instanceof Color) {
            return (Color) displayPaint;
        } else {
            return null;
        }
    }

    /**
     * Return the Paint that should be used for display. This Paint
     * changes, depending on whether the object is selected or not.
     * The display Paint is also set when the line Paint or the select
     * Paint is set, depending on the statue of the
     * <code>selected</code> boolean attribute.
     *
     * @return the Paint used as the edge Paint or foreground Paint,
     *         in the present selected state.
     */
    public Paint getDisplayPaint() {
        return displayPaint;
    }

    /**
     * Set the selected attribute to true, and sets the color to the
     * select color.
     */
    public void select() {
        selected = true;
        displayPaint = getSelectPaint();
        setEdgeMatchesFill();
    }

    /**
     * Set the selected attribute to false, sets the color to the line
     * color.
     */
    public void deselect() {
        selected = false;
        displayPaint = getLinePaint();
        setEdgeMatchesFill();
    }

    /**
     * Return whether the OMGraphic is selected.
     */
    public boolean isSelected() {
        return selected;
    }

    /**
     * Calls select() or deselect() depending on the boolean (select
     * is true).
     */
    public void setSelected(boolean set) {
        if (set) {
            select();
        } else {
            deselect();
        }
    }

    /**
     * Return whether the OMGraphic has matting around the edge.
     */
    public boolean isMatted() {
        return matted;
    }

    /**
     * Set whether the OMGraphic should have matting around the edge.
     */
    public void setMatted(boolean set) {
        matted = set;
    }

    /**
     * Set the background color of the graphic object.
     *
     * @param value java.awt.Color.
     * @deprecated Use setFillPaint instead. Now taking advantage of
     *             the Java2D API.
     */
    public void setFillColor(Color value) {
        setFillPaint(value);
    }

    /**
     * Return the background color of the graphic object. If the fill
     * Paint is not a color, this method will return null.
     *
     * @return the color used for the background.
     */
    public Color getFillColor() {
        if (fillPaint instanceof Color) {
            return (Color) fillPaint;
        } else {
            return null;
        }
    }

    /**
     * Set the fill Paint for this graphic. If the paint value is
     * null, it will be set to OMGraphicConstants.clear.
     *
     * @param paint the Paint object.
     */
    public void setFillPaint(Paint paint) {
        if (paint != null) {
            fillPaint = paint;
            if (Debug.debugging("omGraphics")) {
                Debug.output("OMGraphic.setFillPaint(): fillPaint= "
                        + fillPaint);
            }
        } else {
            fillPaint = clear;
            if (Debug.debugging("omGraphics")) {
                Debug.output("OMGraphic.setFillPaint(): fillPaint is clear");
            }
        }
        setEdgeMatchesFill();
    }

    /**
     * Set the texture mask for the OMGraphic. If not null, then it
     * will be rendered on top of the fill paint. If the fill paint is
     * clear, the texture mask will not be used. If you just want to
     * render the texture mask as is, set the fill paint of the
     * graphic instead. This is really to be used to have a texture
     * added to the graphic, with the fill paint still influencing
     * appearance.
     */
    public void setTextureMask(TexturePaint texture) {
        textureMask = texture;
    }

    /**
     * Return the fill Paint for this graphic.
     */
    public Paint getFillPaint() {
        return fillPaint;
    }

    /**
     * Return the texture mask Paint for this graphic.
     */
    public TexturePaint getTextureMask() {
        return textureMask;
    }

    protected void setEdgeMatchesFill() {
        Paint paint = getDisplayPaint();
        if (fillPaint instanceof Color && paint instanceof Color
                && !isClear(fillPaint)) {
            edgeMatchesFill = ((Color) fillPaint).equals((Color) paint);
        } else {
            edgeMatchesFill = false;
        }
    }

    public boolean getEdgeMatchesFill() {
        return edgeMatchesFill;
    }

    /**
     * Set the Paint used for matting.
     */
    public void setMattingPaint(Paint mPaint) {
        mattingPaint = mPaint;
    }

    /**
     * Get the Paint used for matting.
     */
    public Paint getMattingPaint() {
        return mattingPaint;
    }

    /**
     * Set the Stroke that should be used for the graphic edges. Using
     * a BasicStroke, you can set a stroke that defines the line
     * width, the dash interval and phase. If a null value is passed
     * in, a default BasicStroke will be used.
     *
     * @param s the stroke to use for the graphic edge.
     * @see java.awt.Stroke
     * @see java.awt.BasicStroke
     */
    public void setStroke(Stroke s) {
        if (s != null) {
            stroke = s;
        } else {
            stroke = BASIC_STROKE;
        }
    }

    /**
     * Get the Stroke used for the graphic edge.
     */
    public Stroke getStroke() {
        if (stroke == null) {
            stroke = BASIC_STROKE;
        }
        return stroke;
    }

    /**
     * Set whether an EditableOMGraphic modifying this graphic should
     * show it's palette.
     */
    public void setShowEditablePalette(boolean set) {
        showEditablePalette = set;
    }

    /**
     * Get whether an EditableOMGraphic modifying this graphic should
     * show it's palette.
     */
    public boolean getShowEditablePalette() {
        return showEditablePalette;
    }

    /**
     * A function that takes a float distance, which presumably
     * represents the pixel distance from a point to a graphic, and
     * subtracts half of the line width of the graphic from the
     * distance if the graphic line width is greater than one. This
     * should give a true pixel distance from the graphic, taking into
     * account an embellished line.
     *
     * @param distance pixel distance to the graphic edge with a line
     *        width of one.
     * @return the pixel distance to the true display edge of the
     *         graphic.
     */
    public float normalizeDistanceForLineWidth(float distance) {

        float lineWidth = 1;

        if (stroke instanceof BasicStroke) {
            lineWidth = ((BasicStroke) stroke).getLineWidth();
        }

        if (lineWidth > 1) {
            // extra calculation for lineWidth
            distance -= lineWidth / 2;
            if (distance < 0f) {
                distance = 0f;
            }
        }
        return distance;
    }

    // ////////////////////////////////////////////////////////////////////////

    /**
     * Prepare the graphic for rendering. This must be done before
     * calling <code>render()</code>! If a vector graphic has
     * lat-lon components, then we project these vertices into x-y
     * space. For raster graphics we prepare in a different fashion.
     * <p>
     * If the generate is unsuccessful, it's usually because of some
     * oversight, (for instance if <code>proj</code> is null), and
     * if debugging is enabled, a message may be output to the
     * controlling terminal.
     * <p>
     *
     * @param proj Projection
     * @return boolean true if successful, false if not.
     * @see #regenerate
     */
    public abstract boolean generate(Projection proj);

    /**
     * Paint the graphic. This paints the graphic into the Graphics
     * context. This is similar to <code>paint()</code> function of
     * java.awt.Components. Note that if the graphic has not been
     * generated, it will not be rendered.
     * <P>
     *
     * This method used to be abstract, but with the conversion of
     * OMGraphics to internally represent themselves as java.awt.Shape
     * objects, it's a more generic method. If the OMGraphic hasn't
     * been updated to use Shape objects, it should have its own
     * render method.
     *
     * @param g Graphics2D context to render into.
     */
    public void render(Graphics g) {

        if (matted) {
            if (g instanceof Graphics2D && stroke instanceof BasicStroke) {
                BasicStroke bs = (BasicStroke) stroke;
                ((Graphics2D) g).setStroke(new BasicStroke(bs.getLineWidth() + 2f, bs.getEndCap(), bs.getLineJoin()));
                setGraphicsColor(g, mattingPaint);
                draw(g);
            }
        }

        if (shouldRenderFill()) {
            setGraphicsForFill(g);
            fill(g);

            if (textureMask != null && textureMask != fillPaint) {
                setGraphicsColor(g, textureMask);
                fill(g);
            }
        }

        if (shouldRenderEdge()) {
            setGraphicsForEdge(g);
            draw(g);
        }

        renderLabel(g);
    }

    /**
     * Calls super.setShape(), but also checks the attributes for a
     * label and moves the label accordingly. The label will be placed
     * in the center of the bounding box around the path.
     */
    public void setShape(GeneralPath gp) {
        super.setShape(gp);

        hasLabel = false;

        // Go ahead and set the label location if the shape exists.
        if (gp != null) {
            OMLabeler labeler = (OMLabeler) getAttribute(LABEL);
            if (labeler != null) {
                labeler.setLocation(gp);
                hasLabel = true;
            }
        }
    }

    protected void setHasLabel(boolean val) {
        hasLabel = val;
    }

    /**
     * Quick check of the flag to see if a label attribute has been
     * set. Labels are stored in the attribute table, and that table
     * should only be checked in a generate() method call, and not in
     * the render(). The setShape() and initLabelingDuringGenerate()
     * method calls set this flag which is used to opt-out of labeling
     * methods for better performance.
     *
     * @return true if OMGraphic has label set.
     */
    public boolean getHasLabel() {
        return hasLabel;
    }

    /**
     * The method only needs to be called in an OMGraphic's generate
     * method if the setShape() method isn't called there. The
     * appropriate setLabelLocation method for where the label should
     * be set should be called if this method is going to be used.
     */
    protected void initLabelingDuringGenerate() {
        setHasLabel(getAttribute(LABEL) != null);
    }

    /**
     * Sets the label location at the center of the polygon points. If
     * the hasLabel variable hasn't been set, it no-ops.
     *
     * @param xpoints
     * @param ypoints
     */
    public void setLabelLocation(int[] xpoints, int[] ypoints) {
        if (hasLabel) {
            OMLabeler oml = (OMLabeler) getAttribute(LABEL);
            if (oml != null) {
                oml.setLocation(xpoints, ypoints);
            }
        }
    }

    /**
     * Sets the label location at the given point. If the hasLabel
     * variable hasn't been set, it no-ops.
     *
     * @param p
     */
    public void setLabelLocation(Point p) {
        if (hasLabel) {
            OMLabeler oml = (OMLabeler) getAttribute(LABEL);
            if (oml != null) {
                oml.setLocation(p);
            }
        }
    }

    /**
     * Sets the label location at the center of the bounding box of
     * the path. If the hasLabel variable hasn't been set, it no-ops.
     *
     * @param gp
     */
    public void setLabelLocation(GeneralPath gp) {
        if (hasLabel) {
            OMLabeler oml = (OMLabeler) getAttribute(LABEL);
            if (oml != null) {
                oml.setLocation(gp);
            }
        }
    }

    /**
     * Checks to see if a label should be painted based on what
     * methods were called in generate(), and renders the label if
     * necessary. If the label wasn't set up, a quick no-op occurs.
     *
     * @param g
     */
    public void renderLabel(Graphics g) {
        if (hasLabel) {
            OMLabeler labeler = (OMLabeler) getAttribute(LABEL);
            if (labeler != null) {
                labeler.render(g);
            }
        }
    }

    /**
     * Return true of the fill color/paint should be rendered (not
     * clear).
     */
    public boolean shouldRenderFill() {
        return !isClear(getFillPaint());
    }

    /**
     * Return true if the edge color/paint should be rendered (not
     * clear, or doesn't match the fill color).
     */
    public boolean shouldRenderEdge() {
        // OK, so isClear on the displayPaitn could be inaccurate if
        // another thread changes the display paint on the graphic
        // before it actually gets rendered.
        return !isClear(getDisplayPaint()) || !edgeMatchesFill;
    }

    /**
     * Return the shortest distance from the graphic to an XY-point.
     * <p>
     *
     * This method used to be abstract, but with the conversion of
     * OMGraphics to internally represent themselves as java.awt.Shape
     * objects, it's a more generic method. If the OMGraphic hasn't
     * been updated to use Shape objects, it should have its own
     * distance method.
     *
     * @param x X coordinate of the point.
     * @param y Y coordinate of the point.
     * @return float distance, in pixels, from graphic to the point.
     *         Returns Float.POSITIVE_INFINITY if the graphic isn't
     *         ready (ungenerated).
     */
    public float distance(int x, int y) {
        float distance = Float.POSITIVE_INFINITY;
        if (shouldRenderFill()) {
            distance = super.distance(x, y);
        } else {
            distance = super.distanceToEdge(x, y);
        }

        if (distance != Float.POSITIVE_INFINITY) {
            distance = normalizeDistanceForLineWidth(distance);
        }

        if (hasLabel) {
            OMLabeler labeler = (OMLabeler) getAttribute(LABEL);
            if (labeler != null) {
                float lDistance = labeler.distance(x, y);
                if (lDistance < distance) {
                    distance = lDistance;
                }
            }
        }

        return distance;
    }

    /**
     * Invoke this to regenerate a "dirty" graphic. This method is a
     * wrapper around the <code>generate()</code> method. It invokes
     * <code>generate()</code> only if</code> needToRegenerate()
     * </code> on the graphic returns true. To force a graphic to be
     * generated, call <code>generate()</code> directly.
     *
     * @param proj the Projection
     * @return true if generated, false if didn't do it (maybe a
     *         problem).
     * @see #generate
     */
    public boolean regenerate(Projection proj) {
        boolean ret = false;

        if (proj != null) {

            ret = super.regenerate(proj);

            // handle extra case: OMRasterObject.getNeedToReposition()
            if (!ret && this instanceof OMRasterObject) {
                ret = generate(proj);
            }
        }

        return ret;
    }

    /**
     * Used by the GraphicAttributes object to provide a choice on
     * whether the line type choice can be changed.
     */
    protected boolean hasLineTypeChoice() {
        return true;
    }

    /**
     * Generic return of SinkGraphic for subclasses that don't
     * implement clone properly for some reason.
     */
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return SinkGraphic.getSharedInstance();
        }
    }

    /**
     * Write this object to a stream.
     */
    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();

        // Now write the Stroke. Take into account the stroke member
        // could be null.

        boolean writeStroke = (stroke != OMGraphic.BASIC_STROKE) && stroke != null;

        if (writeStroke) {
            // First write a flag indicating if a Stroke is on the
            // stream.
            oos.writeBoolean(true);
            if (stroke instanceof BasicStroke) {
                BasicStroke s = (BasicStroke) stroke;


                // Then write flag indicating stroke is a BasicStroke
                oos.writeBoolean(true);

                // Write the Stroke data if a Stroke is on this
                // object.
                if (s != null) {
                    oos.writeFloat(s.getLineWidth());
                    oos.writeInt(s.getEndCap());
                    oos.writeInt(s.getLineJoin());
                    oos.writeFloat(s.getMiterLimit());
                    oos.writeObject(s.getDashArray());
                    oos.writeFloat(s.getDashPhase());
                }
            } else if (stroke instanceof Serializable) {
                oos.writeBoolean(false);
                oos.writeObject((Serializable) stroke);
            }

        } else {
            oos.writeBoolean(false);
        }
    }

    /**
     * Read this object from a stream.
     */
    private void readObject(ObjectInputStream ois)
            throws ClassNotFoundException, IOException {
        ois.defaultReadObject();

        // Read the Stroke

        // Get the flag indicating a stroke was streamed
        boolean streamHasStroke = ois.readBoolean();

        // Read and create the stroke
        if (streamHasStroke) {
            boolean isBasicStroke = ois.readBoolean();
            if (isBasicStroke) {
                float linewidth = ois.readFloat();
                int endcap = ois.readInt();
                int linejoin = ois.readInt();
                float miterlimit = ois.readFloat();
                float dasharray[] = (float[]) ois.readObject();
                float dashphase = ois.readFloat();
                stroke = new BasicStroke(linewidth, endcap, linejoin, miterlimit, dasharray, dashphase);
            } else {
                stroke = (Stroke) ois.readObject();
            }
        } else {
            stroke = OMGraphic.BASIC_STROKE;
        }
    }

}
TOP

Related Classes of com.bbn.openmap.omGraphics.OMGraphic

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.