Revision 44984

View differences:

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/line/impl/SimpleLineSymbol.java
30 30
import org.gvsig.compat.print.PrintAttributes;
31 31
import org.gvsig.fmap.dal.feature.Feature;
32 32
import org.gvsig.fmap.geom.Geometry;
33
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
34 33
import org.gvsig.fmap.geom.GeometryLocator;
35 34
import org.gvsig.fmap.geom.GeometryManager;
36 35
import org.gvsig.fmap.geom.exception.CreateGeometryException;
......
44 43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
45 44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ISimpleLineSymbol;
46 45
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.ArrowDecoratorStyle;
47
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.Line2DOffset;
48 46
import org.gvsig.tools.ToolsLocator;
49 47
import org.gvsig.tools.dynobject.DynStruct;
50 48
import org.gvsig.tools.persistence.PersistenceManager;
......
55 53
import org.slf4j.Logger;
56 54
import org.slf4j.LoggerFactory;
57 55

  
58

  
59 56
/**
60
 * SimpleLineSymbol is the most basic symbol for the representation of line objects.
61
 * Allows to define the width of the line, the color and the drawn pattern.
57
 * SimpleLineSymbol is the most basic symbol for the representation of line
58
 * objects. Allows to define the width of the line, the color and the drawn
59
 * pattern.
62 60
 *
63 61
 * @author 2005-2008 jaume dominguez faus - jaume.dominguez@iver.es
64 62
 * @author 2009-     <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
65 63
 */
