Source code: com/xerox/VTM/glyphs/VEllipse.java
1 /* FILE: VEllipse.java
2 * DATE OF CREATION: Oct 14 2001
3 * AUTHOR : Emmanuel Pietriga (emmanuel.pietriga@xrce.xerox.com)
4 * MODIF: Thu Jul 10 16:38:52 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 * Ellipse - cannot be reoriented
34 * @author Emmanuel Pietriga
35 */
36
37 public class VEllipse extends Glyph implements RectangularShape,Cloneable {
38
39 /**half width and height in virtual space*/
40 long vw,vh;
41 /**aspect ratio (width divided by height)*/
42 float ar;
43
44 /**array of projected coordinates - index of camera in virtual space is equal to index of projected coords in this array*/
45 ProjEllipse[] pc;
46
47 /**
48 *creates a new default white ellipse
49 */
50 public VEllipse(){
51 vx=0;
52 vy=0;
53 vz=0;
54 vw=10;
55 vh=10;
56 setColor(Color.white);
57 setBorderColor(Color.black);
58 computeSize();
59 }
60
61 /**
62 *@param x coordinate in virtual space
63 *@param y coordinate in virtual space
64 *@param z altitude in virtual space
65 *@param sx horizontal axis radius in virtual space
66 *@param sy vertical axis radius in virtual space
67 *@param c main shape's color
68 */
69 public VEllipse(long x,long y,float z,long sx,long sy,Color c){
70 vx=x;
71 vy=y;
72 vz=z;
73 vw=sx;
74 vh=sy;
75 orient=0;
76 setColor(c);
77 setBorderColor(Color.black);
78 computeSize();
79 }
80
81 /**called when glyph is created in order to create the initial set of projected coordinates wrt the number of cameras in the space
82 *@param nbCam current number of cameras in the virtual space
83 */
84 public void initCams(int nbCam){
85 pc=new ProjEllipse[nbCam];
86 for (int i=0;i<nbCam;i++){
87 pc[i]=new ProjEllipse();
88 }
89 }
90
91 /**used internally to create new projected coordinates to use with the new camera
92 *@param verifIndex camera index, just to be sure that the number of projected coordinates is consistent with the number of cameras
93 */
94 public void addCamera(int verifIndex){
95 if (pc!=null){
96 if (verifIndex==pc.length){
97 ProjEllipse[] ta=pc;
98 pc=new ProjEllipse[ta.length+1];
99 for (int i=0;i<ta.length;i++){
100 pc[i]=ta[i];
101 }
102 pc[pc.length-1]=new ProjEllipse();
103 }
104 else {System.err.println("VEllipse:Error while adding camera "+verifIndex);}
105 }
106 else {
107 if (verifIndex==0){
108 pc=new ProjEllipse[1];
109 pc[0]=new ProjEllipse();
110 }
111 else {System.err.println("VEllipse:Error while adding camera "+verifIndex);}
112 }
113 }
114
115 /**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*/
116 public void removeCamera(int index){
117 pc[index]=null;
118 }
119
120 /**reset prevMouseIn for projected coordinates nb i*/
121 public void resetMouseIn(int i){
122 if (pc[i]!=null){pc[i].prevMouseIn=false;}
123 }
124
125 /**orientation is disabled*/
126 public float getOrient(){return 0;}
127
128 /**orientation is disabled*/
129 public void orientTo(float angle){}
130
131 /**orientation is disabled*/
132 // public void orientToNS(float angle){}
133
134 /**size is bounding circle radius*/
135 void computeSize(){
136 size=Math.max(vw,vh);
137 ar=(float)vw/(float)vh;
138 }
139
140 /**size is disabled*/
141 public float getSize(){return size;}
142
143 /**size is disabled*/
144 public void sizeTo(float radius){
145 size=radius;
146 if (vw>=vh){vw=(long)size;vh=(long)(vw/ar);}
147 else {vh=(long)size;vw=(long)(vh*ar);}
148 try{vsm.repaintNow();}catch(NullPointerException e){/*System.err.println("VSM null in Glyph "+e);*/}
149 // vsm.constMgr.suggestAValue(this.ID,"sz",size);
150 }
151
152 /**set absolute half width*/
153 public void setWidth(long w){
154 vw=w;
155 computeSize();
156 try{vsm.repaintNow();}catch(NullPointerException e){/*System.err.println("VSM null in Glyph "+e);*/}
157 // vsm.constMgr.suggestAValue(this.ID,"sz",size);
158 }
159
160 /**set absolute half height*/
161 public void setHeight(long h){
162 vh=h;
163 computeSize();
164 try{vsm.repaintNow();}catch(NullPointerException e){/*System.err.println("VSM null in Glyph "+e);*/}
165 // vsm.constMgr.suggestAValue(this.ID,"sz",size);
166 }
167
168 /**get width*/
169 public long getWidth(){return vw;}
170
171 /**get height*/
172 public long getHeight(){return vh;}
173
174 /**size is disabled*/
175 // public void sizeToNS(float radius){
176 // size=radius;
177 // if (vw>=vh){vw=(long)size;vh=(long)(vw/ar);}
178 // else {vh=(long)size;vw=(long)(vh*ar);}
179 // }
180
181 /**size is disabled*/
182 public void reSize(float factor){
183 size*=factor;
184 if (vw>=vh){vw=(long)size;vh=(long)(vw/ar);}
185 else {vh=(long)size;vw=(long)(vh*ar);}
186 try{vsm.repaintNow();}catch(NullPointerException e){/*System.err.println("VSM null in Glyph "+e);*/}
187 // vsm.constMgr.suggestAValue(this.ID,"sz",size);
188 }
189
190 /**used to find out if glyph completely fills the view (in which case it is not necessary to repaint objects at a lower altitude)*/
191 public boolean fillsView(long w,long h,int camIndex){//would be too complex: just say no
192 return false;
193 }
194
195 /**detects whether the given point is inside this glyph or not
196 *@param x EXPECTS PROJECTED JPanel COORDINATE
197 *@param y EXPECTS PROJECTED JPanel COORDINATE
198 */
199 public boolean coordInside(int x,int y,int camIndex){
200 if (pc[camIndex].ellipse.contains(x,y)){return true;}
201 else {return false;}
202 }
203
204 /**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)*/
205 public int mouseInOut(int x,int y,int camIndex){
206 if (coordInside(x,y,camIndex)){//if the mouse is inside the glyph
207 if (!pc[camIndex].prevMouseIn){//if it was not inside it last time, mouse has entered the glyph
208 pc[camIndex].prevMouseIn=true;
209 return 1;
210 }
211 else {return 0;} //if it was inside last time, nothing has changed
212 }
213 else{//if the mouse is not inside the glyph
214 if (pc[camIndex].prevMouseIn){//if it was inside it last time, mouse has exited the glyph
215 pc[camIndex].prevMouseIn=false;
216 return -1;
217 }
218 else {return 0;} //if it was not inside last time, nothing has changed
219 }
220 }
221
222 /**project shape in camera coord sys prior to actual painting*/
223 public void project(Camera c,ViewPanel v){
224 int i=c.getIndex();
225 coef=(float)(c.focal/(c.focal+c.altitude));
226 //find coordinates of object's geom center wrt to camera center and project
227 pc[i].cx=Math.round((vx-c.posx)*coef);
228 pc[i].cy=Math.round((vy-c.posy)*coef);
229 //translate in JPanel coords
230 pc[i].cx=(v.getSize().width/2)+pc[i].cx;
231 pc[i].cy=(v.getSize().height/2)-pc[i].cy;
232 pc[i].cvw=vw*coef;
233 pc[i].cvh=vh*coef;
234 pc[i].ellipse.setFrame(pc[i].cx-vw*coef,pc[i].cy-vh*coef,2*pc[i].cvw,2*pc[i].cvh);
235 }
236
237 /**draw text associated with this glyph
238 *@param i camera index in the virtual space
239 */
240 void textDraw(Graphics2D g,int i){
241 if ((fontSizePolicy>=0) && (text!=null)) { //if appli wants text drawn and if there is a text for this glyph
242 if (!text.equals("")){
243 //g.setColor(this.color);
244 textWidth=(int)g.getFontMetrics().getStringBounds(text,g).getWidth(); //get width of this text : draw if conditions are met
245 if ((fontSizePolicy==1) || ((fontSizePolicy==0) && (textWidth<2*pc[i].cvw))) {
246 if (textPos==1){
247 //textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
248 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy-pc[i].cvh-4);
249 }
250 else if (textPos==-1){
251 textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
252 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy+pc[i].cvh+textHeight);
253 }
254 else {g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy);}
255 }
256 else if (fontSizePolicy==2) { //modify font size to make string fit in glyph THIS OPTION IS RATHER TIME CONSUMING
257 Font tf=new Font(g.getFont().getName(),g.getFont().getStyle(),g.getFont().getSize());
258 int s=1;
259 while (textWidth>2*pc[i].cvw){
260 s=g.getFont().getSize()-2; if (s<0){s=0;break;}
261 g.setFont(new Font(tf.getName(),tf.getStyle(),s));
262 textWidth=(int)g.getFontMetrics().getStringBounds(text,g).getWidth();
263 }
264 if (s>0) {
265 if (textPos==1){
266 //textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
267 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy-pc[i].cvh-4);
268 }
269 else if (textPos==-1){
270 textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
271 g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy+pc[i].cvh+textHeight);
272 }
273 else {g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy);}
274 }
275 g.setFont(tf);
276 }
277 }
278 }
279 }
280
281 /**draw glyph
282 *@param i camera index in the virtual space
283 */
284 public void draw(Graphics2D g,int vW,int vH,int i,Stroke stdS,AffineTransform stdT){
285 if ((pc[i].ellipse.getBounds().width>2) && (pc[i].ellipse.getBounds().height>2)){
286 if (filled){
287 g.setColor(this.color);
288 g.fill(pc[i].ellipse);
289 }
290 g.setColor(borderColor);
291 if (paintBorder){
292 if (stroke!=null){
293 g.setStroke(stroke);
294 g.draw(pc[i].ellipse);
295 g.setStroke(stdS);
296 }
297 else {
298 g.draw(pc[i].ellipse);
299 }
300 }
301 this.textDraw(g,i);
302 }
303 else g.fillRect(pc[i].cx,pc[i].cy,1,1);
304 }
305
306 /**returns a clone of this object (only basic information is cloned for now: shape, orientation, position, size)*/
307 public Object clone(){
308 VEllipse res=new VEllipse(vx,vy,0,vw,vh,color);
309 res.borderColor=this.borderColor;
310 res.selectedColor=this.selectedColor;
311 res.mouseInsideColor=this.mouseInsideColor;
312 res.bColor=this.bColor;
313 return res;
314 }
315
316 }