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

History | View | Annotate | Download (18.7 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.spi.AbstractEditingProvider;
38
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
39
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
40
import org.gvsig.vectorediting.lib.spi.EditingProvider;
41
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
42
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
43

    
44
public class PolylineEditingProvider extends AbstractEditingProvider implements
45
    EditingProvider {
46

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

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

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

    
54
  private boolean arcMode = false;
55

    
56
  private List<MyPolyLinePoint> values;
57

    
58
  private FeatureStore featureStore;
59

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

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

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

    
101
    Curve lineAntPointToPoint = null;
102

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
352
    return angle;
353
  }
354

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

    
371
    double m1 = Double.POSITIVE_INFINITY;
372

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

    
377
    double m2 = Double.POSITIVE_INFINITY;
378

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

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

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

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

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

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

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

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

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

    
414
    return null;
415
  }
416

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

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

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

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

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

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

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

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

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

    
534
      return res;
535
    }
536
  }
537

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

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

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

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

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

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

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

    
614
}