Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/xerox/VTM/glyphs/FPolygon.java


1   /*   FILE: FPolygon.java
2    *   DATE OF CREATION:   Mon Jan 13 13:34:44 2003
3    *   AUTHOR :            Emmanuel Pietriga (emmanuel@w3.org)
4    *   MODIF:              Thu Jul 10 16:28:48 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.Polygon;
15  import java.awt.Stroke;
16  import java.awt.geom.Point2D;
17  import java.awt.geom.AffineTransform;
18  import java.lang.Math;
19  import java.util.Vector;
20  import com.xerox.VTM.engine.*;
21  
22  /**
23   * Custom polygon - CANNOT be resized nor reoriented. This is the old implementation of VPolygon, as found in zvtm 0.8.2. The new version of VPolygon can be resized, but at some cost from the efficiency point of view, so the old version is still provided here and can be used by people who do not intend to resize their Polygon instances (this implementation uses longs instead of doubles for its internal representation of the vertices, see VPolygon for other details) 
24   * @author Emmanuel Pietriga
25   **/
26  
27  public class FPolygon extends Glyph implements Cloneable {
28  
29      /**height=width in virtual space*/
30      long vs;
31  
32      /**array of projected coordinates - index of camera in virtual space is equal to index of projected coords in this array*/
33      ProjPolygon[] pc;
34  
35      /*store x,y vertex coords as relative coordinates w.r.t polygon's centroid*/
36      long[] xcoords;
37      long[] ycoords;
38  
39      /**
40       *@param v list of x,y vertices ABSOLUTE coordinates
41       *@param c fill color
42       */
43      public FPolygon(LongPoint[] v,Color c){
44    vx=0;  //should be zero here first as this is assumed when calling getCentroid later to compute the centroid's coordinates
45    vy=0;  //several lines below
46    vz=0;
47    xcoords=new long[v.length];
48    ycoords=new long[v.length];
49    for (int i=0;i<v.length;i++){
50        xcoords[i]=v[i].x;
51        ycoords[i]=v[i].y;
52    }
53    orient=0;
54    LongPoint ct=getCentroid();
55    vx=ct.x;
56    vy=ct.y;
57    for (int i=0;i<xcoords.length;i++){//translate to get relative coords w.r.t centroid
58        xcoords[i]-=vx;
59        ycoords[i]-=vy;
60    }
61    computeSize();
62    setColor(c);
63    setBorderColor(Color.black);
64      }
65  
66      /**called when glyph is created in order to create the initial set of projected coordinates wrt the number of cameras in the space
67       *@param nbCam current number of cameras in the virtual space
68       */
69      public void initCams(int nbCam){
70    pc=new ProjPolygon[nbCam];
71    for (int i=0;i<nbCam;i++){
72        pc[i]=new ProjPolygon(xcoords.length);
73    }
74      }
75  
76      /**used internally to create new projected coordinates to use with the new camera
77       *@param verifIndex camera index, just to be sure that the number of projected coordinates is consistent with the number of cameras
78       */
79      public void addCamera(int verifIndex){
80    if (pc!=null){
81        if (verifIndex==pc.length){
82      ProjPolygon[] ta=pc;
83      pc=new ProjPolygon[ta.length+1];
84      for (int i=0;i<ta.length;i++){
85          pc[i]=ta[i];
86      }
87      pc[pc.length-1]=new ProjPolygon(xcoords.length);
88        }
89        else {System.err.println("FPolygon:Error while adding camera "+verifIndex);}
90    }
91    else {
92        if (verifIndex==0){
93      pc=new ProjPolygon[1];
94      pc[0]=new ProjPolygon(xcoords.length);
95        }
96        else {System.err.println("FPolygon:Error while adding camera "+verifIndex);}
97    }
98      }
99  
100     /**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*/
101     public void removeCamera(int index){
102   pc[index]=null;
103     }
104 
105     /**reset prevMouseIn for projected coordinates nb i*/
106     public void resetMouseIn(int i){
107   if (pc[i]!=null){pc[i].prevMouseIn=false;}
108     }
109 
110     /**get orientation*/
111     public float getOrient(){return orient;}
112 
113     /**set orientation (absolute) - no effect*/
114     public void orientTo(float angle){
115 //   orient=angle;
116 //   try{vsm.repaintNow();}catch(NullPointerException e){/*System.err.println("VSM null in Glyph "+e);*/}
117     }
118 
119     /**get size (bounding circle radius)*/
120     public float getSize(){return size;}
121 
122     /**compute size (bounding circle radius)*/
123     synchronized void computeSize(){
124    size=0;
125   double f;
126   for (int i=0;i<xcoords.length;i++){//at this point, the xcoords,ycoords should contain relative vertices coordinates (w.r.t vx/vy=centroid)
127       f=Math.sqrt(Math.pow(xcoords[i],2)+Math.pow(ycoords[i],2));
128       if (f>size){size=(float)f;}
129   }
130   vs=Math.round(size);
131     }
132 
133     /**set absolute size by setting bounding circle radius (no effect)*/
134     public synchronized void sizeTo(float radius){
135 //   double ratio=radius/((double)size);
136 //    size=0;
137 //   double f;
138 //   for (int i=0;i<xcoords.length;i++){
139 //       xcoords[i]=Math.round(xcoords[i]*ratio);
140 //       ycoords[i]=Math.round(ycoords[i]*ratio);
141 //       f=Math.sqrt(Math.pow(xcoords[i],2)+Math.pow(ycoords[i],2));
142 //       if (f>size){size=(float)f;}
143 //   }
144 //   vs=Math.round(size);
145 //   try {vsm.repaintNow();}catch (NullPointerException ex){}
146     }
147 
148     /**multiply bounding circle radius by factor (no effect)*/
149     public synchronized void reSize(float factor){
150 //    size=0;
151 //   double f;
152 //   for (int i=0;i<xcoords.length;i++){
153 //       xcoords[i]=Math.round(xcoords[i]*factor);
154 //       ycoords[i]=Math.round(ycoords[i]*factor);
155 //       f=Math.sqrt(Math.pow(xcoords[i],2)+Math.pow(ycoords[i],2));
156 //       if (f>size){size=(float)f;}
157 //   }
158 //   vs=Math.round(size);
159 //   try {vsm.repaintNow();}catch (NullPointerException ex){}
160     }
161 
162     /**used to find out if glyph completely fills the view (in which case it is not necessary to repaint objects at a lower altitude)*/
163     public boolean fillsView(long w,long h,int camIndex){
164   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;}
165   else {return false;}
166     }
167 
168     /**detects whether the given point is inside this glyph or not 
169      *@param x EXPECTS PROJECTED JPanel COORDINATE
170      *@param y EXPECTS PROJECTED JPanel COORDINATE
171      */
172     public boolean coordInside(int x,int y,int camIndex){
173   if (pc[camIndex].p.contains(x,y)){return true;}
174   else {return false;}
175     }
176 
177     /**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)*/
178     public int mouseInOut(int x,int y,int camIndex){
179   if (coordInside(x,y,camIndex)){//if the mouse is inside the glyph
180       if (!pc[camIndex].prevMouseIn){//if it was not inside it last time, mouse has entered the glyph
181     pc[camIndex].prevMouseIn=true;
182     return 1;
183       }
184       else {return 0;}  //if it was inside last time, nothing has changed
185   }
186   else{//if the mouse is not inside the glyph
187       if (pc[camIndex].prevMouseIn){//if it was inside it last time, mouse has exited the glyph
188     pc[camIndex].prevMouseIn=false;
189     return -1;
190       }
191       else {return 0;}  //if it was not inside last time, nothing has changed
192   }
193     }
194 
195     /**list of vertices in relative coordinates (w.r.t polygon centroid)*/
196     public LongPoint[] getVertices(){
197   LongPoint[] res=new LongPoint[xcoords.length];
198   for (int i=0;i<xcoords.length;i++){
199       res[i]=new LongPoint(Math.round(xcoords[i]),Math.round(ycoords[i]));
200   }
201   return res;
202     }
203 
204     /**list of vertices in relative coordinates (absolute coordinates)*/
205     public LongPoint[] getAbsoluteVertices(){
206   LongPoint[] res=new LongPoint[xcoords.length];
207   for (int i=0;i<xcoords.length;i++){
208       res[i]=new LongPoint(Math.round(xcoords[i]+vx),Math.round(ycoords[i]+vy));
209   }
210   return res;
211     }
212 
213     /**
214      *returns a semicolon-separated string representation of the vertex absolute coordinates for this polygon (x and y coordinates seperated by commas, e.g. x1,y1;x2,y2;x3,y3 etc.)
215      */
216     public String getVerticesAsText(){
217   StringBuffer res=new StringBuffer();
218   for (int i=0;i<xcoords.length-1;i++){
219       res.append(Math.round(xcoords[i]+vx)+","+Math.round(ycoords[i]+vy)+";");
220   }
221   res.append(Math.round(xcoords[xcoords.length-1]+vx)+","+Math.round(ycoords[ycoords.length-1]+vy));
222   return res.toString();
223     }
224 
225     /**project shape in camera coord sys prior to actual painting*/
226     public void project(Camera c,ViewPanel v){
227   int i=c.getIndex();
228   coef=(float)(c.focal/(c.focal+c.altitude));
229   //find coordinates of object's geom center wrt to camera center and project
230   pc[i].cx=Math.round((vx-c.posx)*coef);
231   pc[i].cy=Math.round((vy-c.posy)*coef);
232   //translate in JPanel coords
233   pc[i].cx=(v.getSize().width/2)+pc[i].cx;
234   pc[i].cy=(v.getSize().height/2)-pc[i].cy;
235   //project height and construct polygon
236    pc[i].cs=Math.round(vs*coef);  
237   for (int j=0;j<xcoords.length;j++){
238       pc[i].xpcoords[j]=(int)Math.round(pc[i].cx+xcoords[j]*coef);
239       pc[i].ypcoords[j]=(int)Math.round(pc[i].cy-ycoords[j]*coef);
240   }
241   pc[i].p=new Polygon(pc[i].xpcoords,pc[i].ypcoords,xcoords.length);
242     }
243 
244     /**draw text associated with this glyph
245      *@param i camera index in the virtual space
246      */
247     void textDraw(Graphics2D g,int i){
248   if ((fontSizePolicy>=0) && (text!=null)) {
249       if (!text.equals("")){
250     //g.setColor(this.color);
251     textWidth=(int)g.getFontMetrics().getStringBounds(text,g).getWidth();
252     if ((fontSizePolicy==1) || ((fontSizePolicy==0) && (textWidth<2*pc[i].cs))) {
253         if (textPos==1){
254       //textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
255       g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy-pc[i].cs-4);
256         }
257         else if (textPos==-1){
258       textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
259       g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy+pc[i].cs+textHeight);
260         }
261         else {g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy);}
262     }
263     else if (fontSizePolicy==2) {  //modify font size to make string fit in glyph   THIS OPTION IS RATHER TIME CONSUMING
264         Font tf=new Font(g.getFont().getName(),g.getFont().getStyle(),g.getFont().getSize());
265         int s=1;
266         while (textWidth>2*pc[i].cs){
267       s=g.getFont().getSize()-2; if (s<0){s=0;break;}
268       g.setFont(new Font(tf.getName(),tf.getStyle(),s));
269       textWidth=(int)g.getFontMetrics().getStringBounds(text,g).getWidth();
270         }
271         if (s>0) {
272       if (textPos==1){
273           //textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
274           g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy-pc[i].cs-4);
275       }
276       else if (textPos==-1){
277           textHeight=(int)g.getFontMetrics().getStringBounds(text,g).getHeight();
278           g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy+pc[i].cs+textHeight);
279       }
280       else {g.drawString(text,pc[i].cx-textWidth/2,pc[i].cy);}
281         }
282         g.setFont(tf);
283     }
284       }
285   }
286     }
287 
288     /**draw glyph 
289      *@param i camera index in the virtual space
290      */
291     public void draw(Graphics2D g,int vW,int vH,int i,Stroke stdS,AffineTransform stdT){
292    if (pc[i].cs>1){//repaint only if object is visible
293       if (filled) {
294     g.setColor(this.color);
295     g.fillPolygon(pc[i].p);
296       }
297       g.setColor(borderColor);
298       if (paintBorder){
299     if (stroke!=null) {
300         g.setStroke(stroke);
301         g.drawPolygon(pc[i].p);
302         g.setStroke(stdS);
303     }
304     else {
305         g.drawPolygon(pc[i].p);
306     }
307       }
308       this.textDraw(g,i);
309   }
310   else g.fillRect(pc[i].cx,pc[i].cy,1,1);
311     }
312 
313     /**
314      * returns a given FPolygon's area
315      */
316     public double getArea(){
317   double[] xcoordsForArea=new double[xcoords.length];
318   double[] ycoordsForArea=new double[ycoords.length];
319   for (int i=0;i<xcoords.length;i++){
320       xcoordsForArea[i]=vx+xcoords[i];
321       ycoordsForArea[i]=vy+ycoords[i];
322   }
323   int j,k;
324   double res=0;
325   for (j=0;j<xcoords.length;j++){
326       k=(j+1) % xcoords.length;
327       res+=(xcoordsForArea[j]*ycoordsForArea[k]-ycoordsForArea[j]*xcoordsForArea[k]);
328   }
329   res=res/2.0;
330   return ((res<0) ? -res : res);
331     }
332 
333     /**
334      *return the double precision coordinates of this VShape's centroid
335      */
336     public Point2D.Double getPreciseCentroid(){
337   //compute polygon vertices
338   double[] xcoordsForArea=new double[xcoords.length];
339   double[] ycoordsForArea=new double[ycoords.length];
340   for (int i=0;i<xcoords.length;i++){
341       xcoordsForArea[i]=vx+xcoords[i];
342       ycoordsForArea[i]=vy+ycoords[i];
343   }
344   //compute polygon area
345   int j,k;
346   double area=0;
347   for (j=0;j<xcoords.length;j++){
348       k=(j+1) % xcoords.length;
349       area+=(xcoordsForArea[j]*ycoordsForArea[k]-ycoordsForArea[j]*xcoordsForArea[k]);
350   }
351   area=area/2.0;
352   //area=((area<0) ? -area : area);  //do not do that!!! it can change the centroid's coordinates
353                                      //(-x,-y instead of x,y) depending on the order in which the
354                                      //sequence of vertex coords
355   //compute centroid
356   double factor=0;
357   double cx=0;
358   double cy=0;
359   for (j=0;j<xcoords.length;j++){
360       k=(j+1) % xcoords.length;
361       factor=xcoordsForArea[j]*ycoordsForArea[k]-xcoordsForArea[k]*ycoordsForArea[j];
362       cx+=(xcoordsForArea[j]+xcoordsForArea[k])*factor;
363       cy+=(ycoordsForArea[j]+ycoordsForArea[k])*factor;
364   }
365   area*=6.0;
366   factor=1/area;
367   cx*=factor;
368   cy*=factor;
369   Point2D.Double res=new Point2D.Double(cx,cy);
370   return res;
371     }
372 
373     /**
374      *return the coordinates of this VShape's centroid in virtual space
375      */
376     public LongPoint getCentroid(){
377   Point2D.Double p2dd=this.getPreciseCentroid();
378   return new LongPoint(Math.round(p2dd.getX()),Math.round(p2dd.getY()));
379     }
380 
381     /**returns a clone of this object (only basic information is cloned for now: shape, orientation, position, size)*/
382     public Object clone(){
383   LongPoint[] lps=new LongPoint[xcoords.length];
384   for (int i=0;i<lps.length;i++){
385       lps[i]=new LongPoint(xcoords[i]+vx,ycoords[i]+vy);
386   }
387   FPolygon res=new FPolygon(lps,color);
388   res.borderColor=this.borderColor;
389   res.selectedColor=this.selectedColor;
390   res.mouseInsideColor=this.mouseInsideColor;
391   res.bColor=this.bColor;
392   return res;
393     }
394 
395 }