/*
* 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.Point2D;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point3D;
import net.sf.latexdraw.models.MathUtils;
import net.sf.latexdraw.models.ShapeFactory;
import net.sf.latexdraw.models.interfaces.shape.IPoint;
import org.eclipse.jdt.annotation.NonNull;
import static java.lang.Math.PI;
import static java.lang.Math.atan;
/**
* Defines a model of a point. Not a shape.
* @author Arnaud Blouin
*/
class LPoint implements IPoint {
private final @NonNull DoubleProperty x;
private final @NonNull DoubleProperty y;
/**
* Creates a Point2D with coordinates (0, 0).
*/
LPoint() {
this(0d, 0d);
}
/**
* Creates a point from a IPoint
* @param pt The IPoint, if null the default value (0,0) will be used.
*/
LPoint(final IPoint pt) {
this(pt == null ? 0d : pt.getX(), pt == null ? 0d : pt.getY());
}
/**
* Creates a Point2D with the specified coordinates.
* @param xCoord The X-coordinate to set.
* @param yCoord The Y-coordinate to set.
*/
LPoint(final double xCoord, final double yCoord) {
super();
x = new SimpleDoubleProperty(xCoord);
y = new SimpleDoubleProperty(yCoord);
}
@Override
public double computeAngle(final IPoint pt) {
if(!MathUtils.INST.isValidPt(pt)) return java.lang.Double.NaN;
double angle;
final double x2 = pt.getX() - getX();
final double y2 = pt.getY() - getY();
if(MathUtils.INST.equalsDouble(x2, 0d)) {
angle = Math.PI / 2d;
if(y2 < 0d) {
angle = Math.PI * 2d - angle;
}
}else {
angle = x2 < 0d ? Math.PI - atan(-y2 / x2) : atan(y2 / x2);
}
return angle;
}
@Override
public IPoint zoom(final double zoomLevel) {
return ShapeFactory.INST.createPoint(getX() * zoomLevel, getX() * zoomLevel);
}
@Override
public double computeRotationAngle(final IPoint pt1, final IPoint pt2) {
if(!MathUtils.INST.isValidPt(pt1) || !MathUtils.INST.isValidPt(pt2)) {
return Double.NaN;
}
final double thetaOld = computeAngle(pt1);
final double thetaNew = computeAngle(pt2);
return thetaNew - thetaOld;
}
@Override
public IPoint centralSymmetry(final IPoint centre) {
return rotatePoint(centre, Math.PI);
}
@Override
public IPoint rotatePoint(final IPoint gravityC, final double theta) {
if(!MathUtils.INST.isValidPt(gravityC) || !MathUtils.INST.isValidCoord(theta)) {
return null;
}
final IPoint pt = ShapeFactory.INST.createPoint();
final double cosTheta;
final double sinTheta;
double angle = theta;
final double gx = gravityC.getX();
final double gy = gravityC.getY();
if(angle < 0.) {
angle = 2. * PI + angle;
}
angle %= 2. * PI;
if(MathUtils.INST.equalsDouble(angle, 0.)) {
return new LPoint(this);
}
if(MathUtils.INST.equalsDouble(angle - PI / 2., 0.)) {
cosTheta = 0.;
sinTheta = 1.;
}else if(MathUtils.INST.equalsDouble(angle - PI, 0.)) {
cosTheta = -1.;
sinTheta = 0.;
}else if(MathUtils.INST.equalsDouble(angle - 3. * PI / 2., 0.)) {
cosTheta = 0.;
sinTheta = -1.;
}else {
cosTheta = Math.cos(angle);
sinTheta = Math.sin(angle);
}
pt.setX(cosTheta * (getX() - gx) - sinTheta * (getY() - gy) + gx);
pt.setY(sinTheta * (getX() - gx) + cosTheta * (getY() - gy) + gy);
return pt;
}
@Override
public boolean equals(final IPoint p, final double gap) {
return !(!MathUtils.INST.isValidCoord(gap) || !MathUtils.INST.isValidPt(p)) && MathUtils.INST.equalsDouble(getX(), p.getX(), gap) &&
MathUtils.INST.equalsDouble(getY(), p.getY(), gap);
}
@Override
public IPoint getMiddlePoint(final IPoint p) {
return p == null ? null : ShapeFactory.INST.createPoint((getX() + p.getX()) / 2., (getY() + p.getY()) / 2d);
}
@Override
public void translate(final double tx, final double ty) {
if(MathUtils.INST.isValidPt(tx, ty)) setPoint(getX() + tx, getY() + ty);
}
@Override
public IPoint horizontalSymmetry(final IPoint origin) {
if(!MathUtils.INST.isValidPt(origin)) return null;
return ShapeFactory.INST.createPoint(2d * origin.getX() - getX(), getY());
}
@Override
public IPoint verticalSymmetry(final IPoint origin) {
if(!MathUtils.INST.isValidPt(origin)) return null;
return ShapeFactory.INST.createPoint(getX(), 2d * origin.getY() - getY());
}
@Override
public void setPoint(final double newX, final double newY) {
setX(newX);
setY(newY);
}
@Override
public void setX(final double newX) {
if(MathUtils.INST.isValidCoord(newX)) x.set(newX);
}
@Override
public void setY(final double newY) {
if(MathUtils.INST.isValidCoord(newY)) y.set(newY);
}
@Override
public void setPoint(final IPoint pt) {
if(pt != null) setPoint(pt.getX(), pt.getY());
}
@Override
public double distance(final IPoint pt) {
return pt == null ? java.lang.Double.NaN : distance(pt.getX(), pt.getY());
}
@Override
public Point2D.Double toPoint2D() {
return new Point2D.Double(x.getValue(), y.getValue());
}
@Override
public Point3D toPoint3D() {
return new Point3D(x.getValue(), y.getValue(), 0d);
}
@Override
public void setPoint2D(final Point2D pt) {
if(pt != null) setPoint(pt.getX(), pt.getY());
}
@Override
public IPoint substract(final IPoint pt) {
if(pt == null) return null;
return ShapeFactory.INST.createPoint(getX() - pt.getX(), getY() - pt.getY());
}
@Override
public IPoint normalise() {
final double magnitude = magnitude();
return ShapeFactory.INST.createPoint(getX() / magnitude, getY() / magnitude);
}
@Override
public double magnitude() {
return Math.sqrt(getX() * getX() + getY() * getY());
}
@Override
public IPoint add(final IPoint pt) {
final IPoint added = ShapeFactory.INST.createPoint(this);
if(pt != null) added.translate(pt.getX(), pt.getY());
return added;
}
@Override
public @NonNull DoubleProperty xProperty() {
return x;
}
@Override
public @NonNull DoubleProperty yProperty() {
return y;
}
@Override
public double getY() {
return y.get();
}
@Override
public double getX() {
return x.get();
}
@Override
public double distance(double xCoord, double yCoord) {
return Math.sqrt(Math.pow(xCoord - x.get(), 2) + Math.pow(yCoord - y.get(), 2));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp = Double.doubleToLongBits(x.doubleValue());
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y.doubleValue());
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(final Object obj) {
if(this == obj) return true;
if(!(obj instanceof IPoint)) return false;
final IPoint other = (IPoint) obj;
if(Double.doubleToLongBits(x.doubleValue()) != Double.doubleToLongBits(other.getX())) return false;
if(Double.doubleToLongBits(y.doubleValue()) != Double.doubleToLongBits(other.getY())) return false;
return true;
}
@Override
public String toString() {
return "LPoint [x=" + x.doubleValue() + ", y=" + y.doubleValue() + "]";
}
}