1295 lines
44 KiB
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);
|
|
}
|
|
}
|
|
}
|
|
}
|