Revision 326

View differences:

org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.app/org.gvsig.vectorediting.app.mainplugin/src/main/assembly/gvsig-plugin-package.xml
82 82
		<include>org.gvsig:org.gvsig.vectorediting.lib.prov.join</include>
83 83
	    <include>org.gvsig:org.gvsig.vectorediting.lib.prov.stretch</include>
84 84
	    <include>org.gvsig:org.gvsig.vectorediting.lib.prov.extendline</include>
85
	    <include>org.gvsig:org.gvsig.vectorediting.lib.prov.split</include>
85 86

  
86 87
      </includes>
87 88
    </dependencySet>
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.app/org.gvsig.vectorediting.app.mainplugin/src/main/resources-plugin/config.xml
131 131
      <action name="modify-duplicate" label="modify_duplicate" tooltip="modify_duplicate"
132 132
        position="601002900" action-command="modify-duplicate" icon="modify-duplicate"
133 133
        accelerator="" />
134

  
135
       <action name="modify-split-line" label="modify_split_line" tooltip="modify_split_line"
136
        position="601003000" action-command="modify-split-line" icon="modify-split-line"
134
        
135
       <action name="modify-split" label="modify_split" tooltip="modify_split"
136
        position="601003000" action-command="modify-split" icon="modify-split"
137 137
        accelerator="" />
138
        
139
      <action name="modify-split-line" label="modify_split_line" tooltip="modify_split_line"
140
        position="601003050" action-command="modify-split-line" icon="modify-split-line"
141
        accelerator="" />
138 142

  
139 143
      <action name="modify-scale" label="modify_scale" tooltip="modify_scale"
140 144
        position="601003100" action-command="modify-scale" icon="modify-scale"
......
185 189
      <menu text="Layer/Modify/modify_rotate" name="modify-rotate" />
186 190
      <menu text="Layer/Modify/modify_duplicate" name="modify-duplicate" />
187 191
      <menu text="Layer/Modify/modify_split_line" name="modify-split-line" />
192
      <menu text="Layer/Modify/modify_split" name="modify-split" />
188 193
      <menu text="Layer/Modify/modify_scale" name="modify-scale" />
189 194
      <menu text="Layer/Modify/modify_simplify" name="modify-simplify" />
190 195
      <menu text="Layer/Modify/insert_autopolygon" name="insert_autopolygon" />
......
216 221
        <selectable-tool name="modify-move" />
217 222
        <selectable-tool name="modify-rotate" />
218 223
        <selectable-tool name="modify-duplicate" />
224
        <selectable-tool name="modify-split" />
219 225
        <selectable-tool name="modify-split-line" />
220 226
        <selectable-tool name="modify-scale" />
221 227
        <selectable-tool name="modify-simplify" />
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.app/org.gvsig.vectorediting.app.mainplugin/pom.xml
198 198
                org.gvsig.vectorediting.lib.prov.extendline
199 199
    	   </artifactId>
200 200
		</dependency>
201
		<dependency>
202
			<groupId>org.gvsig</groupId>
203
			<artifactId>
204
				org.gvsig.vectorediting.lib.prov.split
205
			</artifactId>
206
		</dependency>
201 207
	</dependencies>
202 208
</project>
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/pom.xml
271 271
      	        </artifactId>
272 272
				<version>1.0.1-SNAPSHOT</version>
273 273
			</dependency>
274
			<dependency>
275
				<groupId>org.gvsig</groupId>
276
				<artifactId>
277
					org.gvsig.vectorediting.lib.prov.split
278
				</artifactId>
279
				<version>1.0.1-SNAPSHOT</version>
280
			</dependency>
274 281
		</dependencies>
275 282
	</dependencyManagement>
276 283
</project>
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/pom.xml
31 31
		<module>org.gvsig.vectorediting.lib.prov.join</module>
32 32
		<module>org.gvsig.vectorediting.lib.prov.stretch</module>
33 33
		<module>org.gvsig.vectorediting.lib.prov.extendline</module>
34
		<module>org.gvsig.vectorediting.lib.prov.split</module>
34 35
	</modules>
35 36
	<dependencies>
36 37
		<dependency>
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/resources/META-INF/services/org.gvsig.tools.library.Library
1
org.gvsig.vectorediting.lib.prov.split.SplitEditingLibrary
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/SplitOperation.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2014 gvSIG Association
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

  
25
package org.gvsig.vectorediting.lib.prov.split.operation;
26

  
27
import org.gvsig.fmap.geom.Geometry;
28
import org.gvsig.fmap.geom.exception.CreateGeometryException;
29
import org.gvsig.fmap.geom.operation.GeometryOperationException;
30
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
31

  
32
/**
33
 * @author llmarques
34
 *
35
 */
