gvsig-vectorediting / org.gvsig.vectorediting.offset / trunk / org.gvsig.vectorediting.offset / org.gvsig.vectorediting.offset.lib / org.gvsig.vectorediting.offset.lib.prov / org.gvsig.vectorediting.offset.lib.prov.offset / src / main / java / org / gvsig / vectorediting / offset / lib / prov / offset / OffsetEditingProvider.java @ 2873
History | View | Annotate | Download (38 KB)
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 |
package org.gvsig.vectorediting.offset.lib.prov.offset; |
25 |
|
26 |
import java.text.DecimalFormat; |
27 |
import java.util.ArrayList; |
28 |
import java.util.HashMap; |
29 |
import java.util.List; |
30 |
import java.util.Map; |
31 |
import org.apache.commons.lang3.StringUtils; |
32 |
import org.gvsig.fmap.dal.exception.DataException; |
33 |
import org.gvsig.fmap.dal.feature.EditableFeature; |
34 |
import org.gvsig.fmap.dal.feature.Feature; |
35 |
import org.gvsig.fmap.dal.feature.FeatureSelection; |
36 |
import org.gvsig.fmap.dal.feature.FeatureStore; |
37 |
import org.gvsig.fmap.geom.Geometry; |
38 |
import static org.gvsig.fmap.geom.Geometry.JOIN_STYLE_ROUND; |
39 |
import org.gvsig.fmap.geom.GeometryException; |
40 |
import org.gvsig.fmap.geom.GeometryLocator; |
41 |
import org.gvsig.fmap.geom.GeometryManager; |
42 |
import org.gvsig.fmap.geom.GeometryUtils; |
43 |
import org.gvsig.fmap.geom.aggregate.Aggregate; |
44 |
import org.gvsig.fmap.geom.aggregate.MultiCurve; |
45 |
import org.gvsig.fmap.geom.aggregate.MultiPoint; |
46 |
import org.gvsig.fmap.geom.aggregate.MultiSurface; |
47 |
import org.gvsig.fmap.geom.operation.GeometryOperationException; |
48 |
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException; |
49 |
import org.gvsig.fmap.geom.primitive.Arc; |
50 |
import org.gvsig.fmap.geom.primitive.Circle; |
51 |
import org.gvsig.fmap.geom.primitive.Circumference; |
52 |
import org.gvsig.fmap.geom.primitive.Curve; |
53 |
import org.gvsig.fmap.geom.primitive.Ellipse; |
54 |
import org.gvsig.fmap.geom.primitive.FilledSpline; |
55 |
import org.gvsig.fmap.geom.primitive.Line; |
56 |
import org.gvsig.fmap.geom.primitive.PeriEllipse; |
57 |
import org.gvsig.fmap.geom.primitive.Point; |
58 |
import org.gvsig.fmap.geom.primitive.Polygon; |
59 |
import org.gvsig.fmap.geom.primitive.Primitive; |
60 |
import org.gvsig.fmap.geom.primitive.Spline; |
61 |
import org.gvsig.fmap.geom.primitive.Surface; |
62 |
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol; |
63 |
import org.gvsig.symbology.SymbologyLocator; |
64 |
import org.gvsig.symbology.SymbologyManager; |
65 |
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text.ISimpleTextSymbol; |
66 |
import org.gvsig.tools.ToolsLocator; |
67 |
import org.gvsig.tools.dataTypes.DataTypes; |
68 |
import org.gvsig.tools.dispose.DisposableIterator; |
69 |
import org.gvsig.tools.dispose.DisposeUtils; |
70 |
import org.gvsig.tools.dynobject.DynObject; |
71 |
import org.gvsig.tools.i18n.I18nManager; |
72 |
import org.gvsig.tools.service.spi.ProviderServices; |
73 |
import org.gvsig.vectorediting.lib.api.DrawingStatus; |
74 |
import org.gvsig.vectorediting.lib.api.EditingServiceParameter; |
75 |
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE; |
76 |
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException; |
77 |
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException; |
78 |
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException; |
79 |
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException; |
80 |
import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException; |
81 |
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider; |
82 |
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus; |
83 |
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter; |
84 |
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameterOptions; |
85 |
import org.gvsig.vectorediting.lib.spi.EditingProvider; |
86 |
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory; |
87 |
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator; |
88 |
import org.gvsig.vectorediting.lib.spi.EditingProviderManager; |
89 |
import org.gvsig.vectorediting.lib.spi.EditingProviderServices; |
90 |
|
91 |
public class OffsetEditingProvider extends AbstractEditingProvider implements |
92 |
EditingProvider { |
93 |
|
94 |
private static final Double PRECISION = 1.0e-5; |
95 |
|
96 |
private static final String SIDE = "_side"; |
97 |
|
98 |
private static final String LEFT = "_left"; |
99 |
|
100 |
private static final String RIGHT = "_right"; |
101 |
|
102 |
private static final String SHORT_LEFT = "_short_left"; |
103 |
|
104 |
private static final String SHORT_RIGHT = "_short_right"; |
105 |
|
106 |
private static final String JOIN_STYLE = "_join_style"; |
107 |
|
108 |
private static final String ROUND = "_round"; |
109 |
|
110 |
private static final String MITRE = "_mitre"; |
111 |
|
112 |
private static final String BEVEL = "_bevel"; |
113 |
|
114 |
private static final String SHORT_ROUND = "_short_round"; |
115 |
|
116 |
private static final String SHORT_MITRE = "_short_mitre"; |
117 |
|
118 |
private static final String SHORT_BEVEL = "_short_bevel"; |
119 |
|
120 |
private final EditingServiceParameter selectionParameter; |
121 |
|
122 |
private final EditingServiceParameter offsetParameter; |
123 |
|
124 |
private final EditingServiceParameter sideParameter; |
125 |
|
126 |
private final DefaultEditingServiceParameter joinStyleParameter; |
127 |
|
128 |
private final EditingServiceParameter equidistantOffsets; |
129 |
|
130 |
private final EditingServiceParameter deleteOriginalGeometriesParameter; |
131 |
|
132 |
// private boolean deleteOriginalGeometries = false;
|
133 |
|
134 |
private Map<EditingServiceParameter, Object> values; |
135 |
|
136 |
// private final Map<String, String> options;
|
137 |
|
138 |
private final FeatureStore featureStore; |
139 |
|
140 |
public OffsetEditingProvider(ProviderServices providerServices, DynObject parameters) {
|
141 |
super(providerServices);
|
142 |
this.featureStore = (FeatureStore) parameters.getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
|
143 |
I18nManager i18nManager = ToolsLocator.getI18nManager(); |
144 |
|
145 |
EditingProviderServices editingProviderServices |
146 |
= (EditingProviderServices) getProviderServices(); |
147 |
|
148 |
this.selectionParameter
|
149 |
= new DefaultEditingServiceParameter("selection", |
150 |
i18nManager.getTranslation("selection"), TYPE.SELECTION);
|
151 |
|
152 |
this.offsetParameter
|
153 |
= new DefaultEditingServiceParameter("offset_distance", |
154 |
i18nManager.getTranslation("offset_distance"),
|
155 |
TYPE.POSITION, TYPE.VALUE, TYPE.DISTANCE); |
156 |
|
157 |
Map<String, String> sideOptions = new HashMap<>(); |
158 |
sideOptions.put(i18nManager.getTranslation(SHORT_LEFT), i18nManager.getTranslation(LEFT)); |
159 |
sideOptions.put(i18nManager.getTranslation(SHORT_RIGHT), i18nManager.getTranslation(RIGHT)); |
160 |
|
161 |
String sideConsoleMsg
|
162 |
= ((EditingProviderServices)providerServices).makeConsoleMessage( |
163 |
i18nManager.getTranslation(SIDE), sideOptions); |
164 |
|
165 |
|
166 |
this.sideParameter
|
167 |
= new DefaultEditingServiceParameter("side", |
168 |
sideConsoleMsg, |
169 |
sideOptions, |
170 |
TYPE.OPTION, TYPE.POSITION).setDataType(DataTypes.STRING); |
171 |
|
172 |
DefaultEditingServiceParameterOptions joinStyleOptions = new DefaultEditingServiceParameterOptions()
|
173 |
.add(i18nManager.getTranslation(ROUND), ROUND, i18nManager.getTranslation(SHORT_ROUND)) |
174 |
.add(i18nManager.getTranslation(MITRE), MITRE, i18nManager.getTranslation(SHORT_MITRE)) |
175 |
.add(i18nManager.getTranslation(BEVEL), BEVEL, i18nManager.getTranslation(SHORT_BEVEL)); |
176 |
|
177 |
|
178 |
String joinStyleConsoleMsg = ((EditingProviderServices)providerServices).makeConsoleMessage(
|
179 |
i18nManager.getTranslation(JOIN_STYLE), joinStyleOptions); |
180 |
|
181 |
this.joinStyleParameter
|
182 |
= new DefaultEditingServiceParameter(
|
183 |
"joinStyle",
|
184 |
joinStyleConsoleMsg, |
185 |
joinStyleOptions, |
186 |
i18nManager.getTranslation(SHORT_ROUND), |
187 |
true,
|
188 |
TYPE.OPTION); //.setDataType(DataTypes.STRING);
|
189 |
this.joinStyleParameter.setDefaultValue(ROUND);
|
190 |
|
191 |
|
192 |
this.equidistantOffsets = new DefaultEditingServiceParameter("equidistant_offsets", "equidistant_offsets", true, TYPE.VALUE); |
193 |
this.equidistantOffsets.setDefaultValue(1); |
194 |
|
195 |
DefaultEditingServiceParameterOptions deleteOriginalGeometriesOptions2 = new DefaultEditingServiceParameterOptions()
|
196 |
.add("delete_original_geometries", true, i18nManager.getTranslation("_yes")) |
197 |
.add("keep_original_geometries", false, i18nManager.getTranslation("_no")); |
198 |
|
199 |
String consoleMsg
|
200 |
= editingProviderServices.makeConsoleMessage( |
201 |
"delete_original_geometries_question", deleteOriginalGeometriesOptions2);
|
202 |
|
203 |
this.deleteOriginalGeometriesParameter
|
204 |
= new DefaultEditingServiceParameter(
|
205 |
i18nManager.getTranslation("delete_original_geometries"),
|
206 |
consoleMsg, |
207 |
deleteOriginalGeometriesOptions2, |
208 |
false,
|
209 |
TYPE.OPTION).setDataType(DataTypes.BOOLEAN); |
210 |
|
211 |
} |
212 |
|
213 |
@Override
|
214 |
public EditingServiceParameter next() {
|
215 |
|
216 |
if (values.get(selectionParameter) == null) { |
217 |
return selectionParameter;
|
218 |
} |
219 |
if (values.get(offsetParameter) == null) { |
220 |
return offsetParameter;
|
221 |
} |
222 |
if (values.get(sideParameter) == null) { |
223 |
Object offsetValue = values.get(offsetParameter);
|
224 |
if (!(offsetValue instanceof Point)) { |
225 |
Double distance = (Double) offsetValue; |
226 |
if (distance >= 0) { |
227 |
return sideParameter;
|
228 |
} |
229 |
} |
230 |
} |
231 |
|
232 |
if (values.get(deleteOriginalGeometriesParameter) == null) { |
233 |
return this.deleteOriginalGeometriesParameter; |
234 |
} |
235 |
|
236 |
return null; |
237 |
} |
238 |
|
239 |
@Override
|
240 |
public DrawingStatus getDrawingStatus(Point mousePosition) throws DrawServiceException { |
241 |
DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
|
242 |
EditingProviderManager editingProviderManager |
243 |
= EditingProviderLocator.getProviderManager(); |
244 |
EditingProviderServices editingProviderServices = |
245 |
(EditingProviderServices) getProviderServices(); |
246 |
int subtype;
|
247 |
try {
|
248 |
subtype = editingProviderServices.getSubType(featureStore); |
249 |
} catch (DataException e2) {
|
250 |
throw new DrawServiceException(e2); |
251 |
} |
252 |
ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
|
253 |
ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
|
254 |
ISymbol auxiliaryLineSymbolEditingDirection = editingProviderManager.getSymbol("auxiliary-line-symbol-editing-direction");
|
255 |
ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
|
256 |
ISymbol polygonSymbolEditing = editingProviderManager.getSymbol("polygon-symbol-editing");
|
257 |
|
258 |
if (values != null) { |
259 |
Number equidistantOffsetsNumberValue = ((Number) values.get(this.equidistantOffsets)); |
260 |
int equidistantOffsetsValue = equidistantOffsetsNumberValue != null ? equidistantOffsetsNumberValue.intValue() : ((Number) this.equidistantOffsets.getDefaultValue()).intValue(); |
261 |
|
262 |
FeatureSelection selected |
263 |
= (FeatureSelection) values.get(selectionParameter); |
264 |
try {
|
265 |
if ((selected != null) && !selected.isEmpty()) { |
266 |
Point point; // = null; |
267 |
double distance = 0.0; |
268 |
double side = 1.0; |
269 |
Object offsetValue = values.get(offsetParameter);
|
270 |
|
271 |
if (offsetValue != null) { |
272 |
if (offsetValue instanceof Point) { |
273 |
distance = Math.abs(getMinDistance(selected, (Point) offsetValue)); |
274 |
} else {
|
275 |
distance = (Double) offsetValue;
|
276 |
} |
277 |
|
278 |
Object sideValue = values.get(sideParameter);
|
279 |
if (sideValue == null) { |
280 |
point = mousePosition; |
281 |
side = Math.signum(getMinDistance(selected, point));
|
282 |
} else {
|
283 |
Double signum = getSideSignum((String) sideValue); |
284 |
if (signum != null) { |
285 |
side = signum; |
286 |
} |
287 |
} |
288 |
} else {
|
289 |
point = mousePosition; |
290 |
Geometry closestGeometry = getClosestGeometry(selected, point); |
291 |
Point closestPoint = getClosestPoint(closestGeometry, point);
|
292 |
distance = getMinDistance(selected, point); //closestPoint.distance(point); //getMinDistance(selected, point);
|
293 |
ISymbol symbol = lineSymbolEditing; |
294 |
Line auxLine = GeometryUtils.createLine(closestPoint, point, subtype);
|
295 |
drawingStatus.addStatus( |
296 |
auxLine, |
297 |
auxiliaryLineSymbolEditing, |
298 |
""
|
299 |
); |
300 |
|
301 |
Point pointText = GeometryUtils.createPoint(
|
302 |
0.5 * (closestPoint.getX() + point.getX()),
|
303 |
0.5 * (closestPoint.getY() + point.getY())
|
304 |
); |
305 |
|
306 |
ISimpleTextSymbol textSymbol = getTextSymbol(); |
307 |
drawingStatus.addStatus( |
308 |
pointText, |
309 |
textSymbol, |
310 |
new DecimalFormat("#.0#").format(distance) |
311 |
); |
312 |
|
313 |
} |
314 |
|
315 |
int joinStyleValue = coerceJoinStyle(values.get(joinStyleParameter));
|
316 |
|
317 |
DisposableIterator it; |
318 |
it = selected.fastIterator(); |
319 |
|
320 |
while (it.hasNext()) {
|
321 |
Feature feat = (Feature) it.next(); |
322 |
|
323 |
ISymbol previewSymbol = this.getPreviewSymbol(feat);
|
324 |
|
325 |
for (int c = 1; c <= equidistantOffsetsValue; c++) { |
326 |
|
327 |
Geometry transformedGeometry = feat.getDefaultGeometry().offset(joinStyleValue, c * distance * side); |
328 |
|
329 |
ISymbol symbol = null;
|
330 |
if (transformedGeometry instanceof Curve || transformedGeometry instanceof MultiCurve) { |
331 |
symbol = lineSymbolEditing; |
332 |
drawingStatus.addStatus(feat.getDefaultGeometry(), auxiliaryLineSymbolEditingDirection, "Direction");
|
333 |
} else if (transformedGeometry instanceof Surface || transformedGeometry instanceof MultiSurface) { |
334 |
symbol = polygonSymbolEditing; |
335 |
} else if (transformedGeometry instanceof Point || transformedGeometry instanceof MultiPoint) { |
336 |
symbol = auxiliaryPointSymbolEditing; |
337 |
} |
338 |
if (transformedGeometry instanceof Aggregate) { |
339 |
int primitivesNumber = ((Aggregate) transformedGeometry).getPrimitivesNumber();
|
340 |
for (int i = 0; i < primitivesNumber; i++) { |
341 |
final Primitive primitive = ((Aggregate) transformedGeometry).getPrimitiveAt(i);
|
342 |
drawingStatus.addStatus(primitive, symbol, "");
|
343 |
drawingStatus.addStatus(primitive, previewSymbol, "");
|
344 |
} |
345 |
} else {
|
346 |
drawingStatus.addStatus(transformedGeometry, symbol, "");
|
347 |
drawingStatus.addStatus(transformedGeometry, previewSymbol, "");
|
348 |
} |
349 |
} |
350 |
} |
351 |
DisposeUtils.disposeQuietly(it); |
352 |
} |
353 |
} catch (Exception e) { |
354 |
throw new DrawServiceException(e); |
355 |
} |
356 |
} |
357 |
return drawingStatus;
|
358 |
} |
359 |
|
360 |
/**
|
361 |
* @param selected
|
362 |
* @param point
|
363 |
* @return
|
364 |
* @throws DataException
|
365 |
* @throws GeometryOperationException
|
366 |
* @throws GeometryOperationNotSupportedException
|
367 |
* @throws GeometryException
|
368 |
*/
|
369 |
private double getMinDistance(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException { |
370 |
// Geometry closestGeometry = getClosestGeometry(selected, point);
|
371 |
// if(closestGeometry != null){
|
372 |
// return closestGeometry.distance(point);
|
373 |
// }
|
374 |
// //No deber?a pasar por aqu?
|
375 |
double minorDistance = Double.POSITIVE_INFINITY; |
376 |
DisposableIterator it; |
377 |
it = selected.fastIterator(); |
378 |
while (it.hasNext()) {
|
379 |
Feature feat = (Feature) it.next(); |
380 |
Geometry geometry = feat.getDefaultGeometry(); |
381 |
double distance = getDistance(geometry, point);
|
382 |
if (distance < minorDistance) {
|
383 |
minorDistance = distance; |
384 |
} |
385 |
} |
386 |
it.dispose(); |
387 |
return minorDistance;
|
388 |
|
389 |
} |
390 |
|
391 |
private Geometry getClosestGeometry(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException { |
392 |
double minorDistance = Double.POSITIVE_INFINITY; |
393 |
DisposableIterator it; |
394 |
it = selected.fastIterator(); |
395 |
Geometry closestGeometry = null;
|
396 |
while (it.hasNext()) {
|
397 |
Feature feat = (Feature) it.next(); |
398 |
Geometry geometry = feat.getDefaultGeometry(); |
399 |
double distance = getDistance(geometry, point);
|
400 |
if (distance < minorDistance) {
|
401 |
closestGeometry = geometry; |
402 |
minorDistance = distance; |
403 |
} |
404 |
} |
405 |
it.dispose(); |
406 |
return closestGeometry;
|
407 |
|
408 |
} |
409 |
|
410 |
/**
|
411 |
* @param geometry
|
412 |
* @param point
|
413 |
* @return
|
414 |
* @throws GeometryOperationException
|
415 |
* @throws GeometryOperationNotSupportedException
|
416 |
* @throws GeometryException
|
417 |
*/
|
418 |
private double getDistance(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException { |
419 |
// Point closest = getClosestPoint(geometry, point);
|
420 |
// if(closest != null) {
|
421 |
// return closest.distance(point);
|
422 |
// }
|
423 |
//No deber?a pasar por aqu?
|
424 |
GeometryManager geomManager = GeometryLocator.getGeometryManager(); |
425 |
if (geometry instanceof Arc) { |
426 |
Arc arc = (Arc) geometry; |
427 |
Point center = arc.getCenterPoint();
|
428 |
double radius = center.distance(arc.getInitPoint());
|
429 |
double distance = center.distance(point) - radius;
|
430 |
return distance;
|
431 |
} |
432 |
|
433 |
if (geometry instanceof Circle) { |
434 |
Circle circle = (Circle) geometry; |
435 |
return circle.getCenter().distance(point) - circle.getRadious();
|
436 |
} |
437 |
if (geometry instanceof Circumference) { |
438 |
Circumference circumference = (Circumference) geometry; |
439 |
return circumference.getCenter().distance(point) - circumference.getRadious();
|
440 |
} |
441 |
if (geometry instanceof PeriEllipse) { |
442 |
double minDistance = Double.POSITIVE_INFINITY; |
443 |
PeriEllipse ellipse = (PeriEllipse) geometry; |
444 |
Geometry[] closestPoints = point.closestPoints(ellipse);
|
445 |
if (closestPoints != null) { |
446 |
for (Geometry closestPoint : closestPoints) {
|
447 |
if (!point.equals(closestPoint)) {
|
448 |
double distance = closestPoint.distance(point);
|
449 |
if (distance < minDistance) {
|
450 |
minDistance = distance; |
451 |
} |
452 |
} |
453 |
} |
454 |
} |
455 |
Ellipse auxEllipse = (Ellipse) geomManager.create(Geometry.TYPES.ELLIPSE, geometry.getGeometryType().getSubType()); |
456 |
auxEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist()); |
457 |
if (auxEllipse.contains(point)) {
|
458 |
return -minDistance;
|
459 |
} |
460 |
return minDistance;
|
461 |
} |
462 |
if (geometry instanceof Ellipse) { |
463 |
Ellipse ellipse = (Ellipse) geometry; |
464 |
PeriEllipse auxPeriEllipse = (PeriEllipse) geomManager.create(Geometry.TYPES.PERIELLIPSE, geometry.getGeometryType().getSubType()); |
465 |
auxPeriEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist()); |
466 |
double distance = getDistance(auxPeriEllipse, point);
|
467 |
|
468 |
return distance;
|
469 |
} |
470 |
|
471 |
if (geometry instanceof Spline || geometry instanceof FilledSpline) { |
472 |
return getDistance(geometry.toLines().getPrimitiveAt(0), point); |
473 |
} |
474 |
|
475 |
if (geometry instanceof Line) { |
476 |
Line line = (Line) geometry; |
477 |
double minDistance = Double.POSITIVE_INFINITY; |
478 |
Geometry[] closestPoints = point.closestPoints(line);
|
479 |
Point closestPoint = null; |
480 |
if (closestPoints != null) { |
481 |
for (Geometry closestPoint1 : closestPoints) {
|
482 |
Point p = (Point) closestPoint1; |
483 |
if (!point.equals(p)) {
|
484 |
double distance = p.distance(point);
|
485 |
if (distance < minDistance) {
|
486 |
minDistance = distance; |
487 |
closestPoint = p; |
488 |
} |
489 |
} |
490 |
} |
491 |
} |
492 |
if (closestPoint != null) { |
493 |
for (int i = 0; i < line.getNumVertices() - 1; i++) { |
494 |
Line segment = (Line) geomManager.create(Geometry.TYPES.LINE, geometry.getGeometryType().getSubType()); |
495 |
segment.addVertex(line.getVertex(i)); |
496 |
segment.addVertex(line.getVertex(i + 1));
|
497 |
if (segment.isWithinDistance(closestPoint, PRECISION)) {
|
498 |
if (line.getVertex(0).equals(line.getVertex(line.getNumVertices() - 1))) { //isClosed |
499 |
if (line.toPolygons().contains(point)) {
|
500 |
return -minDistance;
|
501 |
} |
502 |
return minDistance;
|
503 |
} else {
|
504 |
return getDirectedDistance(closestPoint, point, segment);
|
505 |
} |
506 |
} |
507 |
} |
508 |
} |
509 |
} |
510 |
|
511 |
if (geometry instanceof Polygon) { |
512 |
Polygon polygon = (Polygon) geometry; |
513 |
if (!polygon.contains(point)) {
|
514 |
double minDistance = Double.POSITIVE_INFINITY; |
515 |
Geometry[] closestPoints = point.closestPoints(polygon);
|
516 |
Point closestPoint = null; |
517 |
if (closestPoints != null) { |
518 |
for (Geometry closestPoint1 : closestPoints) {
|
519 |
Point p = (Point) closestPoint1; |
520 |
if (!point.equals(p)) {
|
521 |
double distance = p.distance(point);
|
522 |
if (distance < minDistance) {
|
523 |
minDistance = distance; |
524 |
closestPoint = p; |
525 |
} |
526 |
} |
527 |
} |
528 |
} |
529 |
if (closestPoint != null) { |
530 |
return closestPoint.distance(point);
|
531 |
} |
532 |
} else {
|
533 |
Line auxLine = (Line) polygon.toLines().getPrimitiveAt(0); |
534 |
if (auxLine != null) { |
535 |
return getDistance(auxLine, point);
|
536 |
} |
537 |
} |
538 |
} |
539 |
|
540 |
if (geometry instanceof Aggregate) { |
541 |
double minDistance = Double.POSITIVE_INFINITY; |
542 |
Aggregate aggregate2 = (Aggregate) geometry; |
543 |
for (int i = 0; i < aggregate2.getPrimitivesNumber(); i++) { |
544 |
double distance = getDistance(aggregate2.getPrimitiveAt(i), point);
|
545 |
if (distance < minDistance) {
|
546 |
minDistance = distance; |
547 |
} |
548 |
} |
549 |
return minDistance;
|
550 |
} |
551 |
return 0.0; |
552 |
} |
553 |
|
554 |
|
555 |
private Point getClosestPoint(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException { |
556 |
GeometryManager geomManager = GeometryLocator.getGeometryManager(); |
557 |
if (geometry instanceof Line) { |
558 |
Line line = (Line) geometry; |
559 |
return (Point)line.closestPoints(point)[0]; |
560 |
} else {
|
561 |
return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0]; |
562 |
} |
563 |
// if (geometry instanceof Arc) {
|
564 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
565 |
// }
|
566 |
//
|
567 |
// if (geometry instanceof Circle) {
|
568 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
569 |
// }
|
570 |
// if (geometry instanceof Circumference) {
|
571 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
572 |
// }
|
573 |
// if (geometry instanceof PeriEllipse) {
|
574 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
575 |
// }
|
576 |
// if (geometry instanceof Ellipse) {
|
577 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
578 |
// }
|
579 |
//
|
580 |
// if (geometry instanceof Spline || geometry instanceof FilledSpline) {
|
581 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
582 |
// }
|
583 |
//
|
584 |
//
|
585 |
// if (geometry instanceof Polygon) {
|
586 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
587 |
// }
|
588 |
//
|
589 |
// if (geometry instanceof Aggregate) {
|
590 |
// return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
|
591 |
// }
|
592 |
// return null;
|
593 |
} |
594 |
|
595 |
//
|
596 |
@Override
|
597 |
public void stop() { |
598 |
values.clear(); |
599 |
} |
600 |
|
601 |
@Override
|
602 |
public void restart() throws StartServiceException, InvalidEntryException, StopServiceException { |
603 |
// values.put(selectionParameter, null);
|
604 |
values.put(offsetParameter, null);
|
605 |
values.put(sideParameter, null);
|
606 |
values.put(deleteOriginalGeometriesParameter, null);
|
607 |
} |
608 |
|
609 |
|
610 |
private void validateAndInsertValue(EditingServiceParameter param, |
611 |
Object value) throws InvalidEntryException { |
612 |
I18nManager i18nManager = ToolsLocator.getI18nManager(); |
613 |
|
614 |
try {
|
615 |
if (param == selectionParameter) {
|
616 |
if (value instanceof FeatureSelection) { |
617 |
values.put(param, value); |
618 |
} |
619 |
} else if (param == joinStyleParameter) { |
620 |
if (value instanceof String) { |
621 |
values.put(param, fixJoinStyle(value)); |
622 |
} |
623 |
} else if (param == offsetParameter) { |
624 |
if (value instanceof Point) { |
625 |
Double distance = getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value); |
626 |
if (distance == 0.0) { |
627 |
throw new IllegalArgumentException("distance can't be 0"); |
628 |
} |
629 |
values.put(param, Math.abs(distance));
|
630 |
values.put(sideParameter, coerceSide(distance)); |
631 |
return;
|
632 |
} |
633 |
if (value instanceof Double) { |
634 |
Double distance = (Double) value; |
635 |
if (distance > 0) { |
636 |
values.put(param, value); |
637 |
} else if (distance == 0.0) { |
638 |
throw new IllegalArgumentException("distance can't be 0"); |
639 |
} else {
|
640 |
values.put(param, Math.abs(distance));
|
641 |
values.put(sideParameter, coerceSide(distance)); |
642 |
} |
643 |
} |
644 |
} else if (param == sideParameter) { |
645 |
if (value instanceof Point) { |
646 |
values.put(param, coerceSide(getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value)));
|
647 |
return;
|
648 |
} |
649 |
if (value instanceof String) { |
650 |
values.put(param, coerceSide(value)); |
651 |
} |
652 |
} else if (param == equidistantOffsets) { |
653 |
if (value instanceof Number) { |
654 |
int intValue = ((Number) value).intValue(); |
655 |
if(intValue >= 1) { |
656 |
values.put(param, ((Number) value).intValue());
|
657 |
} |
658 |
} |
659 |
} else if (param == deleteOriginalGeometriesParameter) { |
660 |
values.put(param, param.getOptions2().getValue(value, param.getDefaultValue())); |
661 |
} |
662 |
} catch (Exception e) { |
663 |
throw new InvalidEntryException(e); |
664 |
} |
665 |
|
666 |
} |
667 |
|
668 |
private String coerceSide(Object value) throws InvalidEntryException { |
669 |
|
670 |
if (value instanceof Double) { |
671 |
return (Double) value >= 0 ? LEFT : RIGHT; |
672 |
} |
673 |
if (value instanceof String) { |
674 |
Double signum = getSideSignum((String) value); |
675 |
if (signum != null) { |
676 |
return signum >= 0 ? LEFT : RIGHT; |
677 |
} |
678 |
} |
679 |
throw new InvalidEntryException(null); |
680 |
} |
681 |
|
682 |
private String fixJoinStyle(Object value) throws InvalidEntryException { |
683 |
|
684 |
if (value instanceof String) { |
685 |
I18nManager i18nManager = ToolsLocator.getI18nManager(); |
686 |
String joinStyleTrim = ((String)value).trim(); |
687 |
if (StringUtils.equalsIgnoreCase(joinStyleTrim, ROUND)
|
688 |
|| StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(ROUND), joinStyleTrim)) { |
689 |
return ROUND;
|
690 |
} else if (StringUtils.equalsIgnoreCase(joinStyleTrim, BEVEL) |
691 |
|| StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(BEVEL), joinStyleTrim)) { |
692 |
return BEVEL;
|
693 |
} else if (StringUtils.equalsIgnoreCase(joinStyleTrim, MITRE) |
694 |
|| StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(MITRE), joinStyleTrim)) { |
695 |
return MITRE;
|
696 |
} |
697 |
} |
698 |
throw new InvalidEntryException(null); |
699 |
} |
700 |
|
701 |
private Double getSideSignum(String side) { |
702 |
I18nManager i18nManager = ToolsLocator.getI18nManager(); |
703 |
String sideTrim = side.trim();
|
704 |
if (StringUtils.equalsIgnoreCase(sideTrim, LEFT)
|
705 |
|| StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(LEFT), sideTrim)) { |
706 |
return 1.0; |
707 |
} else if (StringUtils.equalsIgnoreCase(sideTrim, RIGHT) |
708 |
|| StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(RIGHT), sideTrim)) { |
709 |
return -1.0; |
710 |
} |
711 |
return null; |
712 |
} |
713 |
|
714 |
@Override
|
715 |
public List<EditingServiceParameter> getParameters() { |
716 |
List<EditingServiceParameter> list
|
717 |
= new ArrayList<>(); |
718 |
list.add(selectionParameter); |
719 |
list.add(joinStyleParameter); |
720 |
list.add(offsetParameter); |
721 |
list.add(sideParameter); |
722 |
list.add(equidistantOffsets); |
723 |
list.add(deleteOriginalGeometriesParameter); |
724 |
return list;
|
725 |
} |
726 |
|
727 |
@Override
|
728 |
public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException { |
729 |
validateAndInsertValue(parameter, value); |
730 |
} |
731 |
|
732 |
@Override
|
733 |
public void setValue(Object value) throws InvalidEntryException { |
734 |
EditingServiceParameter param = next(); |
735 |
validateAndInsertValue(param, value); |
736 |
} |
737 |
|
738 |
@Override
|
739 |
public void finishAndStore() throws FinishServiceException { |
740 |
|
741 |
FeatureSelection selected |
742 |
= (FeatureSelection) values.get(selectionParameter); |
743 |
try {
|
744 |
if (!selected.isEmpty()) {
|
745 |
double side = 1.0; |
746 |
Object sideValue = values.get(sideParameter);
|
747 |
if (sideValue != null) { |
748 |
if (sideValue instanceof String) { |
749 |
Double signum = getSideSignum((String) sideValue); |
750 |
side = signum != null ? signum : null; |
751 |
} |
752 |
} |
753 |
double distance = ((Double) values.get(offsetParameter)) * side; |
754 |
DisposableIterator it; |
755 |
it = selected.fastIterator(); |
756 |
int joinStyleValue = coerceJoinStyle(values.get(joinStyleParameter));
|
757 |
Number equidistantOffsetsNumberValue = ((Number) values.get(this.equidistantOffsets)); |
758 |
int equidistantOffsetsValue = equidistantOffsetsNumberValue != null ? equidistantOffsetsNumberValue.intValue() : ((Number)this.equidistantOffsets.getDefaultValue()).intValue(); |
759 |
|
760 |
while (it.hasNext()) {
|
761 |
Feature feature = (Feature) it.next(); |
762 |
for (int c = 1; c <= equidistantOffsetsValue; c++) { |
763 |
|
764 |
Geometry geom; |
765 |
try {
|
766 |
geom = feature.getDefaultGeometry().offset(joinStyleValue, c * distance); |
767 |
} catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
|
768 |
throw new FinishServiceException(e); |
769 |
} |
770 |
|
771 |
if ((boolean) values.get(deleteOriginalGeometriesParameter) && c == 1) { |
772 |
// Se sustituye la geometr?a original por la primera calculada
|
773 |
EditableFeature editableFeature |
774 |
= feature.getEditable(); |
775 |
editableFeature.setDefaultGeometry(geom); |
776 |
((EditingProviderServices) getProviderServices()) |
777 |
.updateFeatureInFeatureStore(editableFeature, |
778 |
featureStore); |
779 |
} else {
|
780 |
// Se crea una feature nueva copiando los valores de
|
781 |
// la feature original excepto aquellos que sean PK
|
782 |
EditingProviderServices editingProviderServices |
783 |
= (EditingProviderServices) getProviderServices(); |
784 |
EditableFeature editableFeature |
785 |
= editingProviderServices |
786 |
.getFeatureCopyWithoutUniqueIndex(featureStore, |
787 |
feature); |
788 |
editableFeature.setDefaultGeometry(geom); |
789 |
editingProviderServices |
790 |
.insertFeatureIntoFeatureStore(editableFeature, |
791 |
featureStore); |
792 |
} |
793 |
} |
794 |
|
795 |
} |
796 |
it.dispose(); |
797 |
// featureStore.getFeatureSelection().deselectAll();
|
798 |
} |
799 |
} catch (DataException e) {
|
800 |
throw new FinishServiceException(e); |
801 |
} |
802 |
} |
803 |
|
804 |
private Double getDirectedDistance(Point pointInLine, Point distancePoint, Line line) |
805 |
throws GeometryOperationNotSupportedException, GeometryOperationException {
|
806 |
Double distance = distancePoint.distance(pointInLine);
|
807 |
EditingProviderServices editingProviderServices |
808 |
= (EditingProviderServices) getProviderServices(); |
809 |
Double angle = editingProviderServices.getAngle(pointInLine, distancePoint);
|
810 |
double angleLine = editingProviderServices.getAngle(line.getVertex(0), line.getVertex(1)); |
811 |
|
812 |
Double angleDifference = angle - angleLine;
|
813 |
if (angleDifference < 0) { |
814 |
angleDifference += 2 * Math.PI; |
815 |
} |
816 |
if (angleDifference > Math.PI) { |
817 |
distance = -distance; |
818 |
} |
819 |
return distance;
|
820 |
} |
821 |
|
822 |
@Override
|
823 |
public Geometry finish() throws FinishServiceException { |
824 |
return null; |
825 |
} |
826 |
|
827 |
@Override
|
828 |
public void start() throws StartServiceException { |
829 |
this.values = new HashMap<>(); |
830 |
FeatureSelection selected = null;
|
831 |
if (featureStore != null) { |
832 |
try {
|
833 |
selected |
834 |
= (FeatureSelection) featureStore.getFeatureSelection() |
835 |
.clone(); |
836 |
} catch (DataException e) {
|
837 |
throw new StartServiceException(e); |
838 |
} catch (CloneNotSupportedException e) { |
839 |
// Do nothing
|
840 |
} |
841 |
if ((selected != null) && (selected.getSelectedCount() > 0)) { |
842 |
values.put(selectionParameter, selected); |
843 |
} |
844 |
} |
845 |
} |
846 |
|
847 |
@Override
|
848 |
public String getName() { |
849 |
return OffsetEditingProviderFactory.PROVIDER_NAME;
|
850 |
} |
851 |
|
852 |
private int coerceJoinStyle(Object joinStyle) { |
853 |
if(joinStyle instanceof String) { |
854 |
switch ((String)joinStyle) { |
855 |
default:
|
856 |
case ROUND:
|
857 |
return JOIN_STYLE_ROUND;
|
858 |
case MITRE:
|
859 |
return Geometry.JOIN_STYLE_MITRE;
|
860 |
case BEVEL:
|
861 |
return Geometry.JOIN_STYLE_BEVEL;
|
862 |
} |
863 |
} |
864 |
return JOIN_STYLE_ROUND;
|
865 |
} |
866 |
|
867 |
@Override
|
868 |
public boolean isEnabled(EditingServiceParameter parameter) { |
869 |
if (parameter == joinStyleParameter) {
|
870 |
return true; |
871 |
} |
872 |
if (parameter == equidistantOffsets) {
|
873 |
return true; |
874 |
} |
875 |
return true; |
876 |
} |
877 |
|
878 |
private ISimpleTextSymbol getTextSymbol(){
|
879 |
SymbologyManager symbologyManager = SymbologyLocator.getSymbologyManager(); |
880 |
ISimpleTextSymbol textSymbol = symbologyManager.createSimpleTextSymbol(); |
881 |
textSymbol.setFontSize(10);
|
882 |
return textSymbol;
|
883 |
} |
884 |
|
885 |
@Override
|
886 |
public Object getValue(EditingServiceParameter parameter) { |
887 |
return values!=null?values.get(parameter):null; |
888 |
} |
889 |
|
890 |
|
891 |
} |