Statistics
| Revision:

gvsig-vectorediting / org.gvsig.vectorediting / trunk / org.gvsig.vectorediting / org.gvsig.vectorediting.lib / org.gvsig.vectorediting.lib.prov / org.gvsig.vectorediting.lib.prov.polyline / src / main / java / org / gvsig / vectorediting / lib / prov / polyline / PolylineEditingProvider.java @ 59

History | View | Annotate | Download (17.5 KB)

1
/*
2
 * Copyright 2014 DiSiD Technologies S.L.L. All rights reserved.
3
 * 
4
 * Project  : DiSiD org.gvsig.vectorediting.lib.prov.polyline 
5
 * SVN Id   : $Id$
6
 */
7
package org.gvsig.vectorediting.lib.prov.polyline;
8

    
9
import java.util.ArrayList;
10
import java.util.List;
11

    
12
import org.gvsig.fmap.dal.exception.DataException;
13
import org.gvsig.fmap.dal.feature.FeatureStore;
14
import org.gvsig.fmap.geom.Geometry;
15
import org.gvsig.fmap.geom.GeometryLocator;
16
import org.gvsig.fmap.geom.GeometryManager;
17
import org.gvsig.fmap.geom.aggregate.MultiCurve;
18
import org.gvsig.fmap.geom.aggregate.MultiSurface;
19
import org.gvsig.fmap.geom.exception.CreateGeometryException;
20
import org.gvsig.fmap.geom.operation.GeometryOperationException;
21
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
22
import org.gvsig.fmap.geom.primitive.Arc;
23
import org.gvsig.fmap.geom.primitive.Curve;
24
import org.gvsig.fmap.geom.primitive.Line;
25
import org.gvsig.fmap.geom.primitive.Point;
26
import org.gvsig.fmap.geom.primitive.Surface;
27
import org.gvsig.fmap.geom.type.GeometryType;
28
import org.gvsig.tools.dynobject.DynObject;
29
import org.gvsig.tools.exception.BaseException;
30
import org.gvsig.tools.service.spi.ProviderServices;
31
import org.gvsig.vectorediting.lib.api.DrawingStatus;
32
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
33
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
34
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
35
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
36
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
37
import org.gvsig.vectorediting.lib.spi.EditingProvider;
38
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
39
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
40

    
41
public class PolylineEditingProvider extends AbstractEditingProvider implements
42
    EditingProvider {
43

    
44
  protected GeometryManager geomManager = GeometryLocator.getGeometryManager();
45

    
46
  private EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
47

    
48
  private EditingServiceParameter points = new DefaultEditingServiceParameter(
49
      "Polyline", "Inserts a new point.", TYPE.LIST_POSITIONS, TYPE.OPTION);
50

    
51
  private boolean arcMode = false;
52

    
53
  private List<MyPolyLinePoint> values;
54

    
55
  private FeatureStore featureStore;
56

    
57
  public PolylineEditingProvider(ProviderServices providerServices,
58
      DynObject parameters) {
59
    super(providerServices);
60
    this.featureStore = (FeatureStore) parameters
61
        .getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
62
  }
63
  
64
  /**
65
   * 
66
   * @param angle1
67
   * @param angle2
68
   * @return
69
   */
70
  private static double angleDistance(double angle1, double angle2) {
71
    if (angle1 < angle2) {
72
      return angle2 - angle1;
73
    }
74
    else {
75
      return ((Math.PI * 2) - angle1) + angle2;
76
    }
77
  }
78

    
79
  /**
80
   * 
81
   * @param lastPosition
82
   * @return
83
   * @throws BaseException
84
   */
85
  private DrawingStatus calculatePolyline(Point lastPosition)
86
      throws BaseException {
87
    DrawingStatus geometries = new DefaultDrawingStatus();
88
    Double antm = null;
89
    Double antb = null;
90
    Double m = null;
91
    Double b = null;
92
    boolean right = false;
93
    boolean addGeom = false;
94

    
95
    if (!values.isEmpty()) {
96
      for (int i = 0; i < values.size(); i++) {
97

    
98
        MyPolyLinePoint polyLinePoint = values.get(i);
99
        MyPolyLinePoint polyLineNextPoint = getNextPoint(i);
100

    
101
        Point point = polyLinePoint.getPoint();
102
        Point nextPoint;
103

    
104
        if (polyLineNextPoint == null) {
105
          nextPoint = lastPosition;
106
          addGeom = true;
107
        }
108
        else {
109
          nextPoint = polyLineNextPoint.getPoint();
110
        }
111

    
112
        if (nextPoint == null) {
113
          return geometries;
114
        }
115
        if (polyLinePoint.isArcMode()) {
116

    
117
          Curve lineAntPointToPoint = editingProviderServices.createLine(
118
              point.getX(), point.getY(), nextPoint.getX(), nextPoint.getY(),
119
              featureStore);
120

    
121
          Double[] lineParams = getLineParams(point, nextPoint);
122
          m = lineParams[0];
123
          b = lineParams[1];
124

    
125
          Point[] pointPerpendicular = getPerpendicular(antm, antb, point,
126
              featureStore);
127
          Line linePointPerpendicular = geomManager
128
              .createLine(editingProviderServices.getSubType(featureStore));
129
          linePointPerpendicular.setPoints(pointPerpendicular[0],
130
              pointPerpendicular[1]);
131

    
132
          Point[] bisector = getPerpendicular(m, b,
133
              getMidPoint(point, nextPoint, featureStore), featureStore);
134
          Line lineBisector = geomManager.createLine(editingProviderServices
135
              .getSubType(featureStore));
136
          lineBisector.setPoints(bisector[0], bisector[1]);
137

    
138
          Point center = getIntersection(bisector, pointPerpendicular,
139
              featureStore);
140

    
141
          double startAngle = getAngle(center, point);
142
          double endAngle = getAngle(center, nextPoint);
143

    
144
          double radius = center.distance(point);
145

    
146
          double angleExt = 0.0;
147

    
148
          if (right) {
149
            if (nextPoint.getX() >= point.getX()) {
150
              if (m >= antm) {
151
                angleExt = angleDistance(endAngle, startAngle);
152
                right = !(nextPoint.getY() >= center.getY());
153
              }
154
              else {
155
                angleExt = -angleDistance(startAngle, endAngle);
156
                right = (nextPoint.getY() >= center.getY());
157
              }
158
            }
159
            else {
160
              if (m >= antm) {
161
                angleExt = -angleDistance(startAngle, endAngle);
162
                right = (nextPoint.getY() >= center.getY());
163
              }
164
              else {
165
                angleExt = angleDistance(endAngle, startAngle);
166
                right = !(nextPoint.getY() >= center.getY());
167
              }
168
            }
169
          }
170
          else {
171
            if (nextPoint.getX() < point.getX()) {
172
              if (m >= antm) {
173
                angleExt = angleDistance(endAngle, startAngle);
174
                right = !(nextPoint.getY() >= center.getY());
175
              }
176
              else {
177
                angleExt = -angleDistance(startAngle, endAngle);
178
                right = (nextPoint.getY() >= center.getY());
179
              }
180
            }
181
            else {
182
              if (m >= antm) {
183
                angleExt = -angleDistance(startAngle, endAngle);
184
                right = (nextPoint.getY() >= center.getY());
185
              }
186
              else {
187
                angleExt = angleDistance(endAngle, startAngle);
188
                right = !(nextPoint.getY() >= center.getY());
189
              }
190
            }
191
          }
192

    
193
          Arc arco = editingProviderServices.createArc(center, radius,
194
              startAngle, angleExt, featureStore);
195

    
196
          antm = -(nextPoint.getX() - center.getX())
197
              / (nextPoint.getY() - center.getY());
198
          if (antm == Double.POSITIVE_INFINITY) {
199
            antb = Double.NEGATIVE_INFINITY;
200
            if (nextPoint.getX() == 0) {
201
              antb = 0.0;
202
            }
203
          }
204
          else if (antm == Double.NEGATIVE_INFINITY) {
205
            antb = Double.POSITIVE_INFINITY;
206
            if (nextPoint.getX() == 0) {
207
              antb = 0.0;
208
            }
209
          }
210
          else {
211
            antb = nextPoint.getY() - (antm * nextPoint.getX());
212
          }
213

    
214
          // Draw geometries.
215
          if (addGeom) {
216
            geometries.addGeometry(lineAntPointToPoint);
217
            geometries.addGeometry(center);
218
          }
219
          geometries.addGeometry(arco);
220

    
221
        }
222
        else {
223
          Curve geometry = editingProviderServices.createLine(point.getX(),
224
              point.getY(), nextPoint.getX(), nextPoint.getY(), featureStore);
225
          geometries.addGeometry(geometry);
226

    
227
          Double[] antLineParams = getLineParams(point, nextPoint);
228
          antm = antLineParams[0];
229
          antb = antLineParams[1];
230
          right = (nextPoint.getX() >= point.getX());
231
        }
232
      }
233
      return geometries;
234
    }
235
    else {
236
      // TODO throw exception to be catch by editingBehavior to and error at
237
      // console.
238
    }
239
    return null;
240
  }
241
  
242
  /**
243
   * 
244
   * @param surface
245
   * @return
246
   */
247
  private Surface closeSurfaceIfNecessary(Surface surface) {
248
    if (!isClose(surface) && surface != null) {
249
      Point firstp = surface.getVertex(0);
250
      firstp = (Point) firstp.cloneGeometry();
251
      surface.addVertex(firstp);
252
    }
253
    return surface;
254
  }
255
  
256
  public DrawingStatus draw(Point mousePosition) throws BaseException {
257
    return calculatePolyline(mousePosition);
258
  }
259
  
260
  public void finish() throws BaseException, DataException {
261
    GeometryType storeGeomType = editingProviderServices
262
        .getGeomType(featureStore);
263
    DrawingStatus finalGeometries = calculatePolyline(null);
264
    if (storeGeomType.isTypeOf(SURFACE)) {
265
      Surface surface = geomManager.createPolygon(storeGeomType.getSubType());
266
      for (Geometry geometry : finalGeometries.getGeometries()) {
267
        surface.addVertex((Point) geometry);
268
      }
269
      surface = closeSurfaceIfNecessary(surface);
270
      editingProviderServices.insertGeometryIntoFeatureStore(surface,
271
          featureStore);
272
    }
273
    else if (storeGeomType.isTypeOf(CURVE)) {
274
      for (Geometry geometry : finalGeometries.getGeometries()) {
275
        editingProviderServices.insertGeometryIntoFeatureStore(geometry,
276
            featureStore);
277
      }
278
    }
279
    else if (storeGeomType.isTypeOf(MULTISURFACE)) {
280
      MultiSurface multiSurface;
281
      multiSurface = geomManager.createMultiSurface(storeGeomType.getSubType());
282
      Surface surface = geomManager.createPolygon(storeGeomType.getSubType());
283
      for (Geometry geometry : finalGeometries.getGeometries()) {
284
        if(geometry instanceof Curve){
285
          Curve curve = (Curve) geometry;
286
          for(int i=0; i < curve.getNumVertices(); i++){
287
            surface.addVertex((Point) curve.getVertex(i));
288
          }
289
        }
290
      }
291
      surface = closeSurfaceIfNecessary(surface);
292
      multiSurface.addSurface(surface);
293
      editingProviderServices.insertGeometryIntoFeatureStore(multiSurface,
294
          featureStore);
295
    }
296
    else if (storeGeomType.isTypeOf(MULTICURVE)) {
297
      MultiCurve multiCurve;
298
      multiCurve = geomManager.createMultiCurve(storeGeomType.getSubType());
299
      for (Geometry geometry : finalGeometries.getGeometries()) {
300
        multiCurve.addCurve((Curve) geometry);
301
      }
302
      editingProviderServices.insertGeometryIntoFeatureStore(multiCurve,
303
          featureStore);
304
    }
305
  }
306
  
307
  /**
308
   * 
309
   * @param start
310
   * @param end
311
   * @return
312
   * @throws GeometryOperationNotSupportedException
313
   * @throws GeometryOperationException
314
   */
315
  private static double getAngle(Point start, Point end)
316
      throws GeometryOperationNotSupportedException, GeometryOperationException {
317
    double angle = Math.acos((end.getX() - start.getX()) / start.distance(end));
318

    
319
    if (start.getY() > end.getY()) {
320
      angle = -angle;
321
    }
322

    
323
    if (angle < 0) {
324
      angle += (2 * Math.PI);
325
    }
326

    
327
    return angle;
328
  }
329

    
330
  /**
331
   * 
332
   * @param bisector
333
   * @param perpendicular
334
   * @param featureStore
335
   * @return
336
   * @throws CreateGeometryException
337
   * @throws DataException
338
   */
339
  private Point getIntersection(Point[] bisector, Point[] perpendicular,
340
                                FeatureStore featureStore)
341
      throws CreateGeometryException, DataException {
342
    Point p1 = bisector[0];
343
    Point p2 = bisector[1];
344
    Point p3 = perpendicular[0];
345
    Point p4 = perpendicular[1];
346

    
347
    double m1 = Double.POSITIVE_INFINITY;
348

    
349
    if ((p2.getX() - p1.getX()) != 0) {
350
      m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
351
    }
352

    
353
    double m2 = Double.POSITIVE_INFINITY;
354

    
355
    if ((p4.getX() - p3.getX()) != 0) {
356
      m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
357
    }
358

    
359
    if ((m1 == Double.POSITIVE_INFINITY) && (m2 == Double.POSITIVE_INFINITY)) {
360
      return null;
361
    }
362

    
363
    double b1 = p2.getY() - (m1 * p2.getX());
364

    
365
    double b2 = p4.getY() - (m2 * p4.getX());
366

    
367
    if ((m1 != Double.POSITIVE_INFINITY) && (m2 != Double.POSITIVE_INFINITY)) {
368
      if (m1 == m2) {
369
        return null;
370
      }
371

    
372
      double x = (b2 - b1) / (m1 - m2);
373

    
374
      return editingProviderServices
375
          .createPoint(x, (m1 * x) + b1, featureStore);
376
    }
377
    else if (m1 == Double.POSITIVE_INFINITY) {
378
      double x = p1.getX();
379

    
380
      return editingProviderServices
381
          .createPoint(x, (m2 * x) + b2, featureStore);
382
    }
383
    else if (m2 == Double.POSITIVE_INFINITY) {
384
      double x = p3.getX();
385

    
386
      return editingProviderServices
387
          .createPoint(x, (m1 * x) + b1, featureStore);
388
    }
389

    
390
    return null;
391
  }
392
  
393
  /**
394
   * 
395
   * @param point
396
   * @param nextPoint
397
   * @return
398
   */
399
  private Double[] getLineParams(Point point, Point nextPoint) {
400
    Double[] lineParams = new Double[2];
401
    double denom = nextPoint.getX() - point.getX();
402
    if (denom != 0) {
403
      lineParams[0] = (nextPoint.getY() - point.getY()) / denom;
404
      lineParams[1] = point.getY() - (lineParams[0] * point.getX());
405
    }
406
    else {
407
      if (nextPoint.getY() >= point.getY()) {
408
        lineParams[0] = Double.POSITIVE_INFINITY;
409
        lineParams[1] = Double.NEGATIVE_INFINITY;
410
        if (point.getX() == 0) {
411
          lineParams[1] = 0.0;
412
        }
413
      }
414
      else {
415
        lineParams[0] = Double.NEGATIVE_INFINITY;
416
        lineParams[1] = Double.POSITIVE_INFINITY;
417
        if (point.getX() == 0) {
418
          lineParams[1] = 0.0;
419
        }
420
      }
421
    }
422
    return lineParams;
423
  }
424
  
425
  /**
426
   * 
427
   * @param p1
428
   * @param p2
429
   * @param featureStore
430
   * @return
431
   * @throws CreateGeometryException
432
   * @throws DataException
433
   */
434
  private Point getMidPoint(Point p1, Point p2, FeatureStore featureStore)
435
      throws CreateGeometryException, DataException {
436
    double x = (p1.getX() + p2.getX()) / 2;
437
    double y = (p1.getY() + p2.getY()) / 2;
438
    return editingProviderServices.createPoint(x, y, featureStore);
439
  }
440
  
441
  public String getName() {
442
    return PolylineEditingProviderFactory.PROVIDER_NAME;
443
  }
444

    
445
  /**
446
   * 
447
   * @param i
448
   * @return
449
   */
450
  private MyPolyLinePoint getNextPoint(int i) {
451
    if (!values.isEmpty() && i < values.size() - 1) {
452
      return values.get(i + 1);
453
    }
454
    return null;
455
  }
456
  
457
  public List<EditingServiceParameter> getParameters() {
458
    List<EditingServiceParameter> list = new ArrayList<EditingServiceParameter>();
459
    list.add(points);
460
    return list;
461
  }
462

    
463
  /**
464
   * 
465
   * @param m
466
   * @param b
467
   * @param perp
468
   * @param featureStore
469
   * @return
470
   * @throws CreateGeometryException
471
   * @throws DataException
472
   */
473
  private Point[] getPerpendicular(Double m, Double b, Point perp,
474
                                   FeatureStore featureStore)
475
      throws CreateGeometryException, DataException {
476
    if (m == Double.POSITIVE_INFINITY) {
477
      Point[] res = new Point[2];
478
      res[0] = editingProviderServices
479
          .createPoint(0, perp.getY(), featureStore);
480
      res[1] = editingProviderServices
481
          .createPoint(1, perp.getY(), featureStore);
482
      return res;
483
    }
484
    else if (m == Double.NEGATIVE_INFINITY) {
485
      Point[] res = new Point[2];
486
      res[0] = editingProviderServices
487
          .createPoint(1, perp.getY(), featureStore);
488
      res[1] = editingProviderServices
489
          .createPoint(0, perp.getY(), featureStore);
490
      return res;
491
    }
492
    else {
493
      // Pendiente de la recta perpendicular
494
      Double m1 = -1 / m;
495

    
496
      // b de la funcion de la recta perpendicular
497
      Double b1 = perp.getY() - (m1 * perp.getX());
498

    
499
      // Obtenemos un par de puntos
500
      Point[] res = new Point[2];
501

    
502
      if (Double.isInfinite(m1)) {
503
        res[0] = editingProviderServices.createPoint(perp.getX(), 0.0,
504
            featureStore);
505
        res[1] = editingProviderServices.createPoint(perp.getX(), perp.getY(),
506
            featureStore);
507
      }
508
      else {
509
        res[0] = editingProviderServices.createPoint(0, 0.0 + b1, featureStore);
510
        res[1] = editingProviderServices.createPoint(perp.getX(),
511
            (m1 * perp.getX()) + b1, featureStore);
512
      }
513

    
514
      return res;
515
    }
516
  }
517
  
518
  /**
519
   * 
520
   * @param surface
521
   * @return
522
   */
523
  private boolean isClose(Surface surface) {
524
    
525
    if(surface != null){
526
      Point firstPoint = surface.getVertex(0);
527
      Point lastPoint = surface.getVertex(surface.getNumVertices()-1);
528
      if(firstPoint.equals(lastPoint)){
529
        return true;
530
      }
531
    }
532
    return false;
533
  }
534

    
535
  public EditingServiceParameter next() {
536
    if( values.size() >= 2){
537
      if(arcMode){
538
        points.setDescription("Inserts [L] to change to line mode. Double-click to finish. Inserts new point.");
539
      }
540
      else{
541
        points.setDescription("Inserts [A] to change to arc mode. Double-click to finish. Inserts new point.");
542
      }
543
    }
544
    return points;
545
  }
546

    
547
  public void start() {
548
    values = new ArrayList<MyPolyLinePoint>();
549
  }
550

    
551
  public void stop() {
552
    points.setDescription("Inserts a new point.");
553
    arcMode = false;
554
  }
555
  
556
  /**
557
   * 
558
   * @param param
559
   * @param value
560
   */
561
  private void validateAndInsertValue(EditingServiceParameter param,
562
                                      Object value) {
563
    if (value instanceof String) {
564
      if (values.size() >= 2) {
565
        if (((String) value).equalsIgnoreCase("A")) {
566
          arcMode = true;
567
        }
568
        else if (((String) value).equalsIgnoreCase("L")) {
569
          arcMode = false;
570
        }
571
        if (values.size() > 0) {
572
          values.get(values.size() - 1).setArcMode(arcMode);
573
          return;
574
        }
575
      }
576
    }
577
    else if (param == points && value instanceof Point) {
578
      values.add(new MyPolyLinePoint((Point) value, arcMode));
579
    }
580
  }
581

    
582
  public void value(Object value) {
583
    EditingServiceParameter param = next();
584
    validateAndInsertValue(param, value);
585
  }
586

    
587
}