/*
* This file is part of LaTeXDraw.
* Copyright (c) 2005-2017 Arnaud BLOUIN
* LaTeXDraw is 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; either version 2 of the License, or (at your option) any later version.
* LaTeXDraw is distributed 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.
*/
package net.sf.latexdraw.models.impl;
import java.awt.geom.Line2D;
import net.sf.latexdraw.models.MathUtils;
import net.sf.latexdraw.models.ShapeFactory;
import net.sf.latexdraw.models.interfaces.shape.ILine;
import net.sf.latexdraw.models.interfaces.shape.IPoint;
/**
* A model of a line (not a shape).
* @author Arnaud Blouin
*/
class LLine extends Line2D.Double implements ILine {
private static final long serialVersionUID = 1L;
/** The director coefficient of the line (y=ax+b). */
private double a;
/** y=ax+b. */
private double b;
/**
* Constructs a line from the specified coordinates.
* @param x1 the X coordinate of the start point.
* @param y1 the Y coordinate of the start point.
* @param x2 the X coordinate of the end point.
* @param y2 the Y coordinate of the end point.
* @throws IllegalArgumentException If one of the given coordinate is not valid.
*/
LLine(final double x1, final double y1, final double x2, final double y2) {
this(ShapeFactory.INST.createPoint(x1, y1), ShapeFactory.INST.createPoint(x2, y2));
}
/**
* Creates a line by creating a second point with:
* @param b y = ax+ b
* @param p1 The first point.
* @throws IllegalArgumentException If one of the given parameter is not valid.
*/
LLine(final double b, final IPoint p1) {
this(p1, ShapeFactory.INST.createPoint(0.0, b));
}
/**
* Constructs a line from the specified <code>Point2D</code> objects.
* @param p1 the start <code>Point2D</code> of this line segment.
* @param p2 the end <code>Point2D</code> of this line segment.
* @throws IllegalArgumentException If one of the given points is not valid.
*/
LLine(final IPoint p1, final IPoint p2) {
super();
if(!MathUtils.INST.isValidPt(p1) || !MathUtils.INST.isValidPt(p2)) throw new IllegalArgumentException();
setP1(p1);
setP2(p2);
updateAandB();
}
@Override
public void setLine(final double x1, final double y1, final double x2, final double y2) {
if(MathUtils.INST.isValidPt(x1, y1) && MathUtils.INST.isValidPt(x2, y2)) {
super.setLine(x1, y1, x2, y2);
updateAandB();
}
}
@Override
public boolean isInSegment(final IPoint pt) {
if(pt == null) return false;
final double minX = Math.min(x1, x2);
final double maxX = Math.max(x1, x2);
final double minY = Math.min(y1, y2);
final double maxY = Math.max(y1, y2);
final double x = pt.getX();
final double y = pt.getY();
if(isHorizontalLine()) return MathUtils.INST.equalsDouble(y, minY) && x >= minX && x <= maxX;
if(isVerticalLine()) return MathUtils.INST.equalsDouble(x, minX) && y >= minY && y <= maxY;
return y >= minY && y <= maxY && x >= minX && x <= maxX && MathUtils.INST.equalsDouble(y, getA() * x + getB());
}
@Override
public void updateAandB() {
if(isVerticalLine()) {
a = java.lang.Double.NaN;
b = java.lang.Double.NaN;
}else {
a = (y1 - y2) / (x1 - x2);
b = y1 - a * x1;
}
}
@Override
public IPoint[] findPoints(final IPoint p, final double distance) {
return p == null ? null : findPoints(p.getX(), p.getY(), distance);
}
@Override
public IPoint[] findPoints(final double x, final double y, final double distance) {
if(!MathUtils.INST.isValidPt(x, y) || !MathUtils.INST.isValidCoord(distance)) return null;
if(MathUtils.INST.equalsDouble(distance, 0.)) {
final IPoint[] sol = new LPoint[1];
sol[0] = ShapeFactory.INST.createPoint(x, y);
return sol;
}
if(isVerticalLine()) {
if(isHorizontalLine())// The line is a point. So no position can be computed.
return null;
final IPoint[] sol = new LPoint[2];
sol[0] = ShapeFactory.INST.createPoint(x, y - distance);
sol[1] = ShapeFactory.INST.createPoint(x, y + distance);
return sol;
}
final double aLine = a * a + 1.0;
final double bLine = -2.0 * (x + y * a - a * b);
final double cLine = b * b - 2.0 * y * b + y * y + x * x - distance * distance;
final double delta = bLine * bLine - 4.0 * aLine * cLine;
if(delta > 0.0) {
final double x1b;
final double x2b;
final double y1b;
final double y2b;
final IPoint[] sol = new LPoint[2];
x1b = (-bLine + Math.sqrt(delta)) / (2 * aLine);
x2b = (-bLine - Math.sqrt(delta)) / (2 * aLine);
y1b = a * x1b + b;
y2b = a * x2b + b;
sol[0] = ShapeFactory.INST.createPoint(x1b, y1b);
sol[1] = ShapeFactory.INST.createPoint(x2b, y2b);
return sol;
}else if(MathUtils.INST.equalsDouble(delta, 0.0)) {
final double x2b;
final double y2b;
final IPoint[] sol = new LPoint[1];
x2b = -bLine / 2 * aLine;
y2b = a * x2b + b;
sol[0] = ShapeFactory.INST.createPoint(x2b, y2b);
return sol;
}else return null;
}
@Override
public ILine getPerpendicularLine(final IPoint pt) {
/*//TODO
if(isVerticalLine())
return new Line(new Point2D.Double(-10000, y), new Point2D.Double(10000, y));
if(isHorizontalLine())
return new Line(new Point2D.Double(x, -10000), new Point2D.Double(x, 10000));
final double a2 = -1./getA();
final double b2 = y-a2*x;
return new Line(new Point2D.Double(x, y), new Point2D.Double(-b2/a2, 0.));
*/
if(!MathUtils.INST.isValidPt(pt)) return null;
if(isVerticalLine())//FIXME must always create a perpendicular line + add test
return MathUtils.INST.equalsDouble(pt.getX(), x1) ? ShapeFactory.INST.createLine(pt.getY(), ShapeFactory.INST.createPoint(pt)) : null;
if(MathUtils.INST.equalsDouble(pt.getX(), 0.0)) {
final IPoint pt3 = ShapeFactory.INST.createPoint(getPoint2());
final IPoint pt2 = pt3.rotatePoint(pt, Math.PI / 2.0);
return ShapeFactory.INST.createLine(pt2, pt);
}
if(MathUtils.INST.equalsDouble(a, 0.0)) return ShapeFactory.INST.createLine(pt.getX(), pt.getY(), pt.getX(), pt.getY() - 10.0);
final double a2 = -1.0 / a;
return ShapeFactory.INST.createLine(pt.getY() - a2 * pt.getX(), pt);
}
@Override
public boolean isVerticalLine() {
return MathUtils.INST.equalsDouble(x1, x2);
}
@Override
public boolean isHorizontalLine() {
return MathUtils.INST.equalsDouble(y1, y2);
}
@Override
public IPoint getIntersection(final ILine l) {
if(l == null) return null;
if(MathUtils.INST.equalsDouble(a, l.getA(), 0.00000000001)) return null;
final boolean verticalLine1 = isVerticalLine();
final boolean verticalLine2 = l.isVerticalLine();
final double x;
final double y;
if(verticalLine2) {
if(verticalLine1)// The two lines a parallels
return null;
if(l.isHorizontalLine())// Points of the line l are equal.
return null;
if(isHorizontalLine()) {
x = l.getX1();
y = getY1();
}else {
y = a * l.getX1() + b;
x = (y - b) / a;
}
}else {
final double la = l.getA();
final double lb = l.getB();
if(verticalLine1) {
if(l.isHorizontalLine()) {
x = getX1();
y = l.getY1();
}else {
y = la * getX1() + lb;
x = (y - lb) / la;
}
}else {
x = (b - lb) / (la - a);
y = a * x + b;
}
}
return ShapeFactory.INST.createPoint(x, y);
}
@Override
public IPoint getIntersectionSegment(final ILine l) {
final IPoint p = getIntersection(l);
if(p == null) return null;
final double px = p.getX();
final double py = p.getY();
final IPoint tl = getTopLeftPoint();
final IPoint br = getBottomRightPoint();
final IPoint tl2 = l.getTopLeftPoint();
final IPoint br2 = l.getBottomRightPoint();
if(px >= tl.getX() && px <= br.getX() && py >= tl.getY() && py <= br.getY() && px >= tl2.getX() && px <= br2.getX() && py >= tl2.getY() && py <= br2.getY())
return p;
return null;
}
@Override
public IPoint getTopLeftPoint() {
final IPoint pt1 = getPoint1();
final IPoint pt2 = getPoint2();
return ShapeFactory.INST.createPoint(pt1.getX() < pt2.getX() ? pt1.getX() : pt2.getX(), pt1.getY() < pt2.getY() ? pt1.getY() : pt2.getY());
}
@Override
public IPoint getBottomRightPoint() {
final IPoint pt1 = getPoint1();
final IPoint pt2 = getPoint2();
return ShapeFactory.INST.createPoint(pt1.getX() < pt2.getX() ? pt2.getX() : pt1.getX(), pt1.getY() < pt2.getY() ? pt2.getY() : pt1.getY());
}
@Override
public double getA() {
return a;
}
@Override
public double getB() {
return b;
}
@Override
public IPoint getPoint1() {
return ShapeFactory.INST.createPoint(x1, y1);
}
@Override
public IPoint getPoint2() {
return ShapeFactory.INST.createPoint(x2, y2);
}
@Override
public void setP1(final IPoint pt) {
if(MathUtils.INST.isValidPt(pt)) {
this.x1 = pt.getX();
this.y1 = pt.getY();
}
}
@Override
public void setP2(final IPoint pt) {
if(MathUtils.INST.isValidPt(pt)) {
this.x2 = pt.getX();
this.y2 = pt.getY();
}
}
@Override
public void setX1(final double x1) {
if(MathUtils.INST.isValidCoord(x1)) this.x1 = x1;
}
@Override
public void setX2(final double x2) {
if(MathUtils.INST.isValidCoord(x2)) this.x2 = x2;
}
@Override
public void setY1(final double y1) {
if(MathUtils.INST.isValidCoord(y1)) this.y1 = y1;
}
@Override
public void setY2(final double y2) {
if(MathUtils.INST.isValidCoord(y2)) this.y2 = y2;
}
@Override
public double getLineAngle() {
if(isHorizontalLine()) return 0.;
if(isVerticalLine()) return Math.PI / 2.;
return Math.atan(getA());
}
@Override
public String toString() {
return "LLine [a=" + a + ", b=" + b + ", x1=" + x1 + ", y1=" + y1 + ", x2=" + x2 + ", y2=" + y2 + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
}
}