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

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

    
339
  /**
340
   * @param start
341
   * @param end
342
   * @return
343
   * @throws GeometryOperationNotSupportedException
344
   * @throws GeometryOperationException
345
   */
346
  private static double getAngle(Point start, Point end)
347
      throws GeometryOperationNotSupportedException, GeometryOperationException {
348
    double angle = Math.acos((end.getX() - start.getX()) / start.distance(end));
349

    
350
    if (start.getY() > end.getY()) {
351
      angle = -angle;
352
    }
353

    
354
    if (angle < 0) {
355
      angle += (2 * Math.PI);
356
    }
357

    
358
    return angle;
359
  }
360

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

    
377
    double m1 = Double.POSITIVE_INFINITY;
378

    
379
    if ((p2.getX() - p1.getX()) != 0) {
380
      m1 = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
381
    }
382

    
383
    double m2 = Double.POSITIVE_INFINITY;
384

    
385
    if ((p4.getX() - p3.getX()) != 0) {
386
      m2 = (p4.getY() - p3.getY()) / (p4.getX() - p3.getX());
387
    }
388

    
389
    if ((m1 == Double.POSITIVE_INFINITY) && (m2 == Double.POSITIVE_INFINITY)) {
390
      return null;
391
    }
392

    
393
    double b1 = p2.getY() - (m1 * p2.getX());
394

    
395
    double b2 = p4.getY() - (m2 * p4.getX());
396

    
397
    if ((m1 != Double.POSITIVE_INFINITY) && (m2 != Double.POSITIVE_INFINITY)) {
398
      if (m1 == m2) {
399
        return null;
400
      }
401

    
402
      double x = (b2 - b1) / (m1 - m2);
403

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

    
410
      return editingProviderServices
411
          .createPoint(x, (m2 * x) + b2, featureStore);
412
    }
413
    else if (m2 == Double.POSITIVE_INFINITY) {
414
      double x = p3.getX();
415

    
416
      return editingProviderServices
417
          .createPoint(x, (m1 * x) + b1, featureStore);
418
    }
419

    
420
    return null;
421
  }
422

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

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

    
469
  public String getName() {
470
    return PolylineEditingProviderFactory.PROVIDER_NAME;
471
  }
472

    
473
  /**
474
   * @param i
475
   * @return
476
   */
477
  private MyPolyLinePoint getNextPoint(int i) {
478
    if (!values.isEmpty() && i < values.size() - 1) {
479
      return values.get(i + 1);
480
    }
481
    return null;
482
  }
483

    
484
  public List<EditingServiceParameter> getParameters() {
485
    List<EditingServiceParameter> list = new ArrayList<EditingServiceParameter>();
486
    list.add(points);
487
    return list;
488
  }
489

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

    
522
      // b de la funcion de la recta perpendicular
523
      Double b1 = perp.getY() - (m1 * perp.getX());
524

    
525
      // Obtenemos un par de puntos
526
      Point[] res = new Point[2];
527

    
528
      if (Double.isInfinite(m1)) {
529
        res[0] = editingProviderServices.createPoint(perp.getX(), 0.0,
530
            featureStore);
531
        res[1] = editingProviderServices.createPoint(perp.getX(), perp.getY(),
532
            featureStore);
533
      }
534
      else {
535
        res[0] = editingProviderServices.createPoint(0, 0.0 + b1, featureStore);
536
        res[1] = editingProviderServices.createPoint(perp.getX(),
537
            (m1 * perp.getX()) + b1, featureStore);
538
      }
539

    
540
      return res;
541
    }
542
  }
543

    
544
  /**
545
   * @param surface
546
   * @return
547
   */
548
  private boolean isClose(Surface surface) {
549

    
550
    if (surface != null) {
551
      Point firstPoint = surface.getVertex(0);
552
      Point lastPoint = surface.getVertex(surface.getNumVertices() - 1);
553
      if (firstPoint.equals(lastPoint)) {
554
        return true;
555
      }
556
    }
557
    return false;
558
  }
559

    
560
  public EditingServiceParameter next() {
561
    if (values.size() >= 2) {
562
      if (arcMode) {
563
        points
564
            .setDescription(i18nManager
565
                .getTranslation("inserts_L_to_change_to_line_mode_double_click_to_finish_indate_new_point"));
566

    
567
      }
568
      else {
569
        points
570
            .setDescription(i18nManager
571
                .getTranslation("inserts_A_to_change_to_arc_mode_double_click_to_finish_indate_new_point"));
572
      }
573
    }
574
    return points;
575
  }
576

    
577
  public void start() throws StartServiceException {
578
    stop();
579
    values = new ArrayList<MyPolyLinePoint>();
580

    
581
  }
582

    
583
  public void stop() {
584
    points.setDescription(i18nManager.getTranslation("indicates_new_point"));
585
    arcMode = false;
586
  }
587

    
588
  /**
589
   * @param param
590
   * @param value
591
   */
592
  private void validateAndInsertValue(EditingServiceParameter param,
593
                                      Object value)
594
      throws InvalidEntryException {
595
    if (value instanceof String) {
596
      if (values.size() >= 2) {
597
        if (((String) value).equalsIgnoreCase("A")
598
            || ((String) value).equalsIgnoreCase("L")) {
599
          if (((String) value).equalsIgnoreCase("A")) {
600
            arcMode = true;
601
          }
602
          else if (((String) value).equalsIgnoreCase("L")) {
603
            arcMode = false;
604
          }
605
          if (values.size() > 0) {
606
            values.get(values.size() - 1).setArcMode(arcMode);
607
            return;
608
          }
609
        }
610
        else {
611
          throw new InvalidEntryException(null);
612
        }
613

    
614
      }
615
      else {
616
        throw new InvalidEntryException(null);
617
      }
618
    }
619
    else if (param == points && value instanceof Point) {
620
      values.add(new MyPolyLinePoint((Point) value, arcMode));
621
    }
622
  }
623

    
624
  public void value(Object value) throws InvalidEntryException {
625
    EditingServiceParameter param = next();
626
    validateAndInsertValue(param, value);
627
  }
628

    
629
}