CaRMtl/rene/zirkel/macro/MacroRunner.java
Glen Whitney e2f0f34394 Restore operability of Circle3D from JavaScript
There were two small problems. First, the type-checking in MacroRunner.run
was too strict, so applications that worked manually were failing from
JavaScript. The fix was to replace all of the type-checking code in that
function with a single call to isAdmissible(), which also simplified the code
and removed duplication.

Second, when assembling return values in ExecuteMacro in JSFunctions.java the
code would commit array bounds violations when there were no targets from
the MacroRunner. This commit fixes both problems and avoids silently dropping
the exceptions caught in Circle3D.
2018-09-05 00:21:49 -04:00

1312 lines
50 KiB
Java

/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.zirkel.macro;
/**
* This is an ObjectConstructor, which can run a macro.
*/
// with addons by Dibs for 3D
import eric.JSelectPopup;
import eric.GUI.palette.PaletteManager;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import rene.gui.Global;
import rene.zirkel.ZirkelCanvas;
import rene.zirkel.construction.Construction;
import rene.zirkel.construction.ConstructionException;
import rene.zirkel.construction.DepList;
import rene.zirkel.construction.Selector;
import rene.zirkel.constructors.ObjectConstructor;
import rene.zirkel.objects.AngleObject;
import rene.zirkel.objects.AreaObject;
import rene.zirkel.objects.CircleObject;
import rene.zirkel.objects.ConstructionObject;
import rene.zirkel.objects.ExpressionObject;
import rene.zirkel.objects.FixedAngleObject;
import rene.zirkel.objects.FixedCircleObject;
import rene.zirkel.objects.FunctionObject;
import rene.zirkel.objects.JLocusTrackObject;
import rene.zirkel.objects.LineObject;
import rene.zirkel.objects.PointObject;
import rene.zirkel.objects.PointonObject;
import rene.zirkel.objects.PrimitiveCircleObject;
import rene.zirkel.objects.PrimitiveLineObject;
import rene.zirkel.objects.QuadricObject;
import rene.zirkel.objects.RayObject;
import rene.zirkel.objects.SegmentObject;
import rene.zirkel.objects.TextObject;
import rene.zirkel.objects.TwoPointLineObject;
import rene.zirkel.objects.UserFunctionObject;
import rene.zirkel.objects.VectorObject;
public class MacroRunner extends ObjectConstructor implements Selector {
String S[];
int Param;
Macro M;
ArrayList OCs=new ArrayList();
ArrayList PROMPTs=new ArrayList();
ZirkelCanvas ZC;
ConstructionObject Params[]; // array of parameters.
boolean NewPoint[]; // are the parameters new points?
boolean Fixed[];
double LastX=0, LastY=0;
boolean ShiftDown=false;
static ConstructionObject previewPoint=null;
static boolean keepLine=true;
static boolean keepCircle=true;
/**
* Must be called, when this constructor is started.
*
* @param m
* The macro to be run
*/
public void setMacro(final Macro m, final ZirkelCanvas zc) {
S=m.getPrompts();
Param=0;
M=m;
Params=new ConstructionObject[S.length];
Fixed=new boolean[S.length];
NewPoint=new boolean[S.length];
for (int i=0; i<S.length; i++) {
Fixed[i]=false;
}
}
/**
* At each mouse press, one parameter is chosen. The valid objects are
* determined by the type of the parameter stored in the macro and retrieved
* by getParams(). Once all parameters are entered, the macro is run.
*/
@Override
public void mousePressed(final MouseEvent e, final ZirkelCanvas zc) {
if (!zc.Visual) {
return;
}
ShiftDown=e.isShiftDown();
if (!e.isAltDown()&&isMultipleFinalAccepted()) {
final ConstructionObject o=zc.selectMultipleFinal(e.getX(), e.getY(), false);
if (o!=null) {
LaunchMultipleFinalMacro(e, zc);
reset(zc);
return;
}
}
ConstructionObject o;
final ConstructionObject p[]=M.getParams();
if (p[Param] instanceof PointObject) {
o=zc.selectCreatePoint(e.getX(), e.getY(), e.isAltDown());
} else {
o=zc.selectWithSelector(e.getX(), e.getY(), this);
}
setConstructionObject(o, zc);
}
@Override
public void setConstructionObject(ConstructionObject obj, ZirkelCanvas zc) {
// Il y a eu ambiguité et la méthode est forcément appelée par le
// popupmenu de sélection :
if ((JSelectPopup.isCallerObject()) && (obj instanceof PointonObject) && (M.getParams()[Param] instanceof PointObject)) {
int x=JSelectPopup.getMouseX();
int y=JSelectPopup.getMouseY();
PointObject o=new PointObject(zc.getConstruction(), zc.x(x), zc.y(y), obj);
o.setUseAlpha(true);
zc.addObject(o);
zc.validate();
o.setDefaults();
zc.repaint();
o.edit(zc, false, false);
obj=o;
}
if (obj!=null) {
final int ip=Param;
if (!setNextParameter(obj, zc, ShiftDown)) {
return;
}
NewPoint[ip]=(obj instanceof PointObject&&zc.isNewPoint());
if (Param>=S.length) {
doMacro(zc);
reset(zc);
} else {
getFixed(zc);
}
}
}
@Override
public boolean isAdmissible(final ZirkelCanvas zc,
final ConstructionObject o) {
final ConstructionObject p[]=M.getParams();
if (p[Param] instanceof PointObject) {
return (o instanceof PointObject);
} else if (p[Param] instanceof FixedAngleObject) {
return (o instanceof FixedAngleObject);
} else if (p[Param] instanceof RayObject) {
return (o instanceof RayObject);
} else if (p[Param] instanceof TwoPointLineObject) {
return (o instanceof TwoPointLineObject);
} else if (p[Param] instanceof SegmentObject) {
return (p[Param] instanceof SegmentObject);
} else if (p[Param] instanceof PrimitiveLineObject) {
return (o instanceof PrimitiveLineObject);
} else if (p[Param] instanceof PrimitiveCircleObject) {
return (o instanceof PrimitiveCircleObject);
} else if (p[Param] instanceof FunctionObject) {
return (o instanceof FunctionObject);
} else if (p[Param] instanceof UserFunctionObject) {
return (o instanceof UserFunctionObject);
} else if (p[Param] instanceof AngleObject) {
return (o instanceof AngleObject);
} else if (p[Param] instanceof QuadricObject) {
return (o instanceof QuadricObject);
} else if (p[Param] instanceof ExpressionObject) {
return (o instanceof ExpressionObject||o instanceof AngleObject
||o instanceof FixedAngleObject||o instanceof AreaObject);
} else if (p[Param] instanceof AreaObject) {
return (o instanceof AreaObject);
} else {
return false;
}
}
private void checkIfKeepLine(final ZirkelCanvas zc) {
final Construction c=zc.getConstruction();
PointObject P1org=new PointObject(c, -3, 4);
PointObject P2org=new PointObject(c, -1, 1);
PointObject P3org=new PointObject(c, 1, -2);
P1org.setSuperHidden(true);
P2org.setSuperHidden(true);
P3org.setSuperHidden(true);
Params[Params.length-1]=P1org;
c.add(P1org);
runMacroPreview(zc, false);
final PointObject p1=(PointObject) previewPoint;
Params[Params.length-1]=P2org;
c.add(P2org);
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
Params[Params.length-1]=P3org;
c.add(P3org);
runMacroPreview(zc, false);
final PointObject p3=(PointObject) previewPoint;
final double x1=p2.getX()-p1.getX();
final double y1=p2.getY()-p1.getY();
final double x2=p3.getX()-p1.getX();
final double y2=p3.getY()-p1.getY();
keepLine=(Math.abs(x1*y2-x2*y1)<1e-11);
}
private void checkIfKeepCircle(final ZirkelCanvas zc) {
final Construction c=zc.getConstruction();
PointObject P0org=new PointObject(c, 1, 1);
PointObject P1org=new PointObject(c, 2, -1);
PointObject P2org=new PointObject(c, 3, 2);
PointObject P3org=new PointObject(c, 0, 3);
PointObject P4org=new PointObject(c, -1, 2);
P0org.setSuperHidden(true);
P1org.setSuperHidden(true);
P2org.setSuperHidden(true);
P3org.setSuperHidden(true);
P4org.setSuperHidden(true);
Params[Params.length-1]=P0org;
c.add(P0org);
runMacroPreview(zc, false);
final PointObject p0=(PointObject) previewPoint;
Params[Params.length-1]=P1org;
c.add(P1org);
runMacroPreview(zc, false);
final PointObject p1=(PointObject) previewPoint;
Params[Params.length-1]=P2org;
c.add(P2org);
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
Params[Params.length-1]=P3org;
c.add(P3org);
runMacroPreview(zc, false);
final PointObject p3=(PointObject) previewPoint;
Params[Params.length-1]=P4org;
c.add(P4org);
runMacroPreview(zc, false);
final PointObject p4=(PointObject) previewPoint;
final double x1=Math.sqrt((p1.getX()-p0.getX())
*(p1.getX()-p0.getX())+(p1.getY()-p0.getY())
*(p1.getY()-p0.getY()));
final double x2=Math.sqrt((p2.getX()-p0.getX())
*(p2.getX()-p0.getX())+(p2.getY()-p0.getY())
*(p2.getY()-p0.getY()));
final double x3=Math.sqrt((p3.getX()-p0.getX())
*(p3.getX()-p0.getX())+(p3.getY()-p0.getY())
*(p3.getY()-p0.getY()));
final double x4=Math.sqrt((p4.getX()-p0.getX())
*(p4.getX()-p0.getX())+(p4.getY()-p0.getY())
*(p4.getY()-p0.getY()));
boolean b=Math.abs(x1-x2)<1e-11;
b=b&&Math.abs(x1-x3)<1e-11;
b=b&&Math.abs(x1-x4)<1e-11;
keepCircle=b;
}
public boolean isMultipleFinalAccepted() {
final ConstructionObject p[]=M.getParams();
if (Param<p.length-1) {
return false;
}
if (!(p[p.length-1] instanceof PointObject)) {
return false;
}
final Vector t=M.getTargets();
if (t.size()!=1) {
return false;
}
final ConstructionObject o=(ConstructionObject) t.get(0);
if (!(o instanceof PointObject)) {
return false;
}
return true;
}
public void LaunchLocus(final ZirkelCanvas zc, final Construction c,
final ConstructionObject o) {
final ConstructionObject po[]=new ConstructionObject[0];
final int pn=0;
// Créer un point qui représentera le dernier paramètre
// de la macro. Ce point est ajouté à la construction :
final PointObject pm=new PointObject(c, 0, 0);
pm.setKeep(false);
pm.setTarget(false);
pm.setBound(o);
pm.setSuperHidden(true);
c.add(pm);
o.setTranslation(pm);
pm.validate();
c.added(pm);
// Lancer la macro et récupérer le point créé, qui sera rendu
// super caché :
Params[Params.length-1]=pm;
doMacro(zc);
final PointObject p=(PointObject) previewPoint;
p.setKeep(false);
p.setTarget(false);
p.setSuperHidden(true);
o.setTranslation(p);
p.validate();
c.added(p);
// Créer le lieu du point p lorsque pm varie sur son ConstructionObject o :
final JLocusTrackObject jl=new JLocusTrackObject(c, p, po, pn, o, pm);
// Ajouter ce lieu à la construction :
jl.setKeep(false);
jl.setTarget(false);
jl.setDefaults();
if (!(o instanceof JLocusTrackObject)) {
jl.applyDefaults(o);
}
c.addNoCheck(jl);
o.setTranslation(jl);
jl.validate();
c.added(jl);
}
public void LaunchLocusPreview(final ZirkelCanvas zc, final Construction c,
final ConstructionObject o) {
final ConstructionObject po[]=new ConstructionObject[0];
final int pn=0;
// Créer un point qui représentera le dernier paramètre
// de la macro. Ce point est ajouté à la construction :
final PointObject pm=new PointObject(c, 0, 0);
c.add(pm);
pm.setSuperHidden(true);
Params[Params.length-1]=pm;
// Lancer la macro et récupérer le point créé, qui sera rendu
// super caché :
runMacroPreview(zc, false);
final PointObject p=(PointObject) previewPoint;
p.setSuperHidden(true);
// Créer le lieu du point p lorsque pm varie sur son ConstructionObject o :
final JLocusTrackObject jl=new JLocusTrackObject(c, p, po, pn, o, pm);
// Ajouter ce lieu à la construction :
jl.setKeep(false);
jl.setTarget(false);
jl.setSelectable(false);
jl.setIndicated(true);
c.addNoCheck(jl);
o.setTranslation(jl);
jl.validate();
c.added(jl);
}
public boolean isLineObject(final ConstructionObject o) {
boolean b=o instanceof PrimitiveLineObject;
b=b||(o instanceof AreaObject);
return b;
}
public boolean isCircleObject(final ConstructionObject o) {
final boolean b=o instanceof PrimitiveCircleObject;
return b;
}
public boolean isArcObject(final ConstructionObject c) {
if (c instanceof PrimitiveCircleObject) {
final PrimitiveCircleObject cc=(PrimitiveCircleObject) c;
return cc.hasRange();
}
return false;
}
public void LaunchMultipleFinalMacro(final MouseEvent e,
final ZirkelCanvas zc) {
final ConstructionObject o=zc.selectMultipleFinal(e.getX(), e.getY(),
false);
final Construction c=zc.getConstruction();
if (o!=null) {
final int myX=e.getX();
final int myY=e.getY();
LastX=zc.x(myX);
LastY=zc.y(myY);
if ((!keepLine)&&(isLineObject(o))) {
LaunchLocus(zc, c, o);
return;
}
if ((!keepCircle)&&(isCircleObject(o))) {
LaunchLocus(zc, c, o);
return;
}
if (isArcObject(o)) {
LaunchLocus(zc, c, o);
return;
}
if (o instanceof TwoPointLineObject) {
final TwoPointLineObject tplo=(TwoPointLineObject) o;
final TwoPointLineObject oc=(TwoPointLineObject) tplo.copy(
LastX, LastY);
Params[Params.length-1]=tplo.getP1();
doMacro(zc);
final PointObject p1=(PointObject) previewPoint;
Params[Params.length-1]=tplo.getP2();
doMacro(zc);
final PointObject p2=(PointObject) previewPoint;
oc.setP1P2(p1, p2);
finaliseMacro(c, o, oc);
} else if (o instanceof SegmentObject) {
final SegmentObject tplo=(SegmentObject) o;
tplo.setArrow(((SegmentObject) o).Arrow);
Params[Params.length-1]=tplo.getP1();
runMacroPreview(zc, false);
final PointObject p1=(PointObject) previewPoint;
final PointObject p0=tplo.getP1();
Params[Params.length-1]=new PointObject(c, p0.getX()
+tplo.getDX(), p0.getY()+tplo.getDY());
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
final LineObject oc=new LineObject(c, p1, p2);
finaliseMacroPreview(c, o, oc);
} else if (o instanceof PrimitiveLineObject) {
final PrimitiveLineObject tplo=(PrimitiveLineObject) o;
Params[Params.length-1]=tplo.getP1();
doMacro(zc);
final PointObject p1=(PointObject) previewPoint;
final PointObject p3=tplo.getP1();
final String Pnm=p3.getName();
final String Lnm=tplo.getName();
final PointObject p4=new PointObject(c, p3.getX()
+tplo.getDX(), p3.getY()+tplo.getDY());
p4.setFixed("x("+Pnm+")+x("+Lnm+")", "y("+Pnm
+")+y("+Lnm+")");
p4.setSuperHidden(true);
zc.addObject(p4);
Params[Params.length-1]=p4;
doMacro(zc);
final PointObject p2=(PointObject) previewPoint;
p1.setSuperHidden(true);
p2.setSuperHidden(true);
final LineObject oc=new LineObject(c, p1, p2);
finaliseMacro(c, o, oc);
} else if (o instanceof CircleObject) {
final CircleObject tplo=(CircleObject) o;
final CircleObject oc=(CircleObject) tplo.copy(LastX, LastY);
Params[Params.length-1]=tplo.getP1();
doMacro(zc);
final PointObject p1=(PointObject) previewPoint;
Params[Params.length-1]=tplo.getP2();
doMacro(zc);
final PointObject p2=(PointObject) previewPoint;
p2.setSuperHidden(true);
oc.setP1P2(p1, p2);
finaliseMacro(c, o, oc);
} else if (o instanceof PrimitiveCircleObject) {
final PrimitiveCircleObject tplo=(PrimitiveCircleObject) o;
Params[Params.length-1]=tplo.getP1();
doMacro(zc);
final PointObject p1=(PointObject) previewPoint;
final PointObject p4=new PointObject(c, 0, 0);
p4.setBound(tplo);
p4.setSuperHidden(true);
zc.addObject(p4);
Params[Params.length-1]=p4;
doMacro(zc);
final PointObject p2=(PointObject) previewPoint;
p2.setSuperHidden(true);
final CircleObject oc=new CircleObject(c, p1, p2);
finaliseMacro(c, o, oc);
} else if (o instanceof AreaObject) {
final AreaObject ao=(AreaObject) o;
final AreaObject oc=(AreaObject) ao.copy(LastX, LastY);
oc.V.removeAllElements();
final Enumeration en=ao.V.elements();
while (en.hasMoreElements()) {
final PointObject pt=(PointObject) en.nextElement();
Params[Param]=pt;
doMacro(zc);
oc.V.add((PointObject) previewPoint);
}
finaliseMacro(c, o, oc);
} else {
LaunchLocus(zc, c, o);
}
}
}
public void finaliseMacro(final Construction c, final ConstructionObject o,
final ConstructionObject oc) {
oc.setKeep(false); // necessary for jobs
oc.setTarget(false); // necessary for descriptive constructions
oc.setDefaults();
c.addNoCheck(oc);
o.setTranslation(oc);
oc.validate();
c.added(oc);
}
public void LaunchMultipleFinalMacroPreview(final MouseEvent e,
final ZirkelCanvas zc) {
final ConstructionObject o=zc.selectMultipleFinal(e.getX(), e.getY(),
false);
final Construction c=zc.getConstruction();
if (o!=null) {
final int myX=e.getX();
final int myY=e.getY();
zc.prepareForPreview(e);
checkIfKeepLine(zc);
checkIfKeepCircle(zc);
LastX=zc.x(myX);
LastY=zc.y(myY);
if ((!keepLine)&&(isLineObject(o))) {
LaunchLocusPreview(zc, c, o);
return;
}
if ((!keepCircle)&&(isCircleObject(o))) {
LaunchLocusPreview(zc, c, o);
return;
}
if (isArcObject(o)) {
LaunchLocusPreview(zc, c, o);
return;
}
// if (true) {
// LaunchLocusPreview(zc, c, o);
// return;
// }
if (o instanceof TwoPointLineObject) {
final TwoPointLineObject tplo=(TwoPointLineObject) o;
final TwoPointLineObject oc=(TwoPointLineObject) tplo.copy(
LastX, LastY);
Params[Params.length-1]=tplo.getP1();
runMacroPreview(zc, true);
final PointObject p1=(PointObject) previewPoint;
Params[Params.length-1]=tplo.getP2();
runMacroPreview(zc, true);
final PointObject p2=(PointObject) previewPoint;
oc.setP1P2(p1, p2);
finaliseMacroPreview(c, o, oc);
} else if (o instanceof SegmentObject) {
final SegmentObject tplo=(SegmentObject) o;
tplo.setArrow(((SegmentObject) o).Arrow);
Params[Params.length-1]=tplo.getP1();
runMacroPreview(zc, false);
final PointObject p1=(PointObject) previewPoint;
final PointObject p0=tplo.getP1();
Params[Params.length-1]=new PointObject(c, p0.getX()
+tplo.getDX(), p0.getY()+tplo.getDY());
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
final LineObject oc=new LineObject(c, p1, p2);
finaliseMacroPreview(c, o, oc);
} else if (o instanceof PrimitiveLineObject) {
final PrimitiveLineObject tplo=(PrimitiveLineObject) o;
Params[Params.length-1]=tplo.getP1();
runMacroPreview(zc, false);
final PointObject p1=(PointObject) previewPoint;
final PointObject p0=tplo.getP1();
Params[Params.length-1]=new PointObject(c, p0.getX()
+tplo.getDX(), p0.getY()+tplo.getDY());
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
final LineObject oc=new LineObject(c, p1, p2);
finaliseMacroPreview(c, o, oc);
} else if (o instanceof CircleObject) {
final CircleObject tplo=(CircleObject) o;
final CircleObject oc=(CircleObject) tplo.copy(LastX, LastY);
Params[Params.length-1]=tplo.getP1();
runMacroPreview(zc, true);
final PointObject p1=(PointObject) previewPoint;
Params[Params.length-1]=tplo.getP2();
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
oc.setP1P2(p1, p2);
finaliseMacroPreview(c, o, oc);
} else if (o instanceof PrimitiveCircleObject) {
final PrimitiveCircleObject tplo=(PrimitiveCircleObject) o;
Params[Params.length-1]=tplo.getP1();
runMacroPreview(zc, true);
final PointObject p1=(PointObject) previewPoint;
final PointObject p4=new PointObject(c, tplo.getP1().getX()
+tplo.getR(), tplo.getP1().getY());
p4.setSuperHidden(true);
c.add(p4);
Params[Params.length-1]=p4;
runMacroPreview(zc, false);
final PointObject p2=(PointObject) previewPoint;
final CircleObject oc=new CircleObject(c, p1, p2);
finaliseMacroPreview(c, o, oc);
} else if (o instanceof AreaObject) {
final AreaObject ao=(AreaObject) o;
final AreaObject oc=(AreaObject) ao.copy(LastX, LastY);
oc.V.removeAllElements();
final Enumeration en=ao.V.elements();
while (en.hasMoreElements()) {
final PointObject pt=(PointObject) en.nextElement();
Params[Params.length-1]=pt;
runMacroPreview(zc, true);
oc.V.add((PointObject) previewPoint);
}
finaliseMacroPreview(c, o, oc);
} else {
LaunchLocusPreview(zc, c, o);
}
}
}
public void finaliseMacroPreview(final Construction c,
final ConstructionObject o, final ConstructionObject oc) {
oc.setKeep(false); // necessary for jobs
oc.setTarget(false); // necessary for descriptive constructions
oc.setSelectable(false);
oc.setIndicated(true);
c.addNoCheck(oc);
o.setTranslation(oc);
oc.validate();
c.added(oc);
if (o instanceof SegmentObject) {
c.Vectors=((SegmentObject) o).Arrow;
}
}
private boolean lastIsMultipleObject=false;
@Override
public void mouseMoved(final MouseEvent e, final ZirkelCanvas zc,
final boolean simple) {
final ConstructionObject p[]=M.getParams();
zc.clearIndicated();
zc.clearPreview();
zc.repaint();
if (!e.isAltDown()&&isMultipleFinalAccepted()) {
final ConstructionObject o=zc.selectMultipleFinal(e.getX(), e.getY(), false);
if (o!=null) {
final int myX=e.getX();
final int myY=e.getY();
zc.prepareForPreview(e);
LastX=zc.x(myX);
LastY=zc.y(myY);
LaunchMultipleFinalMacroPreview(e, zc);
zc.indicateMultipleFinal(e.getX(), e.getY());
return;
}
}
if (!(p[Param] instanceof PointObject)&&Param==p.length-1) {
// zc.clearPreview();
// zc.repaint();
final ConstructionObject o=zc.selectWithSelector(e.getX(), e.getY(), this, false);
if (o!=null) {
final int myX=e.getX();
final int myY=e.getY();
zc.prepareForPreview(e);
Params[Param]=o;
LastX=zc.x(myX);
LastY=zc.y(myY);
runMacroPreview(zc, true);
zc.indicateWithSelector(myX, myY, this);
return;
}
}
PointObject lastp=null;
if (p[Param] instanceof PointObject) {
lastp=zc.indicateCreatePoint(e.getX(), e.getY(), true);
} else {
zc.indicateWithSelector(e.getX(), e.getY(), this);
}
if (!simple&&waitForLastPoint()) {
zc.prepareForPreview(e);
if (lastp==null) {
finishConstruction(e, zc);
} else {
int x=(int) zc.col(lastp.getX());
int y=(int) zc.row(lastp.getY());
finishConstruction(x, y, e, zc);
}
}
}
@Override
public boolean waitForLastPoint() {
if (M.countPrompts()>0) {
return false;
}
final ConstructionObject p[]=M.getParams();
return (p[Param] instanceof PointObject)&&Param==p.length-1;
}
@Override
public void finishConstruction(final MouseEvent e, final ZirkelCanvas zc) {
final ConstructionObject p[]=M.getParams();
ConstructionObject o;
if (p[Param] instanceof PointObject) {
o=zc.selectCreatePoint(e.getX(), e.getY(), e.isAltDown());
} else {
return;
}
NewPoint[Param]=true;
Params[Param]=o;
runMacroPreview(zc, true);
}
public void finishConstruction(int x, int y, final MouseEvent e, final ZirkelCanvas zc) {
final ConstructionObject p[]=M.getParams();
ConstructionObject o;
if (p[Param] instanceof PointObject) {
o=zc.selectCreatePoint(x, y, e.isAltDown());
} else {
return;
}
NewPoint[Param]=true;
Params[Param]=o;
runMacroPreview(zc, true);
}
@Override
public void reset(final ZirkelCanvas zc) {
if (zc.Visual) {
super.reset(zc);
Param=0;
if (M!=null&&M.hasFixed()) {
getFixed(zc);
}
showStatus(zc);
} else if (M!=null) // show the input pattern
{
final StringBuffer b=new StringBuffer();
b.append('=');
final String name=M.getName();
if (name.indexOf("(")>0) {
b.append("\""+M.getName()+"\"");
} else {
b.append(M.getName());
}
b.append('(');
for (int i=0; i<M.getParams().length-1; i++) {
b.append(',');
}
b.append(')');
zc.setPrompt(b.toString());
}
}
public void getFixed(final ZirkelCanvas zc) {
if (M==null||!zc.Visual) {
return;
}
final boolean start=(Param==0);
while ((M.isFixed(Param)||M.getPrompts()[Param].startsWith("="))
&&Param<(start?S.length-1:S.length)) {
String name;
if (M.isFixed(Param)) {
name=M.getLast(Param);
} else {
name=M.getPrompts()[Param].substring(1);
}
if (name.equals("")) {
M.setFixed(Param, false);
break;
}
final ConstructionObject o=zc.getConstruction().find(name);
if (o==null) {
M.setFixed(Param, false);
break;
}
if (!setNextParameter(o, zc, false)) {
return;
}
if (Param>=S.length) {
doMacro(zc);
reset(zc);
break;
}
}
showStatus(zc);
}
public void returnPressed(final ZirkelCanvas zc) {
if (M==null||!zc.Visual) {
return;
}
final String name=M.getLast(Param);
if (name.equals("")) {
return;
}
final ConstructionObject o=zc.getConstruction().find(name);
if (!setNextParameter(o, zc, false)) {
return;
}
if (Param>=S.length) {
doMacro(zc);
reset(zc);
} else {
getFixed(zc);
}
}
public boolean setNextParameter(final ConstructionObject o,
final ZirkelCanvas zc, final boolean fix) {
if (!isAdmissible(zc, o)) {
return false;
}
Params[Param]=o;
o.setSelected(true);
if (fix) {
Fixed[Param]=true;
}
zc.getConstruction().addParameter(o);
zc.repaint();
Param++;
return true;
}
public void doMacro(final ZirkelCanvas zc) {
final String value[]=new String[0];
runMacro(zc, value);
}
static DepList DL=new DepList();
@Override
public void showStatus(final ZirkelCanvas zc) {
if (M!=null) {
final ConstructionObject p[]=M.getParams();
String type="???";
// Determine the expected type and display in status line
if (p[Param] instanceof FunctionObject) {
type=Global.name("name.Function");
} else if (p[Param] instanceof PointObject) {
type=Global.name("name.Point");
} else if (p[Param] instanceof FixedAngleObject) {
type=Global.name("name.FixedAngle");
} else if(p[Param] instanceof VectorObject) {
type=Global.name("name.Vector");
} else if (p[Param] instanceof SegmentObject) {
type=Global.name("name.Segment");
} else if (p[Param] instanceof LineObject) {
type=Global.name("name.TwoPointLine");
} else if (p[Param] instanceof RayObject) {
type=Global.name("name.Ray");
} else if (p[Param] instanceof PrimitiveLineObject) {
type=Global.name("name.Line");
} else if (p[Param] instanceof PrimitiveCircleObject) {
type=Global.name("name.Circle");
} else if (p[Param] instanceof ExpressionObject) {
type=Global.name("name.Expression");
} else if (p[Param] instanceof AreaObject) {
type=Global.name("name.Polygon");
} else if (p[Param] instanceof AngleObject) {
type=Global.name("name.Angle");
} else if (p[Param] instanceof QuadricObject) {
type=Global.name("name.Quadric");
}
final String s=M.getLast(Param);
String prompt;
int inc=zc.isDP()?0:1;
if (s.equals("")) {
prompt=ConstructionObject.text4(Global.name("message.runmacro"), M.getName(), ""
+(Param+inc), type, S[Param]);
} else {
prompt=ConstructionObject.text4(Global.name("message.runmacro"), M.getName(), ""
+(Param+inc), type, S[Param])
+" ";
}
zc.showStatus(prompt);
}
}
//Only for JSFunctions/ExecuteMacro
public static ArrayList<String> TargetsNameList = new ArrayList<String>();
public static ArrayList<Integer> TargetsIndexList = new ArrayList<Integer>();
/**
* Run a macro. The macro parameters have already been determined. This is a
* rather complicated function.
*/
public void runMacro(final ZirkelCanvas zc, final Construction c,
final String value[]) {
TargetsNameList.clear();
TargetsIndexList.clear();
OCs.clear();
PROMPTs.clear();
M.setTranslation(c);
final ConstructionObject LastBefore=c.lastButN(0);
final int N=Params.length;
// First clear all parameter flags. This makes it possible to
// check for proper translation of secondary parameters later.
// Secondary parameters without a translation will be
// constructed.
Enumeration e=M.elements();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
o.clearParameter();
o.setTranslation(null);
}
M.clearTranslations();
c.clearTranslators();
final ConstructionObject p[]=M.getParams();
// For all macro parameters, determine the translation to the
// real construction, and do the same for the secondary
// parameters, which belong to the parameter. The secondary
// parameters are stored in the macro at its definition, as
// the primary ones. Also the parameters in the macros are marked
// as such to make sure and prevent construction.
M.initLast(); // Macros remember the parameters for next call
for (int i=0; i<N; i++) {
M.setLast(Params[i].getName(), i);
p[i].setTranslation(Params[i]);
p[i].setMainParameter(true);
if (NewPoint[i]&&p[i].isHidden()) {
Params[i].setHidden(true);
}
if (Params[i] instanceof PointObject&&p[i] instanceof PointObject
&&NewPoint[i]) {
final PointObject pa=(PointObject) Params[i], pp=(PointObject) p[i];
pa.setIncrement(pp.getIncrement());
if (pp.getBound()!=null) {
pa.setBound(pp.getBound());
pa.setInside(pp.isInside());
pa.translate();
}
}
// translate parameters that depend on themself only
if (Params[i] instanceof PointObject&&p[i] instanceof PointObject
&&((PointObject) p[i]).dependsOnItselfOnly()) {
final PointObject P=(PointObject) Params[i];
// Do not transfer self reference to objects that depend on
// something!
// This might crash the construction.
if (!P.depending().hasMoreElements()) {
P.setConstruction(M);
P.setFixed(((PointObject) p[i]).getEX(),
((PointObject) p[i]).getEY());
P.translateConditionals();
P.translate();
P.setConstruction(c);
}
}
if (p[i].isMainParameter()) { // System.out.println("Main Parameter "+p[i].getName());
e=p[i].secondaryParams();
// Copy the list of secondary parameters in the macro,
// which depend from p[i] to DL.
DL.reset();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
// System.out.println("Secondary Parameter "+o.getName()+" of "+p[i].getName());
DL.add(o);
o.setParameter(true);
}
e=DL.elements();
// Get a list of actual secondary params in the
// construction. Then translate the scecondary params
// in the macro definition to the true construction objects.
final Enumeration ep=Params[i].secondaryParams();
while (ep.hasMoreElements()&&e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
final ConstructionObject op=(ConstructionObject) ep.nextElement();
if (o.getTranslation()!=op&&o.getTranslation()!=null) {
zc.warning(Global.name("macro.usage"));
return;
}
o.setTranslation(op);
}
}
}
// Now we generate the objects.
e=M.elements();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
// System.out.println(o.getName()+" "+o.isParameter());
if (!o.isParameter()) { // else do not construct!
// Copy the object and add to construction. Then
// translate the dependencies properly
final ConstructionObject oc=(ConstructionObject) o.copy(
LastX, LastY);
if (oc!=null) {
previewPoint=oc;
oc.setKeep(false); // necessary for jobs
oc.setTarget(false); // necessary for descriptive constructions
c.addNoCheck(oc);
o.setTranslation(oc);
oc.validate();
c.added(oc);
zc.update_distant(oc, 1);
// For the target objects, use default values instead
// of values stored in the macro (point style etc.)
if (o.isTarget()) {
if (!oc.isDPObject()) {
oc.setDPMode(M.createDPObjects);
}
oc.setTargetDefaults();
TargetsNameList.add(oc.getName());
TargetsIndexList.add(oc.getMacroFinalIndex());
}
// else if (o.isHidden()) {
// if (o.isSuperHidden()) oc.setSuperHidden(true);
// else oc.setHidden(true);
// }
if (oc instanceof PointObject&&((PointObject) oc).is3D()) oc.setFixed("x(O)+("+oc.getEX3D()+")*(x(X)-x(O))+("+oc.getEY3D()+")*(x(Y)-x(O))+("+oc.getEZ3D()+")*(x(Z)-x(O))", "y(O)+("+oc.getEX3D()+")*(y(X)-y(O))+("+oc.getEY3D()+")*(y(Y)-y(O))+("+oc.getEZ3D()+")*(y(Z)-y(O))"); //Dibs !important
if ((oc instanceof FixedCircleObject
||oc instanceof FixedAngleObject||oc instanceof ExpressionObject)
&&M.promptFor(o.getName())) {
c.updateCircleDep();
c.dovalidate();
zc.repaint();
final int index=M.getPromptFor(o.getName());
if (index>=value.length||value[index].equals("")) {
OCs.add(oc);
PROMPTs.add(M.getPromptName(o.getName()));
}
}
}
}
}
// Now fix the objects, which depend on later objects
e=M.elements();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
if (!o.isParameter()) {
o.laterTranslate(M);
}
}
c.updateCircleDep();
c.runTranslators(M);
c.dovalidate();
zc.repaint();
int fixed=0;
for (final boolean element : Fixed) {
if (element) {
fixed++;
}
}
if (fixed>0&&fixed<Fixed.length&&!M.hasFixed()) {
String name=M.getName()+" -";
for (int i=0; i<Fixed.length; i++) {
if (Fixed[i]) {
name=name+" "+M.LastParams[i];
}
}
M=zc.copyMacro(M, name, Fixed);
for (int i=0; i<Fixed.length; i++) {
Fixed[i]=false;
}
reset(zc);
}
if (LastBefore!=null&&M.hideDuplicates()) {
zc.hideDuplicates(LastBefore);
}
ZC=zc;
final Thread thread=new Thread(new Runnable() {
@Override
public void run() {
for (int i=0; i<OCs.size(); i++) {
final String myName=(String) PROMPTs.get(i);
final ConstructionObject myCO=(ConstructionObject) OCs.get(i);
new eric.JMacroPrompt(ZC.getFrame(), ZC, myName, myCO);
}
}
});
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public void runMacro(final ZirkelCanvas zc, final String value[]) {
runMacro(zc, zc.getConstruction(), value);
}
public void runMacroPreview(final ZirkelCanvas zc, final boolean visible) {
final Construction c=zc.getConstruction();
M.setTranslation(c);
final int N=Params.length;
// First clear all parameter flags. This makes it possible to
// check for proper translation of secondary parameters later.
// Secondary parameters without a translation will be
// constructed.
Enumeration e=M.elements();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
o.clearParameter();
o.setTranslation(null);
}
M.clearTranslations();
c.clearTranslators();
final ConstructionObject p[]=M.getParams();
// For all macro parameters, determine the translation to the
// real construction, and do the same for the secondary
// parameters, which belong to the parameter. The secondary
// parameters are stored in the macro at its definition, as
// the primary ones. Also the parameters in the macros are marked
// as such to make sure and prevent construction.
for (int i=0; i<N; i++) {
if (Params[i]==null) {
return;
}
M.setLast(Params[i].getName(), i);
p[i].setTranslation(Params[i]);
p[i].setMainParameter(true);
if (NewPoint[i]&&p[i].isHidden()) {
Params[i].setHidden(true);
}
if (p[i].isMainParameter()) {
e=p[i].secondaryParams();
// Copy the list of secondary parameters in the macro,
// which depend from p[i] to DL.
DL.reset();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
DL.add(o);
o.setParameter(true);
}
e=DL.elements();
// Get a list of actual secondary params in the
// construction. Then translate the scecondary params
// in the macro definition to the true construction objects.
final Enumeration ep=Params[i].secondaryParams();
while (ep.hasMoreElements()&&e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
final ConstructionObject op=(ConstructionObject) ep.nextElement();
if (o.getTranslation()!=op&&o.getTranslation()!=null) { // zc.warning(Global.name("macro.usage"));
return;
}
if (o!=null) {
o.setTranslation(op);
}
}
}
}
// Now we generate the objects.
e=M.elements();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
if (!o.isParameter()) // else do not construct!
{ // Copy the object and add to construction. Then
// translate the dependencies properly
final ConstructionObject oc=(ConstructionObject) o.copy(
LastX, LastY);
if (oc!=null) {
previewPoint=oc;
oc.setKeep(false); // necessary for jobs
oc.setTarget(false); // necessary for descriptive constructions
oc.setSelectable(false);
if (visible) {
oc.setIndicated(true);
} else {
oc.setSuperHidden(true);
}
c.addNoCheck(oc);
o.setTranslation(oc);
oc.validate();
c.added(oc);
// For the target objects, use default values instead
// of values stored in the macro (point style etc.)
if (o.isTarget()) {
if (!oc.isDPObject()) {
oc.setDPMode(M.createDPObjects);
}
oc.setTargetDefaults();
if (oc instanceof PointObject&&((PointObject) oc).is3D()) oc.setFixed("x(O)+("+oc.getEX3D()+")*(x(X)-x(O))+("+oc.getEY3D()+")*(x(Y)-x(O))+("+oc.getEZ3D()+")*(x(Z)-x(O))", "y(O)+("+oc.getEX3D()+")*(y(X)-y(O))+("+oc.getEY3D()+")*(y(Y)-y(O))+("+oc.getEZ3D()+")*(y(Z)-y(O))");
}
if (o.isHidden()) {
oc.setHidden(true);
// For black objects, use the default color.
}
// if (oc.getColorIndex()==0) {
// oc.setColor(c.DefaultColor);
// }
}
}
}
// All objects have the chance to translate anything
// (used by start and end points of arcs)
e=M.elements();
while (e.hasMoreElements()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
if (!o.isParameter()) {
o.laterTranslate(M);
}
}
c.updateCircleDep();
// Run the translations of forward references of type @...
c.runTranslators(M);
c.dovalidate();
// c.computeHeavyObjects(zc);
zc.repaint();
}
/**
* Run a macro in javascript mode. This needs a previous setMacro() call!
*/
public void run(final ZirkelCanvas zc, final Construction c) throws ConstructionException {
final ConstructionObject p[]=M.getParams();
final String value[]=new String[M.countPrompts()];
for (int i=0; i<M.countPrompts(); i++) {
value[i]="";
}
for (int i=0; i<p.length; i++) {
final ConstructionObject o=M.getParams()[i];
if (o==null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
Params[i]=o;
}
runMacro(zc, c, value);
// final StringTokenizer t = new StringTokenizer(name, ",");
// final Enumeration e = M.getTargets().elements();
// while (e.hasMoreElements() && t.hasMoreTokens()) {
// final ConstructionObject o = (ConstructionObject) e.nextElement();
// o.getTranslation().setName(t.nextToken().trim());
// }
zc.repaint();
}
/**
* Run a macro in nonvisual mode. This needs a previous setMacro() call!
*/
public void run(final ZirkelCanvas zc, final Construction c,
final String name, final String params[], final int nparams)
throws ConstructionException {
final ConstructionObject p[]=M.getParams();
if (nparams!=p.length+M.countPrompts()) {
throw new ConstructionException(Global.name("exception.nparams"));
}
final String value[]=new String[M.countPrompts()];
for (int i=0; i<M.countPrompts(); i++) {
value[i]=params[p.length+i];
}
for (int i=0; i<p.length; i++) {
final ConstructionObject o=c.find(params[i]);
if (o==null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
if (!isAdmissible(zc, o)) {
throw new ConstructionException(Global.name("exception.type"));
}
Params[i]=o;
Param++;
}
runMacro(zc, c, value);
final StringTokenizer t=new StringTokenizer(name, ",");
final Enumeration e=M.getTargets().elements();
while (e.hasMoreElements()&&t.hasMoreTokens()) {
final ConstructionObject o=(ConstructionObject) e.nextElement();
o.getTranslation().setName(t.nextToken().trim());
}
zc.repaint();
}
public Macro getM() {
return M;
}
}