Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / style / Line2DOffset.java @ 40560

History | View | Annotate | Download (20.5 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style;
25

    
26
import java.awt.Shape;
27
import java.awt.geom.Line2D;
28
import java.awt.geom.PathIterator;
29
import java.awt.geom.Point2D;
30
import java.util.ArrayList;
31
import java.util.HashMap;
32
import java.util.List;
33
import java.util.Map;
34

    
35
import org.gvsig.fmap.geom.Geometry;
36
import org.gvsig.fmap.geom.primitive.GeneralPathX;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39

    
40
import com.vividsolutions.jts.geom.Coordinate;
41
import com.vividsolutions.jts.geom.LineSegment;
42
/**
43
 *
44
 * Line2DOffset.java
45
 *
46
 *
47
 * @author jaume dominguez faus - jaume.dominguez@iver.es Jan 3, 2008
48
 *
49
 */
50

    
51
public class Line2DOffset {
52
        final static private Logger logger = LoggerFactory.getLogger(Line2DOffset.class);
53

    
54
        public static GeneralPathX offsetLine(Shape p, double offset) {
55

    
56
                if (Math.abs(offset) < 1) {
57
                        return new GeneralPathX(p.getPathIterator(null));
58
                }
59
                PathIterator pi = p.getPathIterator(null);
60
                double[] dataCoords = new double[6];
61
                Coordinate from = null, first = null;
62
                List<LineSegment> segments = new ArrayList<LineSegment>();
63
                GeneralPathX offsetSegments = new GeneralPathX();
64
                LineSegment line;
65
                try {
66
                        while (!pi.isDone()) {
67
                                // while not done
68
                                int type = pi.currentSegment(dataCoords);
69

    
70
                                switch (type) {
71
                                case PathIterator.SEG_MOVETO:
72
                                        if(from == null){
73
                                                from = new Coordinate(dataCoords[0], dataCoords[1]);
74
                                                first = from;
75
                                                break;
76
                                        } else {
77
                                                /* Puede significar un agujero en un pol?gono o un salto en una linea.
78
                                                 * Entonces, consumimos los segmentos que llevamos
79
                                                 * y empezamos un nuevo pol?gono o una nueva linea.
80
                                                 */
81
                                                try {
82
                                                        if(((Geometry)p).getType() == Geometry.TYPES.SURFACE){
83
                                                                offsetSegments.append(offsetAndConsumeClosedSegments(offset, segments).getPathIterator(null),
84
                                                                                false);
85
                                                        } else {
86
                                                                offsetSegments.append(offsetAndConsumeSegments(offset, segments).getPathIterator(null),
87
                                                                                false);
88
                                                        }
89
                                                } catch (NotEnoughSegmentsToClosePathException e) {
90
                                                        logger.error(
91
                                                                        e.getMessage(), e);
92
                                                }
93
                                                segments.clear();
94
                                                from = new Coordinate(dataCoords[0], dataCoords[1]);
95
                                                first = from;
96
                                                break;
97
                                        }
98

    
99
                                case PathIterator.SEG_LINETO:
100

    
101
                                        // System.out.println("SEG_LINETO");
102
                                        Coordinate to = new Coordinate(dataCoords[0], dataCoords[1]);
103
                                        if(from.compareTo(to)!=0){
104
                                                line = new LineSegment(from, to);
105
                                                segments.add(line);
106
                                                from = to;
107
                                        }
108
                                        break;
109
                                case PathIterator.SEG_CLOSE:
110
                                        line = new LineSegment(from, first);
111
                                        segments.add(line);
112
                                        //                                        from = first;
113
                                        try {
114
                                                offsetSegments.append(offsetAndConsumeClosedSegments(
115
                                                                offset, segments).getPathIterator(null), false);
116
                                        } catch (NotEnoughSegmentsToClosePathException e) {
117
                                                logger.error(
118
                                                                e.getMessage(), e);
119
                                        }
120
                                        segments.clear();
121
                                        first =null;
122
                                        from = null;
123

    
124
                                        break;
125

    
126
                                } // end switch
127

    
128
                                pi.next();
129
                        }
130
                        offsetSegments.append(offsetAndConsumeSegments(offset, segments)
131
                                        .getPathIterator(null), false);
132

    
133
                        return offsetSegments;
134
                } catch (ParallelLinesCannotBeResolvedException e) {
135
                        logger.error(e.getMessage(), e);
136
                        return new GeneralPathX(p.getPathIterator(null));
137
                }
138
        }
139

    
140
        private static GeneralPathX offsetAndConsumeSegments(double offset,
141
                        List<LineSegment> segments)
142
        throws ParallelLinesCannotBeResolvedException {
143
                Map<LineSegment, LineEquation> offsetLines =
144
                        new HashMap<LineSegment, LineEquation>();
145
                int segmentCount = segments.size();
146
                // first calculate offset lines with the starting point
147
                for (int i = 0; i < segmentCount; i++) {
148
                        LineSegment segment = (LineSegment)segments.get(i);
149
                        double theta = segment.angle();
150
                        //FIXME: ?Esto para qu? es?
151
                        //                        if (Math.abs(theta) % (Math.PI*0.5) < 0.00001){
152
                        //                                theta=theta+0.00000000000001;
153
                        //                        }
154

    
155
                        double xOffset = offset * Math.sin(theta);
156
                        double yOffset = offset * Math.cos(theta);
157

    
158
                        Coordinate p0 = segment.p0;
159
                        double x0 = p0.x + xOffset;
160
                        double y0 = p0.y - yOffset;
161

    
162
                        Coordinate p1 = segment.p1;
163
                        double x1 = p1.x + xOffset;
164
                        double y1 = p1.y - yOffset;
165

    
166
                        LineEquation offsetLine = new LineEquation(theta, x0, y0, x1, y1);
167
                        offsetLines.put(segment, offsetLine);
168
                }
169

    
170
                /*
171
                 * let's now calculate the end point of each segment with the point
172
                 * where each line crosses the next one. this point will be the end
173
                 * point of the first line, and the start point of its next one.
174
                 */
175
                Point2D pIni = null;
176
                Point2D pEnd = null;
177
                GeneralPathX gpx = new GeneralPathX();
178
                for (int i = 0; i < segmentCount; i++) {
179
                        LineSegment segment = (LineSegment)segments.get(0);
180
                        LineEquation eq = (LineEquation)offsetLines.get(segment);
181
                        if (i == 0) {
182
                                pIni = new Point2D.Double(eq.x, eq.y);
183
                        } else {
184
                                pIni = pEnd;
185
                        }
186

    
187
                        if (i < segmentCount - 1) {
188
                                LineEquation eq1 = (LineEquation) offsetLines.get(segments.get(1));
189
                                try{
190
                                        pEnd = eq.resolve(eq1);
191
                                } catch (ParallelLinesCannotBeResolvedException e) { //Las lineas son paralelas y NO son la misma.
192
                                        pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
193
                                        gpx.append(new Line2D.Double(pIni, pEnd)
194
                                        .getPathIterator(null), true); // a?adimos una linea
195
                                        // hasta el final
196
                                        // del primer
197
                                        // segmento
198
                                        //                                         y asignamos como punto final el principio del siguiente segmento
199
                                        //                                         para que en la siguiente iteraci?n lo tome como punto inicial.
200
                                        pIni = pEnd;
201
                                        pEnd = new Point2D.Double(eq1.x, eq1.y);
202
                                        segments.remove(0);
203
                                        continue;
204
                                }
205
                        } else {
206
                                pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
207
                        }
208

    
209
                        gpx.append(new Line2D.Double(pIni, pEnd).getPathIterator(null), true);
210
                        segments.remove(0);
211
                }
212
                return gpx;
213
        }
214

    
215
        private static GeneralPathX offsetAndConsumeClosedSegments(double offset,
216
                        List<LineSegment> segments)
217
        throws ParallelLinesCannotBeResolvedException, NotEnoughSegmentsToClosePathException {
218
                int segmentCount = segments.size();
219
                if (segmentCount > 1) {
220
                        Map<LineSegment, LineEquation> offsetLines = new HashMap<LineSegment, LineEquation>();
221
                        // first calculate offset lines with the starting point
222
                        for (int i = 0; i < segmentCount; i++) {
223
                                LineSegment segment = (LineSegment)segments.get(i);
224
                                double theta = segment.angle();
225
                                //FIXME: ?Esto para qu? es?
226
                                //                        if (Math.abs(theta) % (Math.PI*0.5) < 0.00001){
227
                                //                                theta=theta+0.00000000000001;
228
                                //                        }
229

    
230
                                double xOffset = offset * Math.sin(theta);
231
                                double yOffset = offset * Math.cos(theta);
232

    
233
                                Coordinate p0 = segment.p0;
234
                                double x0 = p0.x + xOffset;
235
                                double y0 = p0.y - yOffset;
236

    
237
                                Coordinate p1 = segment.p1;
238
                                double x1 = p1.x + xOffset;
239
                                double y1 = p1.y - yOffset;
240

    
241
                                LineEquation offsetLine = new LineEquation(theta, x0, y0, x1, y1);
242
                                offsetLines.put(segment, offsetLine);
243
                        }
244

    
245
                        /*
246
                         * let's now calculate the end point of each segment with the point
247
                         * where each line crosses the next one. this point will be the end
248
                         * point of the first line, and the start point of its next one.
249
                         */
250
                        Point2D pIni = null;
251
                        Point2D pEnd = null;
252
                        Point2D firstP = null;
253
                        GeneralPathX gpx = new GeneralPathX();
254
                        for (int i = 0; i < segmentCount; i++) {
255
                                LineSegment segment = (LineSegment)segments.get(0);
256
                                LineEquation eq = offsetLines.get(segment);
257
                                if (i == 0) { //Calculo de la intersecci?n entre el primer segmento y el ?ltimo
258
                                        LineEquation eq0 = offsetLines.get((LineSegment)segments.get(segmentCount-1));
259
                                        try{
260
                                                pIni = eq0.resolve(eq);
261
                                        } catch (ParallelLinesCannotBeResolvedException e) { //Las lineas son paralelas y NO son la misma.
262
                                                //                                                pIni = new Point2D.Double(eq0.xEnd, eq0.yEnd);
263
                                                pIni = new Point2D.Double(eq.x, eq.y);
264
                                        }
265
                                        firstP = pIni;
266
                                } else {
267
                                        pIni = pEnd;
268
                                }
269

    
270
                                if (i < segmentCount - 1) {
271
                                        LineEquation eq1 = offsetLines.get((LineSegment)segments.get(1));
272
                                        try{
273
                                                pEnd = eq.resolve(eq1);
274
                                        } catch (ParallelLinesCannotBeResolvedException e) { //Las lineas son paralelas y NO son la misma.
275
                                                pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
276
                                                gpx.append(new Line2D.Double(pIni, pEnd).getPathIterator(null), true); // a?adimos una linea hasta el final del primer segmento
277
                                                //                                         y asignamos como punto final el principio del siguiente segmento
278
                                                //                                         para que en la siguiente iteraci?n lo tome como punto inicial.
279
                                                pIni = pEnd;
280
                                                pEnd = new Point2D.Double(eq1.x, eq1.y);
281
                                                segments.remove(0);
282
                                                continue;
283
                                        }
284
                                } else {
285
                                        //                                        pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
286
                                        pEnd = new Point2D.Double(firstP.getX(), firstP.getY());
287
                                }
288

    
289
                                gpx.append(new Line2D.Double(pIni, pEnd).getPathIterator(null), true);
290
                                segments.remove(0);
291
                        }
292
                        return gpx;
293
                }
294
                throw new NotEnoughSegmentsToClosePathException(segments);
295

    
296
        }
297

    
298
        //        private static GeneralPathX offsetAndConsumeClosedSegments(double offset,
299
        //                        List<LineSegment> segments)
300
        //        throws ParallelLinesCannotBeResolvedException,
301
        //        NotEnoughSegmentsToClosePathException {
302
        //                int segmentCount = segments.size();
303
        //                if (segmentCount > 1) {
304
        //                        GeneralPathX openPath = offsetAndConsumeSegments(offset, segments);
305
        //                        openPath.closePath();
306
        //                        return openPath;
307
        //                }
308
        //                throw new NotEnoughSegmentsToClosePathException(segments);
309
        //        }
310
}
311

    
312
class LineEquation {
313
        double theta, m, x, y;
314

    
315
        double xEnd, yEnd; // just for simplicity of code
316

    
317
        public LineEquation(double theta, double x, double y, double xEnd,
318
                        double yEnd) {
319
                //                this.theta = Math.tan(theta); //Esto es un error, no podemos confundir el angulo de la recta con su pendiente
320
                this.theta = theta;
321
                this.m = Math.tan(theta);
322
                this.x = x;
323
                this.y = y;
324
                this.xEnd = xEnd;
325
                this.yEnd = yEnd;
326
        }
327

    
328
        public Point2D resolve(LineEquation otherLine)
329
        throws ParallelLinesCannotBeResolvedException {
330
                /*
331
                 * line1 (this): y - y0 = m*(x - x0)
332
                 * line2 (otherLine): y' - y'0 = m'*(x' - x'0)
333
                 */
334

    
335
                double X;
336
                double Y;
337
                if(Math.abs(this.x - this.xEnd)<0.00001) { //Esta linea es vertical
338
                        //                        System.out.println("1 VERTICAL");
339
                        X = this.xEnd;
340
                        if (Math.abs(otherLine.x - otherLine.xEnd)<0.00001){//La otra linea es vertical
341
                                //                                System.out.println("    2 PERPENDICULAR");
342
                                if(Math.abs(this.x - otherLine.x)<0.00001){ //Son la misma linea, devolvemos el primer punto de la otra linea.
343
                                        //                                        System.out.println("        MISMA LINEA");
344
                                        Y = otherLine.y;
345
                                } else { //No son la misma linea, entonces son paralelas, excepcion.
346
                                        //                                        System.out.println("        CASCO POR 1");
347
                                        throw new ParallelLinesCannotBeResolvedException(this, otherLine);
348
                                }
349
                        } else if (Math.abs(otherLine.y - otherLine.yEnd)<0.00001) { //La otra linea es horizontal
350
                                //                                System.out.println("    2 HORIZONTAL");
351
                                Y = otherLine.y;
352
                        } else { //Si no
353
                                //                                System.out.println("    2 CUALQUIERA");
354
                                Y = otherLine.m*(X - otherLine.x)+otherLine.y;
355
                        }
356

    
357
                } else if (Math.abs(this.y - this.yEnd)<0.00001) { //Esta linea es horizontal
358
                        //                        System.out.println("1 HORIZONTAL");
359
                        Y = this.yEnd;
360
                        if (Math.abs(otherLine.y - otherLine.yEnd)<0.00001) { //La otra linea es horizontal
361
                                //                                System.out.println("    2 HORIZONTAL");
362
                                if(Math.abs(this.y - otherLine.y)<0.00001){ //Son la misma linea, devolvemos el primer punto de la otra linea.
363
                                        //                                        System.out.println("        MISMA LINEA");
364
                                        X = otherLine.x;
365
                                } else { //No son la misma linea, entonces son paralelas, excepcion.
366
                                        //                                        System.out.println("        CASCO POR 2");
367
                                        throw new ParallelLinesCannotBeResolvedException(this, otherLine);
368
                                }
369
                        } else if (Math.abs(otherLine.x - otherLine.xEnd)<0.00001){//La otra linea es vertical
370
                                //                                System.out.println("    2 VERTICAL");
371
                                X = otherLine.x;
372
                        } else { //Si no
373
                                //                                System.out.println("    2 CUALQUIERA");
374
                                X = (Y - otherLine.y)/otherLine.m +otherLine.x;
375
                        }
376
                } else { //Esta linea no es ni vertical ni horizontal
377
                        //                        System.out.println("1 CUALQUIERA");
378
                        if (Math.abs(otherLine.y - otherLine.yEnd)<0.00001) { //La otra linea es horizontal
379
                                //                                System.out.println("    2 HORIZONTAL");
380
                                Y = otherLine.y;
381
                                X = (Y - this.y)/this.m +this.x;
382
                        } else if (Math.abs(otherLine.x - otherLine.xEnd)<0.00001){//La otra linea es vertical
383
                                //                                System.out.println("    2 VERTICAL");
384
                                X = otherLine.x;
385
                                Y = this.m*(X - this.x)+this.y;
386
                        } else if ((Math.abs(otherLine.m - this.m)<0.00001)) { //Tienen la misma pendiente
387
                                //                                System.out.println("    MISMA PENDIENTE");
388
                                Y = otherLine.m*(this.x - otherLine.x)+otherLine.y;
389
                                if (Math.abs(this.y - Y)<0.00001){ //Las lineas son la misma
390
                                        //                                        System.out.println("        MISMA LINEA");
391
                                        X = otherLine.x;
392
                                        Y = otherLine.y;
393
                                } else {
394
                                        //                                        System.out.println("        CASCO POR 3");
395
                                        throw new ParallelLinesCannotBeResolvedException(this, otherLine);
396
                                }
397
                        } else {
398
                                //                                System.out.println("    AMBAS CUALESQUIERA");
399
                                double mTimesX = this.m * this.x;
400
                                X = (mTimesX - this.y - otherLine.m * otherLine.x + otherLine.y) / (this.m - otherLine.m);
401
                                Y = this.m * X - mTimesX + this.y;
402
                        }
403
                }
404

    
405
                //                System.out.println("DEVOLVEMOS X = "+X+" Y = "+Y);
406
                return new Point2D.Double(X, Y);
407

    
408
        }
409

    
410
        public String toString() {
411
                return "Y - " + y + " = " + m + "*(X - " + x + ")";
412
        }
413
}
414

    
415
class NotEnoughSegmentsToClosePathException extends Exception {
416
        private static final long serialVersionUID = 95503944546535L;
417

    
418
        public NotEnoughSegmentsToClosePathException(List<LineSegment> segments) {
419
                super("Need at least 2 segments to close a path. I've got "
420
                                + segments.size() + ".");
421
        }
422
}
423

    
424
class ParallelLinesCannotBeResolvedException extends Exception {
425
        private static final long serialVersionUID = 8322556508820067641L;
426

    
427
        public ParallelLinesCannotBeResolvedException(LineEquation eq1,
428
                        LineEquation eq2) {
429
                super("Lines '" + eq1 + "' and '" + eq2
430
                                + "' are parallel and don't share any point!");
431
        }
432
}
433
//public class Line2DOffset {
434

    
435
//private static final double TOL = 1E-8;
436
//private static final double ANGLE_TOL = 0.01/180*Math.PI;
437

    
438
//public static GeneralPathX offsetLine(Shape p, double offset) {
439

    
440
//PathIterator pi = p.getPathIterator(null);
441
//double[] dataCoords = new double[6];
442
//Coordinate from = null, first = null;
443
//ArrayList<LineSegment> segments = new ArrayList<LineSegment>();
444
//GeneralPathX offsetSegments = new GeneralPathX();
445
//try {
446
//while (!pi.isDone()) {
447
//// while not done
448
//int type = pi.currentSegment(dataCoords);
449

    
450
//switch (type) {
451
//case PathIterator.SEG_MOVETO:
452
//from = new Coordinate(dataCoords[0], dataCoords[1]);
453
//first = from;
454
//break;
455

    
456
//case PathIterator.SEG_LINETO:
457

    
458
//// System.out.println("SEG_LINETO");
459
//Coordinate to = new Coordinate(dataCoords[0], dataCoords[1]);
460
//LineSegment line = new LineSegment(from, to);
461
//int size = segments.size();
462
//if (size>0) {
463
//LineSegment prev = segments.get(size-1);
464
//if (line.angle() == prev.angle()) {
465
//if (Math.abs(line.p0.x - prev.p1.x) < TOL &&
466
//Math.abs(line.p0.y - prev.p1.y) < TOL) {
467
//prev.p1 = line.p1;
468
//break;
469
//}
470
//}
471
//}
472
//from = to;
473
//segments.add(line);
474

    
475
//break;
476
//case PathIterator.SEG_CLOSE:
477
//line = new LineSegment(from, first);
478
//segments.add(line);
479
//from = first;
480
//try {
481
//offsetSegments.append(offsetAndConsumeClosedSegments(offset, segments), false);
482
//} catch (NotEnoughSegmentsToClosePathException e) {
483
//Logger.getLogger(Line2DOffset.class).error(e.getMessage(), e);
484
//}
485
//break;
486

    
487
//} // end switch
488

    
489
//pi.next();
490
//}
491
//offsetSegments.append(offsetAndConsumeSegments(offset, segments), true);
492

    
493
//return offsetSegments;
494
//} catch (ParallelLinesCannotBeResolvedException e) {
495
//Logger.getLogger(Line2DOffset.class).error(e.getMessage(), e);
496
//return new GeneralPathX(p);
497
//}
498
//}
499

    
500
//private static GeneralPathX offsetAndConsumeSegments(double offset, ArrayList<LineSegment> segments)  {
501
//Hashtable<LineSegment, LineEquation> offsetLines = new Hashtable<LineSegment, LineEquation>();
502
//int segmentCount = segments.size();
503
//// first calculate offset lines with the starting point
504
//for (int i = 0; i < segmentCount; i++) {
505
//LineSegment segment = segments.get(i);
506
//double theta = segment.angle();
507

    
508
//double xOffset = offset*Math.sin(theta);
509
//double yOffset = offset*Math.cos(theta);
510

    
511
//Coordinate p0 = segment.p0;
512
//double x0 = p0.x + xOffset;
513
//double y0 = p0.y - yOffset;
514

    
515
//Coordinate p1 = segment.p1;
516
//double x1 = p1.x + xOffset;
517
//double y1 = p1.y - yOffset;
518

    
519
//LineEquation offsetLine = new LineEquation(theta, x0, y0, x1, y1, offset);
520
//offsetLines.put(segment, offsetLine);
521
//}
522

    
523
///*
524
//* let's now calculate the end point of each segment with
525
//* the point where each line crosses the next one.
526
//* this point will be the end point of the first line, and
527
//* the start point of its next one.
528
//*/
529
//Point2D pIni = null;
530
//Point2D pEnd = null;
531
//GeneralPathX gpx = new GeneralPathX();
532
//for (int i = 0; i < segmentCount; i++) {
533
//LineSegment segment = segments.get(0);
534
//LineEquation eq = offsetLines.get(segment);
535
//Point2D pAux = null;
536
//if (i < segmentCount -1) {
537
//try {
538
//pAux = eq.resolve(offsetLines.get(segments.get(1)));
539
//if (i == 0) {
540
//pIni = new Point2D.Double(eq.x, eq.y);
541
//} else {
542
//pIni = pEnd;
543
//}
544
//} catch (ParallelLinesCannotBeResolvedException e) {
545
//segments.remove(0);
546
//continue;
547
//}
548
//}
549

    
550

    
551
//if (pAux != null) {
552
//pEnd = pAux;
553
//} else {
554
//pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
555
//}
556

    
557
//gpx.append(new Line2D.Double(pIni, pEnd), true);
558
//segments.remove(0);
559
//}
560
//return gpx;
561
//}
562

    
563
//private static GeneralPathX offsetAndConsumeClosedSegments(double offset, ArrayList<LineSegment> segments) throws ParallelLinesCannotBeResolvedException, NotEnoughSegmentsToClosePathException {
564
//int segmentCount = segments.size();
565
//if (segmentCount > 1) {
566
//GeneralPathX openPath = offsetAndConsumeSegments(offset, segments);
567
//openPath.closePath();
568
//return openPath;
569
//}
570
//throw new NotEnoughSegmentsToClosePathException(segments);
571
//}
572
//}
573

    
574
//class LineEquation {
575
//double theta, x, y;
576
//double xEnd, yEnd; // just for simplicity of code
577
//double offset;
578

    
579
//public LineEquation(double theta, double x, double y, double xEnd, double yEnd, double offset) {
580
//this.theta = theta;
581
//this.x = x;
582
//this.y = y;
583
//this.xEnd = xEnd;
584
//this.yEnd = yEnd;
585
//this.offset = offset;
586
//}
587

    
588
//public Point2D resolve(LineEquation otherLine) throws ParallelLinesCannotBeResolvedException {
589
//double X;
590
//double Y;
591

    
592

    
593
///*
594
//* line1 (this):      y  -  y0 =  m*(x  - x0)
595
//* line2 (otherLine): y' - y'0 = m'*(x' - x'0)
596
//*/
597
//if (otherLine.theta == this.theta)
598
//throw new ParallelLinesCannotBeResolvedException(this, otherLine);
599

    
600
//if (Math.cos(theta) == 0) {
601

    
602
//X = otherLine.x + offset*Math.cos(otherLine.theta);
603
//Y = otherLine.y + offset*Math.sin(otherLine.theta);
604
//} else if (Math.cos(otherLine.theta) == 0) {
605
//X = x + offset*Math.cos(theta);
606
//Y = y + offset*Math.sin(theta);
607
//} else {
608
///*
609
//* m*(X - x0) + y0 = m'*(X - x'0) + y0'
610
//* X = (m*x0 - y0 - m'*x0' + y'0) / (m - m')
611
//*/
612
//double tanTheta = Math.tan(theta);
613
//double otherTanTheta = Math.tan(otherLine.theta);
614
//double thetaTimesX = tanTheta*this.x;
615
//X = (thetaTimesX - this.y - otherTanTheta*otherLine.x + otherLine.y) / (tanTheta - otherTanTheta);
616

    
617
///*
618
//* Y - y0 = m*(X - x0)
619
//* Y = m*X - m*x0 + y0
620
//*/
621
//Y = tanTheta*X - thetaTimesX + this.y;
622
//}
623
//return new Point2D.Double(X, Y);
624
//}
625

    
626
//@Override
627
//public String toString() {
628
//return "Y - "+y+" = "+theta+"*(X - "+x+")";
629
//}
630
//}
631

    
632
//class NotEnoughSegmentsToClosePathException extends Exception {
633
//private static final long serialVersionUID = 95503944546535L;
634
//public NotEnoughSegmentsToClosePathException(ArrayList<LineSegment> segments) {
635
//super("Need at least 2 segments to close a path. I've got "+segments.size()+".");
636
//}
637
//}
638

    
639
//class ParallelLinesCannotBeResolvedException extends Exception {
640
//private static final long serialVersionUID = 8322556508820067641L;
641

    
642
//public ParallelLinesCannotBeResolvedException(LineEquation eq1, LineEquation eq2) {
643
//super("Lines '"+eq1+"' and '"+eq2+"' are parallel and don't share any point!");
644
//}
645
//}