66 64
public class SimpleLineSymbol extends AbstractLineSymbol implements ISimpleLineSymbol {
67 65

  
68
	private static final Logger LOG = LoggerFactory.getLogger(SimpleLineSymbol.class);
66
    private static final Logger LOG = LoggerFactory.getLogger(SimpleLineSymbol.class);
69 67
    public static final String SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME = "SimpleLineSymbol";
70 68

  
71 69
    private static final String SELECTION_SYMBOL = "symbolForSelection";
72 70

  
73
	SimpleLineSymbol symbolForSelection;
74
	private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
71
    SimpleLineSymbol symbolForSelection;
72
    private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
75 73

  
76
	public SimpleLineSymbol() {
77
		super();
78
		setLineWidth(1d);
79
	}
74
    public SimpleLineSymbol() {
75
        super();
76
        setLineWidth(1d);
77
    }
80 78

  
81
	public ISymbol getSymbolForSelection() {
82
		if (symbolForSelection == null) {
83
			symbolForSelection = (SimpleLineSymbol) cloneForSelection();
84
		}else{
85
		    symbolForSelection.setColor(MapContext.getSelectionColor());
86
		}
87
		return symbolForSelection;
88
	}
79
    public ISymbol getSymbolForSelection() {
80
        if (symbolForSelection == null) {
81
            symbolForSelection = (SimpleLineSymbol) cloneForSelection();
82
        } else {
83
            symbolForSelection.setColor(MapContext.getSelectionColor());
84
        }
85
        return symbolForSelection;
86
    }
89 87

  
90
	public void draw(Graphics2D g, AffineTransform affineTransform,
91
			Geometry geom, Feature feature, Cancellable cancel) {
92
        
93
        if( true ) { 
88
    public void draw(Graphics2D g, AffineTransform affineTransform,
89
            Geometry geom, Feature feature, Cancellable cancel) {
90

  
91
        if (true) {
94 92
            // Esto deberia ser para optimiza el pintado de 
95 93
            // geometrias grandes.
96 94
            try {
97 95
                Geometry env = geom.getEnvelope().getGeometry();
98 96
                env.transform(affineTransform);
99 97
                Envelope env2 = env.getEnvelope();
100
                if( env2.getLength(0)<1.5 && env2.getLength(1)<1.5 ) {
98
                if (env2.getLength(0) < 1.5 && env2.getLength(1) < 1.5) {
101 99
                    g.setColor(getColor());
102 100
                    Point upperCorner = env2.getUpperCorner();
103 101
                    int x = (int) upperCorner.getX();
......
105 103
                    g.drawLine(x, y, x, y);
106 104
                    return;
107 105
                }
108
            } catch(Exception ex) {
109
				LOG.warn("Error optimizing the drawing of the geometry. Continues with normal drawing.", ex);
106
            } catch (Exception ex) {
107
                LOG.warn("Error optimizing the drawing of the geometry. Continues with normal drawing.", ex);
110 108
                // Do nothing, continue with the draw of the original geometry
111 109
            }
112 110
        }
113
        
114
		Geometry geomToDraw = geom;
115
		g.setStroke(getLineStyle().getStroke());
116 111

  
117
		if (getLineStyle().getOffset() != 0) {
118
			double offset = getLineStyle().getOffset();
119
			try {
120
				geomToDraw =
121
						geomManager.createSurface(Line2DOffset.offsetLine(
122
								geomToDraw.getShape(), offset), SUBTYPES.GEOM2D);
123
			} catch (CreateGeometryException e) {
124
				LOG.warn("Error creating a polygon with an offset", e);
125
			}
126
		}
127
		g.setColor(getColor());
128
                g.draw(geomToDraw.getShape(affineTransform));
112
        Geometry geomToDraw = geom;
113
        g.setStroke(getLineStyle().getStroke());
129 114

  
130
		ArrowDecoratorStyle arrowDecorator = (ArrowDecoratorStyle) getLineStyle().getArrowDecorator();
115
        if (getLineStyle()!=null && getLineStyle().getOffset() != 0) {
116
            double offset = getLineStyle().getOffset();
117
            try {
118
                geomToDraw = geomToDraw.offset(offset);
119
            } catch (Exception e) {
120
                LOG.warn("Error creating a polygon with an offset", e);
121
            }
122
        }
123
        g.setColor(getColor());
124
        g.draw(geomToDraw.getShape(affineTransform));
131 125

  
132
		if (arrowDecorator != null) {
133
			try {
134
				arrowDecorator.draw(g, affineTransform, geomToDraw, feature);
135
			} catch (CreateGeometryException e) {
136
				LOG.warn("Error drawing geometry.", e);
137
			}
138
		}
139
	}
126
        ArrowDecoratorStyle arrowDecorator = (ArrowDecoratorStyle) getLineStyle().getArrowDecorator();
140 127

  
141
	public int getOnePointRgb() {
142
		return getColor().getRGB();
143
	}
128
        if (arrowDecorator != null) {
129
            try {
130
                arrowDecorator.draw(g, affineTransform, geomToDraw, feature);
131
            } catch (CreateGeometryException e) {
132
                LOG.warn("Error drawing geometry.", e);
133
            }
134
        }
135
    }
144 136

  
145
	public void drawInsideRectangle(Graphics2D g,
146
			AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
147
		g.setColor(getColor());
148
		g.setStroke(getLineStyle().getStroke());
149
		super.drawInsideRectangle(g, scaleInstance, r, properties);
150
	}
137
    public int getOnePointRgb() {
138
        return getColor().getRGB();
139
    }
151 140

  
152
	public void setLineWidth(double width) {
153
		getLineStyle().setLineWidth((float) width);
154
	}
141
    public void drawInsideRectangle(Graphics2D g,
142
            AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
143
        g.setColor(getColor());
144
        g.setStroke(getLineStyle().getStroke());
145
        super.drawInsideRectangle(g, scaleInstance, r, properties);
146
    }
155 147

  
156
	public double getLineWidth() {
157
		return getLineStyle().getLineWidth();
158
	}
148
    public void setLineWidth(double width) {
149
        getLineStyle().setLineWidth((float) width);
150
    }
159 151

  
160
	public Object clone() throws CloneNotSupportedException {
161
		SimpleLineSymbol copy = (SimpleLineSymbol) super.clone();
152
    public double getLineWidth() {
153
        return getLineStyle().getLineWidth();
154
    }
162 155

  
163
		if (symbolForSelection != null) {
164
			copy.symbolForSelection = (SimpleLineSymbol) symbolForSelection
165
					.clone();
166
		}
156
    public Object clone() throws CloneNotSupportedException {
157
        SimpleLineSymbol copy = (SimpleLineSymbol) super.clone();
167 158

  
168
		return copy;
169
	}
159
        if (symbolForSelection != null) {
160
            copy.symbolForSelection = (SimpleLineSymbol) symbolForSelection
161
                    .clone();
162
        }
170 163

  
164
        return copy;
165
    }
166

  
171 167
    public void loadFromState(PersistentState state) throws PersistenceException {
172 168
        // Set parent style properties
173 169
        super.loadFromState(state);
......
180 176
        super.saveToState(state);
181 177

  
182 178
        // Save own properties
183
        if (this.symbolForSelection != null){
179
        if (this.symbolForSelection != null) {
184 180
            state.set(SELECTION_SYMBOL, this.getSymbolForSelection());
185 181
        }
186 182
    }
187 183

  
184
    public static class RegisterPersistence implements Callable {
188 185

  
186
        public Object call() throws Exception {
187
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
188
            if (manager.getDefinition(SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
189
                DynStruct definition = manager.addDefinition(
190
                        SimpleLineSymbol.class,
191
                        SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
192
                        SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME + " Persistence definition",
193
                        null,
194
                        null
195
                );
196
                // Extend the LineSymbol base definition
197
                definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME));
189 198

  
190
	public static class RegisterPersistence implements Callable {
191

  
192
		public Object call() throws Exception {
193
			PersistenceManager manager = ToolsLocator.getPersistenceManager();
194
			if( manager.getDefinition(SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
195
				DynStruct definition = manager.addDefinition(
196
						SimpleLineSymbol.class,
197
						SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
198
						SIMPLE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
199
						null,
200
						null
201
				);
202
				// Extend the LineSymbol base definition
203
				definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME));
204

  
205 199
                definition.addDynFieldObject(SELECTION_SYMBOL).setClassOfValue(SimpleLineSymbol.class);
206 200

  
207
			}
208
			return Boolean.TRUE;
209
		}
201
            }
202
            return Boolean.TRUE;
203
        }
210 204

  
211
	}
205
    }
212 206

  
213
	public static class RegisterSymbol implements Callable {
207
    public static class RegisterSymbol implements Callable {
214 208

  
215
		public Object call() throws Exception {
216
			int[] shapeTypes;
217
			SymbolManager manager = MapContextLocator.getSymbolManager();
209
        public Object call() throws Exception {
210
            int[] shapeTypes;
211
            SymbolManager manager = MapContextLocator.getSymbolManager();
218 212

  
219
	        shapeTypes = new int[] { Geometry.TYPES.CURVE, Geometry.TYPES.ARC,
220
	                Geometry.TYPES.MULTICURVE, Geometry.TYPES.CIRCUMFERENCE,
221
	                Geometry.TYPES.PERIELLIPSE, Geometry.TYPES.SPLINE,
222
	                Geometry.TYPES.LINE, Geometry.TYPES.MULTILINE};
223
	        manager.registerSymbol(ILineSymbol.SYMBOL_NAME,
224
	            shapeTypes,
225
	            SimpleLineSymbol.class);
213
            shapeTypes = new int[]{Geometry.TYPES.CURVE, Geometry.TYPES.ARC,
214
                Geometry.TYPES.MULTICURVE, Geometry.TYPES.CIRCUMFERENCE,
215
                Geometry.TYPES.PERIELLIPSE, Geometry.TYPES.SPLINE,
216
                Geometry.TYPES.LINE, Geometry.TYPES.MULTILINE};
217
            manager.registerSymbol(ILineSymbol.SYMBOL_NAME,
218
                    shapeTypes,
219
                    SimpleLineSymbol.class);
226 220

  
227
			return Boolean.TRUE;
228
		}
221
            return Boolean.TRUE;
222
        }
229 223

  
230
	}
231
        
232
}
224
    }
225

  
226
}
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
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
//}
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
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
 *
