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

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

    
47
public class PolylineEditingProvider extends AbstractEditingProvider implements
48
    EditingProvider {
49

    
50
  protected GeometryManager geomManager = GeometryLocator.getGeometryManager();
51

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

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

    
56
  private EditingServiceParameter points = new DefaultEditingServiceParameter(
57
      "Polyline", 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
  private 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
   * @param lastPosition
89
   * @return
90
   * @throws VectorEditingException
91
   */
92
  private DrawingStatus calculatePolyline(Point lastPosition)
93
      throws VectorEditingException {
94
    DrawingStatus geometries = new DefaultDrawingStatus();
95
    Double antm = null;
96
    Double antb = null;
97
    Double m = null;
98
    Double b = null;
99
    Point center = null;
100
    double radius = 0.0;
101
    double startAngle = 0.0;
102
    double endAngle = 0.0;
103
    double angleExt = 0.0;
104
    boolean right = false;
105
    boolean addGeom = false;
106

    
107
    Curve lineAntPointToPoint = null;
108

    
109
    if (!values.isEmpty()) {
110
      for (int i = 0; i < values.size(); i++) {
111

    
112
        MyPolyLinePoint polyLinePoint = values.get(i);
113
        MyPolyLinePoint polyLineNextPoint = getNextPoint(i);
114

    
115
        Point point = polyLinePoint.getPoint();
116
        Point nextPoint;
117

    
118
        if (polyLineNextPoint == null) {
119
          nextPoint = lastPosition;
120
          addGeom = true;
121
        }
122
        else {
123
          nextPoint = polyLineNextPoint.getPoint();
124
        }
125

    
126
        if (nextPoint == null) {
127
          return geometries;
128
        }
129
        if (polyLinePoint.isArcMode()) {
130
          try {
131

    
132
            lineAntPointToPoint = editingProviderServices.createLine(
133
                point.getX(), point.getY(), nextPoint.getX(), nextPoint.getY(),
134
                featureStore);
135

    
136
            Double[] lineParams = getLineParams(point, nextPoint);
137
            m = lineParams[0];
138
            b = lineParams[1];
139

    
140
            Point[] pointPerpendicular = getPerpendicular(antm, antb, point,
141
                featureStore);
142
            Line linePointPerpendicular = geomManager
143
                .createLine(editingProviderServices.getSubType(featureStore));
144
            linePointPerpendicular.setPoints(pointPerpendicular[0],
145
                pointPerpendicular[1]);
146

    
147
            Point[] bisector = getPerpendicular(m, b,
148
                getMidPoint(point, nextPoint, featureStore), featureStore);
149
            Line lineBisector = geomManager.createLine(editingProviderServices
150
                .getSubType(featureStore));
151
            lineBisector.setPoints(bisector[0], bisector[1]);
152

    
153
            center = getIntersection(bisector, pointPerpendicular, featureStore);
154

    
155
            startAngle = getAngle(center, point);
156
            endAngle = getAngle(center, nextPoint);
157

    
158
            radius = center.distance(point);
159
          }
160
          catch (Exception e) {
161
            throw new DrawServiceException(e);
162
          }
163

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

    
209
          Arc arco = null;
210
          try {
211
            arco = editingProviderServices.createArc(center, radius,
212
                startAngle, angleExt, featureStore);
213
          }
214
          catch (Exception e) {
215
            throw new DrawServiceException(e);
216
          }
217

    
218
          antm = -(nextPoint.getX() - center.getX())
219
              / (nextPoint.getY() - center.getY());
220
          if (antm == Double.POSITIVE_INFINITY) {
221
            antb = Double.NEGATIVE_INFINITY;
222
            if (nextPoint.getX() == 0) {
223
              antb = 0.0;
224
            }
225
          }
226
          else if (antm == Double.NEGATIVE_INFINITY) {
227
            antb = Double.POSITIVE_INFINITY;
228
            if (nextPoint.getX() == 0) {
229
              antb = 0.0;
230
            }
231
          }
232
          else {
233
            antb = nextPoint.getY() - (antm * nextPoint.getX());
234
          }
235

    
236
          // Draw geometries.
237
          if (addGeom) {
238
            geometries.addGeometry(lineAntPointToPoint);
239
            geometries.addGeometry(center);
240
          }
241
          geometries.addGeometry(arco);
242

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

    
264
  /**
265
   * @param surface
266
   * @return
267
   */
268
  private Surface closeSurfaceIfNecessary(Surface surface) {
269
    if (!isClose(surface) && surface != null) {
270
      Point firstp = surface.getVertex(0);
271
      firstp = (Point) firstp.cloneGeometry();
272
      surface.addVertex(firstp);
273
    }
274
    return surface;
275
  }
276

    
277
  public DrawingStatus draw(Point mousePosition) throws DrawServiceException {
278
    try {
279
      return calculatePolyline(mousePosition);
280
    }
281
    catch (Exception e) {
282
      throw new DrawServiceException(e);
283
    }
284
  }
285

    
286
  public void finishAndStore() throws FinishServiceException {
287
    try {
288
      GeometryType storeGeomType = editingProviderServices
289
          .getGeomType(featureStore);
290

    
291
      Geometry geometry = finish();
292
      if (geometry == null) {
293
        if (storeGeomType.isTypeOf(CURVE)) {
294
          DrawingStatus finalGeometries = calculatePolyline(null);
295
          for (Geometry geom : finalGeometries.getGeometries()) {
296
            editingProviderServices.insertGeometryIntoFeatureStore(geom,
297
                featureStore);
298
          }
299
        }
300
        else if (storeGeomType.isTypeOf(MULTICURVE)) {
301
          DrawingStatus finalGeometries = calculatePolyline(null);
302
          MultiCurve multiCurve;
303
          multiCurve = geomManager.createMultiCurve(storeGeomType.getSubType());
304
          for (Geometry geom : finalGeometries.getGeometries()) {
305
            multiCurve.addCurve((Curve) geom);
306
          }
307
          editingProviderServices.insertGeometryIntoFeatureStore(multiCurve,
308
              featureStore);
309
        }
310
      }
311
      else {
312
        editingProviderServices.insertGeometryIntoFeatureStore(geometry,
313
            featureStore);
314
      }
315
    }
316
    catch (Exception e) {
317
      throw new FinishServiceException(e);
318
    }
319
  }
320

    
321
  public Geometry finish() throws FinishServiceException {
322
    try {
323
      GeometryType storeGeomType = editingProviderServices
324
          .getGeomType(featureStore);
325
      if (storeGeomType.isTypeOf(SURFACE)) {
326
        DrawingStatus finalGeometries = calculatePolyline(null);
327
        Surface surface = geomManager.createPolygon(storeGeomType.getSubType());
328
        for (Geometry geometry : finalGeometries.getGeometries()) {
329
          surface.addVertex((Point) geometry);
330
        }
331
        surface = closeSurfaceIfNecessary(surface);
332
        return (Geometry) surface;
333
      }
334
      else if (storeGeomType.isTypeOf(MULTISURFACE)) {
335
        DrawingStatus finalGeometries = calculatePolyline(null);
336
        MultiSurface multiSurface;
337
        multiSurface = geomManager.createMultiSurface(storeGeomType
338
            .getSubType());
339
        Surface surface = geomManager.createPolygon(storeGeomType.getSubType());
340
        for (Geometry geometry : finalGeometries.getGeometries()) {
341
          if (geometry instanceof Curve) {
342
            Curve curve = (Curve) geometry;
343
            for (int i = 0; i < curve.getNumVertices(); i++) {
344
              surface.addVertex((Point) curve.getVertex(i));
345
            }
346
          }
347
        }
348
        surface = closeSurfaceIfNecessary(surface);
349
        multiSurface.addSurface(surface);
350
        return (Geometry) multiSurface;
351
      }
352
      return null;
353
    }
354
    catch (Exception e) {
355
      throw new FinishServiceException(e);
356
    }
357
  }
358

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

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

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

    
378
    return angle;
379
  }
380

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

    
397
    double m1 = Double.POSITIVE_INFINITY;
398

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

    
403
    double m2 = Double.POSITIVE_INFINITY;
404

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

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

    
413
    double b1 = p2.getY() - (m1 * p2.getX());
414

    
415
    double b2 = p4.getY() - (m2 * p4.getX());
416

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

    
422
      double x = (b2 - b1) / (m1 - m2);
423

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

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

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

    
440
    return null;
441
  }
442

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

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

    
489
  public String getName() {
490
    return PolylineEditingProviderFactory.PROVIDER_NAME;
491
  }
492

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

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

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

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

    
545
      // Obtenemos un par de puntos
546
      Point[] res = new Point[2];
547

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

    
560
      return res;
561
    }
562
  }
563

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

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

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

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

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

    
601
  }
602

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

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

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

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

    
652
}