CaRMtl/rene/zirkel/objects/PointonObjectIntersectionObject.java
2018-09-04 22:51:42 -04:00

238 lines
5.7 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;
import rene.util.xml.XmlWriter;
import rene.zirkel.construction.Construction;
import rene.zirkel.expression.Secant;
/**
* An intersection between two object that can bind points on them. The
* intersection is computed by projecting the point to both objects and
* predicting the intersection point.
*
* @author Rene
*/
public class PointonObjectIntersectionObject extends IntersectionObject {
public double Eps = 1e-5;
private boolean xAxisFunctionIntersection = false,
yAxisFunctionIntersection = false;
private FunctionObject F = null;
public PointonObjectIntersectionObject(final Construction c,
final ConstructionObject p1, final ConstructionObject p2) {
super(c, p1, p2);
if ((p1 instanceof AxisObject) && (p2 instanceof FunctionObject)) {
F = (FunctionObject) p2;
if (F.getEX().toString().equals("x")) {
final AxisObject ax = ((AxisObject) p1);
if (ax.DX == 1) {
xAxisFunctionIntersection = true;
} else {
yAxisFunctionIntersection = true;
}
}
} else if ((p2 instanceof AxisObject) && (p1 instanceof FunctionObject)) {
F = (FunctionObject) p1;
if (F.getEX().toString().equals("x")) {
final AxisObject ax = ((AxisObject) p2);
if (ax.DX == 1) {
xAxisFunctionIntersection = true;
} else {
yAxisFunctionIntersection = true;
}
}
}
}
@Override
public void validate(final double x, final double y) {
setXY(x, y);
validate();
}
@Override
public void printArgs(final XmlWriter xml) {
xml.printArg("first", P1.getName());
xml.printArg("second", P2.getName());
xml.printArg("x", "" + getX());
xml.printArg("y", "" + getY());
if (getAway() != null) {
if (StayAway) {
xml.printArg("awayfrom", getAway().getName());
} else {
xml.printArg("closeto", getAway().getName());
}
}
printType(xml);
if (!Restricted) {
xml.printArg("valid", "true");
}
}
/**
* Troublesome function to intersect two objects. This is done by projecting
* the intersection point to each of the objects in turn.
*
* To speed up the convergence, a line intersection is computed, where the
* lines approximate the objects.
*/
@Override
public void validate() {
// if ((P1==null)||(P2==null)) {
// System.out.println(this.getName());
// }
if (!P1.valid() || !P2.valid()) {
Valid = false;
} else {
Valid = true;
}
if (!Valid) {
return;
}
if (yAxisFunctionIntersection) {
try {
setXY(0, F.evaluateF(0));
return;
} catch (final Exception ex) {
}
}
if (xAxisFunctionIntersection) {
try {
double xn = 0;
for (int i = 0; i < 5; i++) {
double distold = projectOnce();
if (!Valid) {
return;
}
final double dist1 = projectOnce();
if (dist1 >= distold && dist1 < Eps) {
break;
}
distold = dist1;
double a = x1 - x;
double b = y1 - y;
double s = Math.max(Math.abs(a), Math.abs(b));
if (Math.abs(s) > 1e-13) {
a /= s;
}
b /= s;
double c = X - x1;
double d = Y - y1;
s = Math.max(Math.abs(c), Math.abs(d));
if (Math.abs(s) > 1e-13) {
c /= s;
}
d /= s;
final double e = a * x1 + b * y1;
final double f = c * X + d * Y;
final double det = a * d - c * b;
if (Math.abs(det) > 1e-13) {
xn = (e * d - f * b) / det;
final double dist2 = projectOnce();
if (dist2 < dist1) {
distold = dist2;
}
}
}
setXY(Secant.compute(F, xn - 1e-1, xn + 1e-1, 1e-10), 0);
return;
} catch (final Exception ex) {
}
}
double distold = projectOnce();
if (!Valid) {
return;
}
for (int i = 0; i < 10; i++) {
final double dist1 = projectOnce();
if (dist1 >= distold && dist1 < Eps) {
return;
}
distold = dist1;
double a = (x1 - x), b = (y1 - y);
double s = Math.max(Math.abs(a), Math.abs(b));
if (Math.abs(s) > 1e-13) {
a /= s;
}
b /= s;
double c = (X - x1), d = (Y - y1);
s = Math.max(Math.abs(c), Math.abs(d));
if (Math.abs(s) > 1e-13) {
c /= s;
}
d /= s;
final double e = a * x1 + b * y1, f = c * X + d * Y;
final double det = a * d - c * b;
if (Math.abs(det) > 1e-13) {
final double xn = (e * d - f * b) / det;
final double yn = (a * f - c * e) / det;
final double xold = X, yold = Y;
setXY(xn, yn);
final double dist2 = projectOnce();
if (dist2 > dist1) // interpolation does not work
{
setXY(xold, yold);
} else {
distold = dist2;
}
}
}
Valid = false;
}
double x, y, x1, y1;
public double projectOnce() {
x = X;
y = Y;
// System.out.println("Before: "+X+" "+Y);
((PointonObject) P1).project(this);
// System.out.println("Projected to "+P1.getName()+": "+X+" "+Y);
final double dist = Math.max(Math.abs(X - x), Math.abs(Y - y));
x1 = X;
y1 = Y;
((PointonObject) P2).project(this);
// System.out.println("Projected to "+P2.getName()+": "+X+" "+Y);
final double dist1 = Math.max(Math.abs(X - x1), Math.abs(Y - y1));
return Math.max(dist, dist1);
}
@Override
public boolean moveable() {
return true;
}
}