36
public interface SplitOperation {
37

  
38
    /**
39
     * Splits the geometry by a other splitter geometry. If splitter does not
40
     * intersect geometry return original geometry.
41
     * 
42
     * @param geometryToBeSplitted
43
     *            to be splitted
44
     * @param splitter
45
     *            the geometry that splits other geometries
46
     * @return If splitter does not intersect return original geometry, else
47
     *         return splitted geometry.
48
     */
49
    public Geometry split(Geometry geometryToBeSplitted, Geometry splitter)
50
        throws GeometryOperationNotSupportedException,
51
        GeometryOperationException, CreateGeometryException;
52

  
53
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/SplitOperationUtils.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2014 gvSIG Association
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

  
25
package org.gvsig.vectorediting.lib.prov.split.operation;
26

  
27
import java.util.HashMap;
28
import java.util.Map;
29

  
30
import org.gvsig.fmap.geom.GeometryLocator;
31
import org.gvsig.fmap.geom.Geometry.TYPES;
32
import org.gvsig.fmap.geom.exception.CreateGeometryException;
33
import org.gvsig.fmap.geom.operation.GeometryOperationException;
34
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
35
import org.gvsig.fmap.geom.primitive.Curve;
36
import org.gvsig.fmap.geom.primitive.Point;
37
import org.gvsig.fmap.geom.primitive.Primitive;
38

  
39
/**
40
 * @author llmarques
41
 *
42
 */
43
public class SplitOperationUtils {
44

  
45
    private static Map<Integer, SplitOperation> operations =
46
        new HashMap<Integer, SplitOperation>();
47

  
48
    private SplitOperationUtils() {
49
    }
50

  
51
    public static void register(SplitOperation operation, int geometryType) {
52
        operations.put(geometryType, operation);
53
    }
54

  
55
    public static SplitOperation getOperation(Primitive geom) {
56
        Integer type = geom.getGeometryType().getType();
57

  
58
        SplitOperation operation = operations.get(type);
59

  
60
        return operation;
61
    }
62

  
63
    // FIXME: Deletes method when geometry manager has this utility method.
64
    public static Point getMidPoint(Point a, Point b, int subtype)
65
        throws CreateGeometryException {
66
        double x = (a.getX() + b.getX()) / 2;
67
        double y = (a.getY() + b.getY()) / 2;
68
        return createPoint(x, y, subtype);
69
    }
70

  
71
    // FIXME: Deletes method when geometry manager has this utility method.
72
    public static Point createPoint(double x, double y, int subtype)
73
        throws CreateGeometryException {
74
        Point point = null;
75
        point =
76
            (Point) GeometryLocator.getGeometryManager().create(TYPES.POINT,
77
                subtype);
78
        point.setX(x);
79
        point.setY(y);
80
        return point;
81
    }
82

  
83
    // FIXME: Deletes method when geometry manager has this utility methods.
84
    public static Point[] getPerpendicular(Double m, Double b, Point perp,
85
        int subtype) throws CreateGeometryException {
86
        if (m == Double.POSITIVE_INFINITY) {
87
            Point[] res = new Point[2];
88
            res[0] = createPoint(0, perp.getY(), subtype);
89
            res[1] = createPoint(1, perp.getY(), subtype);
90
            return res;
91
        } else if (m == Double.NEGATIVE_INFINITY) {
92
            Point[] res = new Point[2];
93
            res[0] = createPoint(1, perp.getY(), subtype);
94
            res[1] = createPoint(0, perp.getY(), subtype);
95
            return res;
96
        } else {
97
            // Pendiente de la recta perpendicular
98
            Double m1 = -1 / m;
99

  
100
            // b de la funcion de la recta perpendicular
101
            Double b1 = perp.getY() - (m1 * perp.getX());
102

  
103
            // Obtenemos un par de puntos
104
            Point[] res = new Point[2];
105

  
106
            if (Double.isInfinite(m1)) {
107
                res[0] = createPoint(perp.getX(), 0.0, subtype);
108
                res[1] = createPoint(perp.getX(), perp.getY(), subtype);
109
            } else {
110
                res[0] = createPoint(0, 0.0 + b1, subtype);
111
                res[1] =
112
                    createPoint(perp.getX(), (m1 * perp.getX()) + b1, subtype);
113
            }
114

  
115
            return res;
116
        }
117
    }
118

  
119
    // FIXME: Deletes method when geometry manager has this utility method.
120
    public static Double[] getLineParams(Point point, Point nextPoint) {
121
        Double[] lineParams = new Double[2];
122
        double denom = nextPoint.getX() - point.getX();
123
        if (denom != 0) {
124
            lineParams[0] = (nextPoint.getY() - point.getY()) / denom;
125
            lineParams[1] = point.getY() - (lineParams[0] * point.getX());
126
        } else {
127
            if (nextPoint.getY() >= point.getY()) {
128
                lineParams[0] = Double.POSITIVE_INFINITY;
129
                lineParams[1] = Double.NEGATIVE_INFINITY;
130
                if (point.getX() == 0) {
131
                    lineParams[1] = 0.0;
132
                }
133
            } else {
134
                lineParams[0] = Double.NEGATIVE_INFINITY;
135
                lineParams[1] = Double.POSITIVE_INFINITY;
136
                if (point.getX() == 0) {
137
                    lineParams[1] = 0.0;
138
                }
139
            }
140
        }
141
        return lineParams;
142
    }
143

  
144
    // FIXME: Deletes method when geometry manager has this utility method.
145
    public static Point getIntersection(Point[] lineA, Point[] lineB,
146
        int subtype) throws CreateGeometryException {
147
        Point p1 = lineA[0];
148
        Point p2 = lineA[1];
149
        Point p3 = lineB[0];
150
        Point p4 = lineB[1];
151

  
152
        double m1 = Double.POSITIVE_INFINITY;
153

  
154
        if ((p2.getX() - p1.getX()) != 0) {
155
            m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
156
        }
157

  
158
        double m2 = Double.POSITIVE_INFINITY;
159

  
160
        if ((p4.getX() - p3.getX()) != 0) {
161
            m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
162
        }
163

  
164
        if ((m1 == Double.POSITIVE_INFINITY)
165
            && (m2 == Double.POSITIVE_INFINITY)) {
166
            return null;
167
        }
168

  
169
        double b1 = p2.getY() - (m1 * p2.getX());
170

  
171
        double b2 = p4.getY() - (m2 * p4.getX());
172

  
173
        if ((m1 != Double.POSITIVE_INFINITY)
174
            && (m2 != Double.POSITIVE_INFINITY)) {
175
            if (m1 == m2) {
176
                return null;
177
            }
178

  
179
            double x = (b2 - b1) / (m1 - m2);
180

  
181
            return createPoint(x, (m1 * x) + b1, subtype);
182
        } else if (m1 == Double.POSITIVE_INFINITY) {
183
            double x = p1.getX();
184

  
185
            return createPoint(x, (m2 * x) + b2, subtype);
186
        } else if (m2 == Double.POSITIVE_INFINITY) {
187
            double x = p3.getX();
188

  
189
            return createPoint(x, (m1 * x) + b1, subtype);
190
        }
191

  
192
        return null;
193
    }
194

  
195
    // FIXME: Deletes method when geometry manager has this utility method.
196
    public static double getAngle(Point start, Point end)
197
        throws GeometryOperationNotSupportedException,
198
        GeometryOperationException {
199
        double angle =
200
            Math.acos((end.getX() - start.getX()) / start.distance(end));
201

  
202
        if (start.getY() > end.getY()) {
203
            angle = -angle;
204
        }
205

  
206
        if (angle < 0) {
207
            angle += (2 * Math.PI);
208
        }
209

  
210
        return angle;
211
    }
212

  
213
    public static Point getCenterOfCurve(Point p1, Point p2, Point p3, Point p4)
214
        throws CreateGeometryException {
215

  
216
        if (!p1.equals(p2) && !p3.equals(p4)) {
217

  
218
            int subtype = p1.getGeometryType().getSubType();
219

  
220
            Point midPointChord1 =
221
                SplitOperationUtils.getMidPoint(p1, p2, subtype);
222
            Point midPointChord2 =
223
                SplitOperationUtils.getMidPoint(p3, p4, subtype);
224

  
225
            Double[] bisector1Params =
226
                SplitOperationUtils.getLineParams(p1, p2);
227

  
228
            Double[] bisector2Params =
229
                SplitOperationUtils.getLineParams(p3, p4);
230

  
231
            Point[] bisector1 =
232
                SplitOperationUtils.getPerpendicular(bisector1Params[0],
233
                    bisector1Params[1], midPointChord1, subtype);
234
            Point[] bisector2 =
235
                SplitOperationUtils.getPerpendicular(bisector2Params[0],
236
                    bisector2Params[1], midPointChord2, subtype);
237

  
238
            return getIntersection(bisector1, bisector2, subtype);
239
        }
240
        return null;
241
    }
242

  
243
    public static Point getCenterOfCurve(Point p1, Point p2, Point p3)
244
        throws CreateGeometryException {
245

  
246
        if (!p1.equals(p2) && !p2.equals(p3)) {
247

  
248
            int subtype = p1.getGeometryType().getSubType();
249

  
250
            Double[] lineAParams = SplitOperationUtils.getLineParams(p1, p2);
251
            Double[] lineBParams = SplitOperationUtils.getLineParams(p2, p3);
252

  
253
            double mA = lineAParams[0]; // slope of A line
254
            double mB = lineBParams[0]; // slope of B line
255
            
256
            if (mB - mA != 0) {
257
                
258
                double x =
259
                    (mA * mB * (p1.getY() - p3.getY()) + mB
260
                        * (p1.getX() + p2.getX()) - mA
261
                        * (p2.getX() + p3.getX()))
262
                        / (2 * (mB - mA));
263

  
264
                Point midPointA =
265
                    SplitOperationUtils.getMidPoint(p1, p2, subtype);
266

  
267
                Point[] bisectorA =
268
                    SplitOperationUtils.getPerpendicular(lineAParams[0],
269
                        lineAParams[1], midPointA, subtype);
270

  
271
                Double[] bisectorAParams =
272
                    SplitOperationUtils.getLineParams(bisectorA[0],
273
                        bisectorA[1]);
274

  
275
                double mBisector = bisectorAParams[0]; // slope of bisector
276
                double yBisector = bisectorAParams[1]; // y-intercept of
277
                                                       // bisector
278

  
279
                double y = x * mBisector + yBisector;
280

  
281
                return createPoint(x, y, subtype);
282

  
283
            }
284
        }
285
        return null;
286
    }
287
    
288
    /**
289
     * Method use to know what segment intersect with projected point. Due to
290
     * accuracy of doubles it is necessary to create a buffer of line to know if
291
     * it intersects.
292
     * 
293
     * @param curve
294
     *            segment of line
295
     * @param projectedPoint
296
     *            of line
297
     * @return true if segment intersects with projected point, else false.
298
     */
299
    public static boolean intersects(Curve curve, Point projectedPoint)
300
        throws GeometryOperationNotSupportedException,
301
        GeometryOperationException {
302

  
303
        double tolerance = 2;
304

  
305
        return curve.buffer(tolerance).intersects(projectedPoint);
306
    }
307
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/CurveSplitOperation.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2014 gvSIG Association
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

  
25
package org.gvsig.vectorediting.lib.prov.split.operation;
26

  
27
import org.gvsig.fmap.geom.Geometry;
28
import org.gvsig.fmap.geom.GeometryLocator;
29
import org.gvsig.fmap.geom.aggregate.MultiCurve;
30
import org.gvsig.fmap.geom.aggregate.MultiPoint;
31
import org.gvsig.fmap.geom.exception.CreateGeometryException;
32
import org.gvsig.fmap.geom.operation.GeometryOperationException;
33
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
34
import org.gvsig.fmap.geom.primitive.Curve;
35
import org.gvsig.fmap.geom.primitive.Point;
36

  
37
/**
38
 * @author llmarques
39
 *
40
 */
41
public class CurveSplitOperation implements SplitOperation {
42

  
43
    /*
44
     * Strategy:
45
     * 
46
     * 1. Get intersection points.
47
     * 2. Get difference between geometry and splitter. If splitter does not
48
     * touch geometry return original geometry.
49
     * 3. If any intersection points are not equal to first or last vertex of
50
     * original geometry, join last and first curve splitted. It's necessary do
51
     * it because the difference between geometry and splitter returns a
52
     * multicurve that its first curve starts at first vertex of ORGINAL and
53
     * ends at first intersection point and its last curve starts at
54
     * last intersection point and ends at last vertex of ORIGINAL geometry, so
55
     * we have to join them. If any intersecion points are equal to first or
56
     * last vertex do nothing.
57
     */
58
    public Geometry split(Geometry geometryToBeSplitted, Geometry splitter)
59
        throws GeometryOperationNotSupportedException,
60
        GeometryOperationException, CreateGeometryException {
61

  
62
        Curve curveToBeSplitted = (Curve) geometryToBeSplitted;
63

  
64
        Geometry intersection = geometryToBeSplitted.intersection(splitter);
65
        MultiCurve multicurveSplitted = null;
66

  
67
        if (intersection instanceof MultiPoint) {
68
            MultiPoint intersectionMultiPoint = (MultiPoint) intersection;
69
            Point firstVertex = intersectionMultiPoint.getPointAt(0);
70
            Point lastVertex =
71
                intersectionMultiPoint.getPointAt(intersectionMultiPoint
72
                    .getPrimitivesNumber() - 1);
73

  
74
            MultiCurve difference =
75
                (MultiCurve) geometryToBeSplitted.difference(splitter);
76

  
77
            if (difference == null) {
78
                return geometryToBeSplitted;
79
            }
80

  
81
            if (!firstVertex.equals(curveToBeSplitted.getVertex(0))
82
                && !lastVertex.equals(curveToBeSplitted.getVertex(0))) {
83

  
84
                Curve firstCurve = difference.getCurveAt(0);
85
                Curve lastCurve =
86
                    difference.getCurveAt(difference.getPrimitivesNumber() - 1);
87

  
88
                Curve union =
89
                    GeometryLocator.getGeometryManager().createLine(
90
                        geometryToBeSplitted.getGeometryType().getSubType());
91
                for (int i = 0; i < lastCurve.getNumVertices(); i++) {
92
                    union.addVertex(lastCurve.getVertex(i));
93
                }
94

  
95
                for (int i = 0; i < firstCurve.getNumVertices(); i++) {
96
                    union.addVertex(firstCurve.getVertex(i));
97
                }
98

  
99
                multicurveSplitted =
100
                    GeometryLocator.getGeometryManager().createMultiCurve(
101
                        geometryToBeSplitted.getGeometryType().getSubType());
102

  
103
                multicurveSplitted.addCurve(union);
104
                for (int i = 1; i < difference.getPrimitivesNumber() - 1; i++) {
105
                    multicurveSplitted.addCurve(difference.getCurveAt(i));
106
                }
107
            } else {
108
                multicurveSplitted = difference;
109
            }
110
        }
111
        return multicurveSplitted;
112
    }
113
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/ArcSplitOperation.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2014 gvSIG Association
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

  
25
package org.gvsig.vectorediting.lib.prov.split.operation;
26

  
27
import java.util.ArrayList;
28
import java.util.Collections;
29
import java.util.Comparator;
30
import java.util.List;
31

  
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34

  
35
import org.gvsig.fmap.geom.Geometry;
36
import org.gvsig.fmap.geom.GeometryLocator;
37
import org.gvsig.fmap.geom.GeometryManager;
38
import org.gvsig.fmap.geom.aggregate.MultiCurve;
39
import org.gvsig.fmap.geom.aggregate.MultiPoint;
40
import org.gvsig.fmap.geom.exception.CreateGeometryException;
41
import org.gvsig.fmap.geom.operation.GeometryOperationException;
42
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
43
import org.gvsig.fmap.geom.primitive.Arc;
44
import org.gvsig.fmap.geom.primitive.Point;
45
import org.gvsig.tools.exception.BaseException;
46

  
47
/**
48
 * @author llmarques
49
 *
50
 */
51
public class ArcSplitOperation implements SplitOperation {
52

  
53
    private static Logger logger = LoggerFactory
54
        .getLogger(ArcSplitOperation.class);
55

  
56
    /*
57
     * Strategy:
58
     * 
59
     * 1. Get intersection points.
60
     * 2. Get center and radius
61
     * 3. Order intersections points by angle
62
     * 4. Iterate over ordered intersection points and create splitted arcs.
63
     * Stop iteration when all intersections points have been iterated.
64
     */
65
    public Geometry split(Geometry geometryToBeSplitted, Geometry splitter)
66
        throws GeometryOperationNotSupportedException,
67
        GeometryOperationException, CreateGeometryException {
68

  
69
        int subtype = geometryToBeSplitted.getGeometryType().getSubType();
70
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
71

  
72
        Arc arcToBeSplitted = (Arc) geometryToBeSplitted;
73

  
74
        MultiPoint intersections =
75
            (MultiPoint) arcToBeSplitted.intersection(splitter);
76

  
77
        if (intersections == null) {
78
            return geometryToBeSplitted;
79
        }
80

  
81
        // Arc#getCenterPoint can return null if two points of arc are the same
82
        Point tmpCenter = arcToBeSplitted.getCenterPoint();
83
        if (tmpCenter == null) {
84
            // If center is null, we use this "trick". Get center of arc
85
            // envelope.
86
            tmpCenter =
87
                SplitOperationUtils.createPoint(arcToBeSplitted.getEnvelope()
88
                    .getCenter(0), arcToBeSplitted.getEnvelope().getCenter(1),
89
                    subtype);
90
        }
91
        final Point center = tmpCenter;
92

  
93
        double radius = center.distance(arcToBeSplitted.getEndPoint());
94

  
95
        // Order intersection points by angle to create arcs correctly
96
        List<Point> orderedIntersectionPoints = new ArrayList<Point>();
97
        for (int i = 0; i < intersections.getPrimitivesNumber(); i++) {
98
            orderedIntersectionPoints.add(intersections.getPointAt(i));
99
        }
100

  
101
        // Sort by angle
102
        Collections.sort(orderedIntersectionPoints, new Comparator<Point>() {
103

  
104
            public int compare(Point p1, Point p2) {
105
                double angle1 = 0;
106
                double angle2 = 0;
107
                try {
108
                    angle1 = SplitOperationUtils.getAngle(center, p1);
109
                    angle2 = SplitOperationUtils.getAngle(center, p2);
110
                } catch (BaseException e) {
111
                    logger.warn("Problems getting angle between center and"
112
                        + " one intersection point");
113
                    return 0;
114
                }
115
                return Double.compare(angle1, angle2);
116
            }
117
        });
118

  
119
        MultiCurve splittedArcs = geoManager.createMultiCurve(subtype);
120

  
121
        for (int i = 0; i < orderedIntersectionPoints.size(); i++) {
122
            Point intersecctionPoint = orderedIntersectionPoints.get(i);
123
            Point nextIntersecctionPoint;
124

  
125
            if (i + 1 >= orderedIntersectionPoints.size()) {
126
                nextIntersecctionPoint = orderedIntersectionPoints.get(0);
127
            } else {
128
                nextIntersecctionPoint = orderedIntersectionPoints.get(i + 1);
129
            }
130

  
131
            double angle1 =
132
                SplitOperationUtils.getAngle(center, intersecctionPoint);
133
            double angle2 =
134
                SplitOperationUtils.getAngle(center, nextIntersecctionPoint);
135

  
136
            Arc arc = (Arc) geoManager.create(Geometry.TYPES.ARC, subtype);
137

  
138
            arc.setPointsStartEnd(center, radius, angle1, angle2);
139
            splittedArcs.addCurve(arc);
140
        }
141

  
142
        return splittedArcs;
143
    }
144
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/splitsurface/SplitGraphNode.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/* Spatial Operations & Editing Tools for uDig
25
 * 
26
 * Axios Engineering under a funding contract with: 
27
 *      Diputación Foral de Gipuzkoa, Ordenación Territorial 
28
 *
29
 *      http://b5m.gipuzkoa.net
30
 *      http://www.axios.es 
31
 *
32
 * (C) 2006, Diputación Foral de Gipuzkoa, Ordenación Territorial (DFG-OT). 
33
 * DFG-OT agrees to licence under Lesser General Public License (LGPL).
34
 * 
35
 * You can redistribute it and/or modify it under the terms of the 
36
 * GNU Lesser General Public License as published by the Free Software 
37
 * Foundation; version 2.1 of the License.
38
 *
39
 * This library is distributed in the hope that it will be useful,
40
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42
 * Lesser General Public License for more details.
43
 */
44
package org.gvsig.vectorediting.lib.prov.split.operation.splitsurface;
45

  
46
import com.vividsolutions.jts.geom.Coordinate;
47
import com.vividsolutions.jts.geomgraph.DirectedEdge;
48
import com.vividsolutions.jts.geomgraph.EdgeEnd;
49
import com.vividsolutions.jts.geomgraph.Node;
50

  
51
/**
52
 * Custom node type. Does nothing special by now but to force the use of {@link SplitEdgeStar}
53
 * instances as the node's list of incident edges and allow to remove edges from its list of
54
 * incident edges.
55
 * 
56
 * @author Gabriel Roldán, Axios Engineering
57
 * @author Mauricio Pazos, Axios Engineering
58
 * @since 1.1.0
59
 */
60
class SplitGraphNode extends Node {
61
    public SplitGraphNode( Coordinate coord, SplitEdgeStar incidentEdges ) {
62
        super(coord, incidentEdges);
63
    }
64

  
65
    public void add( DirectedEdge edge ) {
66
        super.add(edge);
67
    }
68

  
69
    @Override
70
    public void add( EdgeEnd edge ) {
71
        add((DirectedEdge) edge);
72
    }
73

  
74
    /**
75
     * Removes the given <code>edge</code> from this node's {@link #getEdges() edge list}.
76
     * 
77
     * @param edge
78
     */
79
    public void remove( DirectedEdge edge ) {
80
        SplitEdgeStar edges = (SplitEdgeStar) getEdges();
81
        edges.remove(edge);
82
    }
83

  
84
    public String toString() {
85
        StringBuffer sb = new StringBuffer("Node[");
86
        sb.append(coord.x).append(":").append(coord.y);
87
        sb.append(", ").append(label);
88
        sb.append(", ").append(getEdges());
89
        sb.append("]");
90
        return sb.toString();
91
    }
92
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/splitsurface/SurfaceSplitOperation.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2014 gvSIG Association
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

  
25
package org.gvsig.vectorediting.lib.prov.split.operation.splitsurface;
26

  
27
import java.util.ArrayList;
28
import java.util.Iterator;
29
import java.util.List;
30

  
31
import com.vividsolutions.jts.algorithm.CGAlgorithms;
32
import com.vividsolutions.jts.geom.Coordinate;
33
import com.vividsolutions.jts.geom.CoordinateArrays;
34
import com.vividsolutions.jts.geom.GeometryFactory;
35
import com.vividsolutions.jts.geom.LineString;
36
import com.vividsolutions.jts.geom.LinearRing;
37
import com.vividsolutions.jts.geom.Location;
38
import com.vividsolutions.jts.geom.Polygon;
39
import com.vividsolutions.jts.geomgraph.DirectedEdge;
40
import com.vividsolutions.jts.geomgraph.Node;
41

  
42
import org.gvsig.fmap.geom.Geometry;
43
import org.gvsig.fmap.geom.GeometryLocator;
44
import org.gvsig.fmap.geom.GeometryManager;
45
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
46
import org.gvsig.fmap.geom.operation.GeometryOperationException;
47
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
48
import org.gvsig.vectorediting.lib.prov.split.operation.SplitOperation;
49

  
50
/**
51
 * This class is based in the AXIOS team work for UDIG project.
52
 * 
53
 * @author llmarques
54
 *
55
 */
56

  
57
/*
58
 * Performs a split of a LineString, MultiLineString, Polygon or MultiPolygon
59
 * using a provided
60
 * LineString as cutting edge.
61
 * 
62
 * @author Gabriel Roldán, Axios Engineering
63
 * 
64
 * @author Mauricio Pazos, Axios Engineering
65
 * 
66
 * @since 1.1.0
67
 */
68
public class SurfaceSplitOperation implements SplitOperation {
69

  
70
    /**
71
     * Strategy:
72
     * <ul>
73
     * <li>Build a graph with all edges and intersection nodes between polygon
74
     * and linestring.
75
     * <li>Weigth the amount of nodes according to the number of incident edges.
76
     * Nodes are only the intersection beetween polygon bondary and linestring
77
     * and initial points of each part of boundary.
78
     * <li>Weigth edges according to shared (linestring node) or non shared
79
     * (boundary of polygon). Store edge cordinates at edge.
80
     * <li>Iterate over node graph. Start at any node, starting at its first
81
     * segment.
82
     * <li>Iterate always to next node, choosing the edge that its first
83
     * linestring segment that has less left angle (CCW) with the last segment
84
     * of edge linestring.
85
     * <li>Delete non shared used edges that was used
86
     * <li>Decrease weight at 1 of used nodes
87
     * <li>Delete of graph nodes with weight 1
88
     * </ul>
89
     * 
90
     * @author Gabriel Roldán, Axios Engineering
91
     * @author Mauricio Pazos, Axios Engineering
92
     * @since 1.1.0
93
     */
94
    public Geometry split(Geometry geometryToBeSplitted, Geometry splitter)
95
        throws GeometryOperationNotSupportedException,
96
        GeometryOperationException {
97

  
98
        com.vividsolutions.jts.geom.Geometry jtsGeom =
99
            (com.vividsolutions.jts.geom.Geometry) geometryToBeSplitted
100
                .invokeOperation("toJTS", null);
101

  
102
        com.vividsolutions.jts.geom.Geometry jtsSplitter =
103
            (com.vividsolutions.jts.geom.Geometry) splitter.invokeOperation(
104
                "toJTS", null);
105

  
106
        if (jtsGeom instanceof Polygon && jtsSplitter instanceof LineString) {
107
            SplitGraph graph =
108
                new SplitGraph((Polygon) jtsGeom, (LineString) jtsSplitter);
109
            final GeometryFactory gf = jtsGeom.getFactory();
110

  
111
            // store unsplitted holes for later addition
112
            List<LinearRing> unsplittedHoles = findUnsplittedHoles(graph, gf);
113

  
114
            List<List<SplitEdge>> allRings = findRings(graph);
115

  
116
            List<Polygon> resultingPolygons =
117
                buildSimplePolygons(allRings, unsplittedHoles, gf);
118

  
119
            com.vividsolutions.jts.geom.Geometry result;
120
            if (resultingPolygons.size() == 1) {
121
                result = resultingPolygons.get(0);
122
            } else {
123
                Polygon[] array =
124
                    resultingPolygons.toArray(new Polygon[resultingPolygons
125
                        .size()]);
126
                result = gf.createMultiPolygon(array);
127
            }
128

  
129
            GeometryManager manager = GeometryLocator.getGeometryManager();
130
            GeometryOperationContext params = new GeometryOperationContext();
131
            params.setAttribute("JTSGeometry", result);
132
            return (Geometry) manager.invokeOperation("fromJTS", params);
133
        }
134
        return null;
135
    }
136

  
137
    /**
138
     * Finds out and removes from the graph the edges that were originally holes
139
     * in the polygon and were not splitted by the splitting line.
140
     * 
141
     * @param graph
142
     * @param gf
143
     * @return
144
     */
145
    private List<LinearRing> findUnsplittedHoles(SplitGraph graph,
146
        GeometryFactory gf) {
147
        final List<LinearRing> unsplittedHoles = new ArrayList<LinearRing>(2);
148

  
149
        final List<SplitEdge> edges = new ArrayList<SplitEdge>();
150
        for (Iterator it = graph.getEdgeIterator(); it.hasNext();) {
151
            SplitEdge edge = (SplitEdge) it.next();
152
            edges.add(edge);
153
        }
154

  
155
        for (Iterator it = edges.iterator(); it.hasNext();) {
156
            SplitEdge edge = (SplitEdge) it.next();
157
            if (edge.isHoleEdge()) {
158
                Coordinate[] coordinates = edge.getCoordinates();
159
                Coordinate start = coordinates[0];
160
                Coordinate end = coordinates[coordinates.length - 1];
161
                boolean isLinearRing = start.equals2D(end);
162
                if (isLinearRing) {
163
                    graph.remove(edge);
164
                    LinearRing ring = gf.createLinearRing(coordinates);
165
                    unsplittedHoles.add(ring);
166
                }
167
            }
168
        }
169
        return unsplittedHoles;
170
    }
171

  
172
    /**
173
     * Builds a list of rings from the graph's edges
174
     * 
175
     * @param graph
176
     * @return
177
     */
178
    private List<List<SplitEdge>> findRings(SplitGraph graph) {
179
        final List<List<SplitEdge>> rings = new ArrayList<List<SplitEdge>>();
180

  
181
        DirectedEdge startEdge;
182
        // build each ring starting with the first edge belonging to the
183
        // shell found
184
        while ((startEdge = findShellEdge(graph)) != null) {
185
            List<SplitEdge> ring = buildRing(graph, startEdge);
186
            rings.add(ring);
187
        }
188
        return rings;
189
    }
190

  
191
    /**
192
     * Returns the first edge found that belongs to the shell (not an interior
193
     * edge, not one of a hole boundary)
194
     * <p>
195
     * This method relies on shell edges being labeled {@link Location#EXTERIOR
196
     * exterior} to the left and {@link Location#INTERIOR interior} to the
197
     * right.
198
     * </p>
199
     * 
200
     * @param graph
201
     * @return the first shell edge found, or <code>null</code> if there are no
202
     *         more shell edges in <code>graph</code>
203
     */
204
    private DirectedEdge findShellEdge(SplitGraph graph) {
205
        Iterator it = graph.getEdgeEnds().iterator();
206
        DirectedEdge firstShellEdge = null;
207
        while (it.hasNext()) {
208
            DirectedEdge de = (DirectedEdge) it.next();
209
            SplitEdge edge = (SplitEdge) de.getEdge();
210
            if (edge.isShellEdge()) {
211
                firstShellEdge = de;
212
                break;
213
            }
214
        }
215
        return firstShellEdge;
216
    }
217

  
218
    private List<SplitEdge> buildRing(final SplitGraph graph,
219
        final DirectedEdge startEdge) {
220
        final List<SplitEdge> ring = new ArrayList<SplitEdge>();
221

  
222
        // follow this tessellation direction while possible,
223
        // switch to the opposite when not, and continue with
224
        // the same direction while possible.
225
        // Start travelling clockwise, as we start with a shell edge,
226
        // which is in clockwise order
227
        final int direction = CGAlgorithms.COUNTERCLOCKWISE;
228

  
229
        DirectedEdge currentDirectedEdge = startEdge;
230
        DirectedEdge nextDirectedEdge = null;
231

  
232
        while (nextDirectedEdge != startEdge) {
233
            SplitEdge edge = (SplitEdge) currentDirectedEdge.getEdge();
234
            if (ring.contains(edge)) {
235
                throw new IllegalStateException("trying to add edge twice: "
236
                    + edge);
237
            }
238
            ring.add(edge);
239

  
240
            DirectedEdge sym = currentDirectedEdge.getSym();
241
            SplitGraphNode endNode = (SplitGraphNode) sym.getNode();
242
            SplitEdgeStar nodeEdges = (SplitEdgeStar) endNode.getEdges();
243
            nextDirectedEdge =
244
                nodeEdges.findClosestEdgeInDirection(sym, direction);
245

  
246
            assert nextDirectedEdge != null;
247

  
248
            currentDirectedEdge = nextDirectedEdge;
249
        }
250

  
251
        removeUnneededEdges(graph, ring);
252
        return ring;
253
    }
254

  
255
    /**
256
     * Removes from <code>graph</code> the edges in <code>ring</code> that are
257
     * no more needed
258
     * 
259
     * @param graph
260
     * @param ring
261
     */
262
    private void removeUnneededEdges(final SplitGraph graph,
263
        final List<SplitEdge> ring) {
264
        for (SplitEdge edge : ring) {
265
            if (!edge.isInteriorEdge()) {
266
                graph.remove(edge);
267
            }
268
        }
269

  
270
        for (SplitEdge edge : ring) {
271
            if (edge.isInteriorEdge()) {
272
                Node node = graph.find(edge.getCoordinate());
273
                int degree = node.getEdges().getDegree();
274
                if (degree < 2) {
275
                    graph.remove(edge);
276
                }
277
            }
278
        }
279
    }
280

  
281
    private List<Polygon> buildSimplePolygons(List<List<SplitEdge>> allRings,
282
        List<LinearRing> unsplittedHoles, GeometryFactory gf) {
283

  
284
        List<Polygon> polygons = new ArrayList<Polygon>(allRings.size());
285

  
286
        for (List<SplitEdge> edgeList : allRings) {
287
            Polygon poly = buildPolygon(edgeList, gf);
288
            List<LinearRing> thisPolyHoles =
289
                new ArrayList<LinearRing>(unsplittedHoles.size());
290
            for (LinearRing holeRing : unsplittedHoles) {
291
                if (poly.covers(holeRing)) {
292
                    thisPolyHoles.add(holeRing);
293
                }
294
            }
295
            unsplittedHoles.removeAll(thisPolyHoles);
296

  
297
            int numHoles = thisPolyHoles.size();
298
            if (numHoles > 0) {
299
                LinearRing[] holes =
300
                    thisPolyHoles.toArray(new LinearRing[numHoles]);
301
                LinearRing shell =
302
                    gf.createLinearRing(poly.getExteriorRing().getCoordinates());
303
                poly = gf.createPolygon(shell, holes);
304
            }
305

  
306
            polygons.add(poly);
307
        }
308

  
309
        return polygons;
310
    }
311

  
312
    private Polygon buildPolygon(List<SplitEdge> edgeList, GeometryFactory gf) {
313
        List<Coordinate> coords = new ArrayList<Coordinate>();
314
        Coordinate[] lastCoordinates = null;
315
        for (SplitEdge edge : edgeList) {
316
            Coordinate[] coordinates = edge.getCoordinates();
317
            if (lastCoordinates != null) {
318
                Coordinate endPoint =
319
                    lastCoordinates[lastCoordinates.length - 1];
320
                Coordinate startPoint = coordinates[0];
321
                if (!endPoint.equals2D(startPoint)) {
322
                    coordinates = CoordinateArrays.copyDeep(coordinates);
323
                    CoordinateArrays.reverse(coordinates);
324
                }
325
            }
326
            lastCoordinates = coordinates;
327
            for (int i = 0; i < coordinates.length; i++) {
328
                Coordinate coord = coordinates[i];
329
                coords.add(coord);
330
            }
331
        }
332
        Coordinate[] shellCoords = new Coordinate[coords.size()];
333
        coords.toArray(shellCoords);
334
        shellCoords = CoordinateArrays.removeRepeatedPoints(shellCoords);
335
        LinearRing shell = gf.createLinearRing(shellCoords);
336
        Polygon poly = gf.createPolygon(shell, (LinearRing[]) null);
337
        return poly;
338
    }
339

  
340
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/splitsurface/SplitEdgeStar.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/* Spatial Operations & Editing Tools for uDig
25
 * 
26
 * Axios Engineering under a funding contract with: 
27
 *      Diputación Foral de Gipuzkoa, Ordenación Territorial 
28
 *
29
 *      http://b5m.gipuzkoa.net
30
 *      http://www.axios.es 
31
 *
32
 * (C) 2006, Diputación Foral de Gipuzkoa, Ordenación Territorial (DFG-OT). 
33
 * DFG-OT agrees to licence under Lesser General Public License (LGPL).
34
 * 
35
 * You can redistribute it and/or modify it under the terms of the 
36
 * GNU Lesser General Public License as published by the Free Software 
37
 * Foundation; version 2.1 of the License.
38
 *
39
 * This library is distributed in the hope that it will be useful,
40
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42
 * Lesser General Public License for more details.
43
 */
44
package org.gvsig.vectorediting.lib.prov.split.operation.splitsurface;
45

  
46
import java.util.ArrayList;
47
import java.util.Iterator;
48
import java.util.List;
49

  
50
import com.vividsolutions.jts.algorithm.Angle;
51
import com.vividsolutions.jts.algorithm.CGAlgorithms;
52
import com.vividsolutions.jts.geom.Coordinate;
53
import com.vividsolutions.jts.geomgraph.DirectedEdge;
54
import com.vividsolutions.jts.geomgraph.DirectedEdgeStar;
55
import com.vividsolutions.jts.geomgraph.EdgeEnd;
56
import com.vividsolutions.jts.util.Assert;
57

  
58
/**
59
 * A {@link DirectedEdgeStar} for the {@link SplitGraphNode nodes} in a {@link SplitGraph}
60
 * 
61
 * @author Gabriel Roldán, Axios Engineering
62
 * @author Mauricio Pazos, Axios Engineering
63
 * @since 1.1.0
64
 */
65
class SplitEdgeStar extends DirectedEdgeStar {
66

  
67
    /**
68
     * Adds a DirectedEdge to the list of incident edges on this star
69
     * 
70
     * @param de non null directed edge to insert on this node star
71
     */
72
    public void insert( DirectedEdge de ) {
73
        if (de == null) {
74
            throw new NullPointerException();
75
        }
76
        insertEdgeEnd(de, de);
77
    }
78

  
79
    /**
80
     * Overrides {@link DirectedEdgeStar#insert(EdgeEnd)} just to delegate to
81
     * {@link #insert(DirectedEdge)} forcing the argument type
82
     */
83
    @Override
84
    public void insert( EdgeEnd ee ) {
85
        insert((DirectedEdge) ee);
86
    }
87

  
88
    /**
89
     * Removes the given edge from this edge star
90
     * 
91
     * @param edge
92
     * @throws IllegalArgumentException if <code>edge</code> is not one of this star's edges
93
     */
94
    public void remove( DirectedEdge edge ) {
95
        if (edge == null) {
96
            throw new NullPointerException("edge");
97
        }
98
        int degree = getDegree();
99
        Object removed = edgeMap.remove(edge);
100
        int afterDegree = getDegree();
101
        Assert.isTrue(afterDegree == degree - 1);
102
        if (edge != removed) {
103
            throw new IllegalArgumentException(
104
                                               "Tried to remove an edge not registered in this edge star: "
105
                                                       + edge);
106
        }
107
        edgeList = null; // edge list has changed - clear the cache
108
    }
109

  
110
    /**
111
     * Returns the list of Directed edges whose direction is outgoing from this star's node. That
112
     * is, for all the DirectedEdges in the star, if the edge's start point is coincident whith the
113
     * edge star node, returns the same DirectedNode, otherwise returns the edge's
114
     * {@link DirectedEdge#getSym() symmetric edge}.
115
     * 
116
     * @return
117
     */
118
    private List getOutgoingEdges() {
119
        final Coordinate nodeCoord = getCoordinate();
120
        final List edges = getEdges();
121
        final List outgoingEdges = new ArrayList(edges.size());
122
        for( Iterator it = edges.iterator(); it.hasNext(); ) {
123
            DirectedEdge edge = (DirectedEdge) it.next();
124
            if (!nodeCoord.equals2D(edge.getCoordinate())) {
125
                edge = edge.getSym();
126
            }
127
            assert nodeCoord.equals2D(edge.getCoordinate());
128
            outgoingEdges.add(edge);
129
        }
130
        return outgoingEdges;
131
    }
132

  
133
    /**
134
     * Finds the first edge to the passed in in the <code>searchDrirection</code> direction.
135
     * 
136
     * @param searchDirection one of {@link CGAlgorithms#CLOCKWISE},
137
     *        {@link CGAlgorithms#COUNTERCLOCKWISE}
138
     * @return the edge forming the acutest angle with <code>edge</code> in the
139
     *         <code>prefferredDirection</code> or <code>null</code> if there are no edges in
140
     *         the prefferred direction.
141
     */
142
    public DirectedEdge findClosestEdgeInDirection( DirectedEdge edge, final int searchDirection ) {
143
        if (edge == null) {
144
            throw new NullPointerException("edge");
145
        }
146
        if (CGAlgorithms.CLOCKWISE != searchDirection
147
                && CGAlgorithms.COUNTERCLOCKWISE != searchDirection) {
148
            throw new IllegalArgumentException("Allowed values for for searchDirection "
149
                    + "are CGAlgorithms.CLOCKWISE and CGAlgorithms.COUNTERCLOCKWISE: "
150
                    + searchDirection);
151
        }
152

  
153
        // ensure we're using the node's outgoing edge
154
        if (super.findIndex(edge) == -1) {
155
            edge = edge.getSym();
156
            if (super.findIndex(edge) == -1) {
157
                throw new IllegalArgumentException("Edge does not belongs to this edgestar");
158
            }
159
        }
160
        final int degree = getDegree();
161
        if (degree < 2) {
162
            throw new IllegalStateException("there must be at least two edges in the edge star");
163
        }
164
        final Coordinate nodeCoord = getCoordinate();
165

  
166
        assert nodeCoord.equals2D(edge.getCoordinate());
167

  
168
        double acutestAngle = Double.MAX_VALUE;
169
        DirectedEdge acutest = null;
170
        DirectedEdge adjacentEdge = null;
171

  
172
        final Coordinate tip1 = edge.getDirectedCoordinate();
173
        final Coordinate tail = nodeCoord;
174

  
175
        // ensure we're using outgoing edges
176
        final List outgoingEdges = getOutgoingEdges();
177
        for( Iterator it = outgoingEdges.iterator(); it.hasNext(); ) {
178
            adjacentEdge = (DirectedEdge) it.next();
179

  
180
            if (adjacentEdge == edge) {
181
                continue;
182
            }
183

  
184
            Coordinate tip2 = adjacentEdge.getDirectedCoordinate();
185

  
186
            double angle = computeAngleInDirection(tip1, tail, tip2, searchDirection);
187

  
188
            if (angle < acutestAngle) {
189
                acutestAngle = angle;
190
                acutest = adjacentEdge;
191
            }
192
        }
193

  
194
        return acutest;
195
    }
196

  
197
    /**
198
     * Computes the angle comprised between the vector <code>tail:tip1</code> looking in the
199
     * specified <code>direction</code> to the vector <code>tail:tip2</code>
200
     * 
201
     * @param tip1
202
     * @param tail
203
     * @param tip2
204
     * @param direction one of {@link CGAlgorithms#CLOCKWISE},
205
     *        {@link CGAlgorithms#COUNTERCLOCKWISE}
206
     * @return the angle in radians defined by the vectors tail-tip1:tail-tip2 calculated in the
207
     *         specified <code>direction</code> from tail-tip1
208
     */
209
    public double computeAngleInDirection( Coordinate tip1, Coordinate tail, Coordinate tip2,
210
                                           int direction ) {
211
        final int orientation = CGAlgorithms.computeOrientation(tail, tip1, tip2);
212

  
213
        // minimal angle (non oriented)
214
        double angle = Angle.angleBetween(tip1, tail, tip2);
215
        if (orientation != direction) {
216
            angle = Angle.PI_TIMES_2 - angle;
217
        }
218
        return angle;
219
    }
220

  
221
    public String toString() {
222
        StringBuffer sb = new StringBuffer("SplitEdgeStar[degree: ");
223
        sb.append(getDegree()).append(", edges: ");
224
        for( Iterator it = getEdges().iterator(); it.hasNext(); ) {
225
            DirectedEdge de = (DirectedEdge) it.next();
226
            sb.append("DirectedEdge[");
227
            sb.append(de.getEdge()).append(" ");
228
            sb.append("]");
229
        }
230
        sb.append("]");
231
        return sb.toString();
232
    }
233

  
234
}
org.gvsig.vectorediting/trunk/org.gvsig.vectorediting/org.gvsig.vectorediting.lib/org.gvsig.vectorediting.lib.prov/org.gvsig.vectorediting.lib.prov.split/src/main/java/org/gvsig/vectorediting/lib/prov/split/operation/splitsurface/SplitGraphNodeFactory.java
1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/* Spatial Operations & Editing Tools for uDig
25
 * 
26
 * Axios Engineering under a funding contract with: 
27
 *      Diputación Foral de Gipuzkoa, Ordenación Territorial 
28
 *
29
 *      http://b5m.gipuzkoa.net
30
 *      http://www.axios.es 
31
 *
32
 * (C) 2006, Diputación Foral de Gipuzkoa, Ordenación Territorial (DFG-OT). 
33
 * DFG-OT agrees to licence under Lesser General Public License (LGPL).
34
 * 
35
 * You can redistribute it and/or modify it under the terms of the 
36
 * GNU Lesser General Public License as published by the Free Software 
37
 * Foundation; version 2.1 of the License.
38
 *
39
 * This library is distributed in the hope that it will be useful,
40
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42
 * Lesser General Public License for more details.
43
 */
44
package org.gvsig.vectorediting.lib.prov.split.operation.splitsurface;
45

  
46
import com.vividsolutions.jts.geom.Coordinate;
47
import com.vividsolutions.jts.geomgraph.Node;
48
import com.vividsolutions.jts.geomgraph.NodeFactory;
49

  
50
/**
51
 * Custom node factory to create {@link SplitGraphNode}s initialized with an empty
52
 * {@link SplitEdgeStar}
53
 * 
54
 * @author Gabriel Roldán, Axios Engineering
55
 * @author Mauricio Pazos, Axios Engineering
56
 * @since 1.1.0
57
 * @see SplitGraphNode
58
 */
59
class SplitGraphNodeFactory extends NodeFactory {
60

  
61
    public Node createNode( Coordinate coord ) {
62
        return new SplitGraphNode(coord, new SplitEdgeStar());
63
    }
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff