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_DEPRECATED.java @ 44984
History | View | Annotate | Download (24.3 KB)
1 | 40560 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40560 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
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 | 40560 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * 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 | 40560 | jjdelcerro | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
19 | * MA 02110-1301, USA.
|
||
20 | 40435 | jjdelcerro | *
|
21 | 40560 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
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 | 44984 | fdiaz | |
43 | 40435 | jjdelcerro | /**
|
44 | *
|
||
45 | * Line2DOffset.java
|
||
46 | *
|
||
47 | *
|
||
48 | * @author jaume dominguez faus - jaume.dominguez@iver.es Jan 3, 2008
|
||
49 | *
|
||
50 | */
|
||
51 | |||
52 | 44984 | fdiaz | public class Line2DOffset_DEPRECATED { |
53 | 40435 | jjdelcerro | |
54 | 44984 | fdiaz | final static private Logger logger = LoggerFactory.getLogger(Line2DOffset_DEPRECATED.class); |
55 | 40435 | jjdelcerro | |
56 | 44984 | fdiaz | public static GeneralPathX offsetLine(Shape p, double offset) { |
57 | 40435 | jjdelcerro | |
58 | 44984 | fdiaz | if (Math.abs(offset) < 1) { |
59 | return new GeneralPathX(p.getPathIterator(null)); |
||
60 | } |
||
61 | PathIterator pi = p.getPathIterator(null); |
||
62 | double[] dataCoords = new double[6]; |
||
63 | Coordinate from = null, first = null; |
||
64 | List<LineSegment> segments = new ArrayList<LineSegment>(); |
||
65 | GeneralPathX offsetSegments = new GeneralPathX();
|
||
66 | LineSegment line; |
||
67 | try {
|
||
68 | while (!pi.isDone()) {
|
||
69 | // while not done
|
||
70 | int type = pi.currentSegment(dataCoords);
|
||
71 | |||
72 | switch (type) {
|
||
73 | case PathIterator.SEG_MOVETO: |
||
74 | if (from == null) { |
||
75 | from = new Coordinate(dataCoords[0], dataCoords[1]); |
||
76 | first = from; |
||
77 | break;
|
||
78 | } else {
|
||
79 | /* Puede significar un agujero en un pol?gono o un salto en una linea.
|
||
80 | 40435 | jjdelcerro | * Entonces, consumimos los segmentos que llevamos
|
81 | * y empezamos un nuevo pol?gono o una nueva linea.
|
||
82 | 44984 | fdiaz | */
|
83 | try {
|
||
84 | if (((Geometry) p).getType() == Geometry.TYPES.SURFACE) {
|
||
85 | offsetSegments.append(offsetAndConsumeClosedSegments(offset, segments).getPathIterator(null),
|
||
86 | false);
|
||
87 | } else {
|
||
88 | offsetSegments.append(offsetAndConsumeSegments(offset, segments).getPathIterator(null),
|
||
89 | false);
|
||
90 | } |
||
91 | } catch (NotEnoughSegmentsToClosePathException e) {
|
||
92 | logger.error( |
||
93 | e.getMessage(), e); |
||
94 | } |
||
95 | segments.clear(); |
||
96 | from = new Coordinate(dataCoords[0], dataCoords[1]); |
||
97 | first = from; |
||
98 | break;
|
||
99 | } |
||
100 | 40435 | jjdelcerro | |
101 | 44984 | fdiaz | case PathIterator.SEG_LINETO: |
102 | 40435 | jjdelcerro | |
103 | 44984 | fdiaz | // System.out.println("SEG_LINETO");
|
104 | Coordinate to = new Coordinate(dataCoords[0], dataCoords[1]); |
||
105 | if (from.compareTo(to) != 0) { |
||
106 | line = new LineSegment(from, to);
|
||
107 | segments.add(line); |
||
108 | from = to; |
||
109 | } |
||
110 | break;
|
||
111 | case PathIterator.SEG_CLOSE: |
||
112 | line = new LineSegment(from, first);
|
||
113 | segments.add(line); |
||
114 | // from = first;
|
||
115 | try {
|
||
116 | offsetSegments.append(offsetAndConsumeClosedSegments( |
||
117 | offset, segments).getPathIterator(null), false); |
||
118 | } catch (NotEnoughSegmentsToClosePathException e) {
|
||
119 | logger.error( |
||
120 | e.getMessage(), e); |
||
121 | } |
||
122 | segments.clear(); |
||
123 | first = null;
|
||
124 | from = null;
|
||
125 | 40435 | jjdelcerro | |
126 | 44984 | fdiaz | break;
|
127 | 40435 | jjdelcerro | |
128 | 44984 | fdiaz | } // end switch
|
129 | 40435 | jjdelcerro | |
130 | 44984 | fdiaz | pi.next(); |
131 | } |
||
132 | offsetSegments.append(offsetAndConsumeSegments(offset, segments) |
||
133 | .getPathIterator(null), false); |
||
134 | 40435 | jjdelcerro | |
135 | 44984 | fdiaz | return offsetSegments;
|
136 | } catch (ParallelLinesCannotBeResolvedException e) {
|
||
137 | logger.error(e.getMessage(), e); |
||
138 | return new GeneralPathX(p.getPathIterator(null)); |
||
139 | } |
||
140 | } |
||
141 | 40435 | jjdelcerro | |
142 | 44984 | fdiaz | private static GeneralPathX offsetAndConsumeSegments(double offset, |
143 | List<LineSegment> segments)
|
||
144 | throws ParallelLinesCannotBeResolvedException {
|
||
145 | Map<LineSegment, LineEquation> offsetLines
|
||
146 | = new HashMap<LineSegment, LineEquation>(); |
||
147 | int segmentCount = segments.size();
|
||
148 | // first calculate offset lines with the starting point
|
||
149 | for (int i = 0; i < segmentCount; i++) { |
||
150 | LineSegment segment = (LineSegment) segments.get(i); |
||
151 | double theta = segment.angle();
|
||
152 | //FIXME: ?Esto para qu? es?
|
||
153 | // if (Math.abs(theta) % (Math.PI*0.5) < 0.00001){
|
||
154 | // theta=theta+0.00000000000001;
|
||
155 | // }
|
||
156 | 40435 | jjdelcerro | |
157 | 44984 | fdiaz | double xOffset = offset * Math.sin(theta); |
158 | double yOffset = offset * Math.cos(theta); |
||
159 | 40435 | jjdelcerro | |
160 | 44984 | fdiaz | Coordinate p0 = segment.p0; |
161 | double x0 = p0.x + xOffset;
|
||
162 | double y0 = p0.y - yOffset;
|
||
163 | 40435 | jjdelcerro | |
164 | 44984 | fdiaz | Coordinate p1 = segment.p1; |
165 | double x1 = p1.x + xOffset;
|
||
166 | double y1 = p1.y - yOffset;
|
||
167 | 40435 | jjdelcerro | |
168 | 44984 | fdiaz | LineEquation offsetLine = new LineEquation(theta, x0, y0, x1, y1);
|
169 | offsetLines.put(segment, offsetLine); |
||
170 | } |
||
171 | 40435 | jjdelcerro | |
172 | 44984 | fdiaz | /*
|
173 | 40435 | jjdelcerro | * let's now calculate the end point of each segment with the point
|
174 | * where each line crosses the next one. this point will be the end
|
||
175 | * point of the first line, and the start point of its next one.
|
||
176 | 44984 | fdiaz | */
|
177 | Point2D pIni = null; |
||
178 | Point2D pEnd = null; |
||
179 | GeneralPathX gpx = new GeneralPathX();
|
||
180 | for (int i = 0; i < segmentCount; i++) { |
||
181 | LineSegment segment = (LineSegment) segments.get(0);
|
||
182 | LineEquation eq = (LineEquation) offsetLines.get(segment); |
||
183 | if (i == 0) { |
||
184 | pIni = new Point2D.Double(eq.x, eq.y); |
||
185 | } else {
|
||
186 | pIni = pEnd; |
||
187 | } |
||
188 | 40435 | jjdelcerro | |
189 | 44984 | fdiaz | if (i < segmentCount - 1) { |
190 | LineEquation eq1 = (LineEquation) offsetLines.get(segments.get(1));
|
||
191 | try {
|
||
192 | pEnd = eq.resolve(eq1); |
||
193 | } catch (ParallelLinesCannotBeResolvedException e) { //Las lineas son paralelas y NO son la misma. |
||
194 | pEnd = new Point2D.Double(eq.xEnd, eq.yEnd); |
||
195 | gpx.append(new Line2D.Double(pIni, pEnd) |
||
196 | .getPathIterator(null), true); // a?adimos una linea |
||
197 | // hasta el final
|
||
198 | // del primer
|
||
199 | // segmento
|
||
200 | // y asignamos como punto final el principio del siguiente segmento
|
||
201 | // para que en la siguiente iteraci?n lo tome como punto inicial.
|
||
202 | pIni = pEnd; |
||
203 | pEnd = new Point2D.Double(eq1.x, eq1.y); |
||
204 | segments.remove(0);
|
||
205 | continue;
|
||
206 | } |
||
207 | } else {
|
||
208 | pEnd = new Point2D.Double(eq.xEnd, eq.yEnd); |
||
209 | } |
||
210 | 40435 | jjdelcerro | |
211 | 44984 | fdiaz | gpx.append(new Line2D.Double(pIni, pEnd).getPathIterator(null), true); |
212 | segments.remove(0);
|
||
213 | } |
||
214 | return gpx;
|
||
215 | } |
||
216 | 40435 | jjdelcerro | |
217 | 44984 | fdiaz | private static GeneralPathX offsetAndConsumeClosedSegments(double offset, |
218 | List<LineSegment> segments)
|
||
219 | throws ParallelLinesCannotBeResolvedException, NotEnoughSegmentsToClosePathException {
|
||
220 | int segmentCount = segments.size();
|
||
221 | if (segmentCount > 1) { |
||
222 | Map<LineSegment, LineEquation> offsetLines = new HashMap<LineSegment, LineEquation>(); |
||
223 | // first calculate offset lines with the starting point
|
||
224 | for (int i = 0; i < segmentCount; i++) { |
||
225 | LineSegment segment = (LineSegment) segments.get(i); |
||
226 | double theta = segment.angle();
|
||
227 | //FIXME: ?Esto para qu? es?
|
||
228 | // if (Math.abs(theta) % (Math.PI*0.5) < 0.00001){
|
||
229 | // theta=theta+0.00000000000001;
|
||
230 | // }
|
||
231 | 40435 | jjdelcerro | |
232 | 44984 | fdiaz | double xOffset = offset * Math.sin(theta); |
233 | double yOffset = offset * Math.cos(theta); |
||
234 | 40435 | jjdelcerro | |
235 | 44984 | fdiaz | Coordinate p0 = segment.p0; |
236 | double x0 = p0.x + xOffset;
|
||
237 | double y0 = p0.y - yOffset;
|
||
238 | 40435 | jjdelcerro | |
239 | 44984 | fdiaz | Coordinate p1 = segment.p1; |
240 | double x1 = p1.x + xOffset;
|
||
241 | double y1 = p1.y - yOffset;
|
||
242 | 40435 | jjdelcerro | |
243 | 44984 | fdiaz | LineEquation offsetLine = new LineEquation(theta, x0, y0, x1, y1);
|
244 | offsetLines.put(segment, offsetLine); |
||
245 | } |
||
246 | 40435 | jjdelcerro | |
247 | 44984 | fdiaz | /*
|
248 | 40435 | jjdelcerro | * let's now calculate the end point of each segment with the point
|
249 | * where each line crosses the next one. this point will be the end
|
||
250 | * point of the first line, and the start point of its next one.
|
||
251 | 44984 | fdiaz | */
|
252 | Point2D pIni = null; |
||
253 | Point2D pEnd = null; |
||
254 | Point2D firstP = null; |
||
255 | GeneralPathX gpx = new GeneralPathX();
|
||
256 | for (int i = 0; i < segmentCount; i++) { |
||
257 | LineSegment segment = (LineSegment) segments.get(0);
|
||
258 | LineEquation eq = offsetLines.get(segment); |
||
259 | if (i == 0) { //Calculo de la intersecci?n entre el primer segmento y el ?ltimo |
||
260 | LineEquation eq0 = offsetLines.get((LineSegment) segments.get(segmentCount - 1));
|
||
261 | try {
|
||
262 | pIni = eq0.resolve(eq); |
||
263 | } catch (ParallelLinesCannotBeResolvedException e) { //Las lineas son paralelas y NO son la misma. |
||
264 | // pIni = new Point2D.Double(eq0.xEnd, eq0.yEnd);
|
||
265 | pIni = new Point2D.Double(eq.x, eq.y); |
||
266 | } |
||
267 | firstP = pIni; |
||
268 | } else {
|
||
269 | pIni = pEnd; |
||
270 | } |
||
271 | 40435 | jjdelcerro | |
272 | 44984 | fdiaz | if (i < segmentCount - 1) { |
273 | LineEquation eq1 = offsetLines.get((LineSegment) segments.get(1));
|
||
274 | try {
|
||
275 | pEnd = eq.resolve(eq1); |
||
276 | } catch (ParallelLinesCannotBeResolvedException e) { //Las lineas son paralelas y NO son la misma. |
||
277 | pEnd = new Point2D.Double(eq.xEnd, eq.yEnd); |
||
278 | gpx.append(new Line2D.Double(pIni, pEnd).getPathIterator(null), true); // a?adimos una linea hasta el final del primer segmento |
||
279 | // y asignamos como punto final el principio del siguiente segmento
|
||
280 | // para que en la siguiente iteraci?n lo tome como punto inicial.
|
||
281 | pIni = pEnd; |
||
282 | pEnd = new Point2D.Double(eq1.x, eq1.y); |
||
283 | segments.remove(0);
|
||
284 | continue;
|
||
285 | } |
||
286 | } else {
|
||
287 | // pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
|
||
288 | pEnd = new Point2D.Double(firstP.getX(), firstP.getY()); |
||
289 | } |
||
290 | 40435 | jjdelcerro | |
291 | 44984 | fdiaz | gpx.append(new Line2D.Double(pIni, pEnd).getPathIterator(null), true); |
292 | segments.remove(0);
|
||
293 | } |
||
294 | return gpx;
|
||
295 | } |
||
296 | throw new NotEnoughSegmentsToClosePathException(segments); |
||
297 | 40435 | jjdelcerro | |
298 | 44984 | fdiaz | } |
299 | 40435 | jjdelcerro | |
300 | 44984 | fdiaz | // private static GeneralPathX offsetAndConsumeClosedSegments(double offset,
|
301 | // List<LineSegment> segments)
|
||
302 | // throws ParallelLinesCannotBeResolvedException,
|
||
303 | // NotEnoughSegmentsToClosePathException {
|
||
304 | // int segmentCount = segments.size();
|
||
305 | // if (segmentCount > 1) {
|
||
306 | // GeneralPathX openPath = offsetAndConsumeSegments(offset, segments);
|
||
307 | // openPath.closePath();
|
||
308 | // return openPath;
|
||
309 | // }
|
||
310 | // throw new NotEnoughSegmentsToClosePathException(segments);
|
||
311 | // }
|
||
312 | 40435 | jjdelcerro | |
313 | |||
314 | 44984 | fdiaz | private static class LineEquation { |
315 | 40435 | jjdelcerro | |
316 | 44984 | fdiaz | double theta, m, x, y;
|
317 | 40435 | jjdelcerro | |
318 | 44984 | fdiaz | double xEnd, yEnd; // just for simplicity of code |
319 | |||
320 | public LineEquation(double theta, double x, double y, double xEnd, |
||
321 | double yEnd) {
|
||
322 | // this.theta = Math.tan(theta); //Esto es un error, no podemos confundir el angulo de la recta con su pendiente
|
||
323 | this.theta = theta;
|
||
324 | this.m = Math.tan(theta); |
||
325 | this.x = x;
|
||
326 | this.y = y;
|
||
327 | this.xEnd = xEnd;
|
||
328 | this.yEnd = yEnd;
|
||
329 | } |
||
330 | |||
331 | public Point2D resolve(LineEquation otherLine) |
||
332 | throws ParallelLinesCannotBeResolvedException {
|
||
333 | /*
|
||
334 | 40435 | jjdelcerro | * line1 (this): y - y0 = m*(x - x0)
|
335 | * line2 (otherLine): y' - y'0 = m'*(x' - x'0)
|
||
336 | 44984 | fdiaz | */
|
337 | 40435 | jjdelcerro | |
338 | 44984 | fdiaz | double X;
|
339 | double Y;
|
||
340 | if (Math.abs(this.x - this.xEnd) < 0.00001) { //Esta linea es vertical |
||
341 | // System.out.println("1 VERTICAL");
|
||
342 | X = this.xEnd;
|
||
343 | if (Math.abs(otherLine.x - otherLine.xEnd) < 0.00001) {//La otra linea es vertical |
||
344 | // System.out.println(" 2 PERPENDICULAR");
|
||
345 | if (Math.abs(this.x - otherLine.x) < 0.00001) { //Son la misma linea, devolvemos el primer punto de la otra linea. |
||
346 | // System.out.println(" MISMA LINEA");
|
||
347 | Y = otherLine.y; |
||
348 | } else { //No son la misma linea, entonces son paralelas, excepcion. |
||
349 | // System.out.println(" CASCO POR 1");
|
||
350 | throw new ParallelLinesCannotBeResolvedException(this, otherLine); |
||
351 | } |
||
352 | } else if (Math.abs(otherLine.y - otherLine.yEnd) < 0.00001) { //La otra linea es horizontal |
||
353 | // System.out.println(" 2 HORIZONTAL");
|
||
354 | Y = otherLine.y; |
||
355 | } else { //Si no |
||
356 | // System.out.println(" 2 CUALQUIERA");
|
||
357 | Y = otherLine.m * (X - otherLine.x) + otherLine.y; |
||
358 | } |
||
359 | 40435 | jjdelcerro | |
360 | 44984 | fdiaz | } else if (Math.abs(this.y - this.yEnd) < 0.00001) { //Esta linea es horizontal |
361 | // System.out.println("1 HORIZONTAL");
|
||
362 | Y = this.yEnd;
|
||
363 | if (Math.abs(otherLine.y - otherLine.yEnd) < 0.00001) { //La otra linea es horizontal |
||
364 | // System.out.println(" 2 HORIZONTAL");
|
||
365 | if (Math.abs(this.y - otherLine.y) < 0.00001) { //Son la misma linea, devolvemos el primer punto de la otra linea. |
||
366 | // System.out.println(" MISMA LINEA");
|
||
367 | X = otherLine.x; |
||
368 | } else { //No son la misma linea, entonces son paralelas, excepcion. |
||
369 | // System.out.println(" CASCO POR 2");
|
||
370 | throw new ParallelLinesCannotBeResolvedException(this, otherLine); |
||
371 | } |
||
372 | } else if (Math.abs(otherLine.x - otherLine.xEnd) < 0.00001) {//La otra linea es vertical |
||
373 | // System.out.println(" 2 VERTICAL");
|
||
374 | X = otherLine.x; |
||
375 | } else { //Si no |
||
376 | // System.out.println(" 2 CUALQUIERA");
|
||
377 | X = (Y - otherLine.y) / otherLine.m + otherLine.x; |
||
378 | } |
||
379 | } else { //Esta linea no es ni vertical ni horizontal |
||
380 | // System.out.println("1 CUALQUIERA");
|
||
381 | if (Math.abs(otherLine.y - otherLine.yEnd) < 0.00001) { //La otra linea es horizontal |
||
382 | // System.out.println(" 2 HORIZONTAL");
|
||
383 | Y = otherLine.y; |
||
384 | X = (Y - this.y) / this.m + this.x; |
||
385 | } else if (Math.abs(otherLine.x - otherLine.xEnd) < 0.00001) {//La otra linea es vertical |
||
386 | // System.out.println(" 2 VERTICAL");
|
||
387 | X = otherLine.x; |
||
388 | Y = this.m * (X - this.x) + this.y; |
||
389 | } else if ((Math.abs(otherLine.m - this.m) < 0.00001)) { //Tienen la misma pendiente |
||
390 | // System.out.println(" MISMA PENDIENTE");
|
||
391 | Y = otherLine.m * (this.x - otherLine.x) + otherLine.y;
|
||
392 | if (Math.abs(this.y - Y) < 0.00001) { //Las lineas son la misma |
||
393 | // System.out.println(" MISMA LINEA");
|
||
394 | X = otherLine.x; |
||
395 | Y = otherLine.y; |
||
396 | } else {
|
||
397 | // System.out.println(" CASCO POR 3");
|
||
398 | throw new ParallelLinesCannotBeResolvedException(this, otherLine); |
||
399 | } |
||
400 | } else {
|
||
401 | // System.out.println(" AMBAS CUALESQUIERA");
|
||
402 | double mTimesX = this.m * this.x; |
||
403 | X = (mTimesX - this.y - otherLine.m * otherLine.x + otherLine.y) / (this.m - otherLine.m); |
||
404 | Y = this.m * X - mTimesX + this.y; |
||
405 | } |
||
406 | } |
||
407 | 40435 | jjdelcerro | |
408 | 44984 | fdiaz | // System.out.println("DEVOLVEMOS X = "+X+" Y = "+Y);
|
409 | return new Point2D.Double(X, Y); |
||
410 | 40435 | jjdelcerro | |
411 | 44984 | fdiaz | } |
412 | 40435 | jjdelcerro | |
413 | 44984 | fdiaz | public String toString() { |
414 | return "Y - " + y + " = " + m + "*(X - " + x + ")"; |
||
415 | } |
||
416 | 40435 | jjdelcerro | } |
417 | |||
418 | 44984 | fdiaz | private static class NotEnoughSegmentsToClosePathException extends Exception { |
419 | 40435 | jjdelcerro | |
420 | 44984 | fdiaz | private static final long serialVersionUID = 95503944546535L; |
421 | |||
422 | public NotEnoughSegmentsToClosePathException(List<LineSegment> segments) { |
||
423 | super("Need at least 2 segments to close a path. I've got " |
||
424 | + segments.size() + ".");
|
||
425 | } |
||
426 | 40435 | jjdelcerro | } |
427 | |||
428 | 44984 | fdiaz | private static class ParallelLinesCannotBeResolvedException extends Exception { |
429 | 40435 | jjdelcerro | |
430 | 44984 | fdiaz | private static final long serialVersionUID = 8322556508820067641L; |
431 | |||
432 | public ParallelLinesCannotBeResolvedException(LineEquation eq1,
|
||
433 | LineEquation eq2) { |
||
434 | super("Lines '" + eq1 + "' and '" + eq2 |
||
435 | + "' are parallel and don't share any point!");
|
||
436 | } |
||
437 | 40435 | jjdelcerro | } |
438 | 44984 | fdiaz | } |
439 | 40435 | jjdelcerro | //public class Line2DOffset {
|
440 | |||
441 | //private static final double TOL = 1E-8;
|
||
442 | //private static final double ANGLE_TOL = 0.01/180*Math.PI;
|
||
443 | //public static GeneralPathX offsetLine(Shape p, double offset) {
|
||
444 | //PathIterator pi = p.getPathIterator(null);
|
||
445 | //double[] dataCoords = new double[6];
|
||
446 | //Coordinate from = null, first = null;
|
||
447 | //ArrayList<LineSegment> segments = new ArrayList<LineSegment>();
|
||
448 | //GeneralPathX offsetSegments = new GeneralPathX();
|
||
449 | //try {
|
||
450 | //while (!pi.isDone()) {
|
||
451 | //// while not done
|
||
452 | //int type = pi.currentSegment(dataCoords);
|
||
453 | //switch (type) {
|
||
454 | //case PathIterator.SEG_MOVETO:
|
||
455 | //from = new Coordinate(dataCoords[0], dataCoords[1]);
|
||
456 | //first = from;
|
||
457 | //break;
|
||
458 | //case PathIterator.SEG_LINETO:
|
||
459 | //// System.out.println("SEG_LINETO");
|
||
460 | //Coordinate to = new Coordinate(dataCoords[0], dataCoords[1]);
|
||
461 | //LineSegment line = new LineSegment(from, to);
|
||
462 | //int size = segments.size();
|
||
463 | //if (size>0) {
|
||
464 | //LineSegment prev = segments.get(size-1);
|
||
465 | //if (line.angle() == prev.angle()) {
|
||
466 | //if (Math.abs(line.p0.x - prev.p1.x) < TOL &&
|
||
467 | //Math.abs(line.p0.y - prev.p1.y) < TOL) {
|
||
468 | //prev.p1 = line.p1;
|
||
469 | //break;
|
||
470 | //}
|
||
471 | //}
|
||
472 | //}
|
||
473 | //from = to;
|
||
474 | //segments.add(line);
|
||
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 | //} // end switch
|
||
487 | //pi.next();
|
||
488 | //}
|
||
489 | //offsetSegments.append(offsetAndConsumeSegments(offset, segments), true);
|
||
490 | //return offsetSegments;
|
||
491 | //} catch (ParallelLinesCannotBeResolvedException e) {
|
||
492 | //Logger.getLogger(Line2DOffset.class).error(e.getMessage(), e);
|
||
493 | //return new GeneralPathX(p);
|
||
494 | //}
|
||
495 | //}
|
||
496 | //private static GeneralPathX offsetAndConsumeSegments(double offset, ArrayList<LineSegment> segments) {
|
||
497 | //Hashtable<LineSegment, LineEquation> offsetLines = new Hashtable<LineSegment, LineEquation>();
|
||
498 | //int segmentCount = segments.size();
|
||
499 | //// first calculate offset lines with the starting point
|
||
500 | //for (int i = 0; i < segmentCount; i++) {
|
||
501 | //LineSegment segment = segments.get(i);
|
||
502 | //double theta = segment.angle();
|
||
503 | //double xOffset = offset*Math.sin(theta);
|
||
504 | //double yOffset = offset*Math.cos(theta);
|
||
505 | //Coordinate p0 = segment.p0;
|
||
506 | //double x0 = p0.x + xOffset;
|
||
507 | //double y0 = p0.y - yOffset;
|
||
508 | //Coordinate p1 = segment.p1;
|
||
509 | //double x1 = p1.x + xOffset;
|
||
510 | //double y1 = p1.y - yOffset;
|
||
511 | //LineEquation offsetLine = new LineEquation(theta, x0, y0, x1, y1, offset);
|
||
512 | //offsetLines.put(segment, offsetLine);
|
||
513 | //}
|
||
514 | ///*
|
||
515 | //* let's now calculate the end point of each segment with
|
||
516 | //* the point where each line crosses the next one.
|
||
517 | //* this point will be the end point of the first line, and
|
||
518 | //* the start point of its next one.
|
||
519 | //*/
|
||
520 | //Point2D pIni = null;
|
||
521 | //Point2D pEnd = null;
|
||
522 | //GeneralPathX gpx = new GeneralPathX();
|
||
523 | //for (int i = 0; i < segmentCount; i++) {
|
||
524 | //LineSegment segment = segments.get(0);
|
||
525 | //LineEquation eq = offsetLines.get(segment);
|
||
526 | //Point2D pAux = null;
|
||
527 | //if (i < segmentCount -1) {
|
||
528 | //try {
|
||
529 | //pAux = eq.resolve(offsetLines.get(segments.get(1)));
|
||
530 | //if (i == 0) {
|
||
531 | //pIni = new Point2D.Double(eq.x, eq.y);
|
||
532 | //} else {
|
||
533 | //pIni = pEnd;
|
||
534 | //}
|
||
535 | //} catch (ParallelLinesCannotBeResolvedException e) {
|
||
536 | //segments.remove(0);
|
||
537 | //continue;
|
||
538 | //}
|
||
539 | //}
|
||
540 | //if (pAux != null) {
|
||
541 | //pEnd = pAux;
|
||
542 | //} else {
|
||
543 | //pEnd = new Point2D.Double(eq.xEnd, eq.yEnd);
|
||
544 | //}
|
||
545 | //gpx.append(new Line2D.Double(pIni, pEnd), true);
|
||
546 | //segments.remove(0);
|
||
547 | //}
|
||
548 | //return gpx;
|
||
549 | //}
|
||
550 | //private static GeneralPathX offsetAndConsumeClosedSegments(double offset, ArrayList<LineSegment> segments) throws ParallelLinesCannotBeResolvedException, NotEnoughSegmentsToClosePathException {
|
||
551 | //int segmentCount = segments.size();
|
||
552 | //if (segmentCount > 1) {
|
||
553 | //GeneralPathX openPath = offsetAndConsumeSegments(offset, segments);
|
||
554 | //openPath.closePath();
|
||
555 | //return openPath;
|
||
556 | //}
|
||
557 | //throw new NotEnoughSegmentsToClosePathException(segments);
|
||
558 | //}
|
||
559 | //}
|
||
560 | //class LineEquation {
|
||
561 | //double theta, x, y;
|
||
562 | //double xEnd, yEnd; // just for simplicity of code
|
||
563 | //double offset;
|
||
564 | //public LineEquation(double theta, double x, double y, double xEnd, double yEnd, double offset) {
|
||
565 | //this.theta = theta;
|
||
566 | //this.x = x;
|
||
567 | //this.y = y;
|
||
568 | //this.xEnd = xEnd;
|
||
569 | //this.yEnd = yEnd;
|
||
570 | //this.offset = offset;
|
||
571 | //}
|
||
572 | //public Point2D resolve(LineEquation otherLine) throws ParallelLinesCannotBeResolvedException {
|
||
573 | //double X;
|
||
574 | //double Y;
|
||
575 | ///*
|
||
576 | //* line1 (this): y - y0 = m*(x - x0)
|
||
577 | //* line2 (otherLine): y' - y'0 = m'*(x' - x'0)
|
||
578 | //*/
|
||
579 | //if (otherLine.theta == this.theta)
|
||
580 | //throw new ParallelLinesCannotBeResolvedException(this, otherLine);
|
||
581 | //if (Math.cos(theta) == 0) {
|
||
582 | //X = otherLine.x + offset*Math.cos(otherLine.theta);
|
||
583 | //Y = otherLine.y + offset*Math.sin(otherLine.theta);
|
||
584 | //} else if (Math.cos(otherLine.theta) == 0) {
|
||
585 | //X = x + offset*Math.cos(theta);
|
||
586 | //Y = y + offset*Math.sin(theta);
|
||
587 | //} else {
|
||
588 | ///*
|
||
589 | //* m*(X - x0) + y0 = m'*(X - x'0) + y0'
|
||
590 | //* X = (m*x0 - y0 - m'*x0' + y'0) / (m - m')
|
||
591 | //*/
|
||
592 | //double tanTheta = Math.tan(theta);
|
||
593 | //double otherTanTheta = Math.tan(otherLine.theta);
|
||
594 | //double thetaTimesX = tanTheta*this.x;
|
||
595 | //X = (thetaTimesX - this.y - otherTanTheta*otherLine.x + otherLine.y) / (tanTheta - otherTanTheta);
|
||
596 | ///*
|
||
597 | //* Y - y0 = m*(X - x0)
|
||
598 | //* Y = m*X - m*x0 + y0
|
||
599 | //*/
|
||
600 | //Y = tanTheta*X - thetaTimesX + this.y;
|
||
601 | //}
|
||
602 | //return new Point2D.Double(X, Y);
|
||
603 | //}
|
||
604 | //@Override
|
||
605 | //public String toString() {
|
||
606 | //return "Y - "+y+" = "+theta+"*(X - "+x+")";
|
||
607 | //}
|
||
608 | //}
|
||
609 | //class NotEnoughSegmentsToClosePathException extends Exception {
|
||
610 | //private static final long serialVersionUID = 95503944546535L;
|
||
611 | //public NotEnoughSegmentsToClosePathException(ArrayList<LineSegment> segments) {
|
||
612 | //super("Need at least 2 segments to close a path. I've got "+segments.size()+".");
|
||
613 | //}
|
||
614 | //}
|
||
615 | //class ParallelLinesCannotBeResolvedException extends Exception {
|
||
616 | //private static final long serialVersionUID = 8322556508820067641L;
|
||
617 | //public ParallelLinesCannotBeResolvedException(LineEquation eq1, LineEquation eq2) {
|
||
618 | //super("Lines '"+eq1+"' and '"+eq2+"' are parallel and don't share any point!");
|
||
619 | //}
|
||
620 | 44984 | fdiaz | //} |