Bug 13022 fixed: Vectorial export did not clip large segments
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / implementation / g2d / motor / Segment.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  */
11
12 package org.scilab.forge.scirenderer.implementation.g2d.motor;
13
14 import java.awt.Color;
15 import java.awt.Graphics2D;
16 import java.awt.Shape;
17 import java.awt.Stroke;
18 import java.awt.geom.Path2D;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.scilab.forge.scirenderer.tranformations.Vector3d;
24 import org.scilab.forge.scirenderer.tranformations.Vector4d;
25
26 /**
27  * Segment object (for info, when modify rendering check for PolyLine too).
28  *
29  * @author Calixte DENIZET
30  */
31 public class Segment extends ConvexObject implements Comparable<Segment> {
32
33     private Integer hash;
34     protected G2DStroke stroke;
35     protected List<ConvexObject> segmentOn;
36     protected boolean is2D;
37
38     public Segment(Vector3d[] vertices, Color[] colors, G2DStroke stroke, boolean is2D) throws InvalidPolygonException {
39         super(vertices, colors);
40         if (vertices.length != 2) {
41             throw new InvalidPolygonException("Invalid segment: must have 2 vertices.");
42         }
43         this.stroke = stroke;
44         this.is2D = is2D;
45     }
46
47     public Segment(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
48         this(vertices, colors, null, false);
49     }
50
51     public void setStroke(G2DStroke stroke) {
52         this.stroke = stroke;
53     }
54
55     public double getLength() {
56         return vertices[0].minus(vertices[1]).getNorm();
57     }
58
59     public static double getLength(Vector3d[] vertices) {
60         return vertices[0].minus(vertices[1]).getNorm();
61     }
62
63     public void addConvexObject(ConvexObject co) {
64         if (segmentOn == null) {
65             segmentOn = new ArrayList<ConvexObject>(2);
66         }
67         segmentOn.add(co);
68     }
69
70     public void removeConvexObject(ConvexObject co) {
71         if (segmentOn != null) {
72             segmentOn.remove(co);
73         }
74     }
75
76     public void replaceSegment(List<Segment> segs) {
77         if (segmentOn != null) {
78             for (ConvexObject co : segmentOn) {
79                 Triangle t = (Triangle) co;
80                 t.replaceSegment(this, segs);
81             }
82         }
83     }
84
85     public boolean isIn2D() {
86         return isNull(vertices[0].getZ()) && isNull(vertices[1].getZ());
87     }
88
89     public boolean isInFront() {
90         return isEqual(vertices[0].getZ(), -0.5) && isEqual(vertices[1].getZ(), -0.5);
91     }
92
93     @Override
94     public int compareTo(Segment o) {
95         if (equals(o)) {
96             return 0;
97         }
98
99         return getPrecedence() - o.getPrecedence();
100     }
101
102     @Override
103     public boolean equals(Object o) {
104         if (o instanceof Segment) {
105             Segment s = (Segment) o;
106             return (s.vertices[0].equals(vertices[0]) && s.vertices[1].equals(vertices[1]) && s.colors[0].equals(colors[0]) && s.colors[1].equals(colors[1])) || (s.vertices[1].equals(vertices[0]) && s.vertices[0].equals(vertices[1]) && s.colors[1].equals(colors[0]) && s.colors[0].equals(colors[1]));
107         }
108
109         return false;
110     }
111
112     @Override
113     public int isBehind(ConvexObject o) {
114         if (o instanceof Triangle && ((Triangle) o).isSegmentAcross(this)) {
115             return 1;
116         }
117
118         return super.isBehind(o);
119     }
120
121     @Override
122     public List<ConvexObject> breakObject(ConvexObject o) {
123         if (o instanceof Triangle) {
124             return ((Triangle) o).breakObject(this);
125         } else if (o instanceof SpritedRectangle) {
126             return ((SpritedRectangle) o).breakObject(this);
127         }
128
129         return null;
130     }
131
132     @Override
133     public List<ConvexObject> breakObject(Vector4d v) {
134         double[] vv = v.getData();
135
136         if (is2D && vv[2] == 0) {
137             makeClip(vv);
138         }
139
140         Vector3d np = new Vector3d(vv);
141         boolean a = isBehind(vertices[0], np, vv[3]);
142         boolean b = isBehind(vertices[1], np, vv[3]);
143
144         if (a && b) {
145             List<ConvexObject> list = new ArrayList<ConvexObject>(1);
146             list.add(this);
147             return list;
148         }
149
150         if (!a && !b) {
151             return null;
152         }
153
154         double c = (vv[3] + vertices[1].scalar(np)) / v0.scalar(np);
155         Vector3d p = Vector3d.getBarycenter(vertices[0], vertices[1], c, 1 - c);
156         Color color = getColorsBarycenter(colors[0], colors[1], c, 1 - c);
157         Segment s;
158
159         try {
160             if (a) {
161                 s = new Segment(new Vector3d[] {vertices[0], p}, new Color[] {colors[0], color}, this.stroke, this.is2D);
162             } else {
163                 s = new Segment(new Vector3d[] {p, vertices[1]}, new Color[] {color, colors[1]}, this.stroke, this.is2D);
164             }
165
166             List<ConvexObject> list = new ArrayList<ConvexObject>(1);
167             list.add(s);
168
169             return list;
170         } catch (InvalidPolygonException e) { }
171
172         return null;
173     }
174
175     public List<Segment> breakObject(Vector3d p, Vector3d u, Vector3d n) {
176         double c = vertices[1].minus(p).scalar(n) / v0.scalar(n);
177         if (c > 0 && !isNull(c) && c < 1 && !isEqual(c, 1)) {
178             List<Segment> list = new ArrayList<Segment>(2);
179             Vector3d q = Vector3d.getBarycenter(vertices[0], vertices[1], c, 1 - c);
180             Color color = getColorsBarycenter(colors[0], colors[1], c, 1 - c);
181             try {
182                 list.add(new Segment(new Vector3d[] {vertices[0], q}, new Color[] {colors[0], color}, stroke, this.is2D));
183                 list.add(new Segment(new Vector3d[] {q, vertices[1]}, new Color[] {color, colors[1]}, stroke, this.is2D));
184
185                 return list;
186             } catch (InvalidPolygonException e) { }
187         } else {
188             List<Segment> list = new ArrayList<Segment>(1);
189             try {
190                 list.add(new Segment(new Vector3d[] {vertices[0], vertices[1]}, new Color[] {colors[0], colors[1]}, stroke, this.is2D));
191
192                 return list;
193             } catch (InvalidPolygonException e) { }
194         }
195
196         return null;
197     }
198
199     @Override
200     public void draw(Graphics2D g2d) {
201         if (segmentOn == null || segmentOn.isEmpty()) {
202             Path2D polyline = getProjectedPolyLine();
203             g2d.setColor(colors[0]);
204             Stroke oldStroke = g2d.getStroke();
205             if (oldStroke != stroke) {
206                 g2d.setStroke(stroke);
207             }
208
209             Shape oldClip = g2d.getClip();
210             Shape newClip = getClip();
211             if (newClip != null) {
212                 g2d.clip(newClip);
213             }
214
215             g2d.draw(polyline);
216
217             if (oldStroke != stroke) {
218                 g2d.setStroke(oldStroke);
219             }
220
221             if (newClip != null) {
222                 g2d.setClip(oldClip);
223             }
224
225             drawAreas(g2d);
226         }
227     }
228
229     @Override
230     public int hashCode() {
231         if (hash == null) {
232             hash = Arrays.hashCode(vertices) + 19 * Arrays.hashCode(colors);
233         }
234         return hash;
235     }
236
237     @Override
238     public String toString() {
239         return "Segment " + vertices[0].toString() + " " + vertices[1].toString() + " Precedence: " + getPrecedence();
240     }
241 }