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