45
 * Line2DOffset.java
46
 *
47
 *
48
 * @author jaume dominguez faus - jaume.dominguez@iver.es Jan 3, 2008
49
 *
50
 */
51

  
52
public class Line2DOffset_DEPRECATED {
53

  
54
    final static private Logger logger = LoggerFactory.getLogger(Line2DOffset_DEPRECATED.class);
55

  
56
    public static GeneralPathX offsetLine(Shape p, double offset) {
57

  
58
        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
						 * Entonces, consumimos los segmentos que llevamos
81
						 * y empezamos un nuevo pol?gono o una nueva linea.
82
                             */
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

  
101
                    case PathIterator.SEG_LINETO:
102

  
103
                        // 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

  
126
                        break;
127

  
128
                } // end switch
129

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

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

  
142
    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

  
157
            double xOffset = offset * Math.sin(theta);
158
            double yOffset = offset * Math.cos(theta);
159

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

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

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

  
172
        /*
173
		 * 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
         */
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

  
189
            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

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

  
217
    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

  
232
                double xOffset = offset * Math.sin(theta);
233
                double yOffset = offset * Math.cos(theta);
234

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

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

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

  
247
            /*
248
			 * 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
             */
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

  
272
                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

  
291
                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

  
298
    }
299

  
300
    //	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

  
313

  
314
private static class LineEquation {
315

  
316
    double theta, m, x, y;
317

  
318
    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
		 * line1 (this): y - y0 = m*(x - x0)
335
		 * line2 (otherLine): y' - y'0 = m'*(x' - x'0)
336
         */
337

  
338
        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

  
360
        } 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

  
408
        //		System.out.println("DEVOLVEMOS X = "+X+" Y = "+Y);
409
        return new Point2D.Double(X, Y);
410

  
411
    }
412

  
413
    public String toString() {
414
        return "Y - " + y + " = " + m + "*(X - " + x + ")";
415
    }
416
}
417

  
418
private static class NotEnoughSegmentsToClosePathException extends Exception {
419

  
420
    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
}
427

  
428
private static class ParallelLinesCannotBeResolvedException extends Exception {
429

  
430
    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
}
438
}
439
//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);
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff