Re: [OpenMap Users] Re: ESRIPolygonRecord with holes

From: Don Dietrick <dietrick_at_bbn.com>
Date: Thu, 29 Jul 2004 17:20:11 -0400

On Jul 28, 2004, at 1:37 PM, Tore Halset wrote:

> Hello.
>
> Thanks! I am using this now, and it works very well. It would still be
> very nice to have a OMPoly that had support for holes. How can I
> control the linepaint of the hole polygons separatly from the exterior
> polygon?

You can't. I'd add a separate polyline with the different line color
on the inner or outer polygon.

- Don

> Perhaps the fix for BasicGeometry can be included in the standard
> distribution?
> On Jun 25, 2004, at 16:50, alexander sokolov wrote:
>
>> Hi Don,
>>
>> It seems I found a way to treat ESRIPolygonRecord with holes
>> correctly. We can use
>> OMAreaList instead of OMGraphicList to store OMPolys of the
>> ESRIRecord.
>> Modifications are very small (see the method addOMGraphics in
>> attached ESRIPolygonRecord.java)
>> and also we have to set
>>
>> firstPoint to true in appendShapeEdge in the BasicGeometry.java.
>>
>> This modifications works well for me but I am not sure about possible
>> side effects.
>>
>> What do you think about this?
>>
>> Regards
>>
>> Alexander
>>
>>
>>
>>
>> OpenMap Support wrote:
>>
>>> Hi Alexander,
>>>
>>> That's correct, holds aren't handled well for either class. The
>>> code would have to be modified to handle them.
>>>
>>> - Don
>>>
>>> On Jun 22, 2004, at 8:26 AM, alexander sokolov wrote:
>>>
>>>> Hi Don,
>>>>
>>>> I'm trying to work a with shape file of seas with islands and
>>>> it seems neither EsriLayer nor ShapeLayer support ESRI records with
>>>> holes.
>>>> I mean it seems openmap does not pay attention to the order of
>>>> polygon's vertices.
>>>> (clockwise or counterclockwise). Is it so and what we can do?
>>>>
>>>> Regards
>>>> Alexander
>>>>
>>>>
>>>
>>>
>>> =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>>> Don Dietrick, dietrick_at_bbn.com
>>> BBN Technologies, Cambridge, MA
>>> =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>>>
>> //
>> **********************************************************************
>> //
>> // <copyright>
>> //
>> // BBN Technologies, a Verizon Company
>> // 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/layer/shape/
>> ESRIPolygonRecord.java,v $
>> // $RCSfile: ESRIPolygonRecord.java,v $
>> // $Revision: 1.3 $
>> // $Date: 2004/01/26 18:18:11 $
>> // $Author: dietrick $
>> //
>> //
>> **********************************************************************
>>
>>
>> package com.bbn.openmap.layer.shape;
>>
>> import java.io.IOException;
>> import com.bbn.openmap.omGraphics.*;
>> import com.bbn.openmap.omGraphics.geom.*;
>> import com.bbn.openmap.proj.ProjMath;
>>
>> /**
>> * The Polygon record type. This class implements the ESRI Shapefile
>> * polygon AND arc/polyline record types.
>> * _at_author Ray Tomlinson
>> * _at_author Tom Mitchell <tmitchell_at_bbn.com>
>> * _at_author HACK-author blame it on aculline
>> * _at_version $Revision: 1.3 $ $Date: 2004/01/26 18:18:11 $
>> */
>> public class ESRIPolygonRecord extends ESRIRecord {
>>
>> /** Polygon or arc/polyline?. */
>> protected int shapeType = SHAPE_TYPE_POLYGON;
>>
>> /** The bounding box. */
>> public ESRIBoundingBox bounds;
>>
>> /** An array of polygons. */
>> public ESRIPoly[] polygons;
>>
>> public ESRIPolygonRecord() {
>> bounds = new ESRIBoundingBox();
>> polygons = new ESRIPoly[0];
>> }
>>
>> /**
>> * Initialize a polygon record from the given buffer.
>> *
>> * _at_param b the buffer
>> * _at_param off the offset into the buffer where the data starts
>> */
>> public ESRIPolygonRecord(byte b[], int off) throws IOException {
>> super(b, off);
>>
>> int ptr = off+8;
>>
>> shapeType = readLEInt(b, ptr);
>> ptr += 4;
>> if ((shapeType != SHAPE_TYPE_POLYGON) && (shapeType !=
>> SHAPE_TYPE_ARC)) {
>> throw new IOException("Invalid polygon record. Expected
>> shape " +
>> "type " + SHAPE_TYPE_POLYGON + " or
>> type " +
>> SHAPE_TYPE_ARC + ", but found " +
>> shapeType);
>> }
>> boolean ispolyg = isPolygon();
>>
>> bounds = readBox(b, ptr);
>> ptr += 32; // A box is 4 doubles (4 x 8bytes)
>>
>> int numParts = readLEInt(b, ptr);
>> ptr += 4;
>>
>> int numPoints = readLEInt(b, ptr);
>> ptr += 4;
>>
>> if (numParts <= 0) return;
>>
>> polygons = new ESRIPoly[numParts];
>> int origin = 0;
>> int _len;
>> for (int i = 0; i < numParts; i++) {
>>
>> int nextOrigin = readLEInt(b, ptr);
>> ptr += 4;
>>
>> if (i > 0) {
>> _len = nextOrigin - origin;
>> if (ispolyg) ++_len;//connect pairs
>> polygons[i-1] = new ESRIPoly.ESRIFloatPoly(_len);
>> }
>> origin = nextOrigin;
>> }
>> _len = numPoints - origin;
>> if (ispolyg) ++_len;//connect pairs
>> polygons[numParts-1] = new ESRIPoly.ESRIFloatPoly(_len);
>> for (int i = 0; i < numParts; i++) {
>> ptr += polygons[i].read(b, ptr, ispolyg);
>> }
>> }
>>
>> /**
>> * Is this a polygon or a arc/polyline?
>> * _at_return boolean
>> */
>> public boolean isPolygon() {
>> return shapeType == SHAPE_TYPE_POLYGON;
>> }
>>
>> /**
>> * Set the poly type (polygon or arc/polyline).
>> */
>> public void setPolygon(boolean isPolygon) {
>> shapeType = isPolygon ? SHAPE_TYPE_POLYGON : SHAPE_TYPE_ARC;
>> }
>>
>> /**
>> * Add a poly to the record.
>> * _at_param radians coordinates: y,x,y,x,... (lat,lon) order in
>> * RADIANS!
>> */
>> public void add(float radians[]) {
>> ESRIPoly newPoly = new ESRIPoly.ESRIFloatPoly(radians);
>>
>> int numParts = polygons.length;
>> ESRIPoly oldPolys[] = polygons;
>> polygons = new ESRIPoly[numParts + 1];
>> for (int i = 0; i < numParts; i++) {
>> polygons[i] = oldPolys[i];
>> }
>>
>> polygons[numParts] = newPoly;
>>
>> int len = radians.length;
>> for (int i=0; i<len; i+=2) {
>> // REMEMBER: switch to x,y order
>> bounds.addPoint(
>> ProjMath.radToDeg(radians[i+1]),//x (lon)
>> ProjMath.radToDeg(radians[i]));//y (lat)
>> }
>> }
>>
>> /**
>> * Generates 2D OMGraphics and adds them to the given list. If
>> * you are using jdk1.1.X, you'll have to comment out this method,
>> * because jdk1.1.X doesn't know about the java.awt.Stroke and
>> * java.awt.Paint interfaces.
>> *
>> * _at_param list the graphics list
>> * _at_param drawingAttributes the drawingAttributes to paint the
>> poly.
>> */
>> public void addOMGraphics(OMGraphicList list,
>> DrawingAttributes drawingAttributes) {
>>
>> int nPolys = polygons.length;
>> if (nPolys <= 0) return;
>> OMPoly p=null;
>> float[] pts;
>> boolean ispolyg = isPolygon();
>> /*
>> * modifications in the next 4 lines marked with as:
>> * allow to treat ESRIPolygonRecord with holes correctly
>> * (ESRIPolys with counterclockwise order of vertices)
>> *
>> * Note: we also have to set firstPoint to true in
>> * the BasinsGeometry.appendShapeEdge() (probably a bug)
>> * 2004-06-25
>> */
>> OMAreaList sublist = null; //as: was OMGraphicList sublist = null;
>>
>> if (nPolys > 1) {
>> sublist = new OMAreaList(10); //as: was OMGraphicList(10);
>> drawingAttributes.setTo(sublist); //as: new line
>>
>> sublist.setVague(true); // Treat list as one object.
>> list.add(sublist);
>> sublist.setAppObject(new Integer(getRecordNumber()));
>> }
>>
>> for (int i=0, j, k; i<nPolys; i++) {
>> // these points are already in RADIAN lat,lon order!...
>> pts = ((ESRIPoly.ESRIFloatPoly)polygons[i]).getRadians();
>> int len = pts.length;
>> p = new OMPoly(pts,
>> OMGraphic.RADIANS,
>> OMGraphic.LINETYPE_STRAIGHT);
>>
>> drawingAttributes.setTo(p);
>> if (!ispolyg) {
>> p.setIsPolygon(false);
>> }
>>
>> if (sublist != null) {
>> sublist.add(p);
>> } else {
>> // There should be only one.
>> p.setAppObject(new Integer(getRecordNumber()));
>> list.add(p);
>> }
>> }
>> }
>>
>> /**
>> * Generates OMGeometry and adds them to the given list.
>> *
>> * _at_param list the geometry list
>> */
>> public OMGeometry addOMGeometry(OMGeometryList list) {
>>
>> int nPolys = polygons.length;
>> if (nPolys <= 0) {
>> return null;
>> }
>>
>> float[] pts;
>> boolean ispolyg = isPolygon();
>> OMGeometry geom = null;
>>
>> for (int i=0, j, k; i<nPolys; i++) {
>> // these points are already in RADIAN lat,lon order!...
>> pts = ((ESRIPoly.ESRIFloatPoly)polygons[i]).getRadians();
>> int len = pts.length;
>> if (ispolyg) {
>>
>> geom = new PolygonGeometry.LL(pts,
>> OMGraphic.RADIANS,
>>
>> OMGraphic.LINETYPE_STRAIGHT);
>> } else {
>> geom = new PolylineGeometry.LL(pts,
>> OMGraphic.RADIANS,
>>
>> OMGraphic.LINETYPE_STRAIGHT);
>> }
>> list.add(geom);
>> }
>> return geom;
>> }
>>
>> /**
>> * Gets this record's bounding box.
>> *
>> * _at_return a bounding box
>> */
>> public ESRIBoundingBox getBoundingBox() {
>> return bounds;
>> }
>>
>> /**
>> * Gets this record's shape type as an int. Shape types
>> * are enumerated on the ShapeUtils class.
>> *
>> * _at_return the shape type as an int (either SHAPE_TYPE_POLYGON or
>> * SHAPE_TYPE_ARC)
>> */
>> public int getShapeType() {
>> return shapeType;
>> }
>>
>> /**
>> * Yields the length of this record's data portion.
>> * <p>
>> * (44 + (numParts * 4) + (numPoints * 16))
>> * <br>
>> * 3 Integers + 4 doubles == 3 * 4bytes + 4 * 8bytes == 12 + 32
>> == 44.
>> *
>> * _at_return number of bytes equal to the size of this record's data
>> */
>> public int getRecordLength() {
>> int numParts = polygons.length;
>> int numPoints = 0;
>> for (int i = 0; i < numParts; i++) {
>> numPoints += polygons[i].nPoints;
>> }
>> return (44 + (numParts * 4) + (numPoints * 16));
>> }
>>
>> /**
>> * Writes this polygon to the given buffer at the given offset.
>> *
>> * _at_param b the buffer
>> * _at_param off the offset
>> * _at_return the number of bytes written
>> */
>> public int write(byte[] b, int off) {
>> int nBytes = super.write(b, off);
>> nBytes += writeLEInt(b, off + nBytes, shapeType);
>> // bounds
>> nBytes += writeBox(b, off + nBytes, bounds);
>> // numparts
>> int numParts = polygons.length;
>> nBytes += writeLEInt(b, off + nBytes, numParts);
>> // numpoints
>> int numPoints = 0;
>> for (int i = 0; i < numParts; i++) {
>> numPoints += polygons[i].nPoints;
>> }
>> nBytes += writeLEInt(b, off + nBytes, numPoints);
>> // parts
>> int ptr = 0;
>> for (int i = 0; i < numParts; i++) {
>> nBytes += writeLEInt(b, off + nBytes, ptr);
>> ptr += polygons[i].nPoints;
>> }
>>
>> // points
>> for (int i = 0; i < numParts; i++) {
>> // REMEMBER: stored internally as y,x order (lat,lon
>> order)
>> float[] pts =
>> ((ESRIPoly.ESRIFloatPoly)polygons[i]).getRadians();
>> int nPts = pts.length;
>> for (int j=0; j<nPts; j+=2) {
>> nBytes += writeLEDouble(
>> b, off + nBytes,
>> (double)ProjMath.radToDeg(pts[j+1]));//x (lon)
>> nBytes += writeLEDouble(
>> b, off + nBytes,
>> (double)ProjMath.radToDeg(pts[j]));//y (lat)
>> }
>> }
>>
>> // return number of bytes written
>> return nBytes;
>> }
>> }
>> //
>> **********************************************************************
>> //
>> // <copyright>
>> //
>> // BBN Technologies, a Verizon Company
>> // 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/geom/
>> BasicGeometry.java,v $
>> // $RCSfile: BasicGeometry.java,v $
>> // $Revision: 1.8 $
>> // $Date: 2004/01/26 18:18:13 $
>> // $Author: dietrick $
>> //
>> //
>> **********************************************************************
>>
>>
>> package com.bbn.openmap.omGraphics.geom;
>>
>> import com.bbn.openmap.omGraphics.OMGeometry;
>> import com.bbn.openmap.omGraphics.OMGraphicConstants;
>> import com.bbn.openmap.proj.*;
>> import com.bbn.openmap.util.Debug;
>>
>> import java.awt.*;
>> import java.awt.geom.*;
>> import java.io.Serializable;
>>
>> /**
>> * Base class implementation of OpenMap OMGeometry. <p>
>> *
>> * The geometry classes are intended to pull the object location data
>> * out of the OMGraphics. If you have a bunch of OMGraphics that are
>> * all rendered with common attributes, you can create a bunch of
>> * OMGeometry objects to plavce in a OMGeometryList that will render
>> * them all alike.
>> *
>> * _at_see PolygonGeometry
>> * _at_see PolylineGeometry
>> * _at_see com.bbn.openmap.omGraphics.OMGeometryList
>> * _at_see Projection
>> */
>> public abstract class BasicGeometry
>> implements OMGeometry, Serializable, OMGraphicConstants {
>>
>> /**
>> * The lineType describes the way a line will be drawn between
>> * points. LINETYPE_STRAIGHT will mean the line is drawn straight
>> * between the pixels of the endpoints of the line, across the
>> * window. LINETYPE_GREATCIRCLE means the line will be drawn on
>> the
>> * window representing the shortest line along the
>> * land. LINETYPE_RHUMB means a line will be drawn along a
>> constant
>> * bearing between the two points.
>> */
>> protected int lineType = LINETYPE_UNKNOWN;
>>
>> /** Flag to indicate that the object needs to be reprojected. */
>> protected boolean needToRegenerate = true;
>>
>> /**
>> * Space for an application to associate geometry with an
>> * application object. This object can contain attribute
>> * information about the geometry.
>> *
>> * _at_see #setAppObject
>> * _at_see #getAppObject
>> */
>> protected Object appObject;
>>
>> /**
>> * A flag to render this geometry visible.
>> */
>> protected boolean visible = true;
>>
>> /**
>> * The Java 2D containing the Shape of the Graphic. There may be
>> * an array of them, in case the graphic wraps around the earth,
>> * and we need to show the other edge of the graphic on the other
>> * side of the earth.
>> */
>> protected transient GeneralPath shape = null;
>>
>> //////////////////////////////////////////////////////////
>>
>> /**
>> * Set the line type for the graphic, which will affect how the
>> * lines will be drawn. See the definition of the lineType
>> * parameter. Accepts LINETYPE_RHUMB, LINETYPE_STRAIGHT and
>> * LINETYPE_GREATCIRCLE. Any weird values get set to
>> * LINETYPE_STRAIGHT.
>> *
>> * _at_param value the line type of the graphic.
>> * */
>> public void setLineType(int value) {
>> if (lineType == value) return;
>> setNeedToRegenerate(true); // flag dirty
>>
>> lineType = value;
>> }
>>
>> /**
>> * Return the line type.
>> *
>> * _at_return the linetype - LINETYPE_RHUMB, LINETYPE_STRAIGHT,
>> * LINETYPE_GREATCIRCLE or LINETYPE_UNKNOWN.
>> */
>> public int getLineType() {
>> return lineType;
>> }
>>
>> /**
>> * Return the render type.
>> *
>> * _at_return the rendertype of the object - RENDERTYPE_LATLON,
>> * RENDERTYPE_XY, RENDERTYPE_OFFSET and RENDERTYPE_UNKNOWN.
>> */
>> public abstract int getRenderType();
>>
>> /**
>> * Sets the regenerate flag for the graphic.
>> * This flag is used to determine if extra work needs to be done
>> * to prepare the object for rendering.
>> *
>> * _at_param value boolean
>> */
>> public void setNeedToRegenerate(boolean value) {
>> needToRegenerate = value;
>> if (value == true) {
>> shape = null;
>> }
>> }
>>
>> /**
>> * Return the regeneration status.
>> *
>> * _at_return boolean
>> */
>> public boolean getNeedToRegenerate() {
>> return needToRegenerate;
>> }
>>
>> /**
>> * Set the visibility variable.
>> * NOTE:<br>
>> * This is checked by the OMGeometryList when it iterates through
>> its list
>> * for render and gesturing. It is not checked by the internal
>> OMGeometry
>> * methods, although maybe it should be...
>> *
>> * _at_param visible boolean
>> */
>> public void setVisible(boolean visible) {
>> this.visible = visible;
>> }
>>
>> /**
>> * Get the visibility variable.
>> *
>> * _at_return boolean
>> */
>> public boolean isVisible() {
>> return visible;
>> }
>>
>> /**
>> * Let the geometry object know it's selected. No action
>> mandated.
>> */
>> public void select() {}
>>
>> /**
>> * Let the geometry object know it's deselected. No action
>> mandated.
>> */
>> public void deselect() {}
>>
>> /**
>> * Holds an application specific object for later access.
>> * This can be used to associate an application object with
>> * an OMGeometry for later retrieval. For instance, when
>> * the graphic is clicked on, the application gets the OMGeometry
>> * object back from the OMGeometryList, and can then get back
>> * to the application level object through this pointer.
>> *
>> * _at_param obj Object
>> */
>> public synchronized void setAppObject(Object obj) {
>> appObject = obj;
>> }
>>
>> /**
>> * Gets the application's object pointer.
>> *
>> * _at_return Object
>> */
>> public synchronized Object getAppObject() {
>> return appObject;
>> }
>>
>> /////////////////////////////////////////////////////////////////////
>> /////
>>
>> /**
>> * Prepare the geometry 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>
>> *
>> * _at_param proj Projection
>> * _at_return boolean true if successful, false if not.
>> * _at_see #regenerate
>> */
>> public abstract boolean generate(Projection proj);
>>
>> /**
>> *
>> */
>> public boolean isRenderable() {
>> return (!getNeedToRegenerate() &&
>> isVisible() && shape != null);
>> }
>>
>> /**
>> * Paint the graphic, as a filled shape. <P>
>> *
>> * 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 or if it isn't visible, it will not be
>> * rendered. <P>
>> *
>> * This method used to be abstract, but with the conversion of
>> * OMGeometrys to internally represent themselves as
>> java.awt.Shape
>> * objects, it's a more generic method. If the OMGeometry hasn't
>> * been updated to use Shape objects, it should have its own
>> * render method.
>> *
>> * _at_param g Graphics2D context to render into.
>> */
>> public void fill(Graphics g) {
>> if (isRenderable()) {
>> ((Graphics2D)g).fill(shape);
>> }
>> }
>>
>> /**
>> * Paint the graphic, as an outlined shape. <P>
>> *
>> * 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 or if it isn't visible, it will not be
>> * rendered. <P>
>> *
>> * This method used to be abstract, but with the conversion of
>> * OMGeometrys to internally represent themselves as
>> java.awt.Shape
>> * objects, it's a more generic method. If the OMGeometry hasn't
>> * been updated to use Shape objects, it should have its own
>> * render method.
>> *
>> * _at_param g Graphics2D context to render into.
>> */
>> public void draw(Graphics g) {
>> if (isRenderable()) {
>> ((Graphics2D)g).draw(shape);
>> }
>> }
>>
>> /**
>> * Return the shortest distance from the edge of a graphic to an
>> * XY-point. <p>
>> *
>> * _at_param x X coordinate of the point.
>> * _at_param y Y coordinate of the point.
>> * _at_return float distance, in pixels, from graphic to the point.
>> * Returns Float.POSITIVE_INFINITY if the graphic isn't ready
>> * (ungenerated).
>> */
>> public float distanceToEdge(int x, int y) {
>> float temp, distance = Float.POSITIVE_INFINITY;
>>
>> if (getNeedToRegenerate() || shape == null) {
>> return distance;
>> }
>>
>> PathIterator pi2 = shape.getPathIterator(null);
>> FlatteningPathIterator pi = new FlatteningPathIterator(pi2,
>> .25);
>> double[] coords = new double[6];
>> int count = 0;
>> double startPntX = 0;
>> double startPntY = 0;
>> double endPntX = 0;
>> double endPntY = 0;
>>
>> while (!pi.isDone()) {
>> int type = pi.currentSegment(coords);
>> float dist;
>>
>> if (type == PathIterator.SEG_LINETO) {
>> startPntX = endPntX;
>> startPntY = endPntY;
>> endPntX = coords[0];
>> endPntY = coords[1];
>>
>> dist = (float) Line2D.ptSegDist(startPntX, startPntY,
>> endPntX, endPntY, (double)x, (double)y);
>>
>> if (dist < distance) {
>> distance = dist;
>> }
>>
>> if (Debug.debugging("omgraphicdetail")) {
>> Debug.output("Type: " + type + "(" +
>> (count++) + "), " +
>> startPntX + ", " + startPntY + ", " +
>> endPntX + ", " + endPntY + ", " +
>> x + ", " + y +
>> ", distance: " + distance);
>> }
>>
>> } else {
>>
>> // This should be the first and last
>> // condition, SEG_MOVETO and SEG_CLOSE
>> startPntX = coords[0];
>> startPntY = coords[1];
>> endPntX = coords[0];
>> endPntY = coords[1];
>> }
>>
>> pi.next();
>> }
>>
>> return distance;
>> }
>>
>> /**
>> * Return the shortest distance from the graphic to an
>> * XY-point. Checks to see of the point is contained within the
>> * OMGraphic, which may, or may not be the right thing for clear
>> * OMGraphics or lines.<p>
>> *
>> * This method used to be abstract, but with the conversion of
>> * OMGeometrys to internally represent themselves as
>> java.awt.Shape
>> * objects, it's a more generic method. If the OMGeometry hasn't
>> * been updated to use Shape objects, it should have its own
>> * distance method.<p>
>> *
>> * Calls _distance(x, y);
>> *
>> * _at_param x X coordinate of the point.
>> * _at_param y Y coordinate of the point.
>> * _at_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) {
>> return _distance(x, y);
>> }
>>
>> /**
>> * Return the shortest distance from the graphic to an
>> * XY-point. Checks to see of the point is contained within the
>> * OMGraphic, which may, or may not be the right thing for clear
>> * OMGraphics or lines.<p>
>> *
>> * _distance was added so subclasses could make this call if their
>> * geometries/attributes require this action (when fill color
>> * doesn't matter).
>> *
>> * _at_param x X coordinate of the point.
>> * _at_param y Y coordinate of the point.
>> * _at_return float distance, in pixels, from graphic to the point.
>> * Returns Float.POSITIVE_INFINITY if the graphic isn't ready
>> * (ungenerated).
>> */
>> protected float _distance(int x, int y) {
>> float temp, distance = Float.POSITIVE_INFINITY;
>>
>> if (getNeedToRegenerate() || shape == null) {
>> return distance;
>> }
>>
>> if (shape.contains((double)x, (double)y)) {
>> // if (Debug.debugging("omgraphicdetail")) {
>> // Debug.output(" contains " + x + ", " + y);
>> // }
>> return 0f;
>> } else {
>> return distanceToEdge(x, y);
>> }
>> }
>>
>> /**
>> * Answsers the question whether or not the OMGeometry contains
>> * the given pixel point.
>> * <P>
>> * This method used to be abstract, but with the conversion of
>> * OMGeometrys to internally represent themselves as
>> java.awt.Shape
>> * objects, it's a more generic method. If the OMGeometry hasn't
>> * been updated to use Shape objects, it should have its own
>> * contains method.
>> * <P>
>> * This method duplicates a java.awt.Shape method, with some
>> * protection wrapped around it. If you have other queries for
>> * the internal Shape object, just ask for it and then ask it
>> * directly. This method is provided because it is the most
>> * useful, used when determining if a mouse event is occuring over
>> * an object on the map.
>> *
>> * _at_param x X pixel coordinate of the point.
>> * _at_param y Y pixel coordinate of the point.
>> * _at_return getShape().contains(x, y), false if the OMGraphic
>> * hasn't been generated yet.
>> */
>> public boolean contains(int x, int y) {
>> Shape shape = getShape();
>> boolean ret = false;
>>
>> if (shape != null) {
>> ret = shape.contains((double)x, (double)y);
>> }
>>
>> return ret;
>> }
>>
>> /**
>> * 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.
>> *
>> * _at_param proj the Projection
>> * _at_return true if generated, false if didn't do it (maybe a
>> * problem).
>> * _at_see #generate
>> */
>> public boolean regenerate(Projection proj) {
>> if (proj == null) {
>> return false;
>> }
>>
>> if (getNeedToRegenerate()) {
>> return generate(proj);
>> }
>>
>> return false;
>> }
>>
>> /**
>> * Get the java.awt.Shape object that represents the projected
>> * graphic. The array will one Shape object even if the object
>> * wraps around the earth and needs to show up in more than one
>> * place on the map. In conditions like that, the Shape will have
>> * multiple parts.<p>
>> *
>> * The java.awt.Shape object gives you the ability to do a little
>> * spatial analysis on the graphics.
>> *
>> * _at_return java.awt.geom.GeneralPath (a java.awt.Shape object), or
>> * null if the graphic needs to be generated with the current map
>> * projection, or null if the OMGeometry hasn't been updated to
>> * use Shape objects for its internal representation.
>> */
>> public GeneralPath getShape() {
>> return shape;
>> }
>>
>> /**
>> * Set the java.awt.Shape object that represents the projected
>> * graphic. This Shape object should be internally generated, but
>> * this method is provided to clear out the object to save memory,
>> * or to allow a little customization if your requirements
>> * dictate.<p>
>> *
>> * The java.awt.Shape object gives you the ability to do a little
>> * spatial analysis on the graphics.
>> *
>> * _at_param gp java.awt.geom.GeneralPath, or null if the graphic
>> * needs to be generated with the current map projection or to
>> * clear out the object being held by the OMGeometry.
>> */
>> public void setShape(GeneralPath gp) {
>> shape = gp;
>> }
>>
>> /**
>> * Create a Shape object given an array of x points and y points.
>> * The x points a y points should be projected. This method is
>> * used by subclasses that get projected coordinates out of the
>> * projection classes, and they need to build a Shape object from
>> * those coordinates.
>> * _at_param xpoints projected x coordinates
>> * _at_param ypoints projected y coordinates
>> * _at_param isPolygon whether the points make up a polygon, or a
>> * polyline. If it's true, the Shape object returned is a
>> * Polygon. If false, the Shape returned is a GeneralPath object.
>> * _at_return The Shape object for the points.
>> */
>> public static GeneralPath createShape(int xpoints[], int
>> ypoints[], boolean isPolygon) {
>> return createShape(xpoints, ypoints, 0, xpoints.length,
>> isPolygon);
>> }
>>
>> /**
>> * Create a Shape object given an array of x points and y points.
>> * The x points a y points should be projected. This method is
>> * used by subclasses that get projected coordinates out of the
>> * projection classes, and they need to build a Shape object from
>> * those coordinates.
>> * _at_param xpoints projected x coordinates
>> * _at_param ypoints projected y coordinates
>> * _at_param startIndex the starting coordinate index in the array.
>> * _at_param length the number of points to use from the array for
>> the shape.
>> * _at_param isPolygon whether the points make up a polygon, or a
>> * polyline. If it's true, the Shape object returned is a
>> * Polygon. If false, the Shape returned is a GeneralPath object.
>> * _at_return The Shape object for the points.
>> */
>> public static GeneralPath createShape(int xpoints[], int
>> ypoints[],
>> int startIndex, int length,
>> boolean isPolygon) {
>> // used to return a Shape
>>
>> if (xpoints == null || ypoints == null) {
>> return null;
>> }
>>
>> if (startIndex < 0) {
>> startIndex = 0;
>> }
>>
>> if (length > xpoints.length - startIndex) {
>> // Do as much as you can...
>> length = xpoints.length - startIndex - 1;
>> }
>>
>> GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
>> length);
>>
>> if (length > startIndex) {
>> path.moveTo(xpoints[startIndex], ypoints[startIndex]);
>> for (int j = startIndex + 1; j < length; j++) {
>> path.lineTo(xpoints[j], ypoints[j]);
>> }
>>
>> if (isPolygon) {
>> path.closePath();
>> }
>> }
>>
>> return path;
>> }
>>
>> /**
>> * Utility method that iterates over a Shape object and prints
>> out the points.
>> */
>> public static void describeShapeDetail(Shape shape) {
>> describeShapeDetail(shape, .25);
>> }
>>
>> /**
>> * Utility method that iterates over a Shape object and prints out
>> * the points. The flattening is used for a
>> * FlatteningPathIterator, controlling the scope of the path
>> * traversal.
>> */
>> public static void describeShapeDetail(Shape shape, double
>> flattening) {
>> PathIterator pi2 = shape.getPathIterator(null);
>> FlatteningPathIterator pi = new FlatteningPathIterator(pi2,
>> flattening);
>> double[] coords = new double[6];
>> int pointCount = 0;
>>
>> Debug.output(" -- start describeShapeDetail with flattening["
>> + flattening + "]");
>> while (!pi.isDone()) {
>> int type = pi.currentSegment(coords);
>> Debug.output(" Shape point [" + type + "] (" +
>> (pointCount++) + ") " +
>> coords[0] + ", " + coords[1]);
>> pi.next();
>> }
>>
>> Debug.output(" -- end (" + pointCount + ")");
>> }
>>
>> /**
>> * Convenience method to add the coordinates to the given
>> * GeneralPath. You need to close the path yourself if you want
>> * it to be a polygon.
>> * _at_param toShape the GeneralPath Shape object to add the
>> coordinates to.
>> * _at_param xpoints horizontal pixel coordiantes.
>> * _at_param ypoints vertical pixel coordiantes.
>> * _at_return toShape, with coordinates appended.
>> */
>> public static GeneralPath appendShapeEdge(GeneralPath toShape,
>> int xpoints[], int
>> ypoints[]) {
>> return appendShapeEdge(toShape, xpoints, ypoints, 0,
>> xpoints.length);
>> }
>>
>> /**
>> * Convenience method to add the coordinates to the given
>> * GeneralPath. You need to close the path yourself if you want
>> * it to be a polygon.
>> * _at_param toShape the GeneralPath Shape object to add the
>> coordinates to.
>> * _at_param xpoints horizontal pixel coordiantes.
>> * _at_param ypoints vertical pixel coordiantes.
>> * _at_param startIndex the index into pixel coordinate array to
>> start reading from.
>> * _at_param length the number of coordinates to add.
>> * _at_return toShape, with coordinates appended.
>> */
>> public static GeneralPath appendShapeEdge(GeneralPath toShape,
>> int xpoints[], int
>> ypoints[],
>> int startIndex, int
>> length) {
>> return appendShapeEdge(toShape, createShape(xpoints, ypoints,
>> startIndex, length, false));
>> }
>>
>> /**
>> * Convenience method to append the edge of a GeneralPath Shape to
>> * another GeneralPath Shape. A PathIterator is used to figure
>> * out the points to use to add to the toShape. You need to close
>> * the path yourself if you want it to be a polygon.
>> * _at_param toShape the GeneralPath Shape object to add the edge to.
>> * _at_param addShape the GeneralPath Shape to add to the toShape.
>> * _at_return toShape, with coordinates appended. Returns addShape
>> * if toShape was null.
>> */
>> public static GeneralPath appendShapeEdge(GeneralPath toShape,
>> GeneralPath addShape) {
>>
>> boolean DEBUG = Debug.debugging("arealist");
>> int pointCount = 0;
>> boolean firstPoint = true; //as: was false;
>> // See
>> ESRIPolygonRecord.addOMGraphics
>>
>> // If both null, return null.
>> if (addShape == null) {
>> return toShape;
>> }
>>
>> if (toShape == null) {
>> return addShape;
>> }
>>
>> PathIterator pi2 = addShape.getPathIterator(null);
>> FlatteningPathIterator pi = new FlatteningPathIterator(pi2,
>> .25);
>> double[] coords = new double[6];
>>
>> while (!pi.isDone()) {
>> int type = pi.currentSegment(coords);
>> if (firstPoint) {
>> if (DEBUG) {
>> Debug.output("Creating new shape, first point " +
>> (float)coords[0] + ", " +
>> (float)coords[1]);
>> }
>> toShape.moveTo((float)coords[0], (float)coords[1]);
>> firstPoint = false;
>> } else {
>> if (DEBUG) {
>> Debug.output(" adding point [" + type + "] (" +
>> (pointCount++) + ") " +
>> (float)coords[0] + ", " +
>> (float)coords[1]);
>> }
>> toShape.lineTo((float)coords[0], (float)coords[1]);
>> }
>> pi.next();
>> }
>>
>> if (DEBUG) {
>> Debug.output(" -- end point (" + pointCount + ")");
>> }
>>
>> return toShape;
>> }
>>
>>
>> /**
>> * Create a general path from a point plus a height and width;
>> */
>> public static GeneralPath createBoxShape(int x, int y, int width,
>> int height) {
>> int[] xs = new int[4];
>> int[] ys = new int[4];
>>
>> xs[0] = x;
>> ys[0] = y;
>> xs[1] = x + width;
>> ys[1] = y;
>> xs[2] = x + width;
>> ys[2] = y + height;
>> xs[3] = x;
>> ys[3] = y + height;
>>
>> return createShape(xs, ys, true);
>> }
>> }
>
> --
> [To unsubscribe to this list send an email to "majdart_at_bbn.com"
> with the following text in the BODY of the message "unsubscribe
> openmap-users"]
>
>


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Don Dietrick, dietrick_at_bbn.com
BBN Technologies, Cambridge, MA
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

--
[To unsubscribe to this list send an email to "majdart_at_bbn.com"
with the following text in the BODY of the message "unsubscribe openmap-users"]
Received on Thu Jul 29 2004 - 17:22:06 EDT

This archive was generated by hypermail 2.3.0 : Tue Mar 28 2017 - 23:25:05 EDT