Source code: com/xerox/VTM/glyphs/VBoolShape.java
1 /* FILE: VBoolShape.java
2 * DATE OF CREATION: Oct 03 2000
3 * AUTHOR : Emmanuel Pietriga (emmanuel.pietriga@xrce.xerox.com)
4 * MODIF: Thu Jul 10 16:04:57 2003 by Emmanuel Pietriga (emmanuel@w3.org, emmanuel@claribole.net)
5 * Copyright (c) Xerox Corporation, XRCE/Contextual Computing, 2002. All Rights Reserved
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * For full terms see the file COPYING.
18 */
19
20 package com.xerox.VTM.glyphs;
21
22 import java.lang.Math;
23 import java.awt.Color;
24 import java.awt.Graphics2D;
25 import java.awt.Font;
26 import java.awt.Shape;
27 import java.awt.Stroke;
28 import java.awt.geom.*;
29 import java.util.Vector;
30 import com.xerox.VTM.engine.*;
31
32 /**
33 * Boolean shape - defined by a main glyph and a list of boolean operations (applied according to their order in the constructor's array)
34 * -right now we only support RectangularShape derivatives (Ellipse, Rectangle)
35 * @author Emmanuel Pietriga
36 */
37
38 public class VBoolShape extends Glyph implements Cloneable {
39
40 /**list of boolean operations (applied in the order given by the array)*/
41 BooleanOps[] booleanShapes;
42 /**main shape size in virtual space*/
43 long szx,szy;
44 /**1=ellipse 2=rectangle*/
45 int shapeType;
46
47 /**array of projected coordinates - index of camera in virtual space is equal to index of projected coords in this array*/
48 ProjBoolean[] pc;
49
50 /**
51 *@param x coordinate in virtual space
52 *@param y coordinate in virtual space
53 *@param z altitude in virtual space
54 *@param sx horizontal size in virtual space
55 *@param sy vertical size in virtual space
56 *@param st shape type //1=ellipse 2=rectangle
57 *@param b array of boolean operations
58 *@param c main shape's color
59 */
60 public VBoolShape(long x,long y,float z,long sx,long sy,int st,BooleanOps[] b,Color c){
61 vx=x;
62 vy=y;
63 vz=z;
64 szx=sx;
65 szy=sy;
66 shapeType=st;
67 booleanShapes=b;
68 setColor(c);
69 setBorderColor(Color.black);
70 }
71
72 /**called when glyph is created in order to create the initial set of projected coordinates wrt the number of cameras in the space
73 *@param nbCam current number of cameras in the virtual space
74 */
75 public void initCams(int nbCam){
76 pc=new ProjBoolean[nbCam];
77 for (int i=0;i<nbCam;i++){
78 pc[i]=new ProjBoolean();
79 }
80 }
81
82 /**used internally to create new projected coordinates to use with the new camera
83 *@param verifIndex camera index, just to be sure that the number of projected coordinates is consistent with the number of cameras
84 */
85 public void addCamera(int verifIndex){
86 if (pc!=null){
87 if (verifIndex==pc.length){
88 ProjBoolean[] ta=pc;
89 pc=new ProjBoolean[ta.length+1];
90 for (int i=0;i<ta.length;i++){
91 pc[i]=ta[i];
92 }
93 pc[pc.length-1]=new ProjBoolean();
94 }
95 else {System.err.println("VBoolShape:Error while adding camera "+verifIndex);}
96 }
97 else {
98 if (verifIndex==0){
99 pc=new ProjBoolean[1];
100 pc[0]=new ProjBoolean();
101 }
102 else {System.err.println("VBoolShape:Error while adding camera "+verifIndex);}
103 }
104 }
105
106 /**if a camera is removed from the virtual space, we should delete the corresponding projected coordinates, but do not modify the array it self because we do not want to change other cameras' index - just point to null*/
107 public void removeCamera(int index){
108 pc[index]=null;
109 }
110
111 /**reset prevMouseIn for projected coordinates nb i*/
112 public void resetMouseIn(int i){
113 if (pc[i]!=null){pc[i].prevMouseIn=false;}
114 }
115
116 /**orientation is disabled*/
117 public float getOrient(){return 0;}
118
119 /**orientation is disabled*/
120 public void orientTo(float angle){}
121
122 /**orientation is disabled*/
123 public void orientToNS(float angle){}
124
125 /**size is disabled*/
126 public float getSize(){return 0;}
127
128 /**size is disabled*/
129 public void sizeTo(float radius){}
130
131 /**size is disabled*/
132 public void sizeToNS(float radius){}
133
134 /**get full width*/
135 public long getWidth(){return szx;}
136
137 /**get full height*/
138 public long getHeight(){return szy;}
139
140 /**size is disabled*/
141 public void reSize(float factor){}
142
143 /**used to find out if glyph completely fills the view (in which case it is not necessary to repaint objects at a lower altitude)*/
144 public boolean fillsView(long w,long h,int camIndex){//would be too complex: just say no
145 return false;
146 }
147
148 /**detects whether the given point is inside this glyph or not
149 *@param x EXPECTS PROJECTED JPanel COORDINATE
150 *@param y EXPECTS PROJECTED JPanel COORDINATE
151 */
152 public boolean coordInside(int x,int y,int camIndex){
153 if (pc[camIndex].mainArea.contains(x,y)){return true;}
154 else {return false;}
155 }
156
157 /**returns 1 if mouse has entered the glyph, -1 if it has exited the glyph, 0 if nothing has changed (meaning it was already inside or outside it)*/
158 public int mouseInOut(int x,int y,int camIndex){
159 if (coordInside(x,y,camIndex)){//if the mouse is inside the glyph
160 if (!pc[camIndex].prevMouseIn){//if it was not inside it last time, mouse has entered the glyph
161 pc[camIndex].prevMouseIn=true;
162 return 1;
163 }
164 else {return 0;} //if it was inside last time, nothing has changed
165 }
166 else{//if the mouse is not inside the glyph
167 if (pc[camIndex].prevMouseIn){//if it was inside it last time, mouse has exited the glyph
168 pc[camIndex].prevMouseIn=false;
169 return -1;
170 }
171 else {return 0;} //if it was not inside last time, nothing has changed
172 }
173 }
174
175 /**project shape in camera coord sys prior to actual painting*/
176 public void project(Camera c,ViewPanel v){
177 int i=c.getIndex();
178 coef=(float)(c.focal/(c.focal+c.altitude));
179 //find coordinates of object's geom center wrt to camera center and project
180 pc[i].cx=Math.round((vx-c.posx)*coef);
181 pc[i].cy=Math.round((vy-c.posy)*coef);
182 //translate in JPanel coords
183 pc[i].cx=(v.getSize().width/2)+pc[i].cx;
184 pc[i].cy=(v.getSize().height/2)-pc[i].cy;
185 for (int j=0;j<booleanShapes.length;j++){
186 booleanShapes[j].project(coef,pc[i].cx,pc[i].cy);
187 }
188 pc[i].cszx=szx*coef;
189 pc[i].cszy=szy*coef;
190 switch (shapeType) {
191 case 1:{//ellipse
192 pc[i].mainArea=new Area(new Ellipse2D.Float(pc[i].cx-szx/2*coef,pc[i].cy-szy/2*coef,pc[i].cszx,pc[i].cszy));
193 break;
194 }
195 case 2:{//rectangle
196 pc[i].mainArea=new Area(new Rectangle2D.Float(pc[i].cx-szx/2*coef,pc[i].cy-szy/2*coef,pc[i].cszx,pc[i].cszy));
197 break;
198 }
199 default:{//ellipse as default
200 pc[i].mainArea=new Area(new Ellipse2D.Float(pc[i].cx-szx/2*coef,pc[i].cy-szy/2*coef,pc[i].cszx,pc[i].cszy));
201 }
202 }
203 for (int j=0;j<booleanShapes.length;j++){
204 switch (booleanShapes[j].opType) {
205 case 1:{
206 pc[i].mainArea.add(booleanShapes[j].ar);
207 break;
208 }
209 case 2:{
210 pc[i].mainArea.subtract(booleanShapes[j].ar);
211 break;
212 }
213 case 3:{
214 pc[i].mainArea.intersect(booleanShapes[j].ar);
215 break;
216 }
217 case 4:{
218 pc[i].mainArea.exclusiveOr(booleanShapes[j].ar);
219 break;
220 }
221 default:{
222 System.err.println("Error: VBoolShape: boolean operation not defined");
223 }
224 }
225 }
226 }
227
228 /**draw text associated with this glyph
229 *@param i camera index in the virtual space
230 */
231 void textDraw(Graphics2D g,int i){
232 if ((fontSizePolicy>=0) && (text!=null)) { //if appli wants text drawn and if there is a text for this glyph
233 if (!text.equals("")){
234 //g.setColor(this.color);
235 textWidth=(int)g.getFontMetrics().getStringBounds(text,g).getWidth(); //get width of this text : draw if conditions are met
236 if ((fontSizePolicy==1) || ((fontSizePolicy==0) && (textWidth<2*pc[i].cszx))) {
237 if (textPos==1){
238 //textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
239 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy-pc[i].cszy-4);
240 }
241 else if (textPos==-1){
242 textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
243 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy+pc[i].cszy+textHeight);
244 }
245 else {g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy);}
246 }
247 else if (fontSizePolicy==2) { //modify font size to make string fit in glyph THIS OPTION IS RATHER TIME CONSUMING
248 Font tf=new Font(g.getFont().getName(),g.getFont().getStyle(),g.getFont().getSize());
249 int s=1;
250 while (textWidth>2*pc[i].cszx){
251 s=g.getFont().getSize()-2; if (s<0){s=0;break;}
252 g.setFont(new Font(tf.getName(),tf.getStyle(),s));
253 textWidth=(int)g.getFontMetrics().getStringBounds(text,g).getWidth();
254 }
255 if (s>0) {
256 if (textPos==1){
257 //textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
258 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy-pc[i].cszy-4);
259 }
260 else if (textPos==-1){
261 textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
262 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy+pc[i].cszy+textHeight);
263 }
264 else {g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy);}
265 }
266 g.setFont(tf);
267 }
268 }
269 }
270 }
271
272 /**draw glyph
273 *@param i camera index in the virtual space
274 */
275 public void draw(Graphics2D g,int vW,int vH,int i,Stroke stdS,AffineTransform stdT){
276 if ((pc[i].mainArea.getBounds().width>2) && (pc[i].mainArea.getBounds().height>2)){
277 if (filled){
278 g.setColor(this.color);
279 g.fill(pc[i].mainArea);
280 }
281 g.setColor(borderColor);
282 if (paintBorder){
283 if (stroke!=null){
284 g.setStroke(stroke);
285 g.draw(pc[i].mainArea);
286 g.setStroke(stdS);
287 }
288 else {
289 g.draw(pc[i].mainArea);
290 }
291 }
292 this.textDraw(g,i);
293 }
294 else g.fillRect(pc[i].cx,pc[i].cy,1,1);
295 }
296
297 /**public only because accessed by svg export module*/
298 public int getMainShapeType(){
299 return shapeType;
300 }
301
302 /**public only because accessed by svg export module*/
303 public BooleanOps[] getOperations(){
304 return booleanShapes;
305 }
306
307 /**returns a clone of this object (only basic information is cloned for now: shape, orientation, position, size)*/
308 public Object clone(){
309 return new VBoolShape(vx,vy,0,szx,szy,shapeType,booleanShapes,color);
310 }
311 }