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 @ 63

History | View | Annotate | Download (18.6 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.service.spi.ProviderServices;
30
import org.gvsig.vectorediting.lib.api.DrawingStatus;
31
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
32
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
33
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
34
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
35
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
36
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
37
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
38
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
39
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
40
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
41
import org.gvsig.vectorediting.lib.spi.EditingProvider;
42
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
43
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
44

    
45
public class PolylineEditingProvider extends AbstractEditingProvider implements
46
    EditingProvider {
47

    
48
  protected GeometryManager geomManager = GeometryLocator.getGeometryManager();
49

    
50
  private EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
51

    
52
  private EditingServiceParameter points = new DefaultEditingServiceParameter(
53
      "Polyline", "Inserts a new point.", TYPE.LIST_POSITIONS, TYPE.OPTION);
54

    
55
  private boolean arcMode = false;
56

    
57
  private List<MyPolyLinePoint> values;
58

    
59
  private FeatureStore featureStore;
60

    
61
  public PolylineEditingProvider(ProviderServices providerServices,
62
      DynObject parameters) {
63
    super(providerServices);
64
    this.featureStore = (FeatureStore) parameters
65
        .getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
66
  }
67

    
68
  /**
69
   * @param angle1
70
   * @param angle2
71
   * @return
72
   */
73
  private static double angleDistance(double angle1, double angle2) {
74
    if (angle1 < angle2) {
75
      return angle2 - angle1;
76
    }
77
    else {
78
      return ((Math.PI * 2) - angle1) + angle2;
79
    }
80
  }
81

    
82
  /**
83
   * @param lastPosition
84
   * @return
85
   * @throws VectorEditingException
86
   */
87
  private DrawingStatus calculatePolyline(Point lastPosition)
88
      throws VectorEditingException {
89
    DrawingStatus geometries = new DefaultDrawingStatus();
90
    Double antm = null;
91
    Double antb = null;
92
    Double m = null;
93
    Double b = null;
94
    Point center = null;
95
    double radius = 0.0;
96
    double startAngle = 0.0;
97
    double endAngle = 0.0;
98
    double angleExt = 0.0;
99
    boolean right = false;
100
    boolean addGeom = false;
101

    
102
    Curve lineAntPointToPoint = null;
103

    
104
    if (!values.isEmpty()) {
105
      for (int i = 0; i < values.size(); i++) {
106

    
107
        MyPolyLinePoint polyLinePoint = values.get(i);
108
        MyPolyLinePoint polyLineNextPoint = getNextPoint(i);
109

    
110
        Point point = polyLinePoint.getPoint();
111
        Point nextPoint;
112

    
113
        if (polyLineNextPoint == null) {
114
          nextPoint = lastPosition;
115
          addGeom = true;
116
        }
117
        else {
118
          nextPoint = polyLineNextPoint.getPoint();
119
        }
120

    
121
        if (nextPoint == null) {
122
          return geometries;
123
        }
124
        if (polyLinePoint.isArcMode()) {
125
          try {
126

    
127
            lineAntPointToPoint = editingProviderServices.createLine(
128
              point.getX(), point.getY(), nextPoint.getX(), nextPoint.getY(),
129
              featureStore);
130

    
131
          Double[] lineParams = getLineParams(point, nextPoint);
132
          m = lineParams[0];
133
          b = lineParams[1];
134

    
135
          Point[] pointPerpendicular = getPerpendicular(antm, antb, point,
136
              featureStore);
137
          Line linePointPerpendicular = geomManager
138
              .createLine(editingProviderServices.getSubType(featureStore));
139
          linePointPerpendicular.setPoints(pointPerpendicular[0],
140
              pointPerpendicular[1]);
141

    
142
          Point[] bisector = getPerpendicular(m, b,
143
              getMidPoint(point, nextPoint, featureStore), featureStore);
144
          Line lineBisector = geomManager.createLine(editingProviderServices
145
              .getSubType(featureStore));
146
          lineBisector.setPoints(bisector[0], bisector[1]);
147

    
148
            center = getIntersection(bisector, pointPerpendicular, featureStore);
149

    
150
            startAngle = getAngle(center, point);
151
            endAngle = getAngle(center, nextPoint);
152

    
153
            radius = center.distance(point);
154
          }
155
          catch (Exception e) {
156
            throw new DrawServiceException(e);
157
          }
158

    
159
          if (right) {
160
            if (nextPoint.getX() >= point.getX()) {
161
              if (m >= antm) {
162
                angleExt = angleDistance(endAngle, startAngle);
163
                right = !(nextPoint.getY() >= center.getY());
164
              }
165
              else {
166
                angleExt = -angleDistance(startAngle, endAngle);
167
                right = (nextPoint.getY() >= center.getY());
168
              }
169
            }
170
            else {
171
              if (m >= antm) {
172
                angleExt = -angleDistance(startAngle, endAngle);
173
                right = (nextPoint.getY() >= center.getY());
174
              }
175
              else {
176
                angleExt = angleDistance(endAngle, startAngle);
177
                right = !(nextPoint.getY() >= center.getY());
178
              }
179
            }
180
          }
181
          else {
182
            if (nextPoint.getX() < point.getX()) {
183
              if (m >= antm) {
184
                angleExt = angleDistance(endAngle, startAngle);
185
                right = !(nextPoint.getY() >= center.getY());
186
              }
187
              else {
188
                angleExt = -angleDistance(startAngle, endAngle);
189
                right = (nextPoint.getY() >= center.getY());
190
              }
191
            }
192
            else {
193
              if (m >= antm) {
194
                angleExt = -angleDistance(startAngle, endAngle);
195
                right = (nextPoint.getY() >= center.getY());
196
              }
197
              else {
198
                angleExt = angleDistance(endAngle, startAngle);
199
                right = !(nextPoint.getY() >= center.getY());
200
              }
201
            }
202
          }
203

    
204
          Arc arco = null;
205
          try {
206
            arco = editingProviderServices.createArc(center, radius,
207
              startAngle, angleExt, featureStore);
208
          }
209
          catch (Exception e) {
210
            throw new DrawServiceException(e);
211
          }
212

    
213
          antm = -(nextPoint.getX() - center.getX())
214
              / (nextPoint.getY() - center.getY());
215
          if (antm == Double.POSITIVE_INFINITY) {
216
            antb = Double.NEGATIVE_INFINITY;
217
            if (nextPoint.getX() == 0) {
218
              antb = 0.0;
219
            }
220
          }
221
          else if (antm == Double.NEGATIVE_INFINITY) {
222
            antb = Double.POSITIVE_INFINITY;
223
            if (nextPoint.getX() == 0) {
224
              antb = 0.0;
225
            }
226
          }
227
          else {
228
            antb = nextPoint.getY() - (antm * nextPoint.getX());
229
          }
230

    
231
          // Draw geometries.
232
          if (addGeom) {
233
            geometries.addGeometry(lineAntPointToPoint);
234
            geometries.addGeometry(center);
235
          }
236
          geometries.addGeometry(arco);
237

    
238
        }
239
        else {
240
          try {
241
          Curve geometry = editingProviderServices.createLine(point.getX(),
242
              point.getY(), nextPoint.getX(), nextPoint.getY(), featureStore);
243
          geometries.addGeometry(geometry);
244
          }
245
          catch (Exception e) {
246
            throw new DrawServiceException(e);
247
          }
248
          Double[] antLineParams = getLineParams(point, nextPoint);
249
          antm = antLineParams[0];
250
          antb = antLineParams[1];
251
          right = (nextPoint.getX() >= point.getX());
252
        }
253
      }
254
      return geometries;
255
    }
256
    return null;
257
  }
258

    
259
  /**
260
   * @param surface
261
   * @return
262
   */
263
  private Surface closeSurfaceIfNecessary(Surface surface) {
264
    if (!isClose(surface) && surface != null) {
265
      Point firstp = surface.getVertex(0);
266
      firstp = (Point) firstp.cloneGeometry();
267
      surface.addVertex(firstp);
268
    }
269
    return surface;
270
  }
271

    
272
  public DrawingStatus draw(Point mousePosition) throws DrawServiceException {
273
    try {
274
    return calculatePolyline(mousePosition);
275
  }
276
    catch (Exception e) {
277
      throw new DrawServiceException(e);
278
    }
279
  }
280

    
281
  public void finish() throws FinishServiceException {
282
    try {
283
    GeometryType storeGeomType = editingProviderServices
284
        .getGeomType(featureStore);
285
    DrawingStatus finalGeometries = calculatePolyline(null);
286
    if (storeGeomType.isTypeOf(SURFACE)) {
287
      Surface surface = geomManager.createPolygon(storeGeomType.getSubType());
288
      for (Geometry geometry : finalGeometries.getGeometries()) {
289
        surface.addVertex((Point) geometry);
290
      }
291
      surface = closeSurfaceIfNecessary(surface);
292
      editingProviderServices.insertGeometryIntoFeatureStore(surface,
293
          featureStore);
294
    }
295
    else if (storeGeomType.isTypeOf(CURVE)) {
296
      for (Geometry geometry : finalGeometries.getGeometries()) {
297
        editingProviderServices.insertGeometryIntoFeatureStore(geometry,
298
            featureStore);
299
      }
300
    }
301
    else if (storeGeomType.isTypeOf(MULTISURFACE)) {
302
      MultiSurface multiSurface;
303
        multiSurface = geomManager.createMultiSurface(storeGeomType
304
            .getSubType());
305
      Surface surface = geomManager.createPolygon(storeGeomType.getSubType());
306
      for (Geometry geometry : finalGeometries.getGeometries()) {
307
        if(geometry instanceof Curve){
308
          Curve curve = (Curve) geometry;
309
          for(int i=0; i < curve.getNumVertices(); i++){
310
            surface.addVertex((Point) curve.getVertex(i));
311
          }
312
        }
313
      }
314
      surface = closeSurfaceIfNecessary(surface);
315
      multiSurface.addSurface(surface);
316
      editingProviderServices.insertGeometryIntoFeatureStore(multiSurface,
317
          featureStore);
318
    }
319
    else if (storeGeomType.isTypeOf(MULTICURVE)) {
320
      MultiCurve multiCurve;
321
      multiCurve = geomManager.createMultiCurve(storeGeomType.getSubType());
322
      for (Geometry geometry : finalGeometries.getGeometries()) {
323
        multiCurve.addCurve((Curve) geometry);
324
      }
325
      editingProviderServices.insertGeometryIntoFeatureStore(multiCurve,
326
          featureStore);
327
    }
328
  }
329
    catch (Exception e) {
330
      throw new FinishServiceException(e);
331
    }
332
  }
333

    
334
  /**
335
   * @param start
336
   * @param end
337
   * @return
338
   * @throws GeometryOperationNotSupportedException
339
   * @throws GeometryOperationException
340
   */
341
  private static double getAngle(Point start, Point end)
342
      throws GeometryOperationNotSupportedException, GeometryOperationException {
343
    double angle = Math.acos((end.getX() - start.getX()) / start.distance(end));
344

    
345
    if (start.getY() > end.getY()) {
346
      angle = -angle;
347
    }
348

    
349
    if (angle < 0) {
350
      angle += (2 * Math.PI);
351
    }
352

    
353
    return angle;
354
  }
355

    
356
  /**
357
   * @param bisector
358
   * @param perpendicular
359
   * @param featureStore
360
   * @return
361
   * @throws CreateGeometryException
362
   * @throws DataException
363
   */
364
  private Point getIntersection(Point[] bisector, Point[] perpendicular,
365
                                FeatureStore featureStore)
366
      throws CreateGeometryException, DataException {
367
    Point p1 = bisector[0];
368
    Point p2 = bisector[1];
369
    Point p3 = perpendicular[0];
370
    Point p4 = perpendicular[1];
371

    
372
    double m1 = Double.POSITIVE_INFINITY;
373

    
374
    if ((p2.getX() - p1.getX()) != 0) {
375
      m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
376
    }
377

    
378
    double m2 = Double.POSITIVE_INFINITY;
379

    
380
    if ((p4.getX() - p3.getX()) != 0) {
381
      m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
382
    }
383

    
384
    if ((m1 == Double.POSITIVE_INFINITY) && (m2 == Double.POSITIVE_INFINITY)) {
385
      return null;
386
    }
387

    
388
    double b1 = p2.getY() - (m1 * p2.getX());
389

    
390
    double b2 = p4.getY() - (m2 * p4.getX());
391

    
392
    if ((m1 != Double.POSITIVE_INFINITY) && (m2 != Double.POSITIVE_INFINITY)) {
393
      if (m1 == m2) {
394
        return null;
395
      }
396

    
397
      double x = (b2 - b1) / (m1 - m2);
398

    
399
      return editingProviderServices
400
          .createPoint(x, (m1 * x) + b1, featureStore);
401
    }
402
    else if (m1 == Double.POSITIVE_INFINITY) {
403
      double x = p1.getX();
404

    
405
      return editingProviderServices
406
          .createPoint(x, (m2 * x) + b2, featureStore);
407
    }
408
    else if (m2 == Double.POSITIVE_INFINITY) {
409
      double x = p3.getX();
410

    
411
      return editingProviderServices
412
          .createPoint(x, (m1 * x) + b1, featureStore);
413
    }
414

    
415
    return null;
416
  }
417

    
418
  /**
419
   * @param point
420
   * @param nextPoint
421
   * @return
422
   */
423
  private Double[] getLineParams(Point point, Point nextPoint) {
424
    Double[] lineParams = new Double[2];
425
    double denom = nextPoint.getX() - point.getX();
426
    if (denom != 0) {
427
      lineParams[0] = (nextPoint.getY() - point.getY()) / denom;
428
      lineParams[1] = point.getY() - (lineParams[0] * point.getX());
429
    }
430
    else {
431
      if (nextPoint.getY() >= point.getY()) {
432
        lineParams[0] = Double.POSITIVE_INFINITY;
433
        lineParams[1] = Double.NEGATIVE_INFINITY;
434
        if (point.getX() == 0) {
435
          lineParams[1] = 0.0;
436
        }
437
      }
438
      else {
439
        lineParams[0] = Double.NEGATIVE_INFINITY;
440
        lineParams[1] = Double.POSITIVE_INFINITY;
441
        if (point.getX() == 0) {
442
          lineParams[1] = 0.0;
443
        }
444
      }
445
    }
446
    return lineParams;
447
  }
448

    
449
  /**
450
   * @param p1
451
   * @param p2
452
   * @param featureStore
453
   * @return
454
   * @throws CreateGeometryException
455
   * @throws DataException
456
   */
457
  private Point getMidPoint(Point p1, Point p2, FeatureStore featureStore)
458
      throws CreateGeometryException, DataException {
459
    double x = (p1.getX() + p2.getX()) / 2;
460
    double y = (p1.getY() + p2.getY()) / 2;
461
    return editingProviderServices.createPoint(x, y, featureStore);
462
  }
463

    
464
  public String getName() {
465
    return PolylineEditingProviderFactory.PROVIDER_NAME;
466
  }
467

    
468
  /**
469
   * @param i
470
   * @return
471
   */
472
  private MyPolyLinePoint getNextPoint(int i) {
473
    if (!values.isEmpty() && i < values.size() - 1) {
474
      return values.get(i + 1);
475
    }
476
    return null;
477
  }
478

    
479
  public List<EditingServiceParameter> getParameters() {
480
    List<EditingServiceParameter> list = new ArrayList<EditingServiceParameter>();
481
    list.add(points);
482
    return list;
483
  }
484

    
485
  /**
486
   * @param m
487
   * @param b
488
   * @param perp
489
   * @param featureStore
490
   * @return
491
   * @throws CreateGeometryException
492
   * @throws DataException
493
   */
494
  private Point[] getPerpendicular(Double m, Double b, Point perp,
495
                                   FeatureStore featureStore)
496
      throws CreateGeometryException, DataException {
497
    if (m == Double.POSITIVE_INFINITY) {
498
      Point[] res = new Point[2];
499
      res[0] = editingProviderServices
500
          .createPoint(0, perp.getY(), featureStore);
501
      res[1] = editingProviderServices
502
          .createPoint(1, perp.getY(), featureStore);
503
      return res;
504
    }
505
    else if (m == Double.NEGATIVE_INFINITY) {
506
      Point[] res = new Point[2];
507
      res[0] = editingProviderServices
508
          .createPoint(1, perp.getY(), featureStore);
509
      res[1] = editingProviderServices
510
          .createPoint(0, perp.getY(), featureStore);
511
      return res;
512
    }
513
    else {
514
      // Pendiente de la recta perpendicular
515
      Double m1 = -1 / m;
516

    
517
      // b de la funcion de la recta perpendicular
518
      Double b1 = perp.getY() - (m1 * perp.getX());
519

    
520
      // Obtenemos un par de puntos
521
      Point[] res = new Point[2];
522

    
523
      if (Double.isInfinite(m1)) {
524
        res[0] = editingProviderServices.createPoint(perp.getX(), 0.0,
525
            featureStore);
526
        res[1] = editingProviderServices.createPoint(perp.getX(), perp.getY(),
527
            featureStore);
528
      }
529
      else {
530
        res[0] = editingProviderServices.createPoint(0, 0.0 + b1, featureStore);
531
        res[1] = editingProviderServices.createPoint(perp.getX(),
532
            (m1 * perp.getX()) + b1, featureStore);
533
      }
534

    
535
      return res;
536
    }
537
  }
538

    
539
  /**
540
   * @param surface
541
   * @return
542
   */
543
  private boolean isClose(Surface surface) {
544

    
545
    if(surface != null){
546
      Point firstPoint = surface.getVertex(0);
547
      Point lastPoint = surface.getVertex(surface.getNumVertices()-1);
548
      if(firstPoint.equals(lastPoint)){
549
        return true;
550
      }
551
    }
552
    return false;
553
  }
554

    
555
  public EditingServiceParameter next() {
556
    if( values.size() >= 2){
557
      if(arcMode){
558
        points
559
            .setDescription("Inserts [L] to change to line mode. Double-click to finish. Inserts new point.");
560
      }
561
      else{
562
        points
563
            .setDescription("Inserts [A] to change to arc mode. Double-click to finish. Inserts new point.");
564
      }
565
    }
566
    return points;
567
  }
568

    
569
  public void start() throws StartServiceException {
570
    values = new ArrayList<MyPolyLinePoint>();
571
  }
572

    
573
  public void stop() {
574
    points.setDescription("Inserts a new point.");
575
    arcMode = false;
576
  }
577

    
578
  /**
579
   * @param param
580
   * @param value
581
   */
582
  private void validateAndInsertValue(EditingServiceParameter param,
583
                                      Object value) throws InvalidEntryException {
584
    if (value instanceof String) {
585
      if (values.size() >= 2) {
586
        if(((String) value).equalsIgnoreCase("A") || ((String) value).equalsIgnoreCase("L")){
587
        if (((String) value).equalsIgnoreCase("A")) {
588
          arcMode = true;
589
        }
590
        else if (((String) value).equalsIgnoreCase("L")) {
591
          arcMode = false;
592
        }
593
        if (values.size() > 0) {
594
          values.get(values.size() - 1).setArcMode(arcMode);
595
          return;
596
        }
597
        } else{
598
          throw new InvalidEntryException(null);
599
        }
600
        
601
      } else{
602
          throw new InvalidEntryException(null);
603
      }
604
    }
605
    else if (param == points && value instanceof Point) {
606
      values.add(new MyPolyLinePoint((Point) value, arcMode));
607
    }
608
  }
609

    
610
  public void value(Object value) throws InvalidEntryException{
611
    EditingServiceParameter param = next();
612
    validateAndInsertValue(param, value);
613
  }
614

    
615
}