CaRMtl/rene/zirkel/tools/ObjectTracker.java

1295 lines
44 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.tools;
// file: ObjectTracker.java
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import java.util.Vector;
import rene.util.xml.XmlTag;
import rene.util.xml.XmlTree;
import rene.util.xml.XmlWriter;
import rene.gui.Global;
import rene.zirkel.ZirkelCanvas;
import rene.zirkel.construction.Construction;
import rene.zirkel.construction.ConstructionException;
import rene.zirkel.construction.Selector;
import rene.zirkel.constructors.ObjectConstructor;
import rene.zirkel.graphics.MyGraphics;
import rene.zirkel.graphics.PolygonDrawer;
import rene.zirkel.graphics.TrackPainter;
import rene.zirkel.objects.AreaObject;
import rene.zirkel.objects.CircleObject;
import rene.zirkel.objects.ConstructionObject;
import rene.zirkel.objects.ExpressionObject;
import rene.zirkel.objects.FunctionObject;
import rene.zirkel.objects.MoveableObject;
import rene.zirkel.objects.PointObject;
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.TrackObject;
import rene.zirkel.structures.Coordinates;
import rene.zirkel.objects.JLocusTrackObject;
public class ObjectTracker extends ObjectConstructor implements TrackPainter,
Runnable, Selector {
public PointObject PM;
public ConstructionObject O, P;
public int PMax=16, PN;
public ConstructionObject PO[]=new ConstructionObject[PMax];
Vector V=new Vector(), VPM=new Vector();
Vector VO[]=new Vector[PMax];
boolean Animate, Paint;
public boolean Interactive=true;
boolean Other=false;
public ZirkelCanvas ZC;
public ObjectTracker() {
}
public ObjectTracker(final ConstructionObject p, final PointObject pm,
final ConstructionObject o, final ZirkelCanvas zc,
final boolean animate, final boolean paint,
final ConstructionObject po[]) {
P=p;
PM=pm;
O=o;
if (P!=null&&O!=null&&(PM!=null||(O instanceof ExpressionObject))) {
Animate=animate;
Paint=paint;
if (PM!=null) {
PM.project(O);
}
zc.validate();
zc.repaint();
showStatus(zc);
PN=0;
for (int i=0; i<po.length; i++) {
if (i>=PMax||po[i]==null) {
break;
}
PO[PN]=po[i];
VO[i]=new Vector();
PN++;
}
}
}
public boolean isAdmissible(final ZirkelCanvas zc,
final ConstructionObject o) {
if (O==null) {
if (o instanceof ExpressionObject&&((ExpressionObject) o).isSlider()) {
return true;
}
if (o instanceof PrimitiveLineObject) {
return true;
}
if (o instanceof PrimitiveCircleObject) {
return true;
}
if (o instanceof PointObject&&((PointObject) o).isPointOn()) {
return true;
}
return false;
} else {
if (!(o instanceof PointObject)) {
return false;
}
if (!((MoveableObject) o).moveable()) {
return false;
}
if ((O instanceof CircleObject)&&((CircleObject) O).getP2()==o) {
return true;
}
if (zc.depends(O, o)) {
return false;
}
final ConstructionObject bound=((PointObject) o).getBound();
if (bound!=null&&bound!=O) {
return false;
}
return true;
}
}
@Override
public void mousePressed(final MouseEvent e, final ZirkelCanvas zc) {
zc.y(e.getY());
if (P==null) // no point selected yet
{
P=zc.selectPoint(e.getX(), e.getY());
if (P==null) {
P=zc.selectLine(e.getX(), e.getY());
}
if (P!=null) {
P.setSelected(true);
zc.repaint();
}
if (e.isShiftDown()) {
Other=true;
PN=0;
} else {
Other=false;
}
showStatus(zc);
} else if (Other) // want more points to track
{
ConstructionObject P=zc.selectPoint(e.getX(), e.getY());
if (P==null) {
P=zc.selectLine(e.getX(), e.getY());
}
if (P!=null) {
P.setSelected(true);
zc.repaint();
PO[PN]=P;
VO[PN]=new Vector();
PN++;
}
if (!e.isShiftDown()||PN>=PMax) {
Other=false;
}
showStatus(zc);
} else if (O==null) // no object to track on yet
{
O=zc.selectWithSelector(e.getX(), e.getY(), this);
if (O instanceof ExpressionObject) {
zc.clearSelected();
zc.clearIndicated();
Animate=!e.isShiftDown();
Paint=true;
compute(zc);
ZC=zc;
if (Animate) {
zc.validate();
}
zc.repaint();
} else if (O instanceof PointObject&&((PointObject) O).isPointOn()) {
PM=(PointObject) O;
O=PM.getBound();
zc.clearSelected();
zc.clearIndicated();
Animate=!e.isShiftDown();
Paint=true;
compute(zc);
ZC=zc;
if (Animate) {
zc.validate();
}
zc.repaint();
} else {
if (O!=null) {
O.setSelected(true);
zc.repaint();
}
showStatus(zc);
}
} else if (PM==null&&!(O instanceof ExpressionObject)) {
final ConstructionObject pm=zc.selectWithSelector(e.getX(), e.getY(), this);
if (pm==null) {
return;
}
PM=(PointObject) pm;
zc.clearSelected();
zc.clearIndicated();
Animate=!e.isShiftDown();
Paint=true;
compute(zc);
ZC=zc;
if (Animate) {
zc.validate();
}
zc.repaint();
} else if (!e.isControlDown()&&!e.isShiftDown()&&!e.isAltDown()) {
if (!Running&&Interactive&&PM!=null&&PM.nearto(e.getX(), e.getY(), zc)) {
Dragging=true;
zc.getConstruction().shouldSwitch(true);
} else if (Animate) {
if (Paint) {
Paint=false;
} else {
Animate=false;
Paint=true;
if (Running) {
stop();
}
showStatus(zc);
}
} else {
if (Running) {
return;
}
Paint=true;
Animate=true;
compute(zc);
zc.validate();
zc.repaint();
showStatus(zc);
}
}
}
@Override
public void mouseMoved(final MouseEvent e, final ZirkelCanvas zc,
final boolean simple) {
if (PM!=null) {
return;
}
if (P==null||Other) {
zc.indicatePointsOrLines(e.getX(), e.getY());
} else if (O==null) {
zc.indicateWithSelector(e.getX(), e.getY(), this);
} else {
zc.indicateWithSelector(e.getX(), e.getY(), this);
}
}
@Override
public void mouseDragged(final MouseEvent e, final ZirkelCanvas zc) {
if (!Dragging||PM==null) {
return;
}
PM.getY();
PM.move(zc.x(e.getX()), zc.y(e.getY()));
zc.dovalidate();
if (P.valid()) {
zc.repaint();
}
}
@Override
public void mouseReleased(final MouseEvent e, final ZirkelCanvas zc) {
if (!Dragging||PM==null) {
return;
}
zc.getConstruction().shouldSwitch(false);
Dragging=false;
zc.validate();
}
@Override
public void reset(final ZirkelCanvas zc) {
zc.clearSelected();
if (Running) {
stop();
}
PM=null;
P=O=null;
V=new Vector();
PN=0;
for (int i=0; i<PMax; i++) {
VO[i]=null;
}
zc.repaint();
showStatus(zc);
Omit=1;
}
@Override
public void showStatus(final ZirkelCanvas zc) {
if (P==null||Other) {
zc.showStatus(Global.name("message.objecttracker.select"));
} else if (O==null) {
zc.showStatus(Global.name("message.objecttracker.object"));
} else if (PM==null&&!(O instanceof ExpressionObject)) {
zc.showStatus(Global.name("message.objecttracker.selectpoint"));
} else if (Running) {
zc.showStatus(Global.name("message.objecttracker.stop"));
} else {
zc.showStatus(Global.name("message.objecttracker.start"));
}
}
public Enumeration elements() {
return V.elements();
}
public void paint(final MyGraphics g, final ZirkelCanvas zc) {
if (!isComplete()) {
return;
}
if (P==null||!Paint) {
return;
}
Coordinates C;
Enumeration e=V.elements();
double c0, r0, c, r;
g.setColor(P);
PolygonDrawer pd=new PolygonDrawer(false,g, P);
if (e.hasMoreElements()) {
C=(Coordinates) e.nextElement();
c0=zc.col(C.X);
r0=zc.row(C.Y);
pd.startPolygon(c0, r0);
while (e.hasMoreElements()) {
C=(Coordinates) e.nextElement();
c=zc.col(C.X);
r=zc.row(C.Y);
if (Math.abs(c0-c)<100&&Math.abs(r0-r)<100) {
pd.drawTo(c, r);
} else {
pd.finishPolygon();
}
c0=c;
r0=r;
}
pd.finishPolygon();
}
for (int i=0; i<PN; i++) {
e=VO[i].elements();
g.setColor(PO[i]);
pd=new PolygonDrawer(false,g, PO[i]);
if (e.hasMoreElements()) {
C=(Coordinates) e.nextElement();
c0=zc.col(C.X);
r0=zc.row(C.Y);
pd.startPolygon(c0, r0);
while (e.hasMoreElements()) {
C=(Coordinates) e.nextElement();
c=zc.col(C.X);
r=zc.row(C.Y);
if (Math.abs(c0-c)<100&&Math.abs(r0-r)<100) {
pd.drawTo(c, r);
} else {
pd.finishPolygon();
}
c0=c;
r0=r;
}
}
pd.finishPolygon();
}
}
boolean Running=false, Stopped=false;
public void validate(final ZirkelCanvas zc) {
if (!isComplete()) {
return;
}
if (O instanceof ExpressionObject&&!((ExpressionObject) O).isSlider()) {
return;
}
if (Running) {
return;
}
if (PM!=null) {
PM.project(O);
oldx=PM.getX();
oldy=PM.getY();
} else if (O instanceof ExpressionObject) {
oldx=((ExpressionObject) O).getSliderPosition();
}
compute(zc);
if (Animate) {
ZC=zc;
new Thread(this).start();
} else {
if (PM!=null) {
PM.move(oldx, oldy);
}
zc.dovalidate();
zc.repaint();
}
}
double da=0;
double oldx, oldy;
double X, Y, DX, DY;
double XO[]=new double[PMax], YO[]=new double[PMax],
DXO[]=new double[PMax], DYO[]=new double[PMax];
int Omit=1;
public void animate(final ZirkelCanvas zc) {
if (!isComplete()) {
return;
}
zc.getConstruction().clearSwitches();
zc.getConstruction().shouldSwitch(true);
final Enumeration e=VPM.elements();
final Enumeration ev=V.elements();
long time=System.currentTimeMillis();
int i=0;
boolean start=false;
final Graphics ZCG=ZC.getGraphics();
while (e.hasMoreElements()) {
final Coordinates c=(Coordinates) e.nextElement();
final Coordinates cv=(Coordinates) ev.nextElement();
if (PM==null&&!(O instanceof ExpressionObject)) {
break;
}
synchronized (zc) {
if (PM!=null) {
PM.move(c.X, c.Y);
} else if (O instanceof ExpressionObject) {
((ExpressionObject) O).setSliderPosition(c.X);
}
if (!start) {
zc.resetSum();
start=true;
}
}
zc.dovalidate();
i++;
if (i<Omit) {
continue;
}
i=0;
if (zc.isInside(cv.X, cv.Y)) {
if (P!=null&&P.valid()) {
ZC.paint(ZCG);
}
try {
final long t=System.currentTimeMillis();
int h=(int) (t-time);
if (h<0) {
h=0;
}
if (h>50) {
h=50;
}
Thread.sleep(50-h);
time=System.currentTimeMillis();
} catch (final Exception ex) {
}
}
if (Stopped) {
break;
}
}
ZCG.dispose();
zc.getConstruction().shouldSwitch(false);
zc.getConstruction().clearSwitches();
}
public ConstructionObject getObject() {
return O;
}
double mod(final double x) {
if (x>=Math.PI) {
return x-2*Math.PI;
}
if (x<-Math.PI) {
return x+2*Math.PI;
}
return x;
}
public void run() {
if (O instanceof ExpressionObject&&!((ExpressionObject) O).isSlider()) {
return;
}
if (V.size()==0) {
return;
}
if (!Animate) {
return;
}
Running=true;
Stopped=false;
showStatus(ZC);
while (true) {
try {
Thread.sleep(100);
} catch (final Exception ex) {
}
if (ZC.I!=null) {
break;
}
}
while (true) {
if (PM!=null) {
PM.move(oldx, oldy);
} else if (O instanceof ExpressionObject) {
((ExpressionObject) O).setSliderPosition(oldx);
}
animate(ZC);
if (Stopped) {
break;
}
}
if (PM!=null&&!(O instanceof ExpressionObject)) {
if (PM!=null) {
PM.move(oldx, oldy);
} else if (O instanceof ExpressionObject) {
((ExpressionObject) O).setSliderPosition(oldx);
}
ZC.getConstruction().switchBack();
ZC.dovalidate();
ZC.repaint();
}
synchronized (this) {
notify();
}
Running=false;
showStatus(ZC);
}
@Override
public void invalidate(final ZirkelCanvas zc) {
stop();
}
public void stop() {
if (!Running) {
return;
}
Stopped=true;
try {
wait();
} catch (final Exception e) {
}
ZC.repaint();
showStatus(ZC);
}
public void save(final XmlWriter xml) {
if (P==null||O==null||(PM==null&&!(O instanceof ExpressionObject))) {
return;
}
xml.startTagStart("Track");
xml.printArg("track", P.getName());
for (int i=0; i<PN; i++) {
xml.printArg("track"+i, PO[i].getName());
}
xml.printArg("on", O.getName());
if (PM!=null) {
xml.printArg("move", PM.getName());
}
if (Animate&&Paint) {
xml.printArg("animate", "true");
} else if (Animate&&!Paint) {
xml.printArg("animate", "nopaint");
}
if (Omit>1) {
xml.printArg("omit", ""+(Omit-1));
}
xml.finishTagNewLine();
}
@Override
public void pause(final boolean flag) {
if (flag) {
if (Running) {
stop();
}
}
}
/**
* This is the update function, calling docompute.
*
* @param zc
*/
public synchronized void compute(final ZirkelCanvas zc) {
if (!isComplete()) {
return;
}
double x=0, y=0;
if (PM!=null) {
x=PM.getX();
y=PM.getY();
} else if (O instanceof ExpressionObject) {
x=((ExpressionObject) O).getSliderPosition();
}
zc.getConstruction().clearSwitches();
zc.getConstruction().shouldSwitch(true);
docompute(zc);
zc.getConstruction().shouldSwitch(false);
zc.getConstruction().clearSwitches();
if (PM!=null) {
PM.move(x, y);
} else if (O instanceof ExpressionObject) {
((ExpressionObject) O).setSliderPosition(x);
}
zc.dovalidate();
}
/**
* Complicated procedure to recompute the automatic track. In principle, a
* moving point moves on some object, the coordinates of the tracked points
* or the intersections of the tracked lines are stored, as well as the
* positions of the moved point. But if the tracked point gets invalid, the
* movement reverses and the interesections change. Moreover, there is a
* list of secondary tracked objects.
*
* @param zc
*/
public synchronized void docompute(final ZirkelCanvas zc) {
V=new Vector();
for (int i=0; i<PN; i++) {
VO[i]=new Vector();
}
VPM=new Vector();
// Running on a circle:
if (O instanceof PrimitiveCircleObject) {
zc.getConstruction().shouldSwitch(false);
final PrimitiveCircleObject c=(PrimitiveCircleObject) O;
final double x=c.getX(), y=c.getY(), r=c.getR();
PM.project(c);
double amin=0, amax=0, astart=0, anull=0;
final double dmax=0.5;
boolean range=false;
if (c.hasRange()) {
range=true;
final double a1=c.getA1();
final double a2=c.getA2();
double d=a2-a1;
while (d<0) {
d+=2*Math.PI;
}
while (d>=2*Math.PI) {
d-=2*Math.PI;
}
amin=astart=-d/2;
amax=d/2;
anull=(a1+a2)/2;
} else {
amin=astart=-Math.PI*0.9999;
amax=Math.PI*0.9999;
}
double a=astart;
PM.move(x+r*Math.cos(anull+a), y+r*Math.sin(anull+a));
PM.project(c);
zc.getConstruction().validate(P, PM);
zc.resetSum();
double x1=0, y1=0;
boolean started=false;
if (P.valid()) {
zc.getConstruction().shouldSwitch(true);
if (P instanceof PointObject) {
final PointObject p=(PointObject) P;
x1=p.getX();
y1=p.getY();
V.addElement(new Coordinates(x1, y1));
VPM.addElement(new Coordinates(PM.getX(), PM.getY()));
started=true;
} else if (P instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) P;
X=L.getX();
Y=L.getY();
DX=L.getDX();
DY=L.getDY();
started=true;
}
}
final boolean startedO[]=new boolean[PMax];
for (int i=0; i<PN; i++) {
startedO[i]=false;
}
final long time=System.currentTimeMillis();
addSecondary(startedO, zc);
final double dmin=0.001;
if (da<1e-10||da>zc.dx(1)) {
da=zc.dx(1)/10;
}
double aold=a;
double x2=0, y2=0;
while (true) {
a=a+da;
boolean Break=false;
if ((!started||range)&&a>=amax) {
a=amax;
Break=true;
} else if ((!started||range)&&a<=amin) {
a=amin;
Break=true;
} else if (started&&da>0) {
if ((mod(aold-astart)<0&&mod(a-astart)>=0)&&!zc.getConstruction().haveSwitched()) {
Break=true;
a=astart;
}
}
aold=a;
PM.move(x+r*Math.cos(anull+a), y+r*Math.sin(anull+a));
PM.project(c);
zc.getConstruction().validate(P, PM);
if (P.valid()) {
if (!started) {
zc.getConstruction().shouldSwitch(true);
astart=a;
}
boolean valid=false;
if (P instanceof PointObject) {
final PointObject p=(PointObject) P;
x2=p.getX();
y2=p.getY();
valid=true;
} else if (P instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) P;
if (!started) {
X=L.getX();
Y=L.getY();
DX=L.getDX();
DY=L.getDY();
} else {
double xx, yy, dx, dy;
xx=L.getX();
yy=L.getY();
dx=L.getDX();
dy=L.getDY();
final double det=dx*DY-dy*DX;
if (Math.sqrt(Math.abs(det))>1e-9) {
final double h=(-(X-xx)*DY+DX*(Y-yy))/(-det);
x2=xx+h*dx;
y2=yy+h*dy;
valid=true;
}
X=xx;
Y=yy;
DX=dx;
DY=dy;
}
}
final double dist=zc.dCenter(x2, y2);
final boolean different=((int) zc.col(x1)!=(int) zc.col(x2)||(int) zc.row(y1)!=(int) zc.row(y2));
if (valid&&different) {
V.addElement(new Coordinates(x2, y2));
VPM.addElement(new Coordinates(PM.getX(), PM.getY()));
}
final double dp=Math.abs(x2-x1)+Math.abs(y2-y1);
da=updateDA(da, valid, dist, dp, dmin, dmax, zc);
x1=x2;
y1=y2;
started=true;
} else if (started) {
V.addElement(new Coordinates(x2, y2));
VPM.addElement(new Coordinates(PM.getX(), PM.getY()));
da=-da;
}
addSecondary(startedO, zc);
if (Break||System.currentTimeMillis()-time>5000) {
break;
}
}
} // Running on a line:
else if (O instanceof PrimitiveLineObject) {
zc.getConstruction().shouldSwitch(false);
final PrimitiveLineObject l=(PrimitiveLineObject) O;
PM.project(l);
final double lx=l.getX(), ly=l.getY(), ldx=l.getDX(), ldy=l.getDY();
double amin=0, amax=0, astart=0;
double dmax=0.5;
boolean range=false;
if (l instanceof RayObject) {
amin=astart=0;
amax=Math.PI*0.9999;
range=true;
} else if (l instanceof SegmentObject) {
amin=astart=0;
final double r=((SegmentObject) l).getLength();
System.out.println(r);
dmax=r/20;
amax=Math.atan(r)*2;
range=true;
} else {
amin=astart=-Math.PI*0.99999;
amax=Math.PI*0.9999;
}
double a=astart;
double hd=Math.tan(mod(a)/2);
PM.move(lx+hd*ldx, ly+hd*ldy);
PM.project(l);
zc.getConstruction().validate(P, PM);
zc.resetSum();
double x1=0, y1=0;
boolean started=false;
if (P.valid()) {
zc.getConstruction().shouldSwitch(true);
if (P instanceof PointObject) {
final PointObject p=(PointObject) P;
x1=p.getX();
y1=p.getY();
V.addElement(new Coordinates(x1, y1));
VPM.addElement(new Coordinates(PM.getX(), PM.getY()));
started=true;
} else if (P instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) P;
X=L.getX();
Y=L.getY();
DX=L.getDX();
DY=L.getDY();
started=true;
}
}
final boolean startedO[]=new boolean[PMax];
for (int i=0; i<PN; i++) {
startedO[i]=false;
}
final long time=System.currentTimeMillis();
addSecondary(startedO, zc);
final double dmin=0.001;
if (da<1e-10||da>zc.dx(1)) {
da=zc.dx(1)/10;
}
double aold=a;
double x2=0, y2=0;
while (true) {
a=a+da;
boolean Break=false;
if ((!started||range)&&a>=amax) {
a=amax;
Break=true;
} else if ((!started||range)&&a<=amin) {
a=amin;
Break=true;
} else if (started&&da>0) {
if ((mod(aold-astart)<0&&mod(a-astart)>=0)&&!zc.getConstruction().haveSwitched()) {
Break=true;
a=astart;
}
}
aold=a;
hd=Math.tan(mod(a)/2);
PM.move(lx+hd*ldx, ly+hd*ldy);
PM.project(l);
zc.getConstruction().validate(P, PM);
if (P.valid()) {
if (!started) {
zc.getConstruction().shouldSwitch(true);
astart=a;
}
boolean valid=false;
if (P instanceof PointObject) {
final PointObject p=(PointObject) P;
x2=p.getX();
y2=p.getY();
valid=true;
} else if (P instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) P;
if (!started) {
X=L.getX();
Y=L.getY();
DX=L.getDX();
DY=L.getDY();
} else {
double xx, yy, dx, dy;
xx=L.getX();
yy=L.getY();
dx=L.getDX();
dy=L.getDY();
final double det=dx*DY-dy*DX;
if (Math.sqrt(Math.abs(det))>1e-9) {
final double h=(-(X-xx)*DY+DX*(Y-yy))/(-det);
x2=xx+h*dx;
y2=yy+h*dy;
valid=true;
}
X=xx;
Y=yy;
DX=dx;
DY=dy;
}
}
final double dist=zc.dCenter(x2, y2);
final boolean different=((int) zc.col(x1)!=(int) zc.col(x2)||(int) zc.row(y1)!=(int) zc.row(y2));
if (valid&&different) {
V.addElement(new Coordinates(x2, y2));
VPM.addElement(new Coordinates(PM.getX(), PM.getY()));
}
final double dp=Math.abs(x2-x1)+Math.abs(y2-y1);
da=updateDA(da, valid, dist, dp, dmin, dmax, zc);
x1=x2;
y1=y2;
started=true;
} else if (started) {
V.addElement(new Coordinates(x2, y2));
VPM.addElement(new Coordinates(PM.getX(), PM.getY()));
da=-da;
}
addSecondary(startedO, zc);
if (Break||System.currentTimeMillis()-time>5000) {
break;
}
}
} // Running an expression slider:
else if (O instanceof ExpressionObject) {
zc.getConstruction().shouldSwitch(false);
final ExpressionObject eo=(ExpressionObject) O;
if (!eo.isSlider()) {
return;
}
double amin=0, amax=0, astart=0;
double dmax=0.5;
boolean range=false;
amin=astart=0;
final double r=1;
dmax=r/20;
amax=Math.atan(r)*2;
range=true;
double a=astart;
double hd=Math.tan(mod(a)/2);
eo.setSliderPosition(0);
zc.getConstruction().validate(P, null);
zc.resetSum();
double x1=0, y1=0;
boolean started=false;
if (P.valid()) {
zc.getConstruction().shouldSwitch(true);
if (P instanceof PointObject) {
final PointObject p=(PointObject) P;
x1=p.getX();
y1=p.getY();
V.addElement(new Coordinates(x1, y1));
VPM.addElement(new Coordinates(eo.getSliderPosition(), 0));
started=true;
} else if (P instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) P;
X=L.getX();
Y=L.getY();
DX=L.getDX();
DY=L.getDY();
started=true;
}
}
final boolean startedO[]=new boolean[PMax];
for (int i=0; i<PN; i++) {
startedO[i]=false;
}
final long time=System.currentTimeMillis();
addSecondary(startedO, zc);
final double dmin=0.001;
if (da<1e-10||da>zc.dx(1)) {
da=zc.dx(1)/10;
}
double aold=a;
double x2=0, y2=0;
while (true) {
a=a+da;
boolean Break=false;
if ((!started||range)&&a>=amax) {
a=amax;
Break=true;
} else if ((!started||range)&&a<=amin) {
a=amin;
Break=true;
} else if (started&&da>0) {
if ((mod(aold-astart)<0&&mod(a-astart)>=0)&&!zc.getConstruction().haveSwitched()) {
Break=true;
a=astart;
}
}
aold=a;
hd=Math.tan(mod(a)/2);
eo.setSliderPosition(hd);
zc.getConstruction().validate(P, null);
if (P.valid()) {
if (!started) {
zc.getConstruction().shouldSwitch(true);
astart=a;
}
boolean valid=false;
if (P instanceof PointObject) {
final PointObject p=(PointObject) P;
x2=p.getX();
y2=p.getY();
valid=true;
} else if (P instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) P;
if (!started) {
X=L.getX();
Y=L.getY();
DX=L.getDX();
DY=L.getDY();
} else {
double xx, yy, dx, dy;
xx=L.getX();
yy=L.getY();
dx=L.getDX();
dy=L.getDY();
final double det=dx*DY-dy*DX;
if (Math.sqrt(Math.abs(det))>1e-9) {
final double h=(-(X-xx)*DY+DX*(Y-yy))/(-det);
x2=xx+h*dx;
y2=yy+h*dy;
valid=true;
}
X=xx;
Y=yy;
DX=dx;
DY=dy;
}
}
final double dist=zc.dCenter(x2, y2);
final boolean different=((int) zc.col(x1)!=(int) zc.col(x2)||(int) zc.row(y1)!=(int) zc.row(y2));
if (valid&&different) {
V.addElement(new Coordinates(x2, y2));
VPM.addElement(new Coordinates(eo.getSliderPosition(),
0));
}
final double dp=Math.abs(x2-x1)+Math.abs(y2-y1);
da=updateDA(da, valid, dist, dp, dmin, dmax, zc);
x1=x2;
y1=y2;
started=true;
} else if (started) {
V.addElement(new Coordinates(x2, y2));
VPM.addElement(new Coordinates(eo.getSliderPosition(), 0));
da=-da;
}
addSecondary(startedO, zc);
if (Break||System.currentTimeMillis()-time>5000) {
break;
}
}
}
}
public void addSecondary(final boolean startedO[], final ZirkelCanvas zc) {
for (int i=0; i<PN; i++) {
if (PM!=null) {
zc.getConstruction().validate(PO[i], PM);
} else {
zc.getConstruction().validate(PO[i], O);
}
if (!PO[i].valid()) {
continue;
}
if (PO[i] instanceof PointObject) {
final PointObject p=(PointObject) PO[i];
VO[i].addElement(new Coordinates(p.getX(), p.getY()));
} else if (PO[i] instanceof PrimitiveLineObject) {
final PrimitiveLineObject L=(PrimitiveLineObject) PO[i];
if (!startedO[i]) {
XO[i]=L.getX();
YO[i]=L.getY();
DXO[i]=L.getDX();
DYO[i]=L.getDY();
startedO[i]=true;
} else {
double xx, yy, dx, dy;
xx=L.getX();
yy=L.getY();
dx=L.getDX();
dy=L.getDY();
final double det=dx*DYO[i]-dy*DXO[i];
if (Math.sqrt(Math.abs(det))>1e-9) {
final double h=(-(XO[i]-xx)*DYO[i]+DXO[i]*(YO[i]-yy))/(-det);
XO[i]=xx;
YO[i]=yy;
DXO[i]=dx;
DYO[i]=dy;
VO[i].addElement(new Coordinates(xx+h*dx, yy+h*dy));
}
}
}
}
}
public double StepSize=5;
public double updateDA(double da, final boolean valid, final double dist,
final double dp, final double dmin, final double dmax,
final ZirkelCanvas zc) {
if (V.size()>0&&valid) {
if (dist<1.2) {
if (dp>zc.dx(StepSize)) {
da/=2;
} else if (dp<zc.dx(StepSize/2)) {
da*=2;
}
if (da>0&&da<dmin) {
da=dmin;
} else if (da<0&&da>-dmin) {
da=-dmin;
}
if (da>dmax) {
da=dmax;
} else if (da<-dmax) {
da=-dmax;
}
} else {
if (dp>zc.dx(StepSize*10)) {
da/=2;
} else if (dp<zc.dx(StepSize*5)) {
da*=2;
}
if (da>0&&da<dmin) {
da=dmin;
} else if (da<0&&da>-dmin) {
da=-dmin;
}
if (da>dmax) {
da=dmax;
} else if (da<-dmax) {
da=-dmax;
}
}
}
return da;
}
public void increaseOmit() {
Omit++;
}
public void decreaseOmit() {
if (Omit>1) {
Omit--;
}
}
public void setOmit(final int f) {
Omit=f+1;
}
public boolean isComplete() {
return !(P==null||O==null||(PM==null&&!(O instanceof ExpressionObject&&((ExpressionObject) O).isSlider())));
}
public void keep(final ZirkelCanvas zc) {
if (!isComplete()) {
return;
}
final TrackObject t=new TrackObject(zc.getConstruction(), P, PO, PN,
O, PM);
zc.addObject(t);
t.setDefaults();
reset(zc);
t.compute(zc);
zc.validate();
}
@Override
public String getTag() {
return "Track";
}
@Override
public boolean construct(final XmlTree tree, final Construction c)
throws ConstructionException {
if (!testTree(tree, "Track")) {
return false;
}
final XmlTag tag=tree.getTag();
if (!tag.hasParam("on")||!tag.hasParam("track")) {
throw new ConstructionException("Track parameters missing!");
} else {
try {
PointObject pm=null;
try {
pm=(PointObject) c.find(tag.getValue("point"));
} catch (final Exception ex) {
}
final ConstructionObject o=c.find(tag.getValue("on"));
if (pm==null&&!(o instanceof ExpressionObject)) {
throw new ConstructionException("");
}
final ConstructionObject p=c.find(tag.getValue("track"));
final ConstructionObject po[]=new ConstructionObject[PMax];
int pn=0;
for (pn=0; pn<PMax; pn++) {
if (!tag.hasParam("track"+pn)) {
break;
}
po[pn]=c.find(tag.getValue("track"+pn));
if (!(po[pn] instanceof PointObject||po[pn] instanceof PrimitiveLineObject)) {
throw new ConstructionException(
"Track parameters wrong!");
}
}
if (p==null||o==null) {
throw new ConstructionException("Track parameters wrong!");
}
if (!(p instanceof PointObject||p instanceof PrimitiveLineObject)) {
throw new ConstructionException("Track parameters wrong!");
}
if (!(o instanceof PrimitiveCircleObject||o instanceof PrimitiveLineObject||o instanceof QuadricObject||o instanceof AreaObject||o instanceof JLocusTrackObject||o instanceof ExpressionObject||o instanceof FunctionObject)) {
throw new ConstructionException("Track parameters wrong!");
}
TrackObject tr=null;
if (p instanceof PointObject) {
// Il s'agit d'un lieu de point (on utilise le nouvel objet)
tr=new JLocusTrackObject(c, p, po, pn, o, pm);
} else {
// Il s'agit d'une enveloppe de droite (on utilise l'ancien objet)
tr=new TrackObject(c, p, po, pn, o, pm);
}
// final JLocusTrackObject tr = new JLocusTrackObject(c, p, po,
// pn, o, pm);
// final TrackObject tr = new TrackObject(c, p, po,
// pn, o, pm);
if (tag.hasParam("filled")) {
tr.setFilled(true);
}
if (tag.hasParam("fixed")) {
tr.setFixed(true);
}
if (tag.hasParam("dmin")) {
try {
final double db=new Double(tag.getValue("dmin")).doubleValue();
// if (db<0.005) db=0.005;
tr.setDMin(db);
} catch (final Exception e) {
throw new ConstructionException(
"Track parameters wrong!");
}
}
if (tag.hasTrueParam("discrete")) {
tr.setDiscrete(true);
}
setType(tag, tr);
setName(tag, tr);
set(tree, tr);
c.add(tr);
setConditionals(tree, c, tr);
return true;
} catch (final ConstructionException e) { // e.printStackTrace();
throw e;
} catch (final Exception e) { // e.printStackTrace();
throw new ConstructionException("Track Parameters wrong!");
}
}
}
public void setType(final XmlTag tag, final TrackObject p) {
if (tag.hasParam("shape")) {
final String s=tag.getValue("shape");
if (s.equals("square")) {
p.setType(0);
}
if (s.equals("diamond")) {
p.setType(1);
}
if (s.equals("circle")) {
p.setType(2);
}
if (s.equals("dot")) {
p.setType(3);
}
if (s.equals("cross")) {
p.setType(4);
}
if (s.equals("dcross")) {
p.setType(5);
}
}
}
}