468 lines
12 KiB
Java
468 lines
12 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: PrimitiveLineObject.java
|
|
import java.awt.Checkbox;
|
|
import java.awt.Color;
|
|
import java.awt.Frame;
|
|
import java.awt.TextField;
|
|
import java.awt.event.FocusEvent;
|
|
import java.util.Enumeration;
|
|
|
|
import eric.JEricPanel;
|
|
|
|
import rene.gui.Global;
|
|
import rene.gui.IconBar;
|
|
import rene.gui.MyLabel;
|
|
import rene.gui.TextFieldAction;
|
|
import rene.util.xml.XmlWriter;
|
|
import rene.gui.Global;
|
|
import rene.zirkel.ZirkelCanvas;
|
|
import rene.zirkel.construction.Construction;
|
|
import rene.zirkel.expression.ExpressionColor;
|
|
import rene.zirkel.graphics.MyGraphics;
|
|
import rene.zirkel.graphics.MainGraphics;
|
|
import rene.zirkel.structures.Coordinates;
|
|
|
|
|
|
|
|
public class PrimitiveLineObject extends ConstructionObject implements
|
|
PointonObject {
|
|
|
|
protected double X1, Y1, DX, DY;
|
|
protected double DX3D=0;
|
|
protected double DY3D=0;
|
|
protected double DZ3D=0;
|
|
protected PointObject P1;
|
|
PointObject Dep[];
|
|
int NDep;
|
|
boolean Partial = false;
|
|
|
|
public PrimitiveLineObject(final Construction c) {
|
|
super(c);
|
|
setColor(ColorIndex, SpecialColor);
|
|
}
|
|
|
|
public PrimitiveLineObject(final Construction c, final String Nme) {
|
|
super(c, Nme);
|
|
setColor(ColorIndex, SpecialColor);
|
|
}
|
|
|
|
public void setP1DXDY(final PointObject p, final double dx, final double dy) {
|
|
P1 = p;
|
|
DX = dx;
|
|
DY = dy;
|
|
X1 = P1.getX();
|
|
Y1 = P1.getY();
|
|
}
|
|
|
|
@Override
|
|
public void setDefaults() {
|
|
setShowName(Global.getParameter("options.line.shownames", false));
|
|
setShowValue(Global.getParameter("options.line.showvalues", false));
|
|
setColor(Global.getParameter("options.line.color", 0), Global
|
|
.getParameter("options.line.pcolor", (ExpressionColor) null, this));
|
|
setColorType(Global.getParameter("options.line.colortype", 0));
|
|
setHidden(Cn.Hidden);
|
|
setObtuse(Cn.Obtuse);
|
|
setSolid(Cn.Solid);
|
|
setLarge(Global.getParameter("options.line.large", false));
|
|
setBold(Global.getParameter("options.line.bold", false));
|
|
}
|
|
|
|
@Override
|
|
public void setTargetDefaults() {
|
|
setShowName(Global.getParameter("options.line.shownames", false));
|
|
setShowValue(Global.getParameter("options.line.showvalues", false));
|
|
setColor(Global.getParameter("options.line.color", 0), Global
|
|
.getParameter("options.line.pcolor", (ExpressionColor) null, this));
|
|
setColorType(Global.getParameter("options.line.colortype", 0));
|
|
setLarge(Global.getParameter("options.line.large", false));
|
|
setBold(Global.getParameter("options.line.bold", false));
|
|
}
|
|
|
|
@Override
|
|
public String getTag() {
|
|
return "Line";
|
|
}
|
|
|
|
double k1, k2;
|
|
boolean k12valid = false;
|
|
|
|
@Override
|
|
public void paint(final MyGraphics g, final ZirkelCanvas zc) {
|
|
if (!Valid || mustHide(zc)) {
|
|
return;
|
|
}
|
|
|
|
// compute middle of the screen:
|
|
final double xm = (zc.minX() + zc.maxX()) / 2, ym = (zc.minY() + zc
|
|
.maxY()) / 2;
|
|
// compute distance from middle to line:
|
|
final double d = (xm - X1) * DY - (ym - Y1) * DX;
|
|
// compute point with minimal distance
|
|
final double x = xm - d * DY, y = ym + d * DX;
|
|
// compute size of the screen
|
|
final double a = Math.max(zc.maxX() - zc.minX(), zc.maxY() - zc.minY());
|
|
if (Math.abs(d) > a) {
|
|
return;
|
|
}
|
|
// compute distance from closest point to source
|
|
final double b = (x - X1) * DX + (y - Y1) * DY;
|
|
// compute the two visible endpoints
|
|
k1 = b - a;
|
|
k2 = b + a;
|
|
k12valid = true;
|
|
if (Partial && Dep != null && !zc.showHidden()) {
|
|
final double dd = (zc.maxX() - zc.minX()) / 20;
|
|
double dmin = -dd, dmax = +dd;
|
|
if (Dep != null) {
|
|
for (int i = 0; i < NDep; i++) {
|
|
if (!Dep[i].valid() || Dep[i].mustHide(zc)) {
|
|
continue;
|
|
}
|
|
final double s = project(Dep[i].getX(), Dep[i].getY());
|
|
if (s - dd < dmin) {
|
|
dmin = s - dd;
|
|
} else if (s + dd > dmax) {
|
|
dmax = s + dd;
|
|
}
|
|
}
|
|
}
|
|
if (k1 < dmin) {
|
|
k1 = dmin;
|
|
}
|
|
if (k2 > dmax) {
|
|
k2 = dmax;
|
|
}
|
|
}
|
|
final double c1 = zc.col(X1 + k1 * DX), c2 = zc.col(X1 + k2 * DX), r1 = zc
|
|
.row(Y1 + k1 * DY), r2 = zc.row(Y1 + k2 * DY);
|
|
// paint:
|
|
if (isStrongSelected() && g instanceof MainGraphics) {
|
|
((MainGraphics) g).drawMarkerLine(c1, r1, c2, r2);
|
|
}
|
|
|
|
g.setColor(this);
|
|
|
|
if (tracked())
|
|
zc.UniversalTrack.drawTrackLine(this, c1, r1, c2, r2);
|
|
|
|
g.drawLine(c1, r1, c2, r2, this);
|
|
final String s = getDisplayText();
|
|
if (!s.equals("")) {
|
|
g.setLabelColor(this);
|
|
setFont(g);
|
|
DisplaysText = true;
|
|
if (KeepClose) {
|
|
final double side = (YcOffset < 0) ? 1 : -1;
|
|
drawLabel(g, s, zc, X1 + XcOffset * DX, Y1 + XcOffset * DY,
|
|
side * DX, side * DY, 0, 0);
|
|
} else {
|
|
drawLabel(g, s, zc, x + a / 5 * DX, y + a / 5 * DY, DX, DY,
|
|
XcOffset, YcOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean canKeepClose() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void setKeepClose(final double x, final double y) {
|
|
KeepClose = true;
|
|
XcOffset = (x - X1) * DX + (y - Y1) * DY;
|
|
YcOffset = (x - X1) * DY - (y - Y1) * DX;
|
|
}
|
|
|
|
@Override
|
|
public boolean nearto(final int c, final int r, final ZirkelCanvas zc) {
|
|
if (!displays(zc)) {
|
|
return false;
|
|
}
|
|
// compute point at c,r
|
|
final double x = zc.x(c), y = zc.y(r);
|
|
// compute distance from x,y
|
|
final double d = (x - X1) * DY - (y - Y1) * DX;
|
|
// scale in screen coordinates
|
|
Value = Math.abs(zc.col(zc.minX() + d) - zc.col(zc.minX()));
|
|
return Value < zc.selectionSize() * 2;
|
|
}
|
|
|
|
@Override
|
|
public boolean onlynearto(final int c, final int r, final ZirkelCanvas zc) {
|
|
return false;
|
|
}
|
|
|
|
public static Coordinates intersect(final PrimitiveLineObject l1,
|
|
final PrimitiveLineObject l2) // compute the intersection
|
|
// coordinates of two lines
|
|
{
|
|
final double det = -l1.DX * l2.DY + l1.DY * l2.DX;
|
|
if (Math.abs(det) < 1e-10) {
|
|
return null;
|
|
}
|
|
final double a = (-(l2.X1 - l1.X1) * l2.DY + (l2.Y1 - l1.Y1) * l2.DX)
|
|
/ det;
|
|
return new Coordinates(l1.X1 + a * l1.DX, l1.Y1 + a * l1.DY);
|
|
}
|
|
|
|
public static Coordinates intersect(final PrimitiveLineObject l,
|
|
final PrimitiveCircleObject c) // compute the intersection
|
|
// coordinates of a line with a
|
|
// circle
|
|
{
|
|
double x = c.getX(), y = c.getY();
|
|
final double r = c.getR();
|
|
final double d = (x - l.X1) * l.DY - (y - l.Y1) * l.DX;
|
|
if (Math.abs(d) > r + 1e-10) {
|
|
return null;
|
|
}
|
|
x -= d * l.DY;
|
|
y += d * l.DX;
|
|
double h = r * r - d * d;
|
|
if (h > 0) {
|
|
h = Math.sqrt(h);
|
|
} else {
|
|
h = 0;
|
|
}
|
|
return new Coordinates(x + h * l.DX, y + h * l.DY, x - h * l.DX, y - h
|
|
* l.DY);
|
|
}
|
|
|
|
public static Coordinates intersect(final PrimitiveLineObject l,
|
|
final QuadricObject q) {
|
|
// compute the intersection coordinates of a line with a quadric
|
|
// done with XCAS :
|
|
// System.out.println("l.DX="+l.DX+" l.DY="+l.DY);
|
|
final double M = -l.DY, N2 = l.DX, P = -(M * l.X1 + N2 * l.Y1);
|
|
// System.out.println("M="+M+" N2="+N2+" P="+P);
|
|
final double A = q.X[0], B = q.X[1], C = q.X[2], D = q.X[3], E = q.X[4], F = q.X[5];
|
|
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
|
|
if (N2 != 0) {
|
|
final double part1 = -2 * B * M * P - C * N2 * N2 + D * M * N2 + E
|
|
* N2 * P;
|
|
final double part2 = Math.abs(N2)
|
|
* Math.sqrt(-2 * M * D * N2 * C + 4 * P * D * A * N2 + 4
|
|
* P * M * B * C + 4 * E * M * N2 * F - 2 * E * P
|
|
* N2 * C - 2 * E * P * M * D - 4 * M * M * B * F
|
|
- 4 * P * P * A * B - 4 * A * N2 * N2 * F + N2 * N2
|
|
* C * C + M * M * D * D + E * E * P * P);
|
|
|
|
final double part3 = 2 * A * N2 * N2 + 2 * B * M * M + (-2 * E) * M
|
|
* N2;
|
|
x1 = (part1 + part2) / part3;
|
|
if (Double.isNaN(x1)) {
|
|
return null;
|
|
}
|
|
y1 = (-M * x1 - P) / N2;
|
|
x2 = (part1 - part2) / part3;
|
|
y2 = (-M * x2 - P) / N2;
|
|
if (((x2 - x1) / l.DX) < 0) {
|
|
return new Coordinates(x2, y2, x1, y1);
|
|
}
|
|
} else {
|
|
x1 = -P / M;
|
|
x2 = x1;
|
|
final double part1 = -D * M * M + E * M * P;
|
|
final double part2 = Math.abs(M)
|
|
* Math.sqrt(4 * P * M * B * C - 2 * E * P * M * D - 4 * M
|
|
* M * B * F - 4 * P * P * A * B + M * M * D * D + E
|
|
* E * P * P);
|
|
final double part3 = 2 * M * M * B;
|
|
y1 = (part1 + part2) / part3;
|
|
if (Double.isNaN(y1)) {
|
|
return null;
|
|
}
|
|
y2 = (part1 - part2) / part3;
|
|
if (((y2 - y1) / l.DY) < 0) {
|
|
return new Coordinates(x2, y2, x1, y1);
|
|
}
|
|
}
|
|
|
|
return new Coordinates(x1, y1, x2, y2);
|
|
}
|
|
|
|
public double getDX() {
|
|
return DX;
|
|
}
|
|
|
|
public double getDY() {
|
|
return DY;
|
|
}
|
|
|
|
public double getDX3D() {
|
|
return DX3D;
|
|
}
|
|
|
|
public double getDY3D() {
|
|
return DY3D;
|
|
}
|
|
|
|
public double getDZ3D() {
|
|
return DZ3D;
|
|
}
|
|
|
|
@Override
|
|
public double getX() {
|
|
return X1;
|
|
}
|
|
|
|
@Override
|
|
public double getY() {
|
|
return Y1;
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
public String getEquation() {
|
|
double y = DX, x = -DY;
|
|
double c = y * Y1 + x * X1;
|
|
if (c < 0) {
|
|
c = -c;
|
|
x = -x;
|
|
y = -y;
|
|
}
|
|
if (Math.abs(x) < 1e-10 && y < 0) {
|
|
c = -c;
|
|
x = -x;
|
|
y = -y;
|
|
} else if (Math.abs(y) < 1e-10 && x < 0) {
|
|
c = -c;
|
|
x = -x;
|
|
y = -y;
|
|
}
|
|
final String s = helpDisplayValue(true, x, "x");
|
|
return s + helpDisplayValue(s.equals(""), y, "y") + "="
|
|
+ ((Math.abs(c) < 1e-10) ? "0" : helpDisplayNumber(true, c));
|
|
}
|
|
|
|
/**
|
|
* Test, if the projection of (x,y) to the line contains that point.
|
|
*/
|
|
public boolean contains(final double x, final double y) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void printArgs(final XmlWriter xml) {
|
|
if (Partial) {
|
|
xml.printArg("partial", "true");
|
|
}
|
|
}
|
|
|
|
public double project(final double x, final double y) {
|
|
return (x - X1) * DX + (y - Y1) * DY;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final ConstructionObject o) {
|
|
if (!(o instanceof PrimitiveLineObject) || !o.valid()) {
|
|
return false;
|
|
}
|
|
final PrimitiveLineObject l = (PrimitiveLineObject) o;
|
|
return equals(DX * l.DY - DY * l.DX, 0)
|
|
&& equals((X1 - l.X1) * DY - (Y1 - l.Y1) * DX, 0);
|
|
}
|
|
|
|
public PointObject getP1() {
|
|
return P1;
|
|
}
|
|
|
|
public Enumeration points() {
|
|
return depending();
|
|
}
|
|
|
|
@Override
|
|
public boolean locallyLike(final ConstructionObject o) {
|
|
if (!(o instanceof PrimitiveLineObject)) {
|
|
return false;
|
|
}
|
|
return (equals(DX, ((PrimitiveLineObject) o).DX) && equals(DY,
|
|
((PrimitiveLineObject) o).DY))
|
|
|| (equals(-DX, ((PrimitiveLineObject) o).DX) && equals(-DY,
|
|
((PrimitiveLineObject) o).DY));
|
|
}
|
|
|
|
@Override
|
|
public boolean isPartial() {
|
|
return Partial;
|
|
}
|
|
|
|
@Override
|
|
public void setPartial(final boolean partial) {
|
|
if (Partial == partial) {
|
|
return;
|
|
}
|
|
Partial = partial;
|
|
if (partial) {
|
|
Dep = new PointObject[16];
|
|
NDep = 0;
|
|
} else {
|
|
Dep = null;
|
|
}
|
|
}
|
|
|
|
public void addDep(final PointObject p) {
|
|
if (!Partial || Dep == null || NDep >= Dep.length) {
|
|
return;
|
|
}
|
|
Dep[NDep++] = p;
|
|
}
|
|
|
|
@Override
|
|
public void clearCircleDep() {
|
|
NDep = 0;
|
|
}
|
|
|
|
@Override
|
|
public int getDistance(final PointObject P) {
|
|
final double h = project(P.getX(), P.getY());
|
|
final double dx = P.getX() - (getX() + h * getDX());
|
|
final double dy = P.getY() - (getY() + h * getDY());
|
|
final double d = Math.sqrt(dx * dx + dy * dy);
|
|
return (int) Math.round(d * Cn.getPixel());
|
|
}
|
|
|
|
public void project(final PointObject P) {
|
|
final double h = project(P.getX(), P.getY());
|
|
P.setXY(getX() + h * getDX(), getY() + h * getDY());
|
|
P.setA(h);
|
|
}
|
|
|
|
public void project(final PointObject P, final double alpha) {
|
|
P.setXY(getX() + alpha * getDX(), getY() + alpha * getDY());
|
|
}
|
|
|
|
public boolean canInteresectWith(final ConstructionObject o) {
|
|
return true;
|
|
}
|
|
|
|
public void repulse(final PointObject P) {
|
|
project(P);
|
|
}
|
|
}
|