Back to index

wims  3.65+svn20090927
FixedAngleObject.java
Go to the documentation of this file.
00001 package rene.zirkel.objects;
00002 
00003 import java.awt.*;
00004 import java.awt.event.*;
00005 import java.util.*;
00006 
00007 import rene.gui.*;
00008 import rene.dialogs.*;
00009 import rene.util.xml.*;
00010 import rene.zirkel.Zirkel;
00011 import rene.zirkel.ZirkelCanvas;
00012 import rene.zirkel.construction.Construction;
00013 import rene.zirkel.construction.ConstructionException;
00014 import rene.zirkel.construction.Count;
00015 import rene.zirkel.dialogs.EditConditionals;
00016 import rene.zirkel.dialogs.ObjectEditDialog;
00017 import rene.zirkel.expression.Expression;
00018 import rene.zirkel.expression.InvalidException;
00019 import rene.zirkel.graphics.MyGraphics;
00020 import rene.zirkel.graphics.MyGraphics13;
00021 
00022 class FixedAngleEditDialog extends ObjectEditDialog
00023 {      TextField Length;
00024        Checkbox Fixed;
00025        IconBar SizeIB;
00026        ZirkelCanvas ZC;
00027        Button SetButton;
00028        
00029        public FixedAngleEditDialog (Frame f, FixedAngleObject o,
00030               ZirkelCanvas zc)
00031        {      super(f,Zirkel.name("edit.angle.title"),o,"fixedangle");
00032               ZC=zc;
00033        }
00034        
00035        public void addFirst (Panel P)
00036        {      FixedAngleObject o=(FixedAngleObject)O;
00037               Length=new TextFieldAction(this,"Length",o.getE());
00038               P.add(new MyLabel(Zirkel.name("edit.angle.length")));
00039               P.add(Length);
00040               Fixed=new Checkbox("");     
00041               Fixed.setState(!o.isDragable());
00042               P.add(new MyLabel(Zirkel.name("edit.fixed"))); P.add(Fixed);
00043        }
00044 
00045        public void doAction (String o)
00046        {      if (o.equals("Length") && Fixed!=null)
00047               {      Fixed.setState(true);
00048                      super.doAction("OK");
00049               }
00050               else if (o.equals("Set"))
00051               {      ZC.set((FixedAngleObject)O);
00052                      super.doAction("OK");
00053               }
00054               else super.doAction(o);
00055        }
00056 
00057        public void addSecond (Panel P)
00058        {      FixedAngleObject p=(FixedAngleObject)O;   
00059               SizeIB=new IconBar(F);
00060               SizeIB.addToggleGroupLeft("angle",5);
00061               SizeIB.toggle("angle",p.getDisplaySize());
00062               SizeIB.addOnOffLeft("filled");
00063               SizeIB.setState("filled",p.isFilled());
00064               SizeIB.addOnOffLeft("obtuse");
00065               SizeIB.setState("obtuse",p.getObtuse());
00066               SizeIB.addOnOffLeft("inverse");
00067               SizeIB.setState("inverse",p.getInverse());
00068               SizeIB.addOnOffLeft("anglereduce");
00069               SizeIB.setState("anglereduce",p.isReduced());
00070               P.add(new MyLabel("")); P.add(SizeIB);
00071               SizeIB.setIconBarListener(this);
00072        }
00073        
00074        public void addButton (Panel P)
00075        {      SetButton=new ButtonAction(this,
00076                      Zirkel.name("edit.fixedangle.set"),"Set");
00077               P.add(SetButton);
00078        }
00079        
00080        public void iconPressed (String o)
00081        {      if (o.equals("filled"))
00082               {      if (SizeIB.getState("filled"))
00083                      {      IB.setState("isback",true);
00084                      }
00085               }
00086               super.iconPressed(o);
00087        }
00088        
00089        public void setAction ()
00090        {      FixedAngleObject o=(FixedAngleObject)O;
00091               o.setObtuse(SizeIB.getState("obtuse"));
00092               o.setInverse(SizeIB.getState("inverse"));
00093               o.setReduced(SizeIB.getState("anglereduce"));
00094               o.setEditFixed(Length.getText());
00095               o.setDisplaySize(SizeIB.getToggleState("angle"));
00096               o.setFilled(SizeIB.getState("filled"));
00097               o.setDragable(!Fixed.getState());
00098        }
00099 
00100        public void focusGained (FocusEvent e)
00101        {      if (Fixed!=null && Fixed.getState()) Length.requestFocus();
00102               else super.focusGained(e);
00103        }
00104 }
00105 
00106 public class FixedAngleObject extends PrimitiveLineObject
00107        implements MoveableObject, SimulationObject, InsideObject
00108 {      protected PointObject P2;
00109        static Count N=new Count();
00110        double A,A1,A2,AA;
00111        Expression E;
00112        boolean Filled=false;
00113        boolean Inverse=false;
00114        boolean EditAborted=false;
00115        boolean Dragable=false;
00116        boolean Reduced=false;
00117        
00118        public static final int NORMALSIZE=1,SMALL=0,LARGER=2,LARGE=3,RECT=4;
00119        protected int DisplaySize=NORMALSIZE;
00120        
00121        public FixedAngleObject (Construction c, 
00122               PointObject p1, PointObject p2, double x, double y)
00123        {      super(c);
00124               P1=p1; P2=p2;
00125               init(c,x,y);
00126               Unit=Global.getParameter("unit.angle","");
00127        }
00128        
00129        public void init (Construction c, double x, double y, boolean invert)
00130        {      double dx=P1.getX()-P2.getX(),dy=P1.getY()-P2.getY();
00131               A1=Math.atan2(dy,dx);
00132               dx=x-P2.getX(); dy=y-P2.getY();
00133               A2=Math.atan2(dy,dx);
00134               A=A2-A1;
00135               if (A<0) A+=2*Math.PI;
00136               else if (A>2*Math.PI) A-=2*Math.PI;
00137               if (Inverse && Obtuse)
00138               {      A=2*Math.PI-A;
00139               }
00140               if (invert && !Obtuse)
00141               {      if (A>Math.PI)
00142                      {      A=2*Math.PI-A; Inverse=true;
00143                      }
00144                      else Inverse=false;
00145               }
00146               E=new Expression(""+round(A/Math.PI*180,ZirkelCanvas.EditFactor),
00147                      c,this);
00148               validate();
00149               setColor(ColorIndex);
00150               updateText();
00151        }
00152        
00153        public void init (Construction c, double x, double y)
00154        {      init(c,x,y,true);
00155        }
00156 
00157        public void paint (MyGraphics g, ZirkelCanvas zc)
00158        {      if (!Valid || mustHide(zc)) return;
00159               //compute middle of the screen:
00160               double xm=(zc.minX()+zc.maxX())/2,ym=(zc.minY()+zc.maxY())/2;
00161               // compute distance from middle to line:
00162               double d=(xm-X1)*DY-(ym-Y1)*DX;
00163               // compute point with minimal distance
00164               double x=xm-d*DY,y=ym+d*DX;
00165               // compute size of the screen
00166               double a=Math.max(zc.maxX()-zc.minX(),zc.maxY()-zc.minY());
00167               if (Math.abs(d)>a) return;
00168               // compute distance from closest point to source
00169               double b=(x-X1)*DX+(y-Y1)*DY;
00170               // compute the two visible endpoints
00171               double k1=b-a,k2=b+a;
00172               if (k1<0) k1=0;
00173               if (k1>=k2) return;
00174               double c1=zc.col(X1+k1*DX),c2=zc.col(X1+k2*DX),
00175                      r1=zc.row(Y1+k1*DY),r2=zc.row(Y1+k2*DY);
00176               // paint:
00177               g.setColor(this);
00178               if (!Reduced) g.drawLine(c1,r1,c2,r2,this);
00179               double R=zc.col(getDisplaySize(zc))-zc.col(0);
00180               c1=zc.col(X1)-R; r1=zc.row(Y1)-R;
00181               String s=AngleObject.translateToUnicode(getDisplayText());
00182               double DA=(int)(A/Math.PI*180);
00183               if (DA<0) DA+=360;
00184               else if (DA>=360) DA-=360;
00185               if (isStrongSelected() && g instanceof MyGraphics13)
00186               {      ((MyGraphics13)g).drawMarkerArc(c1+R,r1+R,R,A1/Math.PI*180,DA);
00187               }
00188               g.setColor(this);
00189               if (Filled)
00190               {      g.fillArc(c1,r1,2*R+1,2*R+1,A1/Math.PI*180,DA,
00191                             Selected||getColorType()==NORMAL,getColorType()!=THICK,true,this);
00192               }
00193               else 
00194               {      if (DisplaySize==RECT)
00195                      {      double dx1=Math.cos(A1),dy1=Math.sin(A1),
00196                             dx2=Math.cos(A1+DA/180*Math.PI),dy2=Math.sin(A1+DA/180*Math.PI);
00197                             g.drawLine(c1+R+R*dx1,r1+R-R*dy1,c1+R+R*(dx1+dx2),r1+R-R*(dy1+dy2));
00198                             g.drawLine(c1+R+R*(dx1+dx2),r1+R-R*(dy1+dy2),c1+R+R*dx2,r1+R-R*dy2);
00199                      }
00200                      else 
00201                             g.drawCircleArc(c1+R,r1+R,R,A1/Math.PI*180,DA,this);
00202               }
00203               if (!s.equals(""))
00204               {      g.setLabelColor(this);
00205                      setFont(g);
00206                      DisplaysText=true;
00207                      double dx=Math.cos(A1+A/2),dy=Math.sin(A1+A/2);
00208                      if (s.equals("90"+getUnit()) || Name.startsWith("."))
00209                      {      if (KeepClose)
00210                             {      double dof=Math.sqrt(XcOffset*XcOffset+YcOffset*YcOffset);
00211                                    TX1=zc.col(X1+dof*dx)-3; 
00212                                    TY1=zc.row(Y1+dof*dy)-3;
00213                                    TX2=TX1+9;
00214                                    TY2=TY1+9;
00215                                    g.drawRect(zc.col(X1+dof*dx)-1,
00216                                           zc.row(Y1+dof*dy)-1,3,3);
00217                             }
00218                             else
00219                             {      TX1=zc.col(X1+zc.dx(R*AngleObject.LabelScale)*dx+XcOffset)-3; 
00220                                    TY1=zc.row(Y1+zc.dy(R*AngleObject.LabelScale)*dy+YcOffset)-3;
00221                                    TX2=TX1+9;
00222                                    TY2=TY1+9;
00223                                    g.drawRect(zc.col(X1+zc.dx(R*AngleObject.LabelScale)*dx+XcOffset)-1,
00224                                           zc.row(Y1+zc.dy(R*AngleObject.LabelScale)*dy+YcOffset)-1,3,3);
00225                             }
00226                      }
00227                      else
00228                      {      if (KeepClose)
00229                             {      double dof=Math.sqrt(XcOffset*XcOffset+YcOffset*YcOffset);
00230                                    drawCenteredLabel(g,s,zc,
00231                                           X1+dof*dx,Y1+dof*dy,0,0);
00232                             }
00233                             else
00234                                    drawCenteredLabel(g,s,zc,
00235                                           X1+zc.dx(R*AngleObject.LabelScale)*dx,
00236                                                  Y1+zc.dy(R*AngleObject.LabelScale)*dy,
00237                                           XcOffset,YcOffset);
00238                      }
00239               }
00240        }
00241 
00242        public boolean canKeepClose ()
00243        {      return true;
00244        }
00245        
00246        public void setKeepClose (double x, double y)
00247        {      KeepClose=true;
00248               XcOffset=x-X1;
00249               YcOffset=y-Y1;
00250        }
00251 
00252        double getDisplaySize (ZirkelCanvas zc)
00253        {      double R=zc.dx((int)(12*zc.pointSize()));
00254               if (DisplaySize==SMALL || DisplaySize==RECT) R/=2;
00255               else if (DisplaySize==LARGER) R*=2;
00256               else if (DisplaySize==LARGE)
00257               {      double dx=P1.getX()-X1,dy=P1.getY()-Y1;
00258                      R=Math.sqrt(dx*dx+dy*dy);
00259               }
00260               return R;
00261        }
00262 
00263        public String getTag () { return "Angle"; }
00264        public int getN () { return N.next(); }
00265        
00266        public void updateText ()
00267        {      if (E==null || !E.isValid()) return;
00268               setText(text3(Zirkel.name("text.fixedangle"),
00269                      P1.getName(),P2.getName(),E.toString()));
00270        }
00271        
00272        public String getDisplayValue ()
00273        {      if (ZirkelCanvas.AnglesFactor<=2) return ""+(int)(A/Math.PI*180+0.5);
00274               else return ""+round(A/Math.PI*180,ZirkelCanvas.AnglesFactor);
00275        }
00276        
00277        public void validate ()
00278        {      if (!P1.valid() || !P2.valid())
00279               {      Valid=false; 
00280                      return; 
00281               }
00282               else
00283               {      X1=P2.getX(); Y1=P2.getY();
00284                      double dx=P1.getX()-X1,dy=P1.getY()-Y1;
00285                      if (Math.sqrt(dx*dx+dy*dy)<1e-9)
00286                      {      Valid=false; return;
00287                      }
00288                      A1=Math.atan2(dy,dx);
00289                      boolean Negative=false;
00290                      try
00291                      {      if (E!=null && E.isValid()) A=E.getValue()/180*Math.PI;
00292                             if (Obtuse) 
00293                             {      if (Inverse) A=-A;
00294                             }
00295                             else
00296                             {      if (Inverse && Math.sin(A)>0) A=-A;
00297                                    if (!Inverse && Math.sin(A)<0) A=-A;
00298                             }
00299                             if (A<0) Negative=true;
00300                             while (A<0) A=A+2*Math.PI;
00301                             while (A>=2*Math.PI) A=A-2*Math.PI;
00302                             A2=A1+A;
00303                             DX=Math.cos(A2); DY=Math.sin(A2);
00304                             AA=A;
00305                      }
00306                      catch (Exception e)
00307                      {      Valid=false; return;
00308                      }
00309                      if (!Obtuse && A>Math.PI)
00310                      {      A1=A2;
00311                             A=2*Math.PI-A;
00312                             A2=A1+A;
00313                      }
00314                      else if (Obtuse && Negative)
00315                      {      A1=A2;
00316                             A=2*Math.PI-A;
00317                             A2=A1+A;
00318                      }
00319                      Valid=true;
00320               }
00321        }
00322        
00323        public double getLength () { return A; }
00324        public void setFixed (String s)
00325        {      E=new Expression(s,getConstruction(),this);
00326               updateText();
00327        }
00328        
00329        public void round ()
00330        {      try
00331               {      setFixed(round(E.getValue(),ZirkelCanvas.AnglesFactor)+"");
00332                      validate();
00333               }
00334               catch (Exception e) {}
00335        }
00336 
00337        public void setEditFixed (String s)
00338        {      E=new Expression(s,getConstruction(),this);
00339               updateText();
00340        }
00341 
00342        public boolean canFix ()
00343        {      return true;
00344        }
00345 
00346        public void printArgs (XmlWriter xml)
00347        {      xml.printArg("first",P1.getName());
00348               xml.printArg("root",P2.getName());
00349               if (DisplaySize==SMALL) xml.printArg("display","small");
00350               if (DisplaySize==LARGE) xml.printArg("display","large");
00351               if (DisplaySize==LARGER) xml.printArg("display","larger");
00352               if (DisplaySize==RECT) xml.printArg("display","rectangle");
00353               if (Filled) xml.printArg("filled","true");
00354               if (E.isValid()) xml.printArg("fixed",E.toString());
00355               else xml.printArg("fixed",""+A/Math.PI*180);
00356               if (!Obtuse) xml.printArg("acute","true");
00357               if (Inverse) xml.printArg("inverse","true");
00358               if (Reduced) xml.printArg("reduced","true");
00359               if (Dragable) xml.printArg("dragable","true");
00360               super.printArgs(xml);
00361        }      
00362 
00363        public void edit (ZirkelCanvas zc)
00364        {      ObjectEditDialog d;
00365               while (true)
00366               {      d=new FixedAngleEditDialog(zc.getFrame(),this,zc);
00367                      d.setVisible(true);
00368                      zc.repaint();
00369                      EditAborted=false;
00370                      if (d.isAborted())
00371                      {      EditAborted=true;
00372                             break;
00373                      }
00374                      else if (E!=null && !E.isValid())
00375                      {      Frame F=zc.getFrame();
00376                             Warning w=new Warning(F,E.getErrorText(),
00377                                    Zirkel.name("warning"),true);
00378                             w.center(F);
00379                             w.setVisible(true);
00380                      }
00381                      else break;
00382               }
00383               if (d.wantsMore())
00384               {      new EditConditionals(zc.getFrame(),this);
00385                      validate();
00386               }
00387        }
00388 
00389        public boolean nearto (int c, int r, ZirkelCanvas zc)
00390        {      if (!Valid && P2.valid()) return P2.nearto(c,r,zc);
00391               if (!displays(zc)) return false;
00392               //compute point at c,r
00393               double x=zc.x(c),y=zc.y(r);
00394               // compute distance from x,y
00395               double d=(x-X1)*DY-(y-Y1)*DX;
00396               double e=(x-X1)*DX+(y-Y1)*DY;
00397               // scale in screen coordinates
00398               Value=Math.abs(zc.col(zc.minX()+d)-zc.col(zc.minX()));
00399               if (!Reduced && Value<zc.selectionSize() && e>0) return true;
00400               double dx=zc.x(c)-X1,dy=zc.y(r)-Y1;
00401               double size=zc.dx((int)zc.selectionSize());
00402               double rd=getDisplaySize(zc);
00403               double rr=Math.sqrt(dx*dx+dy*dy);
00404               boolean near;
00405               if (Filled || DisplaySize==RECT) near=(rr<rd+size);
00406               else near=(Math.abs(rr-rd)<size);
00407               if (!near) return false;
00408               if (rd<size) return near;
00409               double a=Math.atan2(dy,dx);
00410               if (a<0) a+=2*Math.PI;
00411               double cc=0.05;
00412               if (A1-cc<a && A2+cc>a) return true;
00413               a=a-2*Math.PI;
00414               if (A1-cc<a && A2+cc>a) return true;
00415               a=a+4*Math.PI;
00416               if (A1-cc<a && A2+cc>a) return true;
00417               return false;
00418        }
00419        
00420        public void setDisplaySize (int i) { DisplaySize=i; }
00421        public int getDisplaySize () { return DisplaySize; }
00422 
00423        public Enumeration depending ()
00424        {      super.depending();
00425               depset(P1,P2);
00426               Enumeration e=E.getDepList().elements();
00427               while (e.hasMoreElements())
00428               {      DL.add((ConstructionObject)e.nextElement());
00429               }
00430               return DL.elements();
00431        }
00432 
00433        public void translate ()
00434        {      P1=(PointObject)P1.getTranslation();
00435               P2=(PointObject)P2.getTranslation();
00436               try
00437               {      setFixed(E.toString());
00438                      E.translate();
00439               }
00440               catch (Exception e) {}
00441        }
00442 
00443        public String getE ()
00444        {      return E.toString();
00445        }
00446        
00447        public double getValue ()
00448               throws ConstructionException
00449        {      if (!Valid) throw new InvalidException("exception.invalid");
00450               else return A/Math.PI*180;
00451        }
00452 
00453        public void setFilled (boolean flag)
00454        {      Filled=flag;
00455        }      
00456        public boolean isFilled ()
00457        {      return Filled;
00458        }
00459        public boolean isFilledForSelect ()
00460        {      return false;
00461        }
00462 
00463        public boolean contains (double x, double y)
00464        {      double a=(x-X1)*DX+(y-Y1)*DY;
00465               if (a<1e-9) return false;
00466               return true;
00467        }
00468        public double project (double x, double y)
00469        {      double h=super.project(x,y);
00470               if (h<0) return 0;
00471               return h;
00472        }
00473 
00474        public Enumeration points ()
00475        {      super.depending();
00476               return depset(P2);
00477        }
00478        
00479        public void move (double x, double y)
00480        {      init(getConstruction(),x,y,true);
00481        }
00482        
00483        public boolean moveable ()
00484        {      return Dragable; // E.isNumber();
00485        }
00486        
00487        public boolean isFixed ()
00488        {      return true;
00489        }
00490        
00491        public boolean getInverse ()
00492        {      return Inverse;
00493        }
00494        
00495        public void setInverse (boolean inverse)
00496        {      Inverse=inverse;
00497        }
00498        
00499        public boolean isEditAborted ()
00500        {      return EditAborted;
00501        }
00502 
00503        public boolean isDragable ()
00504        {      return Dragable;
00505        }
00506        
00507        public void setDragable (boolean f)
00508        {      Dragable=f; 
00509        }
00510 
00511        public boolean isReduced ()
00512        {      return Reduced;
00513        }
00514        
00515        public void setReduced (boolean f)
00516        {      Reduced=f; 
00517        }
00518 
00519        public boolean fixedByNumber ()
00520        {      return (E!=null && E.isNumber());
00521        }
00522 
00523        // For the simulate function:
00524        
00528        public void setSimulationValue (double x) 
00529        {      A=x/180*Math.PI;
00530               Expression OldE=E; 
00531               E=null;
00532               validate();
00533               E=OldE;
00534        }
00535        
00539        public void resetSimulationValue () 
00540        {      validate();
00541        }
00542 
00543        public void startDrag(double x, double y) 
00544        {}
00545 
00546        public void dragTo (double x, double y) 
00547        {      move(x,y);
00548        }
00549 
00550        public double containsInside (PointObject P) 
00551        {      double dx=P.getX()-X1,dy=P.getY()-Y1;
00552               double a=Math.atan2(dy,dx);
00553               if (a<A1) a+=2*Math.PI;
00554               double c=1e-5;
00555               if (a>A1 && a<A1+A) return 1;
00556               else if (a>A1-c && a<A1+A+c) return 0.5;
00557               return 0;
00558        }
00559 
00560        public boolean keepInside (PointObject P) 
00561        {      if (containsInside(P)>0) return true;
00562               double x=P.getX(),y=P.getY();
00563               double x1=X1,y1=Y1;
00564               double xmin=x1,ymin=y1,dmin=1e20;
00565               double x2=X1+Math.cos(A1),y2=Y1+Math.sin(A1);
00566               double dx=x2-x1,dy=y2-y1;
00567               double r=dx*dx+dy*dy;
00568               double h=dx*(x-x1)/r+dy*(y-y1)/r;
00569               if (h<0) h=0;
00570               double xh=x1+h*dx,yh=y1+h*dy;
00571               double dist=Math.sqrt((x-xh)*(x-xh)+(y-yh)*(y-yh));
00572               if (dist<dmin)
00573               {      dmin=dist;
00574                      xmin=xh; ymin=yh;
00575               }
00576               x2=X1+Math.cos(A2); y2=Y1+Math.sin(A2);
00577               dx=x2-x1; dy=y2-y1;
00578               r=dx*dx+dy*dy;
00579               h=dx*(x-x1)/r+dy*(y-y1)/r;
00580               if (h<0) h=0;
00581               xh=x1+h*dx; yh=y1+h*dy;
00582               dist=Math.sqrt((x-xh)*(x-xh)+(y-yh)*(y-yh));
00583               if (dist<dmin)
00584               {      dmin=dist;
00585                      xmin=xh; ymin=yh;
00586               }
00587               P.move(xmin,ymin);
00588               return false;
00589        }      
00590 }