1402 lines
35 KiB
Java
1402 lines
35 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.objects;
|
|
|
|
// file: Functionbject.java
|
|
import java.util.Enumeration;
|
|
import java.util.StringTokenizer;
|
|
import java.util.Vector;
|
|
import rene.gui.Global;
|
|
import rene.util.xml.XmlWriter;
|
|
import rene.zirkel.ZirkelCanvas;
|
|
import rene.zirkel.construction.Construction;
|
|
import rene.zirkel.construction.ConstructionException;
|
|
import rene.zirkel.expression.Expression;
|
|
import rene.zirkel.expression.ExpressionColor;
|
|
import rene.zirkel.expression.InvalidException;
|
|
import rene.zirkel.graphics.FunctionPolygonFiller;
|
|
import rene.zirkel.graphics.MyGraphics;
|
|
import rene.zirkel.graphics.PolygonDrawer;
|
|
import rene.zirkel.structures.Coordinates;
|
|
|
|
|
|
/**
|
|
* @author Rene
|
|
*
|
|
* Function objects are parametric or cartesian curves. For parametric
|
|
* functions, depending on a parameter t , x(t) and y(t) are computed
|
|
* and drawn on the screen. For cartesian functions, the parameter x
|
|
* will be used.
|
|
*
|
|
*/
|
|
public class FunctionObject extends ConstructionObject implements
|
|
PointonObject, HeavyObject, DriverObject, Evaluator {
|
|
|
|
Expression EX = null, EY = null;
|
|
public Expression VarMin = null, VarMax = null, DVar = null;
|
|
String LASTEX = "", LASTEY = "", LASTVarMin = "", LASTVarMax = "", LASTDVar = "";
|
|
double X[] = { 0 };
|
|
public String Var[] = { "x" };
|
|
boolean Filled = false;
|
|
Expression Center = null;
|
|
protected int Type = 0;
|
|
public final static int SQUARE = 0, DIAMOND = 1, CIRCLE = 2, DOT = 3,
|
|
CROSS = 4, DCROSS = 5;
|
|
protected boolean Special = false;
|
|
// Vector RefreshList=new Vector();
|
|
public Vector V = new Vector();
|
|
double cx, cy, ww, wh;
|
|
// this is a main object list which tells if the object needs to recompute :
|
|
Vector DriverObjectList = new Vector();
|
|
double c0, r0, c, r;
|
|
private boolean isMinClosed, isMinOpen, isMaxClosed, isMaxOpen;
|
|
|
|
/**
|
|
* Functions are HeavyObjects which means we always must see if it really
|
|
* neads to recompute. Computing a function can be time consuming, but once
|
|
* it's computed, the paint method is fast enough.
|
|
*
|
|
* @param c
|
|
*/
|
|
public FunctionObject(final Construction c) {
|
|
super(c);
|
|
VarMin = new Expression("windowcx-windoww", c, this);
|
|
VarMax = new Expression("windowcx+windoww", c, this);
|
|
DVar = new Expression("0", c, this);
|
|
validate();
|
|
updateText();
|
|
cx = c.getX();
|
|
cy = c.getY();
|
|
ww = c.getW();
|
|
wh = c.getH();
|
|
Type = CROSS;
|
|
}
|
|
|
|
@Override
|
|
public void setDefaults() {
|
|
setShowName(Global.getParameter("options.locus.shownames", false));
|
|
setShowValue(Global.getParameter("options.locus.showvalues", false));
|
|
// setColor(Global.getParameter("options.locus.color", 0), Global
|
|
// .getParameter("options.locus.pcolor", (Color) null));
|
|
setColor(Global.getParameter("options.locus.color", 0));
|
|
setColorType(Global.getParameter("options.locus.colortype", 0));
|
|
setFilled(Global.getParameter("options.locus.filled", false));
|
|
setHidden(Cn.Hidden);
|
|
setObtuse(Cn.Obtuse);
|
|
setSolid(Cn.Solid);
|
|
setLarge(Cn.LargeFont);
|
|
setBold(Cn.BoldFont);
|
|
}
|
|
|
|
@Override
|
|
public void setTargetDefaults() {
|
|
setShowName(Global.getParameter("options.locus.shownames", false));
|
|
setShowValue(Global.getParameter("options.locus.showvalues", false));
|
|
setColor(Global.getParameter("options.locus.color", 0), Global.getParameter("options.locus.pcolor", (ExpressionColor) null, this));
|
|
setColorType(Global.getParameter("options.locus.colortype", 0));
|
|
setFilled(Global.getParameter("options.locus.filled", false));
|
|
setHidden(Cn.Hidden);
|
|
setObtuse(Cn.Obtuse);
|
|
setSolid(Cn.Solid);
|
|
setLarge(Cn.LargeFont);
|
|
setBold(Cn.BoldFont);
|
|
}
|
|
|
|
/**
|
|
* In order to see if the function must be recomputed or not, we have to
|
|
* register, in the DriverObjectList, all objects the function depends on.
|
|
* There are many possibilities for an object to be in this list : if it's
|
|
* used in the def of the function, if it's in the min or max text box,
|
|
* etc...
|
|
*
|
|
* @param c
|
|
*/
|
|
@Override
|
|
public void searchDependencies(final Construction c) {
|
|
DriverObjectList.clear();
|
|
if (RekValidating) {
|
|
return;
|
|
} // should not happen!
|
|
RekValidating = true;
|
|
Enumeration e = c.elements();
|
|
while (e.hasMoreElements()) {
|
|
((ConstructionObject) e.nextElement()).setRekFlag(false);
|
|
}
|
|
final ConstructionObject oEX[] = EX.getDepList().getArray();
|
|
final ConstructionObject oEY[] = EY.getDepList().getArray();
|
|
final ConstructionObject oVarMin[] = VarMin.getDepList().getArray();
|
|
final ConstructionObject oVarMax[] = VarMax.getDepList().getArray();
|
|
final ConstructionObject oDVar[] = DVar.getDepList().getArray();
|
|
|
|
for (final ConstructionObject element : oEX) {
|
|
recursiveSearchDependencies((ConstructionObject) element);
|
|
}
|
|
for (final ConstructionObject element : oEY) {
|
|
recursiveSearchDependencies((ConstructionObject) element);
|
|
}
|
|
for (final ConstructionObject element : oVarMin) {
|
|
recursiveSearchDependencies((ConstructionObject) element);
|
|
}
|
|
for (final ConstructionObject element : oVarMax) {
|
|
recursiveSearchDependencies((ConstructionObject) element);
|
|
}
|
|
for (final ConstructionObject element : oDVar) {
|
|
recursiveSearchDependencies((ConstructionObject) element);
|
|
}
|
|
|
|
e = c.elements();
|
|
while (e.hasMoreElements()) {
|
|
final ConstructionObject oc = (ConstructionObject) e.nextElement();
|
|
if ((oc.isRekFlag()) && (oc.isDriverObject())) {
|
|
DriverObjectList.addElement(oc);
|
|
}
|
|
}
|
|
RekValidating = false;
|
|
NeedsRecompute = true;
|
|
}
|
|
|
|
/**
|
|
* Recursive method called by the searchDependencies method
|
|
*
|
|
* @param o
|
|
*/
|
|
public void recursiveSearchDependencies(final ConstructionObject o) {
|
|
|
|
if (o.isRekFlag()) {
|
|
return;
|
|
}
|
|
o.setRekFlag(true);
|
|
final ConstructionObject d[] = o.getDepArray();
|
|
for (final ConstructionObject element : d) {
|
|
recursiveSearchDependencies(element);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Time consuming method which is called only if it's really necessary :
|
|
*/
|
|
@Override
|
|
public void compute() {
|
|
// Empty the vector which contains the point set of the plot :
|
|
V.clear();
|
|
if (!Valid) {
|
|
return;
|
|
}
|
|
|
|
// Initialisation of varmin, varmax and d (the step variable) :
|
|
double varmin, varmax, d;
|
|
try {
|
|
varmin = VarMin.getValue();
|
|
varmax = VarMax.getValue();
|
|
d = DVar.getValue();
|
|
if (varmin > varmax) {
|
|
final double h = varmin;
|
|
varmin = varmax;
|
|
varmax = h;
|
|
}
|
|
if (d < 0) {
|
|
d = -d;
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
// X[0] represents the 't' variable for parametric plots.
|
|
// When you give X[0] a t value, EX.getValue() and EY.getValue()
|
|
// automatically returns the x(t) and y(t) value.
|
|
// If it's a cartesian function, X[0] represents the 'x' value
|
|
// then EX.getValue() always returns x and EY.getValue() returns
|
|
// the f(x) value.
|
|
X[0] = varmin;
|
|
|
|
// If the function may have discontinuity problems, computing is
|
|
// slower, because it checks for each point if a segment will have
|
|
// to be displayed or not :
|
|
if (mayHaveDiscontinuityPb()) {
|
|
if (d == 0) {
|
|
try {
|
|
// if the user leaves the step text box empty in the
|
|
// properties bar, the step d will represents only one pixel
|
|
// :
|
|
d = new Expression("1/pixel", getConstruction(), this)
|
|
.getValue();
|
|
} catch (final Exception ex) {
|
|
}
|
|
// if the step d defined by user is too small, then correct it :
|
|
} else if (d < (varmax - varmin) / 1000) {
|
|
d = (varmax - varmin) / 1000;
|
|
}
|
|
|
|
double x1 = 0, y1 = 0, x2 = 0, y2 = 0, yM = 0, X0 = 0;
|
|
final int nbsteps = (int) Math.round((varmax - varmin) / d) + 1;
|
|
|
|
try {
|
|
x1 = EX.getValue();
|
|
y1 = EY.getValue();
|
|
V.add(new Coordinates(x1, y1, false));
|
|
} catch (final Exception ex) {
|
|
}
|
|
|
|
/*
|
|
* A(x1,y1=f(x1)) is the first point. B(x2,y2=f(x2)) is the second
|
|
* point. In order to know if a segment must join these two points,
|
|
* we compute the point M(xM,yM=f(xM)), where xM=(x1+x2)/2 :
|
|
*/
|
|
for (int i = 1; i < nbsteps; i++) {
|
|
try {
|
|
X0 = X[0];
|
|
X[0] += d / 2;
|
|
EX.getValue();
|
|
yM = EY.getValue();
|
|
X[0] += d / 2;
|
|
x2 = EX.getValue();
|
|
y2 = EY.getValue();
|
|
|
|
// If A,M and B are on the same horizontal line
|
|
// then segment must be drawn (true) :
|
|
if ((y1 == yM) && (y2 == yM)) {
|
|
V.add(new Coordinates(x2, y2, true));
|
|
|
|
// if f(xM) is in open interval ]f(x1),f(x2)[ :
|
|
} else if (((yM > y1) && (yM < y2))
|
|
|| ((yM > y2) && (yM < y1))) {
|
|
|
|
final double mm = Math.abs(y1 - yM) / Math.abs(y2 - yM);
|
|
|
|
// This is a weird thing, but it seems to work in
|
|
// lots of "basic" situations :
|
|
// If the distance |yM-y1| (or |yM-y2|)
|
|
// represents 10% of the distance |yM-y2| (or |yM-y1|)
|
|
// then may be it's a discontinuity problem, so
|
|
// don't draw the segment [AB] (false)
|
|
if ((mm < 0.1) || (mm > 10)) {
|
|
V.add(new Coordinates(x2, y2, false));
|
|
// Otherwise draw the segment [AB] :
|
|
} else {
|
|
V.add(new Coordinates(x2, y2, true));
|
|
}
|
|
// if f(xM) is not in interval [f(x1),f(x2)], don't
|
|
// draw the segment [AB] (false) :
|
|
} else {
|
|
V.add(new Coordinates(x2, y2, false));
|
|
}
|
|
|
|
x1 = x2;
|
|
y1 = y2;
|
|
} catch (final Exception ex) {
|
|
try {
|
|
X[0] = X0 + d;
|
|
x1 = EX.getValue();
|
|
y1 = EY.getValue();
|
|
V.add(new Coordinates(x1, y1, false));
|
|
} catch (final Exception ex1) {
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (d == 0) {
|
|
d = (varmax - varmin) / 100;
|
|
} else if (d < (varmax - varmin) / 1000) {
|
|
d = (varmax - varmin) / 1000;
|
|
}
|
|
final int nbsteps = (int) Math.round((varmax - varmin) / d) + 1;
|
|
for (int i = 0; i < nbsteps; i++) {
|
|
try {
|
|
V.add(new Coordinates(EX.getValue(), EY.getValue()));
|
|
} catch (final Exception ex) {
|
|
}
|
|
X[0] += d;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setNeedsToRecompte(final boolean n) {
|
|
NeedsRecompute = n;
|
|
}
|
|
|
|
/**
|
|
* Check all objects the function depends on. If one of the have changed,
|
|
* this function return true.
|
|
*
|
|
* @return
|
|
*/
|
|
@Override
|
|
public boolean needsToRecompute() {
|
|
boolean needs = false;
|
|
final Enumeration pl = DriverObjectList.elements();
|
|
while (pl.hasMoreElements()) {
|
|
final DriverObject oc = (DriverObject) pl.nextElement();
|
|
if (oc.somethingChanged()) {
|
|
// There is a "ClearList" which will be cleared
|
|
// at the end of the Construction.computeHeavyObjects method :
|
|
Global.addClearList(oc);
|
|
needs = true;
|
|
}
|
|
}
|
|
|
|
// Also needs to compute when user zoom or move figure in the window :
|
|
if ((Cn.getX() != cx) || (Cn.getY() != cy) || (Cn.getW() != ww)
|
|
|| (Cn.getH() != wh)) {
|
|
cx = Cn.getX();
|
|
cy = Cn.getY();
|
|
ww = Cn.getW();
|
|
wh = Cn.getH();
|
|
needs = true;
|
|
}
|
|
|
|
if (NeedsRecompute) {
|
|
NeedsRecompute = false;
|
|
return true;
|
|
}
|
|
|
|
return needs;
|
|
}
|
|
|
|
@Override
|
|
public void setFilled(final boolean flag) {
|
|
Filled = flag;
|
|
}
|
|
|
|
@Override
|
|
public boolean isFilled() {
|
|
return Filled;
|
|
}
|
|
|
|
@Override
|
|
public String getTag() {
|
|
return "Function";
|
|
}
|
|
|
|
@Override
|
|
public int getN() {
|
|
return N.next();
|
|
}
|
|
|
|
@Override
|
|
public void updateText() {
|
|
if (EX != null && EY != null) {
|
|
setText(text2(Global.name("text.function"), EX.toString(), EY
|
|
.toString()));
|
|
} else {
|
|
setText(text2(Global.name("text.function"), "", ""));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void validate() {
|
|
if (EX != null && EY != null) {
|
|
Valid = EX.isValid() && EY.isValid() && VarMin.isValid()
|
|
&& VarMax.isValid() && DVar.isValid();
|
|
} else {
|
|
Valid = false;
|
|
}
|
|
}
|
|
|
|
public void setExpressions(final String t, String ex, final String ey) {
|
|
|
|
final StringTokenizer tok = new StringTokenizer(t);
|
|
Var = new String[tok.countTokens()];
|
|
X = new double[tok.countTokens()];
|
|
int i = 0;
|
|
while (tok.hasMoreTokens()) {
|
|
Var[i++] = tok.nextToken();
|
|
}
|
|
if (ex.equals("")) {
|
|
ex = Var[0];
|
|
}
|
|
EX = new Expression(ex, getConstruction(), this, Var);
|
|
EY = new Expression(ey, getConstruction(), this, Var);
|
|
validate();
|
|
searchDependencies(Cn);
|
|
}
|
|
|
|
public boolean isCartesian() {
|
|
return EX.toString().equals("x");
|
|
}
|
|
|
|
public boolean mayHaveDiscontinuityPb() {
|
|
final String Pbs[] = { "floor(", "ceil(", "tan(", "sign(" };
|
|
// Continuity pbs are only checked for cartesian functions :
|
|
if (EX.toString().equals("x")) {
|
|
for (final String pb : Pbs) {
|
|
if ((EY.toString().indexOf(pb) != -1)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void setRange(final String min, final String max, final String d) {
|
|
VarMin = new Expression(min, getConstruction(), this);
|
|
VarMax = new Expression(max, getConstruction(), this);
|
|
DVar = new Expression(d, getConstruction(), this);
|
|
searchDependencies(Cn);
|
|
}
|
|
|
|
@Override
|
|
public String getEX() {
|
|
if (EX != null) {
|
|
return EX.toString();
|
|
} else {
|
|
return Var[0];
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getEY() {
|
|
if (EY != null) {
|
|
return EY.toString();
|
|
} else {
|
|
return "0";
|
|
}
|
|
}
|
|
|
|
FunctionPolygonFiller PF = null;
|
|
double C1, C2;
|
|
int C, R, W, H;
|
|
|
|
@Override
|
|
public void paint(final MyGraphics g, final ZirkelCanvas zc) {
|
|
if (!Valid || mustHide(zc)) {
|
|
return;
|
|
}
|
|
Coordinates C = null;
|
|
Enumeration e = V.elements();
|
|
double c, r;
|
|
g.setColor(this);
|
|
String s=getDisplayText();
|
|
if (!s.equals("")) {
|
|
g.setLabelColor(this);
|
|
setFont(g);
|
|
int n = s.length();
|
|
if(s.startsWith("$")){//crise de dollarophobie
|
|
s= s.substring(1, n-1);
|
|
}
|
|
if(V.size()>5){
|
|
//coordonnées du point d'attache
|
|
final Coordinates attache=(Coordinates) V.elementAt((int) Math.floor(V.size()/2+3));
|
|
final Coordinates precedent=(Coordinates) V.elementAt((int) Math.floor(V.size()/2)+2);
|
|
double Dx=attache.X-precedent.X;
|
|
double Dy=attache.Y-precedent.Y;
|
|
double norme=4*Math.sqrt(Dx*Dx+Dy*Dy);
|
|
drawLabel(g, "$\\mathcal{C}_{"+s+"}$", zc, attache.X, attache.Y,0,0, Dy/norme, -Dx/norme);
|
|
}
|
|
}
|
|
|
|
if (Special) {
|
|
if (Filled) {
|
|
PF = new FunctionPolygonFiller(g, this, zc.getY(), zc.getY() + zc.getHeight());
|
|
while (e.hasMoreElements()) {
|
|
C = (Coordinates) e.nextElement();
|
|
PF.add(zc.col(C.X), zc.row(C.Y));
|
|
}
|
|
PF.fillPolygon(zc.row(0));
|
|
e = V.elements();
|
|
g.setColor(this);
|
|
}
|
|
|
|
while (e.hasMoreElements()) {
|
|
C = (Coordinates) e.nextElement();
|
|
PointObject.drawPoint(g, zc, this, C.X, C.Y, Type);
|
|
}
|
|
} else if (Tracked) {
|
|
zc.UniversalTrack.TrackIG.setColor(this);
|
|
zc.UniversalTrack.setActive(true);
|
|
final PolygonDrawer pd = new PolygonDrawer(false,g, this);
|
|
final PolygonDrawer pdt = new PolygonDrawer(false,zc.UniversalTrack.TrackIG, this);
|
|
if (e.hasMoreElements()) {
|
|
C = (Coordinates) e.nextElement();
|
|
c0 = zc.col(C.X);
|
|
r0 = zc.row(C.Y);
|
|
pd.startPolygon(c0, r0);
|
|
pdt.startPolygon(c0, r0);
|
|
}
|
|
while (e.hasMoreElements()) {
|
|
C = (Coordinates) e.nextElement();
|
|
c = zc.col(C.X);
|
|
r = zc.row(C.Y);
|
|
if (Math.abs(pd.c() - c) < 1000 && Math.abs(pd.r() - r) < 1000) {
|
|
pd.drawTo(c, r);
|
|
pdt.drawTo(c, r);
|
|
} else {
|
|
pd.finishPolygon();
|
|
pdt.finishPolygon();
|
|
pd.startPolygon(c, r);
|
|
pdt.startPolygon(c, r);
|
|
}
|
|
}
|
|
pd.finishPolygon();
|
|
pdt.finishPolygon();
|
|
} else {
|
|
if (Filled) {
|
|
PF = new FunctionPolygonFiller(g, this, zc.getY(), zc.getY() + zc.getHeight());
|
|
while (e.hasMoreElements()) {
|
|
C = (Coordinates) e.nextElement();
|
|
PF.add(zc.col(C.X), zc.row(C.Y));
|
|
}
|
|
PF.fillPolygon(zc.row(0));
|
|
e = V.elements();
|
|
g.setColor(this);
|
|
}
|
|
final PolygonDrawer pd = new PolygonDrawer(false,g, this);
|
|
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 (C.join) {
|
|
pd.drawTo(c, r);
|
|
} else {
|
|
pd.finishPolygon();
|
|
pd.startPolygon(c, r);
|
|
}
|
|
}
|
|
pd.finishPolygon();
|
|
}
|
|
|
|
/***********************
|
|
* Painting the bounds *
|
|
***********************/
|
|
double w = 2*zc.pointSize()+2*zc.getOne(), x, y;
|
|
|
|
if(!VarMin.toString().equals("windowcx-windoww")) {
|
|
final Coordinates coord0 = (Coordinates) V.firstElement();
|
|
|
|
if(isMinClosed) {
|
|
x = zc.col(coord0.X) - zc.pointSize() - zc.getOne();
|
|
y = zc.row(coord0.Y) - zc.pointSize() - zc.getOne();
|
|
g.fillOval(x, y, w, w, this.getColor());
|
|
} else if(isMinOpen) {
|
|
//final Coordinates coord1 = (Coordinates) V.elementAt(Math.min(0, V.size()));
|
|
final Coordinates coord1 = (Coordinates) V.elementAt(V.size()==1?0:1);
|
|
double dx = zc.col(coord0.X) - zc.col(coord1.X);
|
|
double dy = zc.row(coord0.Y) - zc.row(coord1.Y);
|
|
x = w/2*dx/(Math.sqrt(dx*dx+dy*dy)) + zc.col(coord0.X) - zc.pointSize() - zc.getOne();
|
|
y = w/2*dy/(Math.sqrt(dx*dx+dy*dy)) + zc.row(coord0.Y) - zc.pointSize() - zc.getOne();
|
|
|
|
double alpha = Math.atan2(coord0.Y-coord1.Y, coord0.X-coord1.X)*180/Math.PI;
|
|
g.drawArc(x, y, w, w, alpha+90, 180);
|
|
}
|
|
}
|
|
if(!VarMax.toString().equals("windowcx+windoww")) {
|
|
final Coordinates coord0=(Coordinates) V.lastElement();
|
|
|
|
if(isMaxClosed) {
|
|
w = 2*zc.pointSize()+2*zc.getOne();
|
|
x = zc.col(coord0.X)-zc.pointSize()-zc.getOne();
|
|
y = zc.row(coord0.Y)-zc.pointSize()-zc.getOne();
|
|
g.fillOval(x, y, w, w, this.getColor());
|
|
} else if(isMaxOpen) {
|
|
final Coordinates coord1 = (Coordinates) V.elementAt(Math.max(V.size()-2,0));
|
|
double dx = zc.col(coord0.X) - zc.col(coord1.X);
|
|
double dy = zc.row(coord0.Y) - zc.row(coord1.Y);
|
|
x = w/2*dx/(Math.sqrt(dx*dx+dy*dy)) + zc.col(coord0.X) - zc.pointSize() - zc.getOne();
|
|
y = w/2*dy/(Math.sqrt(dx*dx+dy*dy)) + zc.row(coord0.Y) - zc.pointSize() - zc.getOne();
|
|
|
|
double alpha = Math.atan2(coord0.Y-coord1.Y, coord0.X-coord1.X)*180/Math.PI;
|
|
g.drawArc(x, y, w, w, alpha+90, 180);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public double getValue() throws ConstructionException {
|
|
if (!Valid) {
|
|
throw new InvalidException("exception.invalid");
|
|
}
|
|
return X[0];
|
|
}
|
|
|
|
public double getValue(final String var) throws ConstructionException {
|
|
if (!Valid) {
|
|
throw new InvalidException("exception.invalid");
|
|
}
|
|
for (int i = 0; i < Var.length; i++) {
|
|
if (var.equals(Var[i])) {
|
|
return X[i];
|
|
}
|
|
}
|
|
return X[0];
|
|
}
|
|
|
|
public double getIntegral() throws ConstructionException {
|
|
return getSum();
|
|
}
|
|
|
|
@Override
|
|
public String getDisplayValue() {
|
|
if (getEX().equals(getVar())) {
|
|
return EY.toString();
|
|
} else {
|
|
return "(" + EX.toString() + "," + EY.toString() + ")";
|
|
}
|
|
}
|
|
|
|
// Mainly to select the track for delete
|
|
@Override
|
|
public boolean nearto(final int x, final int y, final ZirkelCanvas zc) {
|
|
if (!displays(zc)) {
|
|
return false;
|
|
}
|
|
final Enumeration e = V.elements();
|
|
final double xx = zc.x(x), yy = zc.y(y);
|
|
final double mymax = (7 / Cn.getPixel());
|
|
if (Special) {
|
|
Coordinates CS;
|
|
while (e.hasMoreElements()) {
|
|
CS = (Coordinates) e.nextElement();
|
|
if ((Math.abs(CS.X - xx) < mymax)
|
|
&& (Math.abs(CS.Y - yy) < mymax)) {
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
double xA = 0, yA = 0, xB = 0, yB = 0;
|
|
Coordinates CS0, CS1;
|
|
if (e.hasMoreElements()) {
|
|
CS0 = (Coordinates) e.nextElement();
|
|
xA = CS0.X;
|
|
yA = CS0.Y;
|
|
}
|
|
while (e.hasMoreElements()) {
|
|
CS1 = (Coordinates) e.nextElement();
|
|
xB = CS1.X;
|
|
yB = CS1.Y;
|
|
|
|
final double p1 = (xx - xA) * (xB - xA) + (yy - yA) * (yB - yA);
|
|
final double p2 = (xx - xB) * (xA - xB) + (yy - yB) * (yA - yB);
|
|
if ((p1 > 0) && (p2 > 0)) {
|
|
final double aa = xB - xA, bb = yB - yA, cc = bb * xA - aa
|
|
* yA;
|
|
final double d = Math.abs(-bb * xx + aa * yy + cc)
|
|
/ Math.sqrt(aa * aa + bb * bb);
|
|
if (d < mymax) {
|
|
return true;
|
|
}
|
|
}
|
|
xA = xB;
|
|
yA = yB;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean EditAborted;
|
|
|
|
|
|
|
|
@Override
|
|
public void printArgs(final XmlWriter xml) {
|
|
xml.printArg("x", EX.toString());
|
|
xml.printArg("y", EY.toString());
|
|
xml.printArg("var", getVar());
|
|
xml.printArg("min", "" + VarMin);
|
|
xml.printArg("max", "" + VarMax);
|
|
xml.printArg("d", "" + DVar);
|
|
if (Special) {
|
|
xml.printArg("special", "true");
|
|
}
|
|
printType(xml);
|
|
if (Filled) {
|
|
xml.printArg("filled", "true");
|
|
}
|
|
if (getCenter() != null) {
|
|
xml.printArg("center", getCenter().getName());
|
|
}
|
|
xml.printArg("color", ""+getColorIndex());
|
|
if(isMinOpen || isMinClosed) {
|
|
xml.printArg("minbound", isMinOpen?"0":"1"); //0 = open ; 1 = closed
|
|
}
|
|
if(isMaxOpen || isMaxClosed) {
|
|
xml.printArg("maxbound", isMaxOpen?"0":"1");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setType(final int type) {
|
|
Type = type;
|
|
}
|
|
|
|
@Override
|
|
public int getType() {
|
|
return Type;
|
|
}
|
|
|
|
public void printType(final XmlWriter xml) {
|
|
if (Type != 0) {
|
|
switch (Type) {
|
|
case DIAMOND:
|
|
xml.printArg("shape", "diamond");
|
|
break;
|
|
case CIRCLE:
|
|
xml.printArg("shape", "circle");
|
|
break;
|
|
case DOT:
|
|
xml.printArg("shape", "dot");
|
|
break;
|
|
case CROSS:
|
|
xml.printArg("shape", "cross");
|
|
break;
|
|
case DCROSS:
|
|
xml.printArg("shape", "dcross");
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
public ConstructionObject copy(final double x, final double y) {
|
|
|
|
final FunctionObject fo = new FunctionObject(getConstruction());
|
|
fo.copyProperties(this);
|
|
fo.setFilled(this.isFilled()); //bug fix concerning filled curves in macro constructions
|
|
|
|
fo.EX = new Expression(EX.toString(), getConstruction(), fo, Var);
|
|
fo.EY = new Expression(EY.toString(), getConstruction(), fo, Var);
|
|
fo.VarMin = new Expression(VarMin.toString(), getConstruction(), fo);
|
|
fo.VarMax = new Expression(VarMax.toString(), getConstruction(), fo);
|
|
fo.DVar = new Expression(DVar.toString(), getConstruction(), fo);
|
|
fo.Special = Special;
|
|
final ConstructionObject O = getTranslation();
|
|
fo.setTranslation(this);
|
|
fo.EX.translate();
|
|
fo.EY.translate();
|
|
fo.VarMin.translate();
|
|
fo.VarMax.translate();
|
|
fo.DVar.translate();
|
|
fo.translateConditionals();
|
|
fo.X = X;
|
|
fo.Var = Var;
|
|
fo.validate();
|
|
fo.setTranslation(O);
|
|
fo.searchDependencies(Cn.getTranslation());
|
|
return fo;
|
|
}
|
|
|
|
@Override
|
|
public boolean onlynearto(final int x, final int y, final ZirkelCanvas zc) {
|
|
return false;
|
|
// return nearto(x,y,zc);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final ConstructionObject o) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Enumeration depending() {
|
|
DL.reset();
|
|
addDepending(EX);
|
|
addDepending(EY);
|
|
addDepending(VarMin);
|
|
addDepending(VarMax);
|
|
addDepending(DVar);
|
|
return DL.elements();
|
|
}
|
|
|
|
public void addDepending(final Expression E) {
|
|
if (E != null) {
|
|
final Enumeration e = E.getDepList().elements();
|
|
while (e.hasMoreElements()) {
|
|
DL.add((ConstructionObject) e.nextElement());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean hasUnit() {
|
|
return false;
|
|
}
|
|
|
|
public double evaluateF(final double x[]) throws ConstructionException {
|
|
int n = x.length;
|
|
if (n > X.length) {
|
|
n = X.length;
|
|
}
|
|
for (int i = 0; i < n; i++) {
|
|
X[i] = x[i];
|
|
}
|
|
for (int i = n; i < X.length; i++) {
|
|
X[i] = 0;
|
|
}
|
|
try {
|
|
return EY.getValue();
|
|
} catch (final Exception e) {
|
|
throw new ConstructionException("");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public double evaluateF(final double x) throws ConstructionException {
|
|
X[0] = x;
|
|
for (int i = 1; i < X.length; i++) {
|
|
X[i] = 0;
|
|
}
|
|
try {
|
|
return EY.getValue();
|
|
} catch (final Exception e) {
|
|
|
|
throw new ConstructionException("");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getDistance(final PointObject P) {
|
|
double varmin, varmax, dvar;
|
|
try {
|
|
varmin = VarMin.getValue();
|
|
varmax = VarMax.getValue();
|
|
dvar = DVar.getValue();
|
|
if (varmin > varmax) {
|
|
final double h = varmin;
|
|
varmin = varmax;
|
|
varmax = h;
|
|
}
|
|
|
|
if (dvar < 0) {
|
|
dvar = -dvar;
|
|
}
|
|
if (dvar == 0) {
|
|
dvar = (varmax - varmin) / 100;
|
|
} else if (dvar < (varmax - varmin) / 1000) {
|
|
dvar = (varmax - varmin) / 1000;
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
|
|
try {
|
|
// if it's a cartesian function, try to calculate the "real" coords
|
|
// :
|
|
if ((getEX().equals("x"))) {
|
|
double x = (P.getX() < varmin) ? varmin : P.getX();
|
|
x = (P.getX() > varmax) ? varmax : x;
|
|
final double y = evaluateF(x);
|
|
final double dd = Math.sqrt((P.getX() - x) * (P.getX() - x)
|
|
+ (P.getY() - y) * (P.getY() - y));
|
|
return (int) Math.round(dd * Cn.getPixel());
|
|
}
|
|
} catch (final Exception e) {
|
|
}
|
|
|
|
try {
|
|
// if it's a parmetric curve and function is just plot with points :
|
|
if ((!getEX().equals("x")) && (Special)) {
|
|
if (P.haveBoundOrder()) {
|
|
X[0] = P.getBoundOrder();
|
|
final double dd = Math.sqrt((P.getX() - EX.getValue())
|
|
* (P.getX() - EX.getValue())
|
|
+ (P.getY() - EY.getValue())
|
|
* (P.getY() - EY.getValue()));
|
|
return (int) Math.round(dd * Cn.getPixel());
|
|
} else {
|
|
Coordinates CS;
|
|
final Enumeration e = V.elements();
|
|
double delta0 = 0, delta1 = 0, xx = 0, yy = 0;
|
|
int i = 0;
|
|
if (e.hasMoreElements()) {
|
|
CS = (Coordinates) e.nextElement();
|
|
delta0 = Math.abs(CS.X - P.getX())
|
|
+ Math.abs(CS.Y - P.getY());
|
|
xx = CS.X;
|
|
yy = CS.Y;
|
|
}
|
|
|
|
while (e.hasMoreElements()) {
|
|
i++;
|
|
CS = (Coordinates) e.nextElement();
|
|
delta1 = Math.abs(CS.X - P.getX())
|
|
+ Math.abs(CS.Y - P.getY());
|
|
if (delta1 < delta0) {
|
|
delta0 = delta1;
|
|
xx = CS.X;
|
|
yy = CS.Y;
|
|
|
|
}
|
|
}
|
|
final double dd = Math.sqrt((P.getX() - xx)
|
|
* (P.getX() - xx) + (P.getY() - yy)
|
|
* (P.getY() - yy));
|
|
return (int) Math.round(dd * Cn.getPixel());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
|
|
// Otherwise, at Least get the approx coordinates on the polygon :
|
|
if (needsToRecompute()) {
|
|
compute();
|
|
}
|
|
final Enumeration e = V.elements();
|
|
double x = 0, y = 0, x0 = 0, y0 = 0, dmin = 0;
|
|
boolean started = false;
|
|
while (e.hasMoreElements()) {
|
|
final Coordinates c = (Coordinates) e.nextElement();
|
|
final double x1 = c.X;
|
|
final double y1 = c.Y;
|
|
if (!started) {
|
|
dmin = Math.sqrt((P.getX() - x1) * (P.getX() - x1)
|
|
+ (P.getY() - y1) * (P.getY() - y1));
|
|
x0 = x = x1;
|
|
y0 = y = y1;
|
|
started = true;
|
|
} else {
|
|
if (c.flag) {
|
|
double h = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
|
|
if (h < 1e-10) {
|
|
h = 1e-10;
|
|
}
|
|
double g = (P.getX() - x0) * (x1 - x0) + (P.getY() - y0)
|
|
* (y1 - y0);
|
|
if (g < 0) {
|
|
g = 0;
|
|
}
|
|
if (g > h) {
|
|
g = h;
|
|
}
|
|
final double x2 = x0 + g / h * (x1 - x0), y2 = y0 + g / h
|
|
* (y1 - y0);
|
|
final double d = Math.sqrt((P.getX() - x2)
|
|
* (P.getX() - x2) + (P.getY() - y2)
|
|
* (P.getY() - y2));
|
|
if (d < dmin) {
|
|
dmin = d;
|
|
x = x2;
|
|
y = y2;
|
|
}
|
|
}
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
}
|
|
if (started) {
|
|
P.Valid = true;
|
|
final double dd = Math.sqrt((P.getX() - x) * (P.getX() - x)
|
|
+ (P.getY() - y) * (P.getY() - y));
|
|
return (int) Math.round(dd * Cn.getPixel());
|
|
|
|
} else {
|
|
P.Valid = false;
|
|
}
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
|
|
@Override
|
|
public void project(final PointObject P) {
|
|
double varmin, varmax, dvar;
|
|
try {
|
|
|
|
varmin = VarMin.getValue();
|
|
varmax = VarMax.getValue();
|
|
dvar = DVar.getValue();
|
|
if (varmin > varmax) {
|
|
final double h = varmin;
|
|
varmin = varmax;
|
|
varmax = h;
|
|
}
|
|
|
|
if (dvar < 0) {
|
|
dvar = -dvar;
|
|
}
|
|
if (dvar == 0) {
|
|
dvar = (varmax - varmin) / 100;
|
|
} else if (dvar < (varmax - varmin) / 1000) {
|
|
dvar = (varmax - varmin) / 1000;
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// if P is a PointOn (a parmetric curve) and function is just plot
|
|
// with points :
|
|
if ((!getEX().equals("x")) && (P.isPointOnOrMagnet()) && (Special)) {
|
|
if (P.haveBoundOrder()) {
|
|
X[0] = P.getBoundOrder();
|
|
P.setXY(EX.getValue(), EY.getValue());
|
|
return;
|
|
} else {
|
|
Coordinates CS;
|
|
final Enumeration e = V.elements();
|
|
double delta0 = 0, delta1 = 0, xx = 0, yy = 0;
|
|
int i = 0, k = 0;
|
|
if (e.hasMoreElements()) {
|
|
CS = (Coordinates) e.nextElement();
|
|
delta0 = Math.abs(CS.X - P.getX())
|
|
+ Math.abs(CS.Y - P.getY());
|
|
xx = CS.X;
|
|
yy = CS.Y;
|
|
}
|
|
|
|
while (e.hasMoreElements()) {
|
|
i++;
|
|
CS = (Coordinates) e.nextElement();
|
|
delta1 = Math.abs(CS.X - P.getX())
|
|
+ Math.abs(CS.Y - P.getY());
|
|
if (delta1 < delta0) {
|
|
k = i;
|
|
delta0 = delta1;
|
|
xx = CS.X;
|
|
yy = CS.Y;
|
|
|
|
}
|
|
}
|
|
P.setXY(xx, yy);
|
|
P.setBoundOrder(varmin + k * dvar);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// if P is a PointOn (a cartesian function), try to calculate the
|
|
// "real" coords :
|
|
if ((P.isPointOnOrMagnet()) && (getEX().equals("x"))) {
|
|
double x = (P.getX() < varmin) ? varmin : P.getX();
|
|
x = (P.getX() > varmax) ? varmax : x;
|
|
final double y = evaluateF(x);
|
|
P.move(x, y);
|
|
return;
|
|
}
|
|
} catch (final Exception e) {
|
|
}
|
|
|
|
// Otherwise, at Least get the approx coordinates on the polygon :
|
|
if (needsToRecompute()) {
|
|
compute();
|
|
}
|
|
final Enumeration e = V.elements();
|
|
double x = 0, y = 0, x0 = 0, y0 = 0, dmin = 0;
|
|
boolean started = false;
|
|
while (e.hasMoreElements()) {
|
|
final Coordinates c = (Coordinates) e.nextElement();
|
|
final double x1 = c.X;
|
|
final double y1 = c.Y;
|
|
if (!started) {
|
|
dmin = Math.sqrt((P.getX() - x1) * (P.getX() - x1)
|
|
+ (P.getY() - y1) * (P.getY() - y1));
|
|
x0 = x = x1;
|
|
y0 = y = y1;
|
|
started = true;
|
|
} else {
|
|
if (c.flag) {
|
|
double h = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
|
|
if (h < 1e-10) {
|
|
h = 1e-10;
|
|
}
|
|
double g = (P.getX() - x0) * (x1 - x0) + (P.getY() - y0)
|
|
* (y1 - y0);
|
|
if (g < 0) {
|
|
g = 0;
|
|
}
|
|
if (g > h) {
|
|
g = h;
|
|
}
|
|
final double x2 = x0 + g / h * (x1 - x0), y2 = y0 + g / h
|
|
* (y1 - y0);
|
|
final double d = Math.sqrt((P.getX() - x2)
|
|
* (P.getX() - x2) + (P.getY() - y2)
|
|
* (P.getY() - y2));
|
|
if (d < dmin) {
|
|
dmin = d;
|
|
x = x2;
|
|
y = y2;
|
|
}
|
|
}
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
}
|
|
|
|
if (started) {
|
|
P.setXY(x, y);
|
|
P.Valid = true;
|
|
} else {
|
|
P.Valid = false;
|
|
}
|
|
|
|
}
|
|
|
|
public double getSum() {
|
|
double varmin, varmax, dvar;
|
|
boolean reverse = false;
|
|
final boolean parametric = !getEX().equals(getVar());
|
|
try {
|
|
varmin = VarMin.getValue();
|
|
varmax = VarMax.getValue();
|
|
dvar = DVar.getValue();
|
|
if (varmin > varmax) {
|
|
final double h = varmin;
|
|
varmin = varmax;
|
|
varmax = h;
|
|
reverse = true;
|
|
}
|
|
if (dvar < 0) {
|
|
dvar = -dvar;
|
|
}
|
|
if (dvar == 0) {
|
|
dvar = (varmax - varmin) / 100;
|
|
} else if (dvar < (varmax - varmin) / 1000) {
|
|
dvar = (varmax - varmin) / 1000;
|
|
}
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return 0;
|
|
}
|
|
X[0] = varmin;
|
|
double x0 = 0, y0 = 0;
|
|
boolean started = false;
|
|
double sum = 0;
|
|
while (true) {
|
|
try {
|
|
final double x1 = EX.getValue();
|
|
final double y1 = EY.getValue();
|
|
if (parametric) {
|
|
double x = 0, y = 0;
|
|
if (getCenter() != null) {
|
|
x = getCenter().getX();
|
|
y = getCenter().getY();
|
|
}
|
|
if (started) {
|
|
sum += ((x0 - x) * (y1 - y) - (y0 - y) * (x1 - x)) / 2;
|
|
}
|
|
} else {
|
|
if (started) {
|
|
if (Special) {
|
|
if (reverse) {
|
|
sum += (x1 - x0) * y1;
|
|
} else {
|
|
sum += (x1 - x0) * y0;
|
|
}
|
|
} else {
|
|
sum += (x1 - x0) * (y0 + y1) / 2;
|
|
}
|
|
}
|
|
}
|
|
x0 = x1;
|
|
y0 = y1;
|
|
started = true;
|
|
} catch (final Exception e) {
|
|
}
|
|
if (X[0] >= varmax) {
|
|
break;
|
|
}
|
|
X[0] = X[0] + dvar;
|
|
if (X[0] > varmax) {
|
|
X[0] = varmax;
|
|
}
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
public double getLength() {
|
|
double varmin, varmax, dvar;
|
|
try {
|
|
varmin = VarMin.getValue();
|
|
varmax = VarMax.getValue();
|
|
dvar = DVar.getValue();
|
|
if (varmin > varmax) {
|
|
final double h = varmin;
|
|
varmin = varmax;
|
|
varmax = h;
|
|
}
|
|
if (dvar < 0) {
|
|
dvar = -dvar;
|
|
}
|
|
if (dvar == 0) {
|
|
dvar = (varmax - varmin) / 100;
|
|
} else if (dvar < (varmax - varmin) / 1000) {
|
|
dvar = (varmax - varmin) / 1000;
|
|
}
|
|
} catch (final Exception e) {
|
|
Valid = false;
|
|
return 0;
|
|
}
|
|
X[0] = varmin;
|
|
double x0 = 0, y0 = 0;
|
|
boolean started = false;
|
|
double sum = 0;
|
|
while (true) {
|
|
try {
|
|
final double x1 = EX.getValue();
|
|
final double y1 = EY.getValue();
|
|
if (started) {
|
|
sum += Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0)
|
|
* (y1 - y0));
|
|
}
|
|
started = true;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
} catch (final Exception e) {
|
|
}
|
|
if (X[0] >= varmax) {
|
|
break;
|
|
}
|
|
X[0] = X[0] + dvar;
|
|
if (X[0] > varmax) {
|
|
X[0] = varmax;
|
|
}
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
@Override
|
|
public boolean isSpecial() {
|
|
return Special;
|
|
}
|
|
|
|
@Override
|
|
public void setSpecial(final boolean f) {
|
|
Special = f;
|
|
}
|
|
|
|
@Override
|
|
public void project(final PointObject P, final double alpha) {
|
|
project(P);
|
|
}
|
|
|
|
@Override
|
|
public boolean maybeTransparent() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean canDisplayName() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean showValue(){
|
|
return false;
|
|
}
|
|
|
|
public void setCenter(final String s) {
|
|
if (Cn == null) {
|
|
return;
|
|
}
|
|
Center = new Expression("@\"" + s + "\"", Cn, this);
|
|
}
|
|
|
|
@Override
|
|
public boolean isFilledForSelect() {
|
|
return false;
|
|
}
|
|
|
|
public PointObject getCenter() {
|
|
try {
|
|
return (PointObject) Center.getObject();
|
|
} catch (final Exception e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public String getVar() {
|
|
String vars = Var[0];
|
|
for (int i = 1; i < Var.length; i++) {
|
|
vars = vars + " " + Var[i];
|
|
}
|
|
return vars;
|
|
}
|
|
|
|
@Override
|
|
public boolean canInteresectWith(final ConstructionObject o) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isDriverObject() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean somethingChanged() {
|
|
boolean b = !EX.toString().equals(LASTEX);
|
|
b = b || !EY.toString().equals(LASTEY);
|
|
return b;
|
|
}
|
|
|
|
@Override
|
|
public void clearChanges() {
|
|
LASTEX = EX.toString();
|
|
LASTEY = EY.toString();
|
|
}
|
|
|
|
@Override
|
|
public void repulse(final PointObject P) {
|
|
project(P);
|
|
}
|
|
|
|
/******************************
|
|
* Closed or Open Intervals ***
|
|
*******************************/
|
|
public void setMinClosed(boolean b) {
|
|
isMinClosed = b;
|
|
}
|
|
public void setMinOpen(boolean b) {
|
|
isMinOpen = b;
|
|
}
|
|
public boolean getMinClosed() {
|
|
return isMinClosed;
|
|
}
|
|
public boolean getMinOpen() {
|
|
return isMinOpen;
|
|
}
|
|
|
|
public void setMaxClosed(boolean b) {
|
|
isMaxClosed = b;
|
|
}
|
|
public void setMaxOpen(boolean b) {
|
|
isMaxOpen = b;
|
|
}
|
|
public boolean getMaxClosed() {
|
|
return isMaxClosed;
|
|
}
|
|
public boolean getMaxOpen() {
|
|
return isMaxOpen;
|
|
}
|
|
}
|