Revision 41098

View differences:

trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.app/org.gvsig.app.mainplugin/src/main/java/org/gvsig/app/project/documents/view/MapOverview.java
28 28
import java.awt.Color;
29 29
import java.awt.Graphics;
30 30
import java.awt.Graphics2D;
31
import java.awt.Point;
31 32
import java.awt.geom.AffineTransform;
32 33
import java.awt.geom.Line2D;
33 34
import java.awt.geom.Point2D;
......
314 315
		//MapControl asociado
315 316
		return;
316 317
	}
318
	
319
	public void calculateSnapPoint(Point point) {
320
	    /*
321
	     * This is the behavior of a MapControl when there is no snapping.
322
	     * We do the same and save a lot of computations
323
	     */
324
        adjustedPoint = point;
325
        mapAdjustedPoint = null;
326
	}
327
	
328
	
329
	
317 330
}
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.app/org.gvsig.app.mainplugin/src/main/java/org/gvsig/app/project/documents/view/toolListeners/snapping/Snapping.java
64 64

  
65 65
    	// mapControlManager.registerSnapper("InsertPointSnapper", new InsertPointSnapper.class);
66 66
    	
67
    	/*
68
    	 * This snapper is not implemented in a sensible way.
69
    	 * We must think if it makes sense and how to implement it 
70
    	 * 
71
    	mapControlManager.registerSnapper("IntersectionPointSnapper", IntersectionPointSnapper.class);
72
    	*/
67
        mapControlManager.registerSnapper("IntersectionPointSnapper", IntersectionPointSnapper.class);
73 68
    	mapControlManager.registerSnapper("MediumPointSnapper", MediumPointSnapper.class);
74 69
    	mapControlManager.registerSnapper("PerpendicularPointSnapper", PerpendicularPointSnapper.class);
75 70
    	mapControlManager.registerSnapper("TangentPointSnapper", TangentPointSnapper.class);
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.app/org.gvsig.app.mainplugin/src/main/java/org/gvsig/app/project/documents/view/toolListeners/snapping/snappers/IntersectionPointSnapper.java
23 23
 */
