Bug 12212 fixed: Export a polyline in 2D broke it into several segments
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / implementation / g2d / motor / Scene.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.Graphics2D;
15 import java.util.ArrayList;
16 import java.util.Comparator;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.Stack;
21 import java.util.TreeSet;
22
23 import org.scilab.forge.scirenderer.clipping.ClippingPlane;
24
25 final class Scene {
26
27     private static Set<Scene> faces2d = new TreeSet<Scene>(new Comparator<Scene>() {
28         public int compare(Scene o1, Scene o2) {
29             if (o1.object.vertices[0].getZ() == o2.object.vertices[0].getZ()) {
30                 return o1.object.getPrecedence() - o2.object.getPrecedence();
31             }
32
33             return (int) Math.signum(o2.object.vertices[0].getZ() - o1.object.vertices[0].getZ());
34         }
35
36         public boolean equals(Object obj) {
37             return this == obj;
38         }
39     });
40
41     private static List<Scene> faces = new ArrayList<Scene>();
42     private static List<Scene> disabledFaces = new ArrayList<Scene>();
43     private static List<ClippingPlane> clippingPlanes;
44     private static Stack<Scene> stack = new Stack<Scene>();;
45
46     private List<Scene> behind;
47     private List<Scene> onfront;
48     private ConvexObject object;
49     private boolean drawn;
50     private boolean is2d;
51
52     private Scene(final ConvexObject object) {
53         this.object = object;
54     }
55
56     public static final void setClippingPlanes(final List<ClippingPlane> clippingPlanes) {
57         Scene.clippingPlanes = clippingPlanes;
58     }
59
60     private static final List<ConvexObject> breakOnClippingPlane(ConvexObject o) {
61         List<ConvexObject> list = new ArrayList<ConvexObject>(8);
62         List<ConvexObject> tmp = new ArrayList<ConvexObject>(8);
63         list.add(o);
64         if (clippingPlanes != null) {
65             for (ClippingPlane clip : clippingPlanes) {
66                 if (clip.isEnable()) {
67                     tmp.clear();
68                     for (ConvexObject co : list) {
69                         List<ConvexObject> l = co.breakObject(clip.getEquation());
70                         if (l != null) {
71                             tmp.addAll(l);
72                         } else {
73                             list.clear();
74                             return list;
75                         }
76                     }
77                     list.clear();
78                     list.addAll(tmp);
79                     if (list.isEmpty()) {
80                         break;
81                     }
82                 }
83             }
84         }
85         return list;
86     }
87
88     static final void addToRoot(final boolean is2D, final ConvexObject co) {
89         try {
90             List<ConvexObject> broken = breakOnClippingPlane(co);
91             for (ConvexObject object : broken) {
92                 add(is2D, object);
93             }
94         } catch (Exception e) {
95             e.printStackTrace();
96         }
97     }
98
99     private static final void add(final boolean is2D, final ConvexObject object) {
100         synchronized (faces) {
101             Scene st = new Scene(object);
102             if (is2D) {
103                 st.is2d = true;
104                 faces2d.add(st);
105             } else {
106                 Set<Scene> toRemove = new HashSet<Scene>();
107                 List<ConvexObject> toAdd = null;
108
109                 for (Scene face : faces) {
110                     if (face.object instanceof Triangle && object instanceof Segment) {
111                         if (((Triangle) face.object).addSegment((Segment) object)) {
112                             if (st != null) {
113                                 toRemove.add(st);
114                                 st = null;
115                             }
116                         }
117                     } else if (object instanceof Triangle && face.object instanceof Segment) {
118                         if (((Triangle) object).addSegment((Segment) face.object)) {
119                             toRemove.add(face);
120                         }
121                     }
122
123                     if (st != null) {
124                         int r = face.object.isBehind(st.object);
125
126                         if (r == 1) {
127                             // object is behind face.object
128                             addBehind(face, st);
129                             addOnFront(st, face);
130                         } else if (r == -1) {
131                             // face.object is behind object
132                             addBehind(st, face);
133                             addOnFront(face, st);
134                         } else if (r == 2) {
135                             // collision
136                             toAdd = face.object.breakObject(st.object);
137                             if (toAdd != null && !toAdd.isEmpty()) {
138                                 toRemove.add(face);
139                                 toRemove.add(st);
140                                 st = null;
141                                 break;
142                             }
143                         }
144                     }
145                 }
146
147                 if (st != null) {
148                     faces.add(st);
149                 }
150
151                 for (Scene s : toRemove) {
152                     faces.remove(s);
153                     if (s.onfront != null) {
154                         for (Scene ss : s.onfront) {
155                             ss.behind.remove(s);
156                         }
157                     }
158                 }
159                 if (toAdd != null) {
160                     for (ConvexObject co : toAdd) {
161                         add(is2D, co);
162                     }
163                 }
164             }
165         }
166     }
167
168
169     static final void clearDepth() {
170         disabledFaces.addAll(faces);
171         disabledFaces.addAll(faces2d);
172         faces.clear();
173         faces2d.clear();
174     }
175
176     static final void drawRoot(final Graphics2D g2d) {
177         synchronized (faces) {
178             for (Scene face : disabledFaces) {
179                 face.draw(g2d);
180             }
181
182             for (Scene face : disabledFaces) {
183                 face.drawn = false;
184             }
185
186             for (Scene face : faces) {
187                 face.draw(g2d);
188             }
189
190             for (Scene face : faces2d) {
191                 face.draw(g2d);
192             }
193
194             // code to help debug
195             /*for (Scene face : faces) {
196               face.drawn = false;
197               }
198
199               for (Scene face : faces) {
200               if (face.object.marked) {
201               face.object.draw(g2d);
202               }
203               }*/
204         }
205     }
206
207     static final void clear() {
208         disabledFaces.clear();
209         faces.clear();
210         faces2d.clear();
211         stack.clear();
212     }
213
214     static final void clearAll() {
215         clear();
216         clippingPlanes.clear();
217     }
218
219     private final void draw(final Graphics2D g2d) {
220         if (stack.contains(this)) {
221             this.object.addArea(stack.peek().object);
222             return;
223         }
224         if (!drawn) {
225             stack.push(this);
226             drawn = true;
227             if (behind != null && !behind.isEmpty()) {
228                 for (Scene face : behind) {
229                     face.draw(g2d);
230                 }
231             }
232             object.draw(g2d);
233             stack.pop();
234         }
235     }
236
237     private static final void addBehind(Scene face, Scene s) {
238         if (face.behind == null) {
239             face.behind = new ArrayList<Scene>();
240         }
241         face.behind.add(s);
242     }
243
244     private static final void addOnFront(Scene face, Scene s) {
245         if (face.onfront == null) {
246             face.onfront = new ArrayList<Scene>();
247         }
248         face.onfront.add(s);
249     }
250 }