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

History | View | Annotate | Download (19.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.Geometry.TYPES;
18
import org.gvsig.fmap.geom.aggregate.MultiCurve;
19
import org.gvsig.fmap.geom.aggregate.MultiSurface;
20
import org.gvsig.fmap.geom.exception.CreateGeometryException;
21
import org.gvsig.fmap.geom.operation.GeometryOperationException;
22
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
23
import org.gvsig.fmap.geom.primitive.Arc;
24
import org.gvsig.fmap.geom.primitive.Curve;
25
import org.gvsig.fmap.geom.primitive.Line;
26
import org.gvsig.fmap.geom.primitive.OrientablePrimitive;
27
import org.gvsig.fmap.geom.primitive.Point;
28
import org.gvsig.fmap.geom.primitive.Surface;
29
import org.gvsig.fmap.geom.type.GeometryType;
30
import org.gvsig.tools.ToolsLocator;
31
import org.gvsig.tools.dynobject.DynObject;
32
import org.gvsig.tools.i18n.I18nManager;
33
import org.gvsig.tools.service.spi.ProviderServices;
34
import org.gvsig.vectorediting.lib.api.DrawingStatus;
35
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
36
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
37
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
38
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
39
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
40
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
41
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
42
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
43
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
44
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
45
import org.gvsig.vectorediting.lib.spi.EditingProvider;
46
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
47
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
48

    
49
public class PolylineEditingProvider extends AbstractEditingProvider implements
50
    EditingProvider {
51

    
52
  protected EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
53

    
54
  protected I18nManager i18nManager = ToolsLocator.getI18nManager();
55

    
56
  private EditingServiceParameter points = new DefaultEditingServiceParameter(
57
      "Points", i18nManager.getTranslation("indicates_new_point"),
58
      TYPE.LIST_POSITIONS, TYPE.OPTION);
59

    
60
  private boolean arcMode = false;
61

    
62
  private List<MyPolyLinePoint> values;
63

    
64
  protected FeatureStore featureStore;
65

    
66
  public PolylineEditingProvider(ProviderServices providerServices,
67
      DynObject parameters) {
68
    super(providerServices);
69
    this.featureStore = (FeatureStore) parameters
70
        .getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
71
  }
72

    
73
  /**
74
   * @param angle1
75
   * @param angle2
76
   * @return
77
   */
78
  private static double angleDistance(double angle1, double angle2) {
79
    if (angle1 < angle2) {
80
      return angle2 - angle1;
81
    }
82
    else {
83
      return ((Math.PI * 2) - angle1) + angle2;
84
    }
85
  }
86

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

    
109
    GeometryManager geomManager = GeometryLocator.getGeometryManager();
110

    
111
    Curve lineAntPointToPoint = null;
112

    
113
    if (!values.isEmpty()) {
114
      for (int i = 0; i < values.size(); i++) {
115

    
116
        MyPolyLinePoint polyLinePoint = values.get(i);
117
        MyPolyLinePoint polyLineNextPoint = getNextPoint(i);
118

    
119
        Point point = polyLinePoint.getPoint();
120
        Point nextPoint;
121

    
122
        if (polyLineNextPoint == null) {
123
          nextPoint = lastPosition;
124
          addGeom = true;
125
        }
126
        else {
127
          nextPoint = polyLineNextPoint.getPoint();
128
        }
129

    
130
        if (nextPoint == null) {
131
          return geometries;
132
        }
133
        if (polyLinePoint.isArcMode()) {
134
          try {
135

    
136
            lineAntPointToPoint = editingProviderServices.createLine(
137
                point.getX(), point.getY(), nextPoint.getX(), nextPoint.getY(),
138
                featureStore);
139

    
140
            Double[] lineParams = getLineParams(point, nextPoint);
141
            m = lineParams[0];
142
            b = lineParams[1];
143

    
144
            Point[] pointPerpendicular = getPerpendicular(antm, antb, point,
145
                featureStore);
146
            Line linePointPerpendicular = geomManager
147
                .createLine(editingProviderServices.getSubType(featureStore));
148
            linePointPerpendicular.setPoints(pointPerpendicular[0],
149
                pointPerpendicular[1]);
150

    
151
            Point[] bisector = getPerpendicular(m, b,
152
                getMidPoint(point, nextPoint, featureStore), featureStore);
153
            Line lineBisector = geomManager.createLine(editingProviderServices
154
                .getSubType(featureStore));
155
            lineBisector.setPoints(bisector[0], bisector[1]);
156

    
157
            center = getIntersection(bisector, pointPerpendicular, featureStore);
158

    
159
            startAngle = getAngle(center, point);
160
            endAngle = getAngle(center, nextPoint);
161

    
162
            radius = center.distance(point);
163
          }
164
          catch (Exception e) {
165
            throw new DrawServiceException(e);
166
          }
167

    
168
          if (right) {
169
            if (nextPoint.getX() >= point.getX()) {
170
              if (m >= antm) {
171
                angleExt = angleDistance(endAngle, startAngle);
172
                right = !(nextPoint.getY() >= center.getY());
173
              }
174
              else {
175
                angleExt = -angleDistance(startAngle, endAngle);
176
                right = (nextPoint.getY() >= center.getY());
177
              }
178
            }
179
            else {
180
              if (m >= antm) {
181
                angleExt = -angleDistance(startAngle, endAngle);
182
                right = (nextPoint.getY() >= center.getY());
183
              }
184
              else {
185
                angleExt = angleDistance(endAngle, startAngle);
186
                right = !(nextPoint.getY() >= center.getY());
187
              }
188
            }
189
          } else {
190
            if (nextPoint.getX() < point.getX()) {
191
              if (m >= antm) {
192
                angleExt = angleDistance(endAngle, startAngle);
193
                right = !(nextPoint.getY() >= center.getY());
194
              }
195
              else {
196
                angleExt = -angleDistance(startAngle, endAngle);
197
                right = (nextPoint.getY() >= center.getY());
198
              }
199
            } else {
200
              if (m >= antm) {
201
                angleExt = -angleDistance(startAngle, endAngle);
202
                right = (nextPoint.getY() >= center.getY());
203
              }
204
              else {
205
                angleExt = angleDistance(endAngle, startAngle);
206
                right = !(nextPoint.getY() >= center.getY());
207
              }
208
            }
209
          }
210

    
211
          Curve arco = null;
212
          try {
213
            arco = editingProviderServices.createArc(center, radius,
214
                startAngle, angleExt, featureStore);
215
            Curve inverseArc = (Curve)GeometryLocator.getGeometryManager().create(TYPES.CURVE, editingProviderServices.getSubType(featureStore));
216
            if (!point.equals(arco.getVertex(0))){
217
                    System.out.println("point = "+point.toString()+" arco.getVertex(0)="+arco.getVertex(0).toString());
218
                    for (int j = arco.getNumVertices()-1; j >= 0; j--) {
219
                            inverseArc.addVertex(arco.getVertex(j));
220
                                }
221
                    arco = inverseArc;
222
            }
223
          }
224
          catch (Exception e) {
225
            throw new DrawServiceException(e);
226
          }
227

    
228
          antm = -(nextPoint.getX() - center.getX())
229
              / (nextPoint.getY() - center.getY());
230
          if (antm == Double.POSITIVE_INFINITY) {
231
            antb = Double.NEGATIVE_INFINITY;
232
            if (nextPoint.getX() == 0) {
233
              antb = 0.0;
234
            }
235
          }
236
          else if (antm == Double.NEGATIVE_INFINITY) {
237
            antb = Double.POSITIVE_INFINITY;
238
            if (nextPoint.getX() == 0) {
239
              antb = 0.0;
240
            }
241
          }
242
          else {
243
            antb = nextPoint.getY() - (antm * nextPoint.getX());
244
          }
245

    
246
          // Draw geometries.
247
          if (addGeom) {
248
            geometries.addGeometry(lineAntPointToPoint);
249
            geometries.addGeometry(center);
250
          }
251
          geometries.addGeometry(arco);
252

    
253
        }
254
        else {
255
          try {
256
            Curve geometry = editingProviderServices.createLine(point.getX(),
257
                point.getY(), nextPoint.getX(), nextPoint.getY(), featureStore);
258
            geometries.addGeometry(geometry);
259
          }
260
          catch (Exception e) {
261
            throw new DrawServiceException(e);
262
          }
263
          Double[] antLineParams = getLineParams(point, nextPoint);
264
          antm = antLineParams[0];
265
          antb = antLineParams[1];
266
          right = (nextPoint.getX() >= point.getX());
267
        }
268
      }
269
      return geometries;
270
    }
271
    return null;
272
  }
273

    
274
  /**
275
   * @param surface
276
   * @return
277
   */
278
  protected Surface closeSurfaceIfNecessary(Surface surface) {
279
    if (!isClose(surface) && surface != null) {
280
      Point firstp = surface.getVertex(0);
281
      firstp = (Point) firstp.cloneGeometry();
282
      surface.addVertex(firstp);
283
    }
284
    return surface;
285
  }
286

    
287
  public DrawingStatus getDrawingStatus(Point mousePosition) throws DrawServiceException {
288
    try {
289
      return calculatePolyline(mousePosition);
290
    }
291
    catch (Exception e) {
292
      throw new DrawServiceException(e);
293
    }
294
  }
295

    
296
  public void finishAndStore() throws FinishServiceException {
297
    try {
298
      Geometry geometry = finish();
299
      if (geometry != null) {
300
        editingProviderServices.insertGeometryIntoFeatureStore(geometry,
301
            featureStore);
302
      }
303
    }
304
    catch (Exception e) {
305
      throw new FinishServiceException(e);
306
    }
307
  }
308

    
309
        public Geometry finish() throws FinishServiceException {
310
                try {
311
                        GeometryManager geomManager = GeometryLocator.getGeometryManager();
312
                        GeometryType storeGeomType = editingProviderServices
313
                                        .getGeomType(featureStore);
314
                        Line line = geomManager.createLine(storeGeomType.getSubType());
315
                        calculateFinalGeometry(storeGeomType, line);
316

    
317
                        if (storeGeomType.isTypeOf(CURVE)) {
318
                                return line;
319
                        } else if (storeGeomType.isTypeOf(MULTICURVE)) {
320
                                MultiCurve multiCurve = geomManager.createMultiCurve(storeGeomType.getSubType());
321
                                multiCurve.addCurve((Curve) line);
322
                                return line;
323
                        }
324
                        return null;
325
                } catch (Exception e) {
326
                        throw new FinishServiceException(e);
327
                }
328
        }
329

    
330
        /**
331
         * Calculate the final geometry reversing the geometries of the drawingStatus if needed.
332
         *
333
         * @param geometryType
334
         * @param orientablePrimitive
335
         * @throws DataException
336
         * @throws CreateGeometryException
337
         * @throws VectorEditingException
338
         */
339
        protected void calculateFinalGeometry(GeometryType geometryType, OrientablePrimitive orientablePrimitive)
340
                        throws DataException, CreateGeometryException, VectorEditingException {
341
                DrawingStatus drawingStatus = calculatePolyline(null);
342
                Point vertexAnt = null;
343
                for (Geometry geometry : drawingStatus.getGeometries()) {
344
                        if (geometry instanceof Curve) {
345
                                Curve curve = (Curve) geometry;
346
                                for (int i = 0; i < curve.getNumVertices(); i++) {
347
                                        if (vertexAnt == null
348
                                                        || !vertexAnt.equals(curve.getVertex(i))) {
349
                                                orientablePrimitive.addVertex((Point) curve.getVertex(i));
350
                                                vertexAnt = curve.getVertex(i);
351
                                        }
352
                                }
353
                        }
354
                }
355
        }
356

    
357
  /**
358
   * @param start
359
   * @param end
360
   * @return
361
   * @throws GeometryOperationNotSupportedException
362
   * @throws GeometryOperationException
363
   */
364
  private static double getAngle(Point start, Point end)
365
      throws GeometryOperationNotSupportedException, GeometryOperationException {
366
    double angle = Math.acos((end.getX() - start.getX()) / start.distance(end));
367

    
368
    if (start.getY() > end.getY()) {
369
      angle = -angle;
370
    }
371

    
372
    if (angle < 0) {
373
      angle += (2 * Math.PI);
374
    }
375

    
376
    return angle;
377
  }
378

    
379
  /**
380
   * @param bisector
381
   * @param perpendicular
382
   * @param featureStore
383
   * @return
384
   * @throws CreateGeometryException
385
   * @throws DataException
386
   */
387
  private Point getIntersection(Point[] bisector, Point[] perpendicular,
388
                                FeatureStore featureStore)
389
      throws CreateGeometryException, DataException {
390
    Point p1 = bisector[0];
391
    Point p2 = bisector[1];
392
    Point p3 = perpendicular[0];
393
    Point p4 = perpendicular[1];
394

    
395
    double m1 = Double.POSITIVE_INFINITY;
396

    
397
    if ((p2.getX() - p1.getX()) != 0) {
398
      m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
399
    }
400

    
401
    double m2 = Double.POSITIVE_INFINITY;
402

    
403
    if ((p4.getX() - p3.getX()) != 0) {
404
      m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
405
    }
406

    
407
    if ((m1 == Double.POSITIVE_INFINITY) && (m2 == Double.POSITIVE_INFINITY)) {
408
      return null;
409
    }
410

    
411
    double b1 = p2.getY() - (m1 * p2.getX());
412

    
413
    double b2 = p4.getY() - (m2 * p4.getX());
414

    
415
    if ((m1 != Double.POSITIVE_INFINITY) && (m2 != Double.POSITIVE_INFINITY)) {
416
      if (m1 == m2) {
417
        return null;
418
      }
419

    
420
      double x = (b2 - b1) / (m1 - m2);
421

    
422
      return editingProviderServices
423
          .createPoint(x, (m1 * x) + b1, featureStore);
424
    }
425
    else if (m1 == Double.POSITIVE_INFINITY) {
426
      double x = p1.getX();
427

    
428
      return editingProviderServices
429
          .createPoint(x, (m2 * x) + b2, featureStore);
430
    }
431
    else if (m2 == Double.POSITIVE_INFINITY) {
432
      double x = p3.getX();
433

    
434
      return editingProviderServices
435
          .createPoint(x, (m1 * x) + b1, featureStore);
436
    }
437

    
438
    return null;
439
  }
440

    
441
  /**
442
   * @param point
443
   * @param nextPoint
444
   * @return
445
   */
446
  private Double[] getLineParams(Point point, Point nextPoint) {
447
    Double[] lineParams = new Double[2];
448
    double denom = nextPoint.getX() - point.getX();
449
    if (denom != 0) {
450
      lineParams[0] = (nextPoint.getY() - point.getY()) / denom;
451
      lineParams[1] = point.getY() - (lineParams[0] * point.getX());
452
    }
453
    else {
454
      if (nextPoint.getY() >= point.getY()) {
455
        lineParams[0] = Double.POSITIVE_INFINITY;
456
        lineParams[1] = Double.NEGATIVE_INFINITY;
457
        if (point.getX() == 0) {
458
          lineParams[1] = 0.0;
459
        }
460
      }
461
      else {
462
        lineParams[0] = Double.NEGATIVE_INFINITY;
463
        lineParams[1] = Double.POSITIVE_INFINITY;
464
        if (point.getX() == 0) {
465
          lineParams[1] = 0.0;
466
        }
467
      }
468
    }
469
    return lineParams;
470
  }
471

    
472
  /**
473
   * @param p1
474
   * @param p2
475
   * @param featureStore
476
   * @return
477
   * @throws CreateGeometryException
478
   * @throws DataException
479
   */
480
  private Point getMidPoint(Point p1, Point p2, FeatureStore featureStore)
481
      throws CreateGeometryException, DataException {
482
    double x = (p1.getX() + p2.getX()) / 2;
483
    double y = (p1.getY() + p2.getY()) / 2;
484
    return editingProviderServices.createPoint(x, y, featureStore);
485
  }
486

    
487
  public String getName() {
488
    return PolylineEditingProviderFactory.PROVIDER_NAME;
489
  }
490

    
491
  /**
492
   * @param i
493
   * @return
494
   */
495
  private MyPolyLinePoint getNextPoint(int i) {
496
    if (!values.isEmpty() && i < values.size() - 1) {
497
      return values.get(i + 1);
498
    }
499
    return null;
500
  }
501

    
502
  public List<EditingServiceParameter> getParameters() {
503
    List<EditingServiceParameter> list = new ArrayList<EditingServiceParameter>();
504
    list.add(points);
505
    return list;
506
  }
507

    
508
  /**
509
   * @param m
510
   * @param b
511
   * @param perp
512
   * @param featureStore
513
   * @return
514
   * @throws CreateGeometryException
515
   * @throws DataException
516
   */
517
  private Point[] getPerpendicular(Double m, Double b, Point perp,
518
                                   FeatureStore featureStore)
519
      throws CreateGeometryException, DataException {
520
    if (m == Double.POSITIVE_INFINITY) {
521
      Point[] res = new Point[2];
522
      res[0] = editingProviderServices
523
          .createPoint(0, perp.getY(), featureStore);
524
      res[1] = editingProviderServices
525
          .createPoint(1, perp.getY(), featureStore);
526
      return res;
527
    }
528
    else if (m == Double.NEGATIVE_INFINITY) {
529
      Point[] res = new Point[2];
530
      res[0] = editingProviderServices
531
          .createPoint(1, perp.getY(), featureStore);
532
      res[1] = editingProviderServices
533
          .createPoint(0, perp.getY(), featureStore);
534
      return res;
535
    }
536
    else {
537
      // Pendiente de la recta perpendicular
538
      Double m1 = -1 / m;
539

    
540
      // b de la funcion de la recta perpendicular
541
      Double b1 = perp.getY() - (m1 * perp.getX());
542

    
543
      // Obtenemos un par de puntos
544
      Point[] res = new Point[2];
545

    
546
      if (Double.isInfinite(m1)) {
547
        res[0] = editingProviderServices.createPoint(perp.getX(), 0.0,
548
            featureStore);
549
        res[1] = editingProviderServices.createPoint(perp.getX(), perp.getY(),
550
            featureStore);
551
      }
552
      else {
553
        res[0] = editingProviderServices.createPoint(0, 0.0 + b1, featureStore);
554
        res[1] = editingProviderServices.createPoint(perp.getX(),
555
            (m1 * perp.getX()) + b1, featureStore);
556
      }
557

    
558
      return res;
559
    }
560
  }
561

    
562
  /**
563
   * @param surface
564
   * @return
565
   */
566
  private boolean isClose(Surface surface) {
567

    
568
    if (surface != null) {
569
      Point firstPoint = surface.getVertex(0);
570
      Point lastPoint = surface.getVertex(surface.getNumVertices() - 1);
571
      if (firstPoint.equals(lastPoint)) {
572
        return true;
573
      }
574
    }
575
    return false;
576
  }
577

    
578
  public EditingServiceParameter next() {
579
    if (values.size() >= 2) {
580
      if (arcMode) {
581
        points
582
            .setDescription(i18nManager
583
                .getTranslation("inserts_L_to_change_to_line_mode_double_click_to_finish_indate_new_point"));
584

    
585
      }
586
      else {
587
        points
588
            .setDescription(i18nManager
589
                .getTranslation("inserts_A_to_change_to_arc_mode_double_click_to_finish_indate_new_point"));
590
      }
591
    }
592
    return points;
593
  }
594

    
595
  public void start() throws StartServiceException {
596
    stop();
597
    values = new ArrayList<MyPolyLinePoint>();
598

    
599
  }
600

    
601
  public void stop() {
602
    if (values != null) {
603
      values.clear();
604
    }
605
    points.setDescription(i18nManager.getTranslation("indicates_new_point"));
606
    arcMode = false;
607
  }
608

    
609
  /**
610
   * @param param
611
   * @param value
612
   */
613
  private void validateAndInsertValue(EditingServiceParameter param,
614
                                      Object value)
615
      throws InvalidEntryException {
616
    if (value instanceof String) {
617
      if (values.size() >= 2) {
618
        if (((String) value).equalsIgnoreCase("A")
619
            || ((String) value).equalsIgnoreCase("L")) {
620
          if (((String) value).equalsIgnoreCase("A")) {
621
            arcMode = true;
622
          }
623
          else if (((String) value).equalsIgnoreCase("L")) {
624
            arcMode = false;
625
          }
626
          if (values.size() > 0) {
627
            values.get(values.size() - 1).setArcMode(arcMode);
628
            return;
629
          }
630
        }
631
        else {
632
          throw new InvalidEntryException(null);
633
        }
634

    
635
      }
636
      else {
637
        throw new InvalidEntryException(null);
638
      }
639
    }
640
    else if (param == points && value instanceof Point) {
641
      values.add(new MyPolyLinePoint((Point) value, arcMode));
642
    }
643
  }
644

    
645
  public void setValue(Object value) throws InvalidEntryException {
646
    EditingServiceParameter param = next();
647
    validateAndInsertValue(param, value);
648
  }
649

    
650
}