0001: /* uDig - User Friendly Desktop Internet GIS client
0002: * http://udig.refractions.net
0003: * (C) 2004, Refractions Research Inc.
0004: *
0005: * This library is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU Lesser General Public
0007: * License as published by the Free Software Foundation;
0008: * version 2.1 of the License.
0009: *
0010: * This library is distributed in the hope that it will be useful,
0011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013: * Lesser General Public License for more details.
0014: */
0015: package net.refractions.udig.tools.edit.support;
0016:
0017: import java.awt.Rectangle;
0018: import java.awt.Shape;
0019: import java.awt.geom.AffineTransform;
0020: import java.awt.geom.GeneralPath;
0021: import java.awt.geom.PathIterator;
0022: import java.awt.geom.Point2D;
0023: import java.awt.geom.Rectangle2D;
0024: import java.util.ArrayList;
0025: import java.util.Collections;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.ListIterator;
0031: import java.util.Map;
0032: import java.util.Set;
0033: import java.util.concurrent.atomic.AtomicReference;
0034:
0035: import org.eclipse.jface.viewers.IContentProvider;
0036: import org.eclipse.jface.viewers.TreeViewer;
0037: import org.eclipse.jface.viewers.Viewer;
0038:
0039: import net.refractions.udig.project.ui.internal.LayersView;
0040: import net.refractions.udig.tools.edit.EditPlugin;
0041: import net.refractions.udig.tools.edit.preferences.PreferenceUtil;
0042:
0043: import com.vividsolutions.jts.geom.Coordinate;
0044: import com.vividsolutions.jts.geom.Envelope;
0045:
0046: /**
0047: * Represents the simplest shape. GeomShapes are made up of PrimitiveShapes.
0048: * <p>
0049: * This is not a composite pattern.
0050: * </p>
0051: *
0052: * @author jones
0053: * @since 1.1.0
0054: */
0055: public class PrimitiveShape implements Iterable<Point>, Shape {
0056: private Map<Point, List<PointCoordMap>> pointsToModel = new HashMap<Point, List<PointCoordMap>>();
0057: private Map<LazyCoord, PointCoordMap> coordsToModel = new HashMap<LazyCoord, PointCoordMap>();
0058: private List<PointCoordMap> points = new ArrayList<PointCoordMap>();
0059: private final List<LazyCoord> coordinates = new ArrayList<LazyCoord>();
0060: private final AtomicReference<Mutator> mutable = new AtomicReference<Mutator>();
0061: private final EditGeom owner;
0062: private Envelope envelope;
0063:
0064: public PrimitiveShape(EditGeom owner) {
0065: this .owner = owner;
0066: }
0067:
0068: public PrimitiveShape(PrimitiveShape shape) {
0069: this (shape.owner);
0070: points.addAll(shape.points);
0071: for (LazyCoord coord : shape.coordinates) {
0072: coordinates.add(new LazyCoord(coord));
0073: }
0074: }
0075:
0076: public int getNumPoints() {
0077: return points.size();
0078: }
0079:
0080: public Point getPoint(int i) {
0081: return points.get(i).point;
0082: }
0083:
0084: public int getNumCoords() {
0085: return coordinates.size();
0086: }
0087:
0088: public Coordinate getCoord(int i) {
0089: LazyCoord coord = coordinates.get(i);
0090: Point point = coordsToModel.get(coord).point;
0091: return coord.get(point);
0092: }
0093:
0094: @Override
0095: public String toString() {
0096: if (points.size() == 0)
0097: return "[]"; //$NON-NLS-1$
0098: StringBuffer buffer = new StringBuffer("["); //$NON-NLS-1$
0099: for (PointCoordMap point : points) {
0100: buffer.append(point.point.toString());
0101: buffer.append(","); //$NON-NLS-1$
0102: }
0103: buffer.deleteCharAt(buffer.length() - 1);
0104: buffer.append("]"); //$NON-NLS-1$
0105: return buffer.toString();
0106: }
0107:
0108: Mutator getMutator() {
0109: // Since all copies of a mutable do the same thing this race condition doesn't matter.
0110: if (mutable.get() == null)
0111: mutable.set(new Mutator());
0112: return mutable.get();
0113: }
0114:
0115: class Mutator implements Iterable<Point> {
0116:
0117: /**
0118: * Adds a point and its corresponding coordinate
0119: *
0120: * @param p point to add
0121: * @param coords corresponding coordinate or null.
0122: */
0123: public void addPoint(Point p, List<Coordinate> coords) {
0124: addPoint(points.size(), p, coords);
0125: }
0126:
0127: /**
0128: * Adds a point and its corresponding coordinate
0129: *
0130: * @param i index of point location. Coordinate will be added as the last of the coordinates
0131: * at that location.
0132: * @param p point to add
0133: * @param coords corresponding coordinate or null.
0134: */
0135: public List<LazyCoord> addPoint(int i, Point p,
0136: List<Coordinate> coords) {
0137: List<Coordinate> c = coords;
0138: PointCoordMap bag = getBag(i, p);
0139: if (c == null)
0140: c = Collections.singletonList(getEditBlackboard()
0141: .toCoord(p));
0142: List<LazyCoord> lazyCoords = addAll(bag.coords.size(),
0143: bag.coords, p, c);
0144: List<PointCoordMap> bags = pointsToModel.get(p);
0145: if (bags == null) {
0146: bags = new ArrayList<PointCoordMap>();
0147: pointsToModel.put(p, bags);
0148: }
0149: if (!bags.contains(bag))
0150: bags.add(bag);
0151:
0152: int index;
0153: if (coordinates.size() == 0)
0154: index = 0;
0155: else if (bag.coords.size() > 1) {
0156: LazyCoord lazyCoord = bag.coords
0157: .get(bag.coords.size() - 2);
0158: index = coordinates.indexOf(lazyCoord) + 1;
0159: } else if (i == 0) {
0160: index = 0;
0161: } else {
0162: // add after last coordinate in last bag
0163: PointCoordMap lastbag = points.get(i - 1);
0164: if (lastbag == bag)
0165: lastbag = points.get(i - 2);
0166:
0167: index = coordinates.indexOf(lastbag.coords
0168: .get(lastbag.coords.size() - 1)) + 1;
0169: }
0170:
0171: for (LazyCoord coord : lazyCoords) {
0172: coordinates.add(index++, coord);
0173: coordsToModel.put(coord, bag);
0174: }
0175: if (!owner.initializing)
0176: getEditGeom().setChanged(true);
0177: return lazyCoords;
0178: }
0179:
0180: private List<LazyCoord> addAll(int i,
0181: List<LazyCoord> coordinates, Point p, List<Coordinate> c) {
0182: int j = i;
0183: EditBlackboard bb = getEditBlackboard();
0184: ArrayList<LazyCoord> coords = new ArrayList<LazyCoord>(c
0185: .size());
0186: for (Coordinate coordinate : c) {
0187: LazyCoord lazyCoord = new LazyCoord(p, coordinate, bb);
0188: coordinates.add(j++, lazyCoord);
0189: coords.add(lazyCoord);
0190: }
0191: return coords;
0192: }
0193:
0194: private PointCoordMap getBag(int i, Point p) {
0195: // if previous point or next point is same as point to add then return that bag
0196: if (i > 0 && i <= points.size()) {
0197: if (points.get(i - 1).point.equals(p)) {
0198: return points.get(i - 1);
0199: }
0200: if (points.size() > i + 1
0201: && points.get(i + 1).point.equals(p)) {
0202: return points.get(i + 1);
0203: }
0204: }
0205: PointCoordMap bag = new PointCoordMap(p);
0206: points.add(i, bag);
0207: return bag;
0208: }
0209:
0210: /**
0211: * Adds a coordinate
0212: *
0213: * @param i index of coordinate to add.
0214: * @param c corresponding coordinate or null.
0215: */
0216: public void addCoordinate(int i, Coordinate c) {
0217: Point p = getEditBlackboard().toPoint(c);
0218: coordinates
0219: .add(i, new LazyCoord(p, c, getEditBlackboard()));
0220: // /TODO
0221: getEditGeom().setChanged(true);
0222: }
0223:
0224: /**
0225: * Remove a point and all the coordinates mapping to it.
0226: *
0227: * @param i index of point to remove
0228: */
0229: public Point removePoint(int i) {
0230: PointCoordMap p = points.remove(i);
0231: pointsToModel.remove(p.point);
0232: List<LazyCoord> coords = p.coords;
0233: for (LazyCoord coord : coords) {
0234: for (Iterator<LazyCoord> iter = coordinates.iterator(); iter
0235: .hasNext();) {
0236: if (iter.next() == coord) {
0237: iter.remove();
0238: }
0239: }
0240: }
0241: getEditGeom().setChanged(true);
0242: return p.point;
0243: }
0244:
0245: /**
0246: * Remove a coordinate at location i. Mapped points will be deleted too.
0247: *
0248: * @param i index of coordinate to remove
0249: */
0250: public Coordinate removeCoordinate(int i) {
0251: getEditGeom().setChanged(true);
0252: LazyCoord coord = coordinates.remove(i);
0253: return coord.get(coordsToModel.get(coord).point);
0254: }
0255:
0256: /**
0257: * Remove a point and all the coordinates mapping to it.
0258: */
0259: public boolean remove(Point p) {
0260: List<PointCoordMap> mods = pointsToModel.get(p);
0261: if (mods == null || mods.size() == 0)
0262: return false;
0263:
0264: int min = Integer.MAX_VALUE;
0265: int firstBag = 0;
0266: int current = 0;
0267: for (Iterator<PointCoordMap> iter = mods.iterator(); iter
0268: .hasNext();) {
0269: PointCoordMap element = iter.next();
0270: int i = points.indexOf(element);
0271: if (i < min) {
0272: min = i;
0273: firstBag = current;
0274: }
0275: current++;
0276: }
0277:
0278: PointCoordMap shapePoint = mods.remove(firstBag);
0279: points.remove(shapePoint);
0280: coordinates.removeAll(shapePoint.coords);
0281: getEditGeom().setChanged(true);
0282: return true;
0283: }
0284:
0285: /**
0286: * Remove a coordinate at location i. Mapped points will be deleted too.
0287: *
0288: * @param i index of coordinate to remove
0289: */
0290: public boolean remove(Coordinate c) {
0291: getEditGeom().setChanged(true);
0292: return coordinates.remove(c);
0293: }
0294:
0295: public LazyCoord removePoint(int pointIndex, Coordinate coord) {
0296:
0297: PointCoordMap p = points.get(pointIndex);
0298: LazyCoord lcoord = null;
0299: for (Iterator<LazyCoord> iter = p.coords.iterator(); iter
0300: .hasNext();) {
0301: LazyCoord lc = iter.next();
0302: if (lc.coord.equals(coord)) {
0303: lcoord = lc;
0304: iter.remove();
0305: break;
0306: }
0307: }
0308:
0309: if (p.coords.isEmpty()) {
0310: points.remove(pointIndex);
0311: List<PointCoordMap> bags = pointsToModel.get(p.point);
0312: bags.remove(p);
0313: if (bags.isEmpty())
0314: pointsToModel.remove(p.point);
0315: }
0316:
0317: if (lcoord == null)
0318: return null;
0319:
0320: for (Iterator<LazyCoord> iter = coordinates.iterator(); iter
0321: .hasNext();) {
0322: LazyCoord next = iter.next();
0323: if (next == lcoord) {
0324: iter.remove();
0325: coordsToModel.remove(next);
0326: }
0327: }
0328: getEditGeom().setChanged(true);
0329: return lcoord;
0330: }
0331:
0332: /**
0333: * Resets shape
0334: */
0335: public void clear() {
0336: getEditGeom().setChanged(true);
0337: coordinates.clear();
0338: points.clear();
0339: }
0340:
0341: public boolean hasPoint(Point pointOnLine) {
0342: return pointsToModel.containsKey(pointOnLine);
0343: }
0344:
0345: /**
0346: * @return Returns an iterator that iterates over all points in shape.
0347: */
0348: public ListIterator<Point> iterator() {
0349: return new ListIterator<Point>() {
0350: ListIterator<PointCoordMap> iter = points
0351: .listIterator();
0352: PointCoordMap current;
0353:
0354: public boolean hasNext() {
0355: return iter.hasNext();
0356: }
0357:
0358: public Point next() {
0359: current = iter.next();
0360: return current.point;
0361: }
0362:
0363: public boolean hasPrevious() {
0364: return iter.hasPrevious();
0365: }
0366:
0367: public Point previous() {
0368: current = iter.previous();
0369: return current.point;
0370: }
0371:
0372: public int nextIndex() {
0373: return iter.nextIndex();
0374: }
0375:
0376: public int previousIndex() {
0377: return iter.previousIndex();
0378: }
0379:
0380: public void remove() {
0381: iter.remove();
0382: }
0383:
0384: public void set(Point o) {
0385: List<PointCoordMap> maps = pointsToModel
0386: .get(current.point);
0387: maps.remove(current);
0388: if (maps.isEmpty())
0389: pointsToModel.remove(current.point);
0390: maps = pointsToModel.get(o);
0391: if (maps == null) {
0392: maps = new ArrayList<PointCoordMap>();
0393: pointsToModel.put(o, maps);
0394: }
0395: maps.add(current);
0396: current.point = o;
0397: getEditGeom().setChanged(true);
0398: }
0399:
0400: public void add(Point o) {
0401:
0402: ArrayList<LazyCoord> list = new ArrayList<LazyCoord>();
0403: list.add(new LazyCoord(o, getEditBlackboard()
0404: .toCoord(o), getEditBlackboard()));
0405: iter.add(new PointCoordMap(o, list));
0406: getEditGeom().setChanged(true);
0407: }
0408:
0409: };
0410: }
0411:
0412: /**
0413: * @return Returns an iterator that iterates over all coordinates in shape. May be modified
0414: */
0415: public ListIterator<Coordinate> coordIterator() {
0416:
0417: return new ListIterator<Coordinate>() {
0418:
0419: ListIterator<LazyCoord> iter = coordinates
0420: .listIterator();
0421: private LazyCoord current;
0422:
0423: public boolean hasNext() {
0424: return iter.hasNext();
0425: }
0426:
0427: public Coordinate next() {
0428: current = iter.next();
0429: return current
0430: .get(coordsToModel.get(current).point);
0431: }
0432:
0433: public boolean hasPrevious() {
0434: return iter.hasPrevious();
0435: }
0436:
0437: public Coordinate previous() {
0438: current = iter.previous();
0439: return current
0440: .get(coordsToModel.get(current).point);
0441: }
0442:
0443: public int nextIndex() {
0444: return iter.nextIndex();
0445: }
0446:
0447: public int previousIndex() {
0448: return iter.previousIndex();
0449: }
0450:
0451: public void remove() {
0452: iter.remove();
0453: PointCoordMap bag = coordsToModel.remove(current);
0454: points.remove(bag.point);
0455: }
0456:
0457: public void set(Coordinate o) {
0458: current.set(o, getEditBlackboard().toPoint(o));
0459: }
0460:
0461: public void add(Coordinate o) {
0462: addPoint(iter.nextIndex() - 1, getEditBlackboard()
0463: .toPoint(o), Collections.singletonList(o));
0464: }
0465:
0466: };
0467: }
0468:
0469: /**
0470: *
0471: */
0472: public void reverse() {
0473: Collections.reverse(points);
0474: Collections.reverse(coordinates);
0475: }
0476:
0477: public List<LazyCoord> getLazyCoordsAt(int i) {
0478: return points.get(i).coords;
0479: }
0480:
0481: /**
0482: * Applies the transform to all the points in the shape. This is the start of a migration.
0483: * This method will update the EditBlackboard rather than the edit blackboard updating
0484: * itself and the Primitive Shape. The pointCoordCalculator must have been updated already
0485: * with the new toScreen and toWorld transforms.
0486: *
0487: * @param oldToNew
0488: */
0489: Map<? extends Point, ? extends List<Point>> transform(
0490: AffineTransform oldToScreen,
0491: AffineTransform oldToWorld,
0492: PointCoordCalculator pointCoordCalculator) {
0493: if (Math.abs(pointCoordCalculator.toScreen.getDeterminant()
0494: - oldToScreen.getDeterminant()) > 0.000001) {
0495: return transformInternal(pointCoordCalculator);
0496: } else {
0497:
0498: return translate(AffineTransform.getTranslateInstance(
0499: pointCoordCalculator.toScreen.getTranslateX()
0500: - oldToScreen.getTranslateX(),
0501: pointCoordCalculator.toScreen.getTranslateY()
0502: - oldToScreen.getTranslateY()));
0503: }
0504: }
0505:
0506: private HashMap<Point, List<Point>> transformInternal(
0507: PointCoordCalculator pointCoordCalculator) {
0508: List<PointCoordMap> oldPoints = points;
0509:
0510: HashMap<Point, List<Point>> oldPointToNew = new HashMap<Point, List<Point>>();
0511:
0512: points = new ArrayList<PointCoordMap>();
0513: pointsToModel.clear();
0514: coordsToModel.clear();
0515: EditBlackboard editBlackboard = owner.getEditBlackboard();
0516:
0517: for (PointCoordMap map : oldPoints) {
0518: Point oldPoint = map.point;
0519: for (Iterator<LazyCoord> iter = map.coords.iterator(); iter
0520: .hasNext();) {
0521: LazyCoord c = iter.next();
0522: PointCoordMap tmp = map;
0523: Coordinate coord = c.get(oldPoint);
0524:
0525: Point newPoint = pointCoordCalculator
0526: .toPoint(coord);
0527: // So that all the vertices don't make a big mess look around point in a 3x3
0528: // radius
0529: // if another point is there add to that point.
0530: Point overLappingPoint;
0531: overLappingPoint = getEditBlackboard()
0532: .overVertex(
0533: newPoint,
0534: PreferenceUtil.instance()
0535: .getVertexRadius());
0536:
0537: if (overLappingPoint != null
0538: && getEditBlackboard().isCollapseVertices())
0539: newPoint = overLappingPoint;
0540:
0541: if (!newPoint.equals(oldPoint)) {
0542: tmp = new PointCoordMap(newPoint);
0543: tmp.coords.add(c);
0544: iter.remove();
0545: }
0546:
0547: c.pointCoordCalculator = new PointCoordCalculator(
0548: pointCoordCalculator);
0549: c.start = newPoint;
0550:
0551: List<Point> pointMapping = oldPointToNew
0552: .get(oldPoint);
0553: if (pointMapping == null) {
0554: pointMapping = new ArrayList<Point>();
0555: pointMapping.add(newPoint);
0556: oldPointToNew.put(oldPoint, pointMapping);
0557: } else {
0558: pointMapping.add(newPoint);
0559: }
0560: tmp.point = newPoint;
0561:
0562: coordsToModel.put(c, tmp);
0563:
0564: // update shape
0565: points.add(tmp);
0566: List<PointCoordMap> list = pointsToModel
0567: .get(newPoint);
0568: if (list == null) {
0569: List<PointCoordMap> l = new ArrayList<PointCoordMap>();
0570: l.add(tmp);
0571: pointsToModel.put(newPoint, l);
0572: } else {
0573: list.add(tmp);
0574: }
0575:
0576: // update Blackboard.
0577: List<LazyCoord> coords = editBlackboard.coordMapping
0578: .get(newPoint);
0579: if (coords == null) {
0580: List<LazyCoord> l = new ArrayList<LazyCoord>(
0581: tmp.coords);
0582: editBlackboard.coordMapping.put(newPoint, l);
0583: } else {
0584: coords.addAll(tmp.coords);
0585: }
0586:
0587: Set<EditGeom> mappedGeoms = editBlackboard.geomMapping
0588: .get(newPoint);
0589: if (mappedGeoms == null) {
0590: Set<EditGeom> l = new HashSet<EditGeom>();
0591: l.add(getEditGeom());
0592: editBlackboard.geomMapping.put(newPoint, l);
0593: } else {
0594: if (!mappedGeoms.contains(getEditGeom()))
0595: mappedGeoms.add(getEditGeom());
0596: }
0597:
0598: }
0599: }
0600: return oldPointToNew;
0601: }
0602:
0603: private Map<? extends Point, ? extends List<Point>> translate(
0604: AffineTransform oldToNew) {
0605: List<PointCoordMap> oldPoints = points;
0606:
0607: HashMap<Point, List<Point>> oldPointToNew = new HashMap<Point, List<Point>>();
0608:
0609: points = new ArrayList<PointCoordMap>();
0610: pointsToModel.clear();
0611: EditBlackboard editBlackboard = owner.getEditBlackboard();
0612:
0613: int diffX = (int) oldToNew.getTranslateX();
0614: int diffY = (int) oldToNew.getTranslateY();
0615: for (PointCoordMap map : oldPoints) {
0616:
0617: Point newPoint = Point.valueOf(
0618: map.point.getX() + diffX, map.point.getY()
0619: + diffY);
0620: List<Point> pointMapping = oldPointToNew.get(map.point);
0621: if (pointMapping == null) {
0622: pointMapping = new ArrayList<Point>();
0623: pointMapping.add(newPoint);
0624: oldPointToNew.put(map.point, pointMapping);
0625: } else {
0626: pointMapping.add(newPoint);
0627: }
0628: map.point = newPoint;
0629:
0630: // update shape
0631: points.add(map);
0632: List<PointCoordMap> list = pointsToModel.get(newPoint);
0633: if (list == null) {
0634: List<PointCoordMap> l = new ArrayList<PointCoordMap>();
0635: l.add(map);
0636: pointsToModel.put(newPoint, l);
0637: } else {
0638: list.add(map);
0639: }
0640:
0641: // update Blackboard.
0642: List<LazyCoord> coords = editBlackboard.coordMapping
0643: .get(newPoint);
0644: if (coords == null) {
0645: List<LazyCoord> l = new ArrayList<LazyCoord>(
0646: map.coords);
0647: editBlackboard.coordMapping.put(newPoint, l);
0648: } else {
0649: coords.addAll(map.coords);
0650: }
0651:
0652: Set<EditGeom> mappedGeoms = editBlackboard.geomMapping
0653: .get(newPoint);
0654: if (mappedGeoms == null) {
0655: Set<EditGeom> l = new HashSet<EditGeom>();
0656: l.add(getEditGeom());
0657: editBlackboard.geomMapping.put(newPoint, l);
0658: } else {
0659: if (!mappedGeoms.contains(getEditGeom()))
0660: mappedGeoms.add(getEditGeom());
0661: }
0662:
0663: }
0664: return oldPointToNew;
0665: }
0666:
0667: /**
0668: * Moves a single LazyCoord from the start point to the end point. Keeps the order of the
0669: * coordinates in the same order.
0670: *
0671: * @param start
0672: * @param end
0673: * @param coord
0674: */
0675: public void move(Point start, Point end, LazyCoord coord) {
0676:
0677: PointCoordMap toRemove = null;
0678:
0679: for (PointCoordMap map : pointsToModel.get(start)) {
0680: if (map.coords.contains(coord)) {
0681: List<PointCoordMap> startBags = pointsToModel
0682: .get(start);
0683: PointCoordMap endBag = null;
0684: int startIndex = points.indexOf(map);
0685: PointCoordMap before = new PointCoordMap(start);
0686: endBag = new PointCoordMap(end);
0687: PointCoordMap after = new PointCoordMap(start);
0688:
0689: points.remove(startIndex);
0690: int i = 0;
0691: for (LazyCoord coord2 : map.coords) {
0692: if (i < map.coords.indexOf(coord)) {
0693: before.coords.add(coord2);
0694: coordsToModel.put(coord2, before);
0695: } else if (i > map.coords.indexOf(coord)) {
0696: after.coords.add(coord2);
0697: coordsToModel.put(coord2, after);
0698: }
0699: i++;
0700: }
0701: boolean addedBefore = false;
0702: boolean addedAfter = false;
0703: if (before.coords.size() > 0) {
0704: points.add(startIndex, before);
0705: startBags.add(before);
0706: addedBefore = true;
0707: }
0708: points.add(addedBefore ? startIndex + 1
0709: : startIndex, endBag);
0710: if (after.coords.size() > 0) {
0711: points.add(addedBefore ? startIndex + 2
0712: : startIndex + 1, after);
0713: startBags.add(after);
0714: addedAfter = true;
0715: }
0716:
0717: toRemove = map;
0718: List<PointCoordMap> endBags = pointsToModel
0719: .get(end);
0720:
0721: if (endBags == null) {
0722: endBags = new ArrayList<PointCoordMap>();
0723: pointsToModel.put(end, endBags);
0724: }
0725: if (!endBags.contains(endBag))
0726: endBags.add(endBag);
0727:
0728: endBag.coords.add(coord);
0729: coordsToModel.put(coord, endBag);
0730:
0731: if (addedBefore && !addedAfter || !addedBefore
0732: && addedAfter) {
0733: attemptBeforeAndAfterVertexCollapse(startIndex);
0734: attemptBeforeAndAfterVertexCollapse(startIndex + 1);
0735: } else if (addedBefore && addedAfter) {
0736: attemptBeforeAndAfterVertexCollapse(startIndex);
0737: attemptBeforeAndAfterVertexCollapse(startIndex + 2);
0738: } else if (!addedBefore && !addedAfter) {
0739: attemptBeforeAndAfterVertexCollapse(startIndex);
0740: }
0741:
0742: }
0743:
0744: break;
0745: }
0746:
0747: if (toRemove != null) {
0748: pointsToModel.get(start).remove(toRemove);
0749: }
0750: }
0751:
0752: private void attemptBeforeAndAfterVertexCollapse(int index) {
0753: if (points.size() == 1 || index > points.size() - 1)
0754: return;
0755:
0756: int before = index - 1;
0757: int after = index + 1;
0758:
0759: if (before > -1) {
0760: boolean changed = doCollapseVertices(index, before);
0761: if (changed) {
0762: index = before;
0763: after--;
0764: }
0765: }
0766:
0767: if (after < points.size()) {
0768: doCollapseVertices(after, index);
0769: }
0770: }
0771:
0772: private boolean doCollapseVertices(int index, int before) {
0773: boolean changed = false;
0774: PointCoordMap currentMap = points.get(index);
0775: PointCoordMap beforeMap = points.get(before);
0776: if (currentMap.point.equals(beforeMap.point)) {
0777: changed = true;
0778: points.remove(index);
0779: pointsToModel.get(currentMap.point).remove(currentMap);
0780:
0781: for (LazyCoord coord : currentMap.coords) {
0782: coordsToModel.put(coord, beforeMap);
0783: beforeMap.coords.add(coord);
0784: }
0785: }
0786: return changed;
0787: }
0788:
0789: public Iterator<Point> getCopyIterator() {
0790: return new Iterator<Point>() {
0791: List<PointCoordMap> newPoints = new ArrayList<PointCoordMap>(
0792: points);
0793: Iterator<PointCoordMap> iter;
0794:
0795: public boolean hasNext() {
0796: if (iter == null)
0797: iter = newPoints.iterator();
0798: return iter.hasNext();
0799: }
0800:
0801: public Point next() {
0802: if (iter == null)
0803: iter = newPoints.iterator();
0804: return iter.next().point;
0805: }
0806:
0807: public void remove() {
0808: throw new IllegalArgumentException(
0809: "not supported; to inefficient"); //$NON-NLS-1$
0810: }
0811:
0812: };
0813: }
0814:
0815: /**
0816: * Returns lazycoords at point.
0817: *
0818: * @param point
0819: * @return
0820: */
0821: public List<LazyCoord> getLazyCoordsAt(Point point) {
0822: List<PointCoordMap> bags = pointsToModel.get(point);
0823: List<LazyCoord> coords = new ArrayList<LazyCoord>();
0824: if (bags == null) {
0825: return Collections.<LazyCoord> emptyList();
0826: }
0827: for (PointCoordMap map : bags) {
0828: coords.addAll(map.coords);
0829: }
0830:
0831: return coords;
0832: }
0833:
0834: public void move(int deltaX, int deltaY) {
0835: Map<Point, List<PointCoordMap>> newPointsToModel = new HashMap<Point, List<PointCoordMap>>();
0836:
0837: for (Point point : this ) {
0838: Point dest = Point.valueOf(point.getX() + deltaX, point
0839: .getY()
0840: + deltaY);
0841: List<PointCoordMap> oldBags = pointsToModel
0842: .remove(point);
0843:
0844: if (oldBags == null)
0845: continue;
0846:
0847: newPointsToModel.put(dest, oldBags);
0848:
0849: for (PointCoordMap map : oldBags) {
0850: map.point = dest;
0851: }
0852: }
0853:
0854: for (Map.Entry<Point, List<PointCoordMap>> entry : newPointsToModel
0855: .entrySet()) {
0856: List<PointCoordMap> newBags = pointsToModel.get(entry
0857: .getKey());
0858: if (newBags == null) {
0859: pointsToModel.put(entry.getKey(), entry.getValue());
0860: } else {
0861: newBags.addAll(entry.getValue());
0862: }
0863: }
0864:
0865: pointsToModel = newPointsToModel;
0866:
0867: }
0868:
0869: }
0870:
0871: /**
0872: * @return Returns the owner.
0873: */
0874: public EditGeom getEditGeom() {
0875: return owner;
0876: }
0877:
0878: public EditBlackboard getEditBlackboard() {
0879: return owner.getEditBlackboard();
0880: }
0881:
0882: /**
0883: * @return Returns an iterator that iterates over all visible points in shape. Not modifyable
0884: */
0885: public Iterator<Point> iterator() {
0886: final PointCoordMap[] array = points
0887: .toArray(new PointCoordMap[points.size()]);
0888: return new Iterator<Point>() {
0889: int i = -1;
0890:
0891: public boolean hasNext() {
0892: return i < array.length - 1;
0893: }
0894:
0895: public Point next() {
0896: i++;
0897: return array[i].point;
0898: }
0899:
0900: public void remove() {
0901: throw new UnsupportedOperationException(
0902: "This is iterator does not allow modification"); //$NON-NLS-1$
0903: }
0904: };
0905: }
0906:
0907: /**
0908: * @return Returns an iterator that iterates over all visible coordinates in shape. Not
0909: * modifyible
0910: */
0911: public Iterator<Coordinate> coordIterator() {
0912: return getMutator().coordIterator();
0913: }
0914:
0915: private static class PointCoordMap {
0916: Point point;
0917: final List<LazyCoord> coords;
0918:
0919: public PointCoordMap(Point p, List<LazyCoord> coords) {
0920: point = p;
0921: this .coords = coords;
0922: }
0923:
0924: public PointCoordMap(Point p) {
0925: point = p;
0926: this .coords = new ArrayList<LazyCoord>();
0927: }
0928:
0929: @Override
0930: public String toString() {
0931: return "{" + point + "=" + coords + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0932: }
0933: }
0934:
0935: /**
0936: * Returns an array with all the coordinates in shape.
0937: *
0938: * @return an array with all the coordinates in shape.
0939: */
0940: public Coordinate[] coordArray() {
0941: Coordinate[] array = new Coordinate[coordinates.size()];
0942: Iterator<Coordinate> iter = coordIterator();
0943: for (int i = 0; i < array.length; i++) {
0944: array[i] = iter.next();
0945: }
0946: return array;
0947: }
0948:
0949: /**
0950: * returns true if the point is contained in this shape.
0951: *
0952: * @param p an arbitrary point
0953: * @return Returns true if the point is contained in this shape.
0954: */
0955: public boolean hasVertex(Point p) {
0956: return pointsToModel.containsKey(p);
0957: }
0958:
0959: boolean hasVertex(Point p, LazyCoord coord) {
0960: List<PointCoordMap> list = pointsToModel.get(p);
0961: if (list == null)
0962: return false;
0963:
0964: for (PointCoordMap map : list) {
0965: if (map.coords == null)
0966: return false;
0967: for (LazyCoord coord2 : map.coords) {
0968: if (coord2 == coord)
0969: return true;
0970: }
0971: }
0972: return false;
0973: }
0974:
0975: /**
0976: * Returns a {@link ClosestEdge} object that has information about the point that closest to the
0977: * click paramter and is on an edge of the part.
0978: *
0979: * @param click the point to use as the reference point
0980: * @return
0981: */
0982: public ClosestEdge getClosestEdge(Point click,
0983: boolean treatUnknownAsPolygon) {
0984: if (getNumPoints() == 0)
0985: return null;
0986: final int endIndex;
0987: int startIndex, lastIndex;
0988: Point coord1;
0989:
0990: if ((getEditGeom().getShapeType() == ShapeType.UNKNOWN && treatUnknownAsPolygon)
0991: || getEditGeom().getShapeType() == ShapeType.POLYGON) {
0992: lastIndex = getNumPoints() - 1;
0993: coord1 = getPoint(lastIndex);
0994: startIndex = 0;
0995: endIndex = getNumPoints() - 1;
0996: } else if ((getEditGeom().getShapeType() == ShapeType.UNKNOWN && !treatUnknownAsPolygon)
0997: || getEditGeom().getShapeType() == ShapeType.LINE) {
0998: lastIndex = 0;
0999: coord1 = getPoint(lastIndex);
1000: startIndex = 1;
1001: endIndex = getNumPoints() - 1;
1002:
1003: } else {
1004: // points don't have edges
1005: return null;
1006: }
1007:
1008: double mindist = Double.MAX_VALUE;
1009:
1010: int prev = -1;
1011: Point closestPoint = null;
1012: for (int i = startIndex; i <= endIndex; i++) {
1013: Point coord2 = getPoint(i);
1014: try {
1015: Point point = EditUtils.instance.closestPointOnEdge(
1016: coord1, coord2, click);
1017: if (point == null) {
1018: continue;
1019: }
1020: int x = click.getX() - point.getX();
1021: int y = click.getY() - point.getY();
1022: double dist = Math.sqrt(x * x + y * y);
1023: if (dist < mindist) {
1024: mindist = dist;
1025: prev = lastIndex;
1026: closestPoint = point;
1027: }
1028: } finally {
1029: coord1 = coord2;
1030: lastIndex = i;
1031: }
1032: }
1033:
1034: if (closestPoint == null)
1035: return null;
1036: return new ClosestEdge(mindist, prev, closestPoint, this );
1037: }
1038:
1039: /**
1040: * Returns the bounding box of the Shape in pixel space.
1041: *
1042: * @return the bounding box of the Shape in pixel space.
1043: */
1044: public Rectangle getBounds() {
1045: int minx = Integer.MAX_VALUE;
1046: int maxx = Integer.MIN_VALUE;
1047: int miny = Integer.MAX_VALUE;
1048: int maxy = Integer.MIN_VALUE;
1049: for (Point point : getMutator()) {
1050: if (point.getX() < minx)
1051: minx = point.getX();
1052: if (point.getX() > maxx)
1053: maxx = point.getX();
1054: if (point.getY() < miny)
1055: miny = point.getY();
1056: if (point.getY() > maxy)
1057: maxy = point.getY();
1058: }
1059:
1060: return new Rectangle(minx, miny, maxx - minx, maxy - miny);
1061: }
1062:
1063: /**
1064: * Returns true if the point is contained in the shape or on the edge. It is considered on the
1065: * edge if it is within {@link PreferenceUtil#getVertexRadius()} of the edge.
1066: *
1067: * @param point An astrbitrary point
1068: * @param treatUnknownGeomsAsPolygon if {@link EditGeom#getShapeType()} return UNKOWN this
1069: * parameter is used to determine if this shape should be considered a polygon.
1070: * @return true if the point is contained in the shape.
1071: */
1072: public boolean contains(Point point,
1073: boolean treatUnknownGeomsAsPolygon) {
1074: return contains(point, treatUnknownGeomsAsPolygon, false);
1075: }
1076:
1077: /**
1078: * Returns true if the point is contained in the shape or on the edge.
1079: *
1080: * @param point An astrbitrary point
1081: * @param treatUnknownGeomsAsPolygon if {@link EditGeom#getShapeType()} return UNKOWN this
1082: * parameter is used to determine if this shape should be considered a polygon.
1083: * @param ignoreVertexRadius if true then the point is only considered to be on the edge if it
1084: * is directly on the edge. (within 1 pixel of the line).
1085: * @return true if the point is contained in the shape.
1086: */
1087: public boolean contains(Point point,
1088: boolean treatUnknownGeomsAsPolygon,
1089: boolean ignoreVertexRadius) {
1090:
1091: if (points.size() == 0)
1092: return false;
1093:
1094: int vertexRadius;
1095: if (ignoreVertexRadius)
1096: vertexRadius = 1;
1097: else {
1098: vertexRadius = PreferenceUtil.instance().getVertexRadius();
1099: }
1100:
1101: if (points.size() == 1) {
1102: Point click = points.get(0).point;
1103: int x = click.getX() - point.getX();
1104: int y = click.getY() - point.getY();
1105: double dist = Math.sqrt(x * x + y * y);
1106:
1107: return dist < vertexRadius;
1108: }
1109:
1110: Point overVertex = getEditBlackboard().overVertex(point,
1111: vertexRadius);
1112: if (overVertex != null && pointsToModel.containsKey(overVertex))
1113: return true;
1114:
1115: ClosestEdge edge = getClosestEdge(point,
1116: treatUnknownGeomsAsPolygon);
1117: if (edge != null && edge.getDistanceToEdge() < vertexRadius)
1118: return true;
1119:
1120: PrimitiveShapeIterator iter = PrimitiveShapeIterator
1121: .getPathIterator(this );
1122: iter.setPolygon(isPolygon(treatUnknownGeomsAsPolygon));
1123: GeneralPath path = new GeneralPath();
1124: path.append(iter, false);
1125: return path.contains(point.getX(), point.getY());
1126: }
1127:
1128: public Rectangle2D getBounds2D() {
1129: return null;
1130: }
1131:
1132: public boolean contains(double x, double y) {
1133: return contains(Point.valueOf((int) x, (int) y), true);
1134: }
1135:
1136: public boolean contains(Point2D p) {
1137: return contains(Point.valueOf((int) p.getX(), (int) p.getY()),
1138: true);
1139: }
1140:
1141: public boolean intersects(double x, double y, double w, double h) {
1142: return false;
1143: }
1144:
1145: public boolean intersects(Rectangle2D r) {
1146: return false;
1147: }
1148:
1149: public boolean contains(double x, double y, double w, double h) {
1150: return false;
1151: }
1152:
1153: public boolean contains(Rectangle2D r) {
1154: return false;
1155: }
1156:
1157: public PathIterator getPathIterator(AffineTransform at) {
1158: return PrimitiveShapeIterator.getPathIterator(this );
1159: }
1160:
1161: public PathIterator getPathIterator(AffineTransform at,
1162: double flatness) {
1163: return PrimitiveShapeIterator.getPathIterator(this );
1164: }
1165:
1166: /**
1167: * Returns all the coordinates that map to the point at location i.
1168: *
1169: * @param i index of a point in the shape
1170: * @return Returns all the coordinates that map to the point at location i.
1171: */
1172: public List<Coordinate> getCoordsAt(int i) {
1173: PointCoordMap bag = points.get(i);
1174: return new CoordResolvingList(bag.coords, bag.point);
1175: }
1176:
1177: public List<Coordinate> getCoordsAt(Point point) {
1178: return new CoordResolvingList(getMutator().getLazyCoordsAt(
1179: point), point);
1180: }
1181:
1182: public int getAssociatedPointIndex(int coordIndex) {
1183: return points.indexOf(coordsToModel.get((coordinates
1184: .get(coordIndex))));
1185: }
1186:
1187: public boolean hasVertex(Coordinate start) {
1188: // Point point = getEditBlackboard().toPoint(start);
1189: // List<LazyCoord> coords = getMutator().getLazyCoordsAt(point);
1190: // for( LazyCoord coord : coords ) {
1191: // if( coord.get(coordsToModel.get(coord).point).equals(start) )
1192: // return true;
1193: // }
1194: for (LazyCoord coord : coordinates) {
1195: if (coord.get(coordsToModel.get(coord).point).equals(start))
1196: return true;
1197: }
1198: return false;
1199: }
1200:
1201: public void assertValid() {
1202: if (!EditPlugin.isDebugging(EditPlugin.RUN_ASSERTIONS))
1203: return;
1204: if (getNumCoords() == 0 && getNumPoints() != 0
1205: || getNumCoords() != 0 && getNumPoints() == 0)
1206: throw new AssertionError(
1207: "Num Coords=" + getNumCoords() + " NumPoints=" + getNumPoints()); //$NON-NLS-1$ //$NON-NLS-2$
1208:
1209: if (getNumCoords() < 1) {
1210: return;
1211: }
1212:
1213: for (LazyCoord lz : coordinates) {
1214: if (!coordsToModel.containsKey(lz))
1215: throw new AssertionError(lz
1216: + " should be in coordsToModel but isn't"); //$NON-NLS-1$
1217: PointCoordMap bag = coordsToModel.get(lz);
1218: Point findVertex = bag.point;
1219: if (findVertex == null)
1220: throw new AssertionError(
1221: bag.point
1222: + " should equal findVertex(getEditBlackboard().toPoint(lz.get(bag.point)), snappingRadius, false)"); //$NON-NLS-1$
1223:
1224: boolean found = false;
1225: for (LazyCoord lz2 : bag.coords) {
1226: if (lz2 == lz) {
1227: found = true;
1228: break;
1229: }
1230: }
1231: if (!found) {
1232: throw new AssertionError(lz
1233: + " is not in the mapped bag " + bag); //$NON-NLS-1$
1234: }
1235: if (getEditBlackboard().coordMapping.containsKey(bag.point)) {
1236: found = false;
1237: List<LazyCoord> list = getEditBlackboard().coordMapping
1238: .get(bag.point);
1239: for (LazyCoord lz2 : list) {
1240: if (lz2 == lz) {
1241: found = true;
1242: break;
1243: }
1244: }
1245:
1246: if (!found) {
1247: throw new AssertionError(
1248: lz
1249: + " is not in editblackboard's coordMapping"); //$NON-NLS-1$
1250: }
1251: } else {
1252: throw new AssertionError(bag.point
1253: + " should be in the blackboard but isn't"); //$NON-NLS-1$
1254: }
1255:
1256: }
1257:
1258: for (PointCoordMap b : points) {
1259: for (LazyCoord coordinate : b.coords) {
1260: if (!coordinates.contains(coordinate)) {
1261: throw new AssertionError(
1262: coordinate
1263: + " is not in the list of coordinate but it should be"); //$NON-NLS-1$
1264: }
1265: if (!coordsToModel.containsKey(coordinate)) {
1266: throw new AssertionError(coordinate
1267: + " is not in coordsToModel map"); //$NON-NLS-1$
1268: }
1269: if (!pointsToModel.containsKey(b.point))
1270: throw new AssertionError(b.point
1271: + " is not in pointsToModel map"); //$NON-NLS-1$
1272: }
1273: if (!getEditBlackboard().coordMapping.get(b.point)
1274: .containsAll(b.coords)) {
1275: throw new AssertionError(
1276: "Not all coordinates in bags are in editblackboard"); //$NON-NLS-1$
1277: }
1278: if (!getEditBlackboard().geomMapping.get(b.point).contains(
1279: getEditGeom())) {
1280: throw new AssertionError(
1281: "EditGeom is not mapped to " + b.point + " in edit blackboard's geomMapping"); //$NON-NLS-1$ //$NON-NLS-2$
1282: }
1283: }
1284:
1285: EditPlugin.trace(EditPlugin.RUN_ASSERTIONS,
1286: "shape is valid", null); //$NON-NLS-1$
1287: }
1288:
1289: public boolean contains(Coordinate startCoord,
1290: boolean treatUnknownGeomsAsPolygon) {
1291:
1292: for (int i = 0; i < getNumCoords() - 1; i++) {
1293: Coordinate intersection = EditUtils.instance
1294: .closestCoordinateOnEdge(getCoord(i),
1295: getCoord(i + 1), startCoord);
1296: if (intersection != null && intersection.equals(startCoord))
1297: return true;
1298: }
1299:
1300: PrimitiveShapeIterator iter = PrimitiveShapeIterator
1301: .getPathIterator(this );
1302: iter.setPolygon(treatUnknownGeomsAsPolygon);
1303: Shape s = iter.toShape();
1304: return s.contains(startCoord.x, startCoord.y);
1305: }
1306:
1307: /**
1308: * Returns the point closest to location. The search is a square of height and width radius + 1.
1309: *
1310: * @param location the locations to start searching from.
1311: * @param radius the distance away from location to search.
1312: * @return the point closest to location or null if no point exists.
1313: */
1314: public Point overVertex(Point location, int radius) {
1315: return overVertex(location, radius, false);
1316: }
1317:
1318: /**
1319: * Returns the point closest to location. If ignore is true the point at locations will not be
1320: * returned. The search is a square of height and width radius + 1.
1321: *
1322: * @param location the locations to start searching from.
1323: * @param radius radius the distance away from location to search.
1324: * @param ignore true if the vertex at location is ignored
1325: * @return the point closest to location or null if no point exists.
1326: */
1327: public synchronized Point overVertex(Point location, int radius,
1328: boolean ignore) {
1329: List<PointCoordMap> list = this .pointsToModel.get(location);
1330: if (!ignore && list != null && !list.isEmpty())
1331: return location;
1332: for (int i = 1; i <= radius; i++) {
1333: Point result = findVertex(location, i);
1334: if (result != null)
1335: return result;
1336: }
1337: return null;
1338: }
1339:
1340: /**
1341: * Searchs for a vertext in a square i pixels away from the location.
1342: *
1343: * @param location center of search
1344: * @param i distance from center to search (is not an area search)
1345: * @param ignore
1346: * @param element
1347: */
1348: private Point findVertex(Point location, int i) {
1349:
1350: final int maxX = location.getX() + i;
1351: final int maxY = location.getY() + i;
1352: final int minX = location.getX() - i;
1353: final int minY = location.getY() - i;
1354:
1355: for (int x = minX; x <= maxX; x++) {
1356: Point temp = Point.valueOf(x, minY);
1357: List<PointCoordMap> list = pointsToModel.get(temp);
1358: if (list != null && list.size() > 0)
1359: return temp;
1360: }
1361:
1362: for (int y = minY + 1; y <= maxY; y++) {
1363: Point temp = Point.valueOf(maxX, y);
1364: List<PointCoordMap> list = pointsToModel.get(temp);
1365: if (list != null && list.size() > 0)
1366: return temp;
1367: }
1368:
1369: for (int x = maxX - 1; x >= minX; x--) {
1370: Point temp = Point.valueOf(x, maxY);
1371: List<PointCoordMap> list = pointsToModel.get(temp);
1372: if (list != null && list.size() > 0)
1373: return temp;
1374: }
1375:
1376: for (int y = maxY - 1; y >= minY; y--) {
1377: Point temp = Point.valueOf(minX, y);
1378: List<PointCoordMap> list = pointsToModel.get(temp);
1379: if (list != null && list.size() > 0)
1380: return temp;
1381: }
1382:
1383: return null;
1384: }
1385:
1386: public Envelope getEnvelope() {
1387: if (envelope == null) {
1388: envelope = new Envelope();
1389: for (int i = 0; i < getNumCoords(); i++) {
1390: envelope.expandToInclude(getCoord(i));
1391: }
1392: }
1393: return envelope;
1394: }
1395:
1396: /**
1397: * Currently a simple stupid implementation for detecting if 2 polygons overlap. Currently it
1398: * only check the points not the real coordinates so this method must be used with care. Just
1399: * iterates through all the edges in one shape and checks if it overlap with an edge in the
1400: * other shape.
1401: *
1402: * <pre>
1403: * ------------------
1404: * | --------- |
1405: * | | | |
1406: * ----|-------|-----
1407: * | |
1408: * ---------
1409: * </pre>
1410: *
1411: * Above is considered overlapping but below is <em>only</em> if acceptTouches is true:
1412: *
1413: * <pre>
1414: * ------------------
1415: * | |
1416: * | |
1417: * ------------------
1418: * | |
1419: * ---------
1420: * </pre>
1421: *
1422: * <p>
1423: * <b>Note:</b> If one of the shapes is a point and the other is a line or a point then acceptTouches must be true
1424: * other or this method will always return false.
1425: * </p>
1426: *
1427: * @param shape2 other shape to test against
1428: * @param acceptTouches if true then this method will return true if the two shapes simply touch
1429: * (but don't fully overlap). See above for more details
1430: * @return true if the two shapes overlap
1431: */
1432: public boolean overlap(PrimitiveShape shape2,
1433: boolean treatUnknownAsPolygon, boolean acceptTouches) {
1434:
1435: if (getNumPoints() == 0)
1436: return false;
1437:
1438: if (shape2.getNumPoints() == 0)
1439: return false;
1440:
1441: if (getNumPoints() == 1)
1442: return shape2.contains(getPoint(0), treatUnknownAsPolygon,
1443: true)
1444: && isAcceptableIntersection(shape2, getPoint(0),
1445: acceptTouches);
1446:
1447: if (shape2.getNumPoints() == 1)
1448: return contains(shape2.getPoint(0), treatUnknownAsPolygon,
1449: true)
1450: && isAcceptableIntersection(this , shape2
1451: .getPoint(0), acceptTouches);
1452:
1453: Point last, current;
1454:
1455: PrimitiveShapeIterator piter = PrimitiveShapeIterator
1456: .getPathIterator(this );
1457: piter.setPolygon(isPolygon(treatUnknownAsPolygon));
1458: Shape s = piter.toShape();
1459:
1460: PrimitiveShapeIterator piter2 = PrimitiveShapeIterator
1461: .getPathIterator(shape2);
1462: piter2.setPolygon(isPolygon(treatUnknownAsPolygon));
1463: Shape s2 = piter2.toShape();
1464:
1465: for (Point point : shape2) {
1466: if (s.contains(point.getX(), point.getY())
1467: && isAcceptableIntersection(this , point,
1468: acceptTouches))
1469: return true;
1470: }
1471:
1472: Iterator<Point> iter = iterator();
1473: last = iter.next();
1474:
1475: while (iter.hasNext()) {
1476: current = iter.next();
1477:
1478: // now check if this shape's vertices are contained in the other shape
1479: if (s2.contains(last.getX(), last.getY())
1480: && isAcceptableIntersection(shape2, last,
1481: acceptTouches))
1482: return true;
1483:
1484: if (edgeIntersect(last, current, shape2, acceptTouches))
1485: return true;
1486:
1487: last = current;
1488: }
1489: if (isPolygon(treatUnknownAsPolygon)) {
1490: // do edge from last point to first point
1491: if (edgeIntersect(getPoint(getNumPoints() - 1),
1492: getPoint(0), shape2, acceptTouches))
1493: return true;
1494: }
1495:
1496: return false;
1497: }
1498:
1499: /**
1500: * detects if the edge intersects with any of the edges in the shape
1501: */
1502: private boolean edgeIntersect(Point last, Point current,
1503: PrimitiveShape shape2, boolean acceptTouches) {
1504: Iterator<Point> iter2 = shape2.iterator();
1505: Point last2 = iter2.next();
1506:
1507: while (iter2.hasNext()) {
1508: Point current2 = iter2.next();
1509:
1510: Point intersection = EditUtils.instance.intersectingLines(
1511: last, current, last2, current2);
1512: if (intersection != null
1513: && isAcceptableIntersection(intersection, last2,
1514: current2, acceptTouches)
1515: && isAcceptableIntersection(intersection, last,
1516: current, acceptTouches)) {
1517: // TODO compare coordinates to ensure it is a real intersection.
1518: return true;
1519: }
1520: last2 = current2;
1521: }
1522:
1523: return false;
1524: }
1525:
1526: /**
1527: * Detects if the intersection is just a touch. If it is <em>not</em> then it returns true. If it
1528: * is then it returns true only if a touch is considered to be an intersection.
1529: * @see #isAcceptableIntersection(Point, Point, Point, boolean)
1530: */
1531: private boolean isAcceptableIntersection(PrimitiveShape shape,
1532: Point point, boolean acceptTouches) {
1533: if (shape.getNumPoints() == 1) {
1534: if (point.equals(shape.getPoint(0)))
1535: return acceptTouches;
1536: }
1537: Envelope envelope2 = new Envelope(point.getX() - 0.1, point
1538: .getX() + 0.1, point.getY() - 0.1, point.getY() + 0.1);
1539: if (EditUtils.instance.overEdgePixelPrecision(shape, envelope2)) {
1540: return acceptTouches;
1541: }
1542: return true;
1543: }
1544:
1545: /**
1546: * Detects if the intersection is just a touch. If it is <em>not</em> then it returns true. If it
1547: * is then it returns true only if a touch is considered to be an intersection.
1548: * @see #isAcceptableIntersection(PrimitiveShape, Point, boolean)
1549: */
1550: private boolean isAcceptableIntersection(Point intersection,
1551: Point endPoint1, Point endPoint2, boolean acceptTouches) {
1552: if (intersection.equals(endPoint1)
1553: || intersection.equals(endPoint2))
1554: return acceptTouches;
1555: return true;
1556: }
1557:
1558: private boolean isPolygon(boolean treatUnknownAsPolygon) {
1559: return owner.getShapeType() == ShapeType.POLYGON
1560: || (owner.getShapeType() == ShapeType.UNKNOWN && treatUnknownAsPolygon);
1561: }
1562:
1563: }
|