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

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 GeometryManager geomManager = GeometryLocator.getGeometryManager();
53

    
54
  protected EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
55

    
56
  protected I18nManager i18nManager = ToolsLocator.getI18nManager();
57

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

    
62
  private boolean arcMode = false;
63

    
64
  private List<MyPolyLinePoint> values;
65

    
66
  protected FeatureStore featureStore;
67

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

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

    
89
  /**
90
   *
91
   *
92
   * @param lastPosition
93
   * @return
94
   * @throws VectorEditingException
95
   */
96
  private DrawingStatus calculatePolyline(Point lastPosition)
97
      throws VectorEditingException {
98
    DrawingStatus geometries = new DefaultDrawingStatus();
99
    Double antm = null;
100
    Double antb = null;
101
    Double m = null;
102
    Double b = null;
103
    Point center = null;
104
    double radius = 0.0;
105
    double startAngle = 0.0;
106
    double endAngle = 0.0;
107
    double angleExt = 0.0;
108
    boolean right = false;
109
    boolean addGeom = false;
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 draw(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
                        GeometryType storeGeomType = editingProviderServices
312
                                        .getGeomType(featureStore);
313
                        Line line = geomManager.createLine(storeGeomType.getSubType());
314
                        calculateFinalGeometry(storeGeomType, line);
315

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

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

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

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

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

    
375
    return angle;
376
  }
377

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

    
394
    double m1 = Double.POSITIVE_INFINITY;
395

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

    
400
    double m2 = Double.POSITIVE_INFINITY;
401

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

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

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

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

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

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

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

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

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

    
437
    return null;
438
  }
439

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

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

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

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

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

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

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

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

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

    
557
      return res;
558
    }
559
  }
560

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

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

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

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

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

    
598
  }
599

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

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

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

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

    
649
}