001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032: package com.vividsolutions.jump.workbench.model;
033:
034: import com.vividsolutions.jts.geom.Envelope;
035: import com.vividsolutions.jts.geom.GeometryFactory;
036: import com.vividsolutions.jts.io.ParseException;
037: import com.vividsolutions.jts.io.WKTReader;
038: import com.vividsolutions.jts.util.Assert;
039:
040: import com.vividsolutions.jump.coordsys.CoordinateSystem;
041: import com.vividsolutions.jump.coordsys.Reprojector;
042: import com.vividsolutions.jump.feature.Feature;
043: import com.vividsolutions.jump.feature.FeatureCollection;
044: import com.vividsolutions.jump.util.Blackboard;
045: import com.vividsolutions.jump.util.Block;
046: import com.vividsolutions.jump.workbench.ui.WorkbenchFrame;
047: import com.vividsolutions.jump.workbench.ui.GUIUtil;
048: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
049: import com.vividsolutions.jump.workbench.ui.LayerViewPanelProxy;
050: import com.vividsolutions.jump.workbench.ui.renderer.style.BasicStyle;
051: import com.vividsolutions.jump.workbench.ui.style.AbstractPalettePanel;
052:
053: import java.awt.Color;
054: import java.awt.geom.Line2D;
055:
056: import java.lang.ref.WeakReference;
057: import java.lang.reflect.InvocationTargetException;
058:
059: import java.util.*;
060:
061: import javax.swing.JInternalFrame;
062:
063: /**
064: * Registry of Layers in a Task.
065: * @see Task
066: * @see Layer
067: */
068: public class LayerManager {
069: private static int layerManagerCount = 0;
070: private UndoableEditReceiver undoableEditReceiver = new UndoableEditReceiver();
071: private CoordinateSystem coordinateSystem = CoordinateSystem.UNSPECIFIED;
072:
073: //As we introduce threaded drawing and other threaded tasks to the
074: //workbench, we should be careful not to create situations in which
075: //ConcurrentModificationExceptions can occur. [Jon Aquino]
076: //Go with List rather than name-to-category map, because category names can
077: //now change. [Jon Aquino]
078: private ArrayList categories = new ArrayList();
079:
080: //Store weak references to layers rather than the layers themselves -- if a layer
081: //is lucky enough to have all its strong references released, let it dispose of
082: //itself immediately [Jon Aquino]
083: private ArrayList layerReferencesToDispose = new ArrayList();
084: private boolean firingEvents = true;
085: private ArrayList layerListeners = new ArrayList();
086: private Iterator firstColors;
087: private Blackboard blackboard = new Blackboard();
088:
089: public LayerManager() {
090: firstColors = firstColors().iterator();
091: layerManagerCount++;
092: }
093:
094: public UndoableEditReceiver getUndoableEditReceiver() {
095: return undoableEditReceiver;
096: }
097:
098: public void deferFiringEvents(Runnable r) {
099: boolean firingEvents = isFiringEvents();
100: setFiringEvents(false);
101:
102: try {
103: r.run();
104: } finally {
105: setFiringEvents(firingEvents);
106: }
107: }
108:
109: private Collection firstColors() {
110: ArrayList firstColors = new ArrayList();
111:
112: for (Iterator i = AbstractPalettePanel.basicStyles().iterator(); i
113: .hasNext();) {
114: BasicStyle basicStyle = (BasicStyle) i.next();
115:
116: if (!basicStyle.isRenderingFill()) {
117: continue;
118: }
119:
120: firstColors.add(basicStyle.getFillColor());
121: }
122:
123: return firstColors;
124: }
125:
126: public Color generateLayerFillColor() {
127: //<<TODO>> Ensure that colour is not being used by another layer [Jon Aquino]
128: Color color = firstColors.hasNext() ? (Color) firstColors
129: .next()
130: : new Color((int) Math.floor(Math.random() * 256),
131: (int) Math.floor(Math.random() * 256),
132: (int) Math.floor(Math.random() * 256));
133: color = new Color(color.getRed(), color.getGreen(), color
134: .getBlue());
135:
136: return color;
137: }
138:
139: public Layer addLayer(String categoryName, Layer layer) {
140: addLayerable(categoryName, layer);
141:
142: return layer;
143: }
144:
145: public void addLayerable(String categoryName, Layerable layerable) {
146: if (layerable instanceof Layer) {
147: if (size() == 0
148: && getCoordinateSystem() == CoordinateSystem.UNSPECIFIED) {
149: setCoordinateSystem(((Layer) layerable)
150: .getFeatureCollectionWrapper()
151: .getFeatureSchema().getCoordinateSystem());
152: } else {
153: reproject((Layer) layerable, coordinateSystem);
154: }
155: layerReferencesToDispose.add(new WeakReference(layerable));
156: }
157:
158: addCategory(categoryName);
159:
160: Category cat = getCategory(categoryName);
161: cat.add(0, layerable);
162:
163: //Fire metadata changed so that the visual modified markers are updated. [Jon Aquino]
164: fireLayerChanged(layerable, LayerEventType.METADATA_CHANGED);
165: }
166:
167: private void reproject(Layer layer,
168: CoordinateSystem coordinateSystem) {
169: try {
170: Assert
171: .isTrue(
172: indexOf(layer) == -1,
173: "If the LayerManager contained this layer, we'd need to be concerned about rolling back on an error [Jon Aquino]");
174:
175: if (!Reprojector.instance().wouldChangeValues(
176: layer.getFeatureCollectionWrapper()
177: .getFeatureSchema().getCoordinateSystem(),
178: coordinateSystem)) {
179: return;
180: }
181:
182: for (Iterator i = layer.getFeatureCollectionWrapper()
183: .iterator(); i.hasNext();) {
184: Feature feature = (Feature) i.next();
185: Reprojector.instance().reproject(
186: feature.getGeometry(),
187: layer.getFeatureCollectionWrapper()
188: .getFeatureSchema()
189: .getCoordinateSystem(),
190: coordinateSystem);
191: }
192: } finally {
193: //Even if #isReprojectionNecessary returned false, we still need to set
194: //the CoordinateSystem to the new value [Jon Aquino]
195: layer.getFeatureCollectionWrapper().getFeatureSchema()
196: .setCoordinateSystem(coordinateSystem);
197: }
198: }
199:
200: public void addCategory(String categoryName) {
201: addCategory(categoryName, categories.size());
202: }
203:
204: public void addCategory(String categoryName, int index) {
205: if (getCategory(categoryName) != null) {
206: return;
207: }
208:
209: Category category = new Category();
210: category.setLayerManager(this );
211:
212: //Can't fire events because this Category hasn't been added to the
213: //LayerManager yet. [Jon Aquino]
214: boolean firingEvents = isFiringEvents();
215: setFiringEvents(false);
216:
217: try {
218: category.setName(categoryName);
219: } finally {
220: setFiringEvents(firingEvents);
221: }
222:
223: categories.add(index, category);
224: fireCategoryChanged(category, CategoryEventType.ADDED,
225: indexOf(category));
226: }
227:
228: public Category getCategory(String name) {
229: for (Iterator i = categories.iterator(); i.hasNext();) {
230: Category category = (Category) i.next();
231:
232: if (category.getName().equals(name)) {
233: return category;
234: }
235: }
236:
237: return null;
238: }
239:
240: public List getCategories() {
241: return Collections.unmodifiableList(categories);
242: }
243:
244: /**
245: * @param name the name of the layer. A number will be appended if a layer
246: * with the same name already exists. Set to null to automatically generate a
247: * new name.
248: */
249: public Layer addLayer(String categoryName, String layerName,
250: FeatureCollection featureCollection) {
251: String actualName = (layerName == null) ? "Layer" : layerName;
252: Layer layer = new Layer(actualName, generateLayerFillColor(),
253: featureCollection, this );
254: addLayerable(categoryName, layer);
255:
256: return layer;
257: }
258:
259: public Layer addOrReplaceLayer(String categoryName,
260: String layerName, FeatureCollection featureCollection) {
261: Layer oldLayer = getLayer(layerName);
262:
263: if (oldLayer != null) {
264: remove(oldLayer);
265: }
266:
267: Layer newLayer = addLayer(categoryName, layerName,
268: featureCollection);
269:
270: if (oldLayer != null) {
271: newLayer.setStyles(oldLayer.cloneStyles());
272: }
273:
274: return newLayer;
275: }
276:
277: /**
278: * @return a unique layer name based on the given name
279: */
280: public String uniqueLayerName(String name) {
281: if (!isExistingLayerableName(name)) {
282: return name;
283: }
284:
285: //<<TODO:REMOVE>> debug [Jon Aquino]
286: if (name == "Relative Vectors") {
287: new Throwable().printStackTrace(System.err);
288: }
289:
290: int i = 2;
291: String newName;
292:
293: do {
294: newName = name + " (" + i + ")";
295: i++;
296: } while (isExistingLayerableName(newName));
297:
298: return newName;
299: }
300:
301: private boolean isExistingLayerableName(String name) {
302: for (Iterator i = getLayerables(Layerable.class).iterator(); i
303: .hasNext();) {
304: Layerable layerable = (Layerable) i.next();
305:
306: if (layerable.getName().equals(name)) {
307: return true;
308: }
309: }
310:
311: return false;
312: }
313:
314: public void remove(Layerable layerable) {
315: for (Iterator i = categories.iterator(); i.hasNext();) {
316: Category c = (Category) i.next();
317: int index = c.indexOf(layerable);
318:
319: if (index != -1) {
320: c.remove(layerable);
321: fireLayerChanged(layerable, LayerEventType.REMOVED, c,
322: index);
323: }
324: }
325: }
326:
327: public void removeIfEmpty(Category category) {
328: if (!category.isEmpty()) {
329: return;
330: }
331:
332: int categoryIndex = indexOf(category);
333: categories.remove(category);
334: fireCategoryChanged(category, CategoryEventType.REMOVED,
335: categoryIndex);
336: }
337:
338: public int indexOf(Category category) {
339: return categories.indexOf(category);
340: }
341:
342: public void fireCategoryChanged(Category category,
343: CategoryEventType type) {
344: fireCategoryChanged(category, type, indexOf(category));
345: }
346:
347: private void fireCategoryChanged(final Category category,
348: final CategoryEventType type, final int categoryIndex) {
349: if (!firingEvents) {
350: return;
351: }
352:
353: //[sstein 2.Feb.2007] old line results sometimes in ConcurrentModificationException
354: //for (Iterator i = layerListeners.iterator(); i.hasNext();) {
355: //[sstein 2.Feb.2007] new line by Larry
356: for (Iterator i = new ArrayList(layerListeners).iterator(); i
357: .hasNext();) {//LDB added
358: final LayerListener layerListener = (LayerListener) i
359: .next();
360: fireLayerEvent(new Runnable() {
361: public void run() {
362: layerListener.categoryChanged(new CategoryEvent(
363: category, type, categoryIndex));
364: }
365: });
366: }
367: }
368:
369: public void fireFeaturesChanged(final Collection features,
370: final FeatureEventType type, final Layer layer) {
371: Assert.isTrue(type != FeatureEventType.GEOMETRY_MODIFIED);
372: fireFeaturesChanged(features, type, layer, null);
373: }
374:
375: public void fireGeometryModified(final Collection features,
376: final Layer layer, final Collection oldFeatureClones) {
377: Assert.isTrue(oldFeatureClones != null);
378: fireFeaturesChanged(features,
379: FeatureEventType.GEOMETRY_MODIFIED, layer,
380: oldFeatureClones);
381: }
382:
383: private void fireFeaturesChanged(final Collection features,
384: final FeatureEventType type, final Layer layer,
385: final Collection oldFeatureClones) {
386: if (!firingEvents) {
387: return;
388: }
389:
390: //New ArrayList to avoid ConcurrentModificationException [Jon Aquino]
391: for (Iterator i = new ArrayList(layerListeners).iterator(); i
392: .hasNext();) {
393: final LayerListener layerListener = (LayerListener) i
394: .next();
395: fireLayerEvent(new Runnable() {
396: public void run() {
397: layerListener.featuresChanged(new FeatureEvent(
398: features, type, layer, oldFeatureClones));
399: }
400: });
401: }
402: }
403:
404: private void fireLayerEvent(Runnable eventFirer) {
405: //In general, LayerListeners are GUI components. Therefore, notify
406: //them on the event dispatching thread.[Jon Aquino]
407: try {
408: GUIUtil.invokeOnEventThread(eventFirer);
409: } catch (InterruptedException e) {
410: Assert.shouldNeverReachHere();
411: } catch (InvocationTargetException e) {
412: e.printStackTrace(System.err);
413: Assert.shouldNeverReachHere();
414: }
415:
416: //Note that if the current thread (in which the model was changed) is not
417: //the event dispatching thread, the model changes and the listener notifications
418: //will be asynchronous -- for example, all the model changes might be done
419: //before the listener notifications even begin. This may be a
420: //problem for a threaded plug-in that does moderately complex
421: //insertions and deletions of nodes in the layer tree (e.g. you may see
422: //duplicate tree nodes). If you encounter this problem, try making the
423: //model changes (e.g. #addLayer) on the event thread using
424: //GUIUtil#invokeOnEventThread. [Jon Aquino]
425: }
426:
427: /**
428: * If layerChangeType is DELETED, layerIndex will of course be the index of
429: * the layer in the category prior to removal (not -1).
430: */
431: private void fireLayerChanged(final Layerable layerable,
432: final LayerEventType layerChangeType,
433: final Category category, final int layerIndex) {
434: if (!firingEvents) {
435: return;
436: }
437:
438: //New ArrayList to avoid ConcurrentModificationException [Jon Aquino]
439: for (Iterator i = new ArrayList(layerListeners).iterator(); i
440: .hasNext();) {
441: final LayerListener layerListener = (LayerListener) i
442: .next();
443: fireLayerEvent(new Runnable() {
444: public void run() {
445: layerListener.layerChanged(new LayerEvent(
446: layerable, layerChangeType, category,
447: layerIndex));
448: }
449: });
450: }
451: }
452:
453: //<<TODO:DESIGN>> Most callers of #fireLayerChanged(Layer, LayerChangeType,
454: //LayerCategory, layerIndex) can use this simpler method instead. [Jon Aquino]
455: public void fireLayerChanged(Layerable layerable,
456: LayerEventType type) {
457: Category cat = getCategory(layerable);
458:
459: if (cat == null) {
460: Assert
461: .isTrue(
462: !isFiringEvents(),
463: "If this event is being fired because you are constructing a Layer, "
464: + "cat will be null because you haven't yet added the Layer to the LayerManager. "
465: + "While constructing a layer, you should set firingEvents "
466: + "to false. (Layerable = "
467: + layerable.getName() + ")");
468:
469: return;
470: }
471:
472: fireLayerChanged(layerable, type, cat, cat.indexOf(layerable));
473: }
474:
475: public void setFiringEvents(boolean firingEvents) {
476: this .firingEvents = firingEvents;
477: }
478:
479: public boolean isFiringEvents() {
480: return firingEvents;
481: }
482:
483: /**
484: * @return an iterator over the layers, from bottom to top. Layers with
485: * #drawingLast = true appear last.
486: */
487: public Iterator reverseIterator(Class layerableClass) {
488: ArrayList layerablesCopy = new ArrayList(
489: getLayerables(layerableClass));
490: Collections.reverse(layerablesCopy);
491: moveLayersDrawnLastToEnd(layerablesCopy);
492:
493: return layerablesCopy.iterator();
494: }
495:
496: private void moveLayersDrawnLastToEnd(List layerables) {
497: ArrayList layersDrawnLast = new ArrayList();
498:
499: for (Iterator i = layerables.iterator(); i.hasNext();) {
500: Layerable layerable = (Layerable) i.next();
501:
502: if (!(layerable instanceof Layer)) {
503: continue;
504: }
505:
506: Layer layer = (Layer) layerable;
507:
508: if (layer.isDrawingLast()) {
509: layersDrawnLast.add(layer);
510: i.remove();
511: }
512: }
513:
514: layerables.addAll(layersDrawnLast);
515: }
516:
517: /**
518: * @return Layers, not all Layerables
519: */
520: public Iterator iterator() {
521: //<<TODO:PERFORMANCE>> Create an iterator that doesn't build a Collection of
522: //Layers first (unlike #getLayers) [Jon Aquino]
523: return getLayers().iterator();
524: }
525:
526: /**
527: * @return null if there is no such layer
528: */
529: public Layer getLayer(String name) {
530: for (Iterator i = iterator(); i.hasNext();) {
531: Layer layer = (Layer) i.next();
532:
533: if (layer.getName().equals(name)) {
534: return layer;
535: }
536: }
537:
538: return null;
539: }
540:
541: public void addLayerListener(LayerListener layerListener) {
542: Assert.isTrue(!layerListeners.contains(layerListener));
543: layerListeners.add(layerListener);
544: }
545:
546: public void removeLayerListener(LayerListener layerListener) {
547: layerListeners.remove(layerListener);
548: }
549:
550: public Layer getLayer(int index) {
551: return (Layer) getLayers().get(index);
552: }
553:
554: public int size() {
555: return getLayers().size();
556: }
557:
558: //<<TODO:MAINTAINABILITY>> Search for uses of #getLayerListModel and see if
559: //they can be replaced by #iterator [Jon Aquino]
560: public Envelope getEnvelopeOfAllLayers() {
561: return getEnvelopeOfAllLayers(false);
562: }
563:
564: /**
565: * @param visibleLayersOnly
566: * @return
567: */
568: public Envelope getEnvelopeOfAllLayers(boolean visibleLayersOnly) {
569: Envelope envelope = new Envelope();
570: for (Iterator i = iterator(); i.hasNext();) {
571: Layer layer = (Layer) i.next();
572: if (visibleLayersOnly && !layer.isVisible()) {
573: continue;
574: }
575: envelope.expandToInclude(layer
576: .getFeatureCollectionWrapper().getEnvelope());
577: }
578: return envelope;
579: }
580:
581: /**
582: * @return -1 if the layer does not exist
583: */
584: public int indexOf(Layer layer) {
585: return getLayers().indexOf(layer);
586: }
587:
588: public Category getCategory(Layerable layerable) {
589: for (Iterator i = categories.iterator(); i.hasNext();) {
590: Category category = (Category) i.next();
591:
592: if (category.contains(layerable)) {
593: return category;
594: }
595: }
596:
597: return null;
598: }
599:
600: public List getLayers() {
601: return getLayerables(Layer.class);
602: }
603:
604: /**
605: * To get all Layerables, set layerableClass to Layerable.class.
606: */
607: public List getLayerables(Class layerableClass) {
608: Assert.isTrue(Layerable.class.isAssignableFrom(layerableClass));
609:
610: ArrayList layers = new ArrayList();
611:
612: //Create new ArrayLists to avoid ConcurrentModificationExceptions. [Jon Aquino]
613: for (Iterator i = new ArrayList(categories).iterator(); i
614: .hasNext();) {
615: Category c = (Category) i.next();
616:
617: for (Iterator j = new ArrayList(c.getLayerables())
618: .iterator(); j.hasNext();) {
619: Layerable l = (Layerable) j.next();
620:
621: if (!(layerableClass.isInstance(l))) {
622: continue;
623: }
624:
625: layers.add(l);
626: }
627: }
628:
629: return layers;
630: }
631:
632: public List getVisibleLayers(boolean includeFence) {
633: ArrayList visibleLayers = new ArrayList(getLayers());
634:
635: for (Iterator i = visibleLayers.iterator(); i.hasNext();) {
636: Layer layer = (Layer) i.next();
637:
638: if (layer.getName().equals(FenceLayerFinder.LAYER_NAME)
639: && !includeFence) {
640: i.remove();
641:
642: continue;
643: }
644:
645: if (!layer.isVisible()) {
646: i.remove();
647: }
648: }
649:
650: return visibleLayers;
651: }
652:
653: /**
654: * SIGLE [obedel] on 2005 then [mmichaud] on 2007-05-22
655: * To free the memory allocated for a layer
656: * Called by RemoveSelectedLayersPlugin
657: * @param layerViewPanel the layerViewPanel displaying this layerable
658: * @param layarable the layerable to remove
659: */
660: public void dispose(WorkbenchFrame frame, Layerable layerable) {
661: // removing all LayerRenderers for this Layer
662: JInternalFrame[] internalFrames = frame.getInternalFrames();
663: for (int i = 0; i < internalFrames.length; i++) {
664: JInternalFrame internalFrame = internalFrames[i];
665: if (internalFrame instanceof LayerViewPanelProxy) {
666: ((LayerViewPanelProxy) internalFrame)
667: .getLayerViewPanel().getRenderingManager()
668: .removeLayerRenderer(layerable);
669: }
670: //layerViewPanel.getRenderingManager().removeLayerRenderer(layerable);
671: }
672: for (Iterator i = categories.iterator(); i.hasNext();) {
673: Category c = (Category) i.next();
674: // deleting the layer from the category
675: int index = c.indexOf(layerable);
676: if (index != -1) {
677: c.remove(layerable);
678: for (Iterator j = layerReferencesToDispose.iterator(); j
679: .hasNext();) {
680: WeakReference reference = (WeakReference) j.next();
681: Layer layer = (Layer) reference.get();
682: if (layer == layerable) {
683: // removing the reference to layer
684: layer.dispose();
685: layerManagerCount--;
686: }
687: }
688: // changing appearance of layer tree
689: fireLayerChanged(layerable, LayerEventType.REMOVED, c,
690: index);
691: }
692: }
693: }
694:
695: public void dispose() {
696: for (Iterator i = layerReferencesToDispose.iterator(); i
697: .hasNext();) {
698: WeakReference reference = (WeakReference) i.next();
699: Layer layer = (Layer) reference.get();
700:
701: if (layer != null) {
702: layer.dispose();
703: }
704: }
705:
706: layerManagerCount--;
707:
708: //Undo actions may be holding on to expensive resources; therefore, send
709: //#die to each to request that the resources be freed. [Jon Aquino]
710: undoableEditReceiver.getUndoManager().discardAllEdits();
711: }
712:
713: public static int layerManagerCount() {
714: return layerManagerCount;
715: }
716:
717: /**
718: * Editability is not enforced; all parties are responsible for heeding the
719: * editability of a layer.
720: */
721: public Collection getEditableLayers() {
722: ArrayList editableLayers = new ArrayList();
723:
724: for (Iterator i = getLayers().iterator(); i.hasNext();) {
725: Layer layer = (Layer) i.next();
726:
727: if (layer.isEditable()) {
728: editableLayers.add(layer);
729: }
730: }
731:
732: return editableLayers;
733: }
734:
735: public Blackboard getBlackboard() {
736: return blackboard;
737: }
738:
739: public Collection getLayersWithModifiedFeatureCollections() {
740: ArrayList layersWithModifiedFeatureCollections = new ArrayList();
741:
742: for (Iterator i = iterator(); i.hasNext();) {
743: Layer layer = (Layer) i.next();
744:
745: if (layer.isFeatureCollectionModified()) {
746: layersWithModifiedFeatureCollections.add(layer);
747: }
748: }
749:
750: return layersWithModifiedFeatureCollections;
751: }
752:
753: public void setCoordinateSystem(CoordinateSystem coordinateSystem) {
754: this .coordinateSystem = coordinateSystem;
755:
756: //Don't automatically reproject layers here, because I'd like to use an
757: //EditTransaction, but that requires a LayerViewPanelContext, which is not
758: //available to this LayerManager (but would be available to a plug-in) [Jon Aquino]
759: }
760:
761: public static void main(String[] args) throws ParseException {
762: System.out.println(Line2D.linesIntersect(708248.882609455,
763: 2402253.07294874, 708249.523621829, 2402244.3124463,
764: 708247.896591321, 2402252.48269854, 708261.854734465,
765: 2402182.39086576));
766: System.out
767: .println(new WKTReader()
768: .read(
769: "LINESTRING(708248.882609455 2402253.07294874, 708249.523621829 2402244.3124463)")
770: .intersects(
771: new WKTReader()
772: .read("LINESTRING(708247.896591321 2402252.48269854, 708261.854734465 2402182.39086576)")));
773: }
774:
775: public CoordinateSystem getCoordinateSystem() {
776: return coordinateSystem;
777: }
778:
779: //[UT] 25.08.2005 added
780: public void fireFeaturesAttChanged(final Collection features,
781: final FeatureEventType type, final Layer layer,
782: final Collection oldFeatureClones) {
783: Assert.isTrue(type != FeatureEventType.GEOMETRY_MODIFIED);
784: fireFeaturesChanged(features, type, layer, oldFeatureClones);
785:
786: }
787: }
|