Source code: com/xerox/VTM/glyphs/VClippedPath.java
1 /* FILE: VClippedPath.java
2 * DATE OF CREATION: Wed Feb 05 10:50:50 2003
3 * AUTHOR : Emmanuel Pietriga (emmanuel@w3.org)
4 * MODIF: Thu Jul 10 16:25:40 2003 by Emmanuel Pietriga (emmanuel@w3.org, emmanuel@claribole.net)
5 * Copyright (c) Emmanuel Pietriga, 2002. All Rights Reserved
6 * Licensed under the GNU LGPL. For full terms see the file COPYING.
7 */
8
9 package com.xerox.VTM.glyphs;
10
11 import java.awt.Color;
12 import java.awt.Graphics2D;
13 import java.awt.Font;
14 import java.awt.Stroke;
15 import java.awt.geom.GeneralPath;
16 import java.awt.geom.PathIterator;
17 import java.awt.geom.AffineTransform;
18 import java.util.Vector;
19 import com.xerox.VTM.engine.*;
20 import com.xerox.VTM.svg.*;
21
22 /**
23 * General path - similar to a VPath, but implements an experimental clipping algorithm that should enhance performances (quicker rendering) when only part of the path is actually seen (draw only curves/segments that are seen)
24 * @author Emmanuel Pietriga
25 **/
26
27 public class VClippedPath extends VPath implements Cloneable {
28
29 private ClippedPathSeg[] segs;
30 LongPoint firstPoint;
31 LongPoint lastPoint;
32
33 private void addSeg(LongPoint p,short segType){
34 if (firstPoint==null){
35 firstPoint=p;
36 }
37 else if (segs==null){
38 segs=new ClippedPathSeg[1];
39 segs[0]=new ClippedPathSeg((firstPoint.x+p.x)/2,(firstPoint.y+p.y)/2,(p.x-firstPoint.x)/2,-(p.y-firstPoint.y)/2,segType,p.x,-p.y);
40 lastPoint=p;
41 }
42 else {
43 ClippedPathSeg[] tmpArray=new ClippedPathSeg[segs.length+1];
44 System.arraycopy(segs,0,tmpArray,0,segs.length);
45 segs=tmpArray;
46 segs[segs.length-1]=new ClippedPathSeg((lastPoint.x+p.x)/2,(lastPoint.y+p.y)/2,(p.x-lastPoint.x)/2,-(p.y-lastPoint.y)/2,segType,p.x,-p.y);
47 lastPoint=p;
48 }
49 }
50
51 public VClippedPath(){
52 super();
53 }
54
55 /**
56 *@param x coordinate in virtual space
57 *@param y coordinate in virtual space
58 *@param z altitude
59 *@param c fill color
60 */
61 public VClippedPath(long x,long y,float z,Color c){
62 super(x,y,z,c);
63 }
64
65 /**
66 *@param z altitude
67 *@param c fill color
68 *@param svg valid <i>d</i> attribute of an SVG <i>path</i> element. m as first coords are taken into account, so any coord list beginning with one of these instructions will make the path begin elsewhere than at (x,y). Absolute commands (uppercase letters) as first coords have the side effect of assigning first point with these values instead of x,y (overriden)
69 */
70 public VClippedPath(float z,Color c,String svg){
71 super(z,c,svg);
72 }
73
74 /**
75 * new path, begins at (vx,vy)
76 */
77 public void resetPath(){
78 super.resetPath();
79 firstPoint=null;
80 segs=null;
81 }
82
83 /**
84 * add a new segment to the path, from current point to point (x,y)
85 *@param x coordinate in virtual space
86 *@param y coordinate in virtual space
87 *@param abs true if absolute coordinates, false if relative coordinates (w.r.t last point)
88 */
89 public void addSegment(long x,long y,boolean abs){
90 if (abs){lp.setLocation(x,y);}
91 else {lp.translate(x,y);}
92 path.lineTo(lp.x,-lp.y);
93 addSeg(new LongPoint(lp.x,lp.y),ClippedPathSeg.SEG_TYPE_SEG);
94 realHotSpot.setLocation((vx+lp.x)/2,(vy+lp.y)/2);
95 computeSize();
96 }
97
98
99 /**
100 * add a new quadratic curve to the path, from current point to point (x,y), with control point (x1,y1)
101 *@param x coordinate in virtual space
102 *@param y coordinate in virtual space
103 *@param x1 coordinate in virtual space
104 *@param y1 coordinate in virtual space
105 *@param abs true if absolute coordinates, false if relative coordinates (w.r.t last point)
106 */
107 public void addQdCurve(long x,long y,long x1,long y1,boolean abs){
108 if (abs){
109 path.quadTo(x1,-y1,x,-y);
110 addSeg(new LongPoint(x1,y1),ClippedPathSeg.SEG_TYPE_QD1);
111 addSeg(new LongPoint(x,y),ClippedPathSeg.SEG_TYPE_QD2);
112 lp.setLocation(x,y);
113 }
114 else {
115 path.quadTo(lp.x+x1,-(lp.y+y1),lp.x+x,-(lp.y+y));
116 addSeg(new LongPoint(lp.x+x1,lp.y+y1),ClippedPathSeg.SEG_TYPE_QD1);
117 addSeg(new LongPoint(lp.x+x,lp.y+y),ClippedPathSeg.SEG_TYPE_QD2);
118 lp.translate(x,y);
119 }
120 realHotSpot.setLocation((vx+lp.x)/2,(vy+lp.y)/2);
121 computeSize();
122 }
123
124 /**
125 * add a new cubic curve to the path, from current point to point (x,y), with control points (x1,y1) and (x2,y2)
126 *@param x coordinate in virtual space
127 *@param y coordinate in virtual space
128 *@param x1 coordinate in virtual space
129 *@param y1 coordinate in virtual space
130 *@param x2 coordinate in virtual space
131 *@param y2 coordinate in virtual space
132 *@param abs true if absolute coordinates, false if relative coordinates (w.r.t last point)
133 */
134 public void addCbCurve(long x,long y,long x1,long y1,long x2,long y2,boolean abs){
135 if (abs){
136 path.curveTo(x1,-y1,x2,-y2,x,-y);
137 addSeg(new LongPoint(x1,y1),ClippedPathSeg.SEG_TYPE_CB1);
138 addSeg(new LongPoint(x2,y2),ClippedPathSeg.SEG_TYPE_CB2);
139 addSeg(new LongPoint(x,y),ClippedPathSeg.SEG_TYPE_CB3);
140 lp.setLocation(x,y);
141 }
142 else {
143 path.curveTo(lp.x+x1,-(lp.y+y1),lp.x+x2,-(lp.y+y2),lp.x+x,-(lp.y+y));
144 addSeg(new LongPoint(lp.x+x1,lp.y+y1),ClippedPathSeg.SEG_TYPE_CB1);
145 addSeg(new LongPoint(lp.x+x2,lp.y+y2),ClippedPathSeg.SEG_TYPE_CB2);
146 addSeg(new LongPoint(lp.x+x,lp.y+y),ClippedPathSeg.SEG_TYPE_CB3);
147 lp.translate(x,y);
148 }
149 realHotSpot.setLocation((vx+lp.x)/2,(vy+lp.y)/2);
150 computeSize();
151 }
152
153 /**
154 * "jump" to point (x,y) without drawing anything
155 *@param x coordinate in virtual space
156 *@param y coordinate in virtual space
157 *@param abs true if absolute coordinates, false if relative coordinates (w.r.t last point)
158 */
159 public void jump(long x,long y, boolean abs){
160 if (abs){lp.setLocation(x,y);}
161 else {lp.translate(x,y);}
162 path.moveTo(lp.x,-lp.y);
163 addSeg(new LongPoint(lp.x,lp.y),ClippedPathSeg.SEG_TYPE_JMP);
164 if (getPathLength()==1){vx=lp.x;vy=lp.y;}
165 realHotSpot.setLocation((vx+lp.x)/2,(vy+lp.y)/2);
166 computeSize();
167 }
168
169
170 /**draw glyph
171 *@param i camera index in the virtual space
172 */
173 public void draw(Graphics2D g,int vW,int vH,int i,Stroke stdS,AffineTransform stdT){
174 if (visibilityHasChanged()){constructVisiblePath();}
175 g.setColor(this.color);
176 if (true){//replace by something using projected size (so that we do not paint it if too small)
177 at=AffineTransform.getTranslateInstance(pc[i].cx,pc[i].cy);
178 at.concatenate(AffineTransform.getScaleInstance(coef,coef));
179 g.setTransform(at);
180 if (stroke!=null){
181 g.setStroke(stroke);
182 g.draw(path);
183 g.setStroke(stdS);
184 }
185 else {
186 g.draw(path);
187 }
188 g.setTransform(stdT);
189 }
190 }
191
192 /**used to find out if it is necessary to project and draw the glyph in the current view - override default method in Glyph*/
193 public boolean drawMe(long w1,long h1,long w2,long h2,int i){//i should be the camera's index (used only by some glyph classes redefining this method from the one in Glyph)
194 boolean res=false;
195 if (forcedDrawing){return true;}
196 else {
197 if (((realHotSpot.x>=w2) && (realHotSpot.x<=w1) && (realHotSpot.y>=h2) && (realHotSpot.y<=h1)) || (((realHotSpot.x-drawingRadius)<=w1) && ((realHotSpot.x+drawingRadius)>=w2) && ((realHotSpot.y-drawingRadius)<=h1) && ((realHotSpot.y+drawingRadius)>=h2))){
198 try {
199 for (int j=0;j<segs.length;j++){
200 if (((segs[j].x>=w2) && (segs[j].x<=w1) && (segs[j].y>=h2) && (segs[j].y<=h1)) || (((segs[j].x-segs[j].w)<=w1) && ((segs[j].x+segs[j].w)>=w2) && ((segs[j].y-segs[j].h)<=h1) && ((segs[j].y+segs[j].h)>=h2))){
201 segs[j].setVisible(true);
202 res=true;
203 }
204 else {segs[j].setVisible(false);}
205 }
206 // return false;
207 }
208 catch (NullPointerException ex){return false;}
209 }
210 // else {
211 // return false;
212 // }
213 }
214 //printVis();
215 return res;
216 }
217
218 void printVis(){
219 System.err.print("[");
220 for (int i=0;i<segs.length;i++){
221 System.err.print(segs[i].visible+",");
222 }
223 System.err.print("]");
224 System.err.println(visibilityHasChanged());
225 }
226
227 private boolean visibilityHasChanged(){
228 for (int i=0;i<segs.length;i++){
229 if (segs[i].wasVisible!=segs[i].visible){return true;}
230 }
231 return false;
232 }
233
234 void constructVisiblePath(){
235 path=new GeneralPath();
236 path.moveTo(firstPoint.x,-firstPoint.y);
237 for (int i=0;i<segs.length;){
238 if (segs[i].type==ClippedPathSeg.SEG_TYPE_CB1){
239 if (segs[i].visible || segs[i+1].visible || segs[i+2].visible){
240 path.curveTo(segs[i].java2Dx,segs[i].java2Dy,segs[i+1].java2Dx,segs[i+1].java2Dy,segs[i+2].java2Dx,segs[i+2].java2Dy);
241 }
242 i+=3;
243 }
244 else if (segs[i].type==ClippedPathSeg.SEG_TYPE_QD1){
245 if (segs[i].visible || segs[i+1].visible){
246 path.quadTo(segs[i].java2Dx,segs[i].java2Dy,segs[i+1].java2Dx,segs[i+1].java2Dy);
247 }
248 i+=2;
249 }
250 else if (segs[i].type==ClippedPathSeg.SEG_TYPE_SEG){
251 if (segs[i].visible){
252 path.lineTo(segs[i].java2Dx,segs[i].java2Dy);
253 }
254 i++;
255 }
256 else if (segs[i].type==ClippedPathSeg.SEG_TYPE_JMP){
257 if (segs[i].visible){
258 path.moveTo(segs[i].java2Dx,segs[i].java2Dy);
259 }
260 i++;
261 }
262 else if (segs[i].type==ClippedPathSeg.SEG_TYPE_CB2){i+=2;}
263 else if (segs[i].type==ClippedPathSeg.SEG_TYPE_QD2){i++;}
264 else if (segs[i].type==ClippedPathSeg.SEG_TYPE_CB3){i++;}
265 }
266 }
267
268 /**returns a clone of this object - not yet implemented for VClippedPath*/
269 public Object clone(){
270 VClippedPath res=new VClippedPath();
271 res.borderColor=this.borderColor;
272 res.selectedColor=this.selectedColor;
273 res.mouseInsideColor=this.mouseInsideColor;
274 res.bColor=this.bColor;
275 return res;
276 }
277
278 }
279