24 24
package org.gvsig.app.project.documents.view.toolListeners.snapping.snappers;
25 25

  
26
import java.awt.geom.PathIterator;
27 26
import java.awt.geom.Point2D;
27
import java.util.ArrayList;
28
import java.util.Iterator;
28 29
import java.util.List;
29 30

  
31
import com.vividsolutions.jts.geom.GeometryFactory;
32
import com.vividsolutions.jts.geom.MultiPoint;
33
import com.vividsolutions.jts.geom.Point;
34

  
30 35
import org.slf4j.Logger;
31 36
import org.slf4j.LoggerFactory;
32 37

  
33 38
import org.gvsig.fmap.geom.Geometry;
34
import org.gvsig.fmap.geom.operation.GeometryOperationException;
35
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
39
import org.gvsig.fmap.geom.aggregate.MultiCurve;
40
import org.gvsig.fmap.geom.aggregate.MultiSurface;
36 41
import org.gvsig.fmap.geom.primitive.Curve;
42
import org.gvsig.fmap.geom.primitive.Envelope;
43
import org.gvsig.fmap.geom.primitive.Surface;
37 44
import org.gvsig.fmap.mapcontrol.PrimitivesDrawer;
38 45
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapperGeometriesVectorial;
39 46
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.impl.AbstractSnapper;
......
49 56
    implements ISnapperGeometriesVectorial {
50 57
    private static final Logger LOG = LoggerFactory.getLogger(IntersectionPointSnapper.class);
51 58
    
52
	private static int maxPointsGeom = 1000;
53
	private List<Geometry> geometries;
54
	private static long lastLogTime = 0;
59
    public static final int MAX_GEOMETRIES_IN_RELAXED_LIST = 30;
60
    public static final int MAX_GEOMETRIES_WITHIN_TOLERANCE = 5;
61
    
62
	private List relaxedList = null;
63
	private GeometryFactory jtsGeoFact = null;
64
	private long errorMsgCount = 0;
55 65

  
56
    public Point2D getSnapPoint(Point2D point, Geometry geom,
57
        double tolerance, Point2D lastPointEntered) {
58
    	if (!(geom instanceof Curve)){
59
    		return null;
60
    	}
61
    	Point2D result = null;
62

  
63
        if (geometries == null) {
66
    public Point2D getSnapPoint(
67
        Point2D point,
68
        Geometry geom,
69
        double tolerance,
70
        Point2D lastPointEntered) {
71
        
72
        if (geom == null) {
64 73
            return null;
65 74
        }
66

  
67
        for (int i = 0; i < geometries.size(); i++) {
68
        	Point2D r = intersects(geom, geometries.get(i), point, tolerance);
69

  
70
            if (r != null) {
71
                result = r;
72
            }
75
        
76
        if (relaxedList == null
77
            || relaxedList.size() < 2 /* We need 2 to intersect */
78
            || relaxedList.size() > MAX_GEOMETRIES_IN_RELAXED_LIST) {
79
            /*
80
             * If there are a lot of geometries, we assume the user
81
             * is not interested in snapping now. The relaxed list
82
             * might be long because the spatial index used perhaps
83
             * is "lazy" so the value of MAX_GEOMETRIES_IN_RELAXED_LIST
84
             * has to be not very small
85
             */
86
            return null;
73 87
        }
74

  
75
        return result;
76
    }
77

  
78
    private Point2D intersects(Geometry geometry1, Geometry geometry2, Point2D point,
79
            double tolerance) {
80
    	
81
    	//If there is a topology error don't intersects
82
    	if ((geometry1 == null) || (geometry2 == null)){
83
    	    return null;
84
    	}
85

  
86
    	if (hasMoreThanVertices(geometry1, maxPointsGeom)
87
    	    || hasMoreThanVertices(geometry2, maxPointsGeom)) {
88
    	    
89
    	    return null;
90
    	}
91
    	    
92
    	Geometry geometry;
88
        
89
        List<Geometry> refinedList = null;
93 90
        try {
94
            geometry = geometry1.intersection(geometry2);
95
            if ((geometry != null) && (geometry.getType() == Geometry.TYPES.POINT)){
96
                return geometry.getHandlers(Geometry.SELECTHANDLER)[0].getPoint();
91
            refinedList = refineList(relaxedList, point, tolerance);
92
        } catch (Exception e1) {
93
            errorMsgCount++;
94
            if (errorMsgCount % 100 == 0) {
95
                /*
96
                 * Prevents too many lines in logger. If this happens,
97
                 * it will happen many times, so we'll see it in the log file.
98
                 */
99
                LOG.info("Error while refining list: " + e1.getMessage());
100
                errorMsgCount = 0;
97 101
            }
98
        } catch (GeometryOperationNotSupportedException e) {
99
            LOG.error("Unable to intersect these geometries", e);
100
        } catch (GeometryOperationException e) {
101
            LOG.error("Unable to intersect these geometries", e);
102
        } catch (Exception e) {
102
            return null;
103
        }
104
        
105
        if (refinedList.size() > MAX_GEOMETRIES_WITHIN_TOLERANCE) {
103 106
            /*
104
             * Sometimes there is a JTS TopologyException.
105
             * The cause is unknown because it's difficult to
106
             * reproduce, but probably caused by extremely similar
107
             * geometries. This is unlikely to cause functionality
108
             * problems, so we'll only log it once every 5 seconds
109
             * (otherwise the user can see performance issues because
110
             * this exception is thrown many times in those strange
111
             * cases) 
107
             * This refined list contains the geometries that are
108
             * close to the current mouse. Again we use an upper limit
109
             * to prevent the case where the user is in a zoom where
110
             * he is not interested in snapping.
112 111
             */
113
            long curr_time = System.currentTimeMillis();
114
            // This ensures not more than one log every 5 seconds
115
            if (curr_time - lastLogTime > 5000) {
116
                LOG.info("Error while intersecting: " + e.getMessage());
117
                lastLogTime = curr_time;
112
            return null;
113
        }
114
        
115
        List<Point> interPoints = getInterPoints(refinedList);
116
        
117
        if (interPoints.size() == 0) {
118
            return null;
119
        }
120
        
121
        com.vividsolutions.jts.geom.Geometry jtsg = null;
122
        try {
123
            jtsg = (com.vividsolutions.jts.geom.Geometry) geom.invokeOperation("toJTS", null);
124
        } catch (Exception e) {
125
            errorMsgCount++;
126
            if (errorMsgCount % 100 == 0) {
127
                /*
128
                 * Prevents too many lines in logger. If this happens,
129
                 * it will happen many times, so we'll see it in the log file.
130
                 */
131
                LOG.info("Error while refining list: " + e.getMessage());
132
                errorMsgCount = 0;
118 133
            }
119
        }    
120
    	
121
    	return null;
134
            return null;
135
        }
136
        
137
        double zerodist = 0.001 * tolerance;
138
        int n = interPoints.size();
139
        Point po = null;
140
        for (int i=0; i<n; i++) {
141
            po = interPoints.get(i);
142
            if (point.distance(po.getX(), po.getY()) < tolerance) {
143
                // This is a candidate, now we check that it belongs to the
144
                // current geometry
145
                if (jtsg.distance(po) < zerodist) {
146
                    return new Point2D.Double(po.getX(), po.getY());
147
                }
148
            }
149
        }
150
        return null;
122 151
    }
123 152

  
153

  
154
    private List<Geometry> refineList(
155
        List geomlist,
156
        Point2D point,
157
        double tolerance) throws Exception {
158
        
159
        List<Geometry> resp = new ArrayList<Geometry>();
160
        if (geomlist == null || geomlist.size() == 0) {
161
            return resp;
162
        }
163
        
164
        double point_tol_north = point.getY() + tolerance; 
165
        double point_tol_south = point.getY() - tolerance;
166
        double point_tol_east = point.getX() + tolerance;
167
        double point_tol_west = point.getX() - tolerance;
168
        
169
        Geometry item = null;
170
        Envelope env = null;
171
        Iterator iter = geomlist.iterator();
172
        while (iter.hasNext()) {
173
            item = (Geometry) iter.next();
174
            
175
            if (item.intersects(
176
                point_tol_west, point_tol_south,
177
                point_tol_east - point_tol_west,
178
                point_tol_north - point_tol_south)) {
179
                
180
                resp.add(item);
181
            }
182
        }
183
        return resp;
184
    }
185

  
186

  
124 187
    public void draw(PrimitivesDrawer primitivesDrawer, Point2D pPixels) {
125 188
    	primitivesDrawer.setColor(getColor());
126 189

  
......
139 202
    }
140 203

  
141 204
	public void setGeometries(List geoms) {
142
	    this.geometries = geoms;		
205
	    relaxedList = leaveUsefulGeometries(geoms);
143 206
	}
144 207
	
208
	private List<Point> getInterPoints(List geomes) {
209
	    
210
	    List<Point> resp = new ArrayList<Point>();
211
	    List borders = getJTSBorders(geomes);
212
	    com.vividsolutions.jts.geom.Geometry jtsg1 = null;
213
	    com.vividsolutions.jts.geom.Geometry jtsg2 = null;
214
	    com.vividsolutions.jts.geom.Geometry jtsinter = null;
215
	    int n = borders.size();
216
	    Point jtsp = null;
217
	    MultiPoint jtsmp = null;
218
	    
219
	    for (int i=0; i<n; i++) {
220
	        for (int j=0; j<i; j++) {
221
	            if (i != j) {
222
	                jtsg1 = (com.vividsolutions.jts.geom.Geometry) borders.get(i);
223
	                jtsg2 = (com.vividsolutions.jts.geom.Geometry) borders.get(j);
224
	                jtsinter = jtsg1.intersection(jtsg2);
225
	                if (jtsinter instanceof Point) {
226
	                    jtsp = (Point) jtsinter;
227
	                    resp.add(jtsp);
228
	                } else {
229
	                    if (jtsinter instanceof MultiPoint) {
230
	                        
231
	                        jtsmp = (MultiPoint) jtsinter;
232
	                        int m = jtsmp.getNumGeometries();
233
	                        for (int k=0; k<m; k++) {
234
	                            jtsp = (Point) jtsmp.getGeometryN(k);
235
	                            resp.add(jtsp);
236
	                        }
237
	                    }
238
	                }
239
	            }
240
	        }
241
	    }
242
	    return resp;
243
	}
145 244
	
146
	   
147
	/**
148
     * Tells whether geometry has more than n vertices using its path
149
     * iterator
150
     * @param geom
151
     * @param n
152
     * @return
153
     */
154
    private static boolean hasMoreThanVertices(Geometry geom, int n) {
245

  
246
    private List getJTSBorders(List gvsigGeoms) {
155 247
        
156
        PathIterator piter = geom.getPathIterator(null);
157
        if (piter == null) {
158
            return false;
159
        }
248
        List resp = new ArrayList();
249
        com.vividsolutions.jts.geom.Geometry jtsborder = null;
160 250
        
161
        if (n < 1) {
162
            return true;
251
        if (gvsigGeoms != null && gvsigGeoms.size() > 0) {
252
            
253
            Iterator iter = gvsigGeoms.iterator();
254
            Object itemobj = null;
255
            
256
            while (iter.hasNext()) {
257
                itemobj = iter.next();
258
                if (itemobj instanceof Geometry) {
259
                    jtsborder = getJTSBorder((Geometry) itemobj);
260
                    if (jtsborder != null) {
261
                        resp.add(jtsborder);
262
                    }
263
                }
264
            }
163 265
        }
266
        return resp;
267
    }
164 268

  
165
        int cnt = n;
166
        while (!piter.isDone()) {
167
            piter.next();
168
            cnt--;
169
            if (cnt == 0) {
170
                return true;
269
    private com.vividsolutions.jts.geom.Geometry getJTSBorder(Geometry geom) {
270
        
271
        com.vividsolutions.jts.geom.Geometry resp = null;
272
        
273
        if (geom instanceof Curve || geom instanceof MultiCurve) {
274
            
275
            try {
276
                resp = (com.vividsolutions.jts.geom.Geometry)
277
                    geom.invokeOperation("toJTS", null);
278
            } catch (Exception e) {
279
                errorMsgCount++;
280
                if (errorMsgCount % 100 == 0) {
281
                    /*
282
                     * Prevents too many lines in logger. If this happens,
283
                     * it will happen many times, so we'll see it in the log file.
284
                     */
285
                    LOG.info("Error while refining list: " + e.getMessage());
286
                    errorMsgCount = 0;
287
                }
288
                return null;
171 289
            }
290
            return resp;
291
            
292
        } else {
293
            if (geom instanceof Surface || geom instanceof MultiSurface) {
294
                
295
                try {
296
                    resp = (com.vividsolutions.jts.geom.Geometry)
297
                        geom.invokeOperation("toJTS", null);
298
                    return resp.getBoundary();
299
                } catch (Exception e) {
300
                    
301
                    errorMsgCount++;
302
                    if (errorMsgCount % 100 == 0) {
303
                        /*
304
                         * Prevents too many lines in logger. If this happens,
305
                         * it will happen many times, so we'll see it in the log file.
306
                         */
307
                        LOG.info("Error while refining list: " + e.getMessage());
308
                        errorMsgCount = 0;
309
                    }
310
                    return null;
311
                }
312
                
313
            } else {
314
                return null;
315
            }
172 316
        }
173
        return false;
317
        
174 318
    }
319
  
320
    
321
    private List<Geometry> leaveUsefulGeometries(List geoms) {
322
        
323
        List resp = new ArrayList();
324
        if (geoms == null || geoms.size() == 0) {
325
            return resp;
326
        }
327
        
328
        Object item = null;
329
        Iterator iter = geoms.iterator();
330
        while (iter.hasNext()) {
331
            item = iter.next();
332
            if (item instanceof Curve || item instanceof Surface
333
                || item instanceof MultiCurve || item instanceof MultiSurface) {
334
                resp.add(item);
335
            }
336
        }
337
        return resp;
338
    }        
339

  
175 340
}
trunk/org.gvsig.desktop/org.gvsig.desktop.library/org.gvsig.fmap.control/src/main/java/org/gvsig/fmap/mapcontrol/MapControl.java
502 502
     * 
503 503
     * @see ViewPort#fromMapPoint(Point2D)
504 504
     */
505
    private Point2D adjustedPoint;
505
    protected Point2D adjustedPoint;
506 506
    /**
507 507
     * <p>
508 508
     * Determines if the position of the snap of the mouse's cursor on the
......
557 557
     * 
558 558
     * @see MapControl#toMapPoint
559 559
     */
560
    private Point2D mapAdjustedPoint;
560
    protected Point2D mapAdjustedPoint;
561 561

  
562 562
    /**
563 563
     * Renderer used to draw the layers.

Also available in: Unified diff