package ddddbb.math;
/**
* Class representing a Point or Vector of a given dimension.
*
* In all methods that take another Point p as argument the dimension of p must
* be less or equal to this dimension. If it is less then the unset coordinates
* are assumed to be 0.
*/
public class Point implements Comparable<Point>{
public final double[] x; // this should be read only; made public for sake of simplicity
/** creates Point of dimension n
* subclassing to Point3d or Point4d
* for n==3 or n==4 respectively.
* All create methods perform the proper subclassing.
*/
public static Point create(int n) {
if (n==3) return new Point3d();
if (n==4) return new Point4d();
return new Point(n);
}
protected Point(int n) {
x = new double[n];
}
protected Point(double[] x) {
this.x = x;
}
public Point clone() {
Point res = new Point(x.length);
for (int d=0;d<x.length;d++) {
res.x[d] = x[d];
}
return res;
}
public static Point create(int[] x) {
Point res = create(x.length);
for (int d=0;d<x.length;d++) {
res.x[d] = x[d];
}
return res;
}
/** creates Point, x remains unreferenced by this */
public static Point create(double[] x) {
Point res = create(x.length);
for (int i=0;i<x.length;i++) {
res.x[i] = x[i];
}
return res;
}
/** creates a Point referencing x */
public static Point wrap(double[] x) {
return new Point(x);
}
// /** creates vector of dimension dim from Axis a */
// public static Point create(DSignedAxis a, int dim) {
// Point res = create(dim);
// for (int i=0;i<dim;i++) res.x[i] = 0;
// res.x[a.axis()]=a.pmSign();
// return res;
// }
/** returns the dimension of this */
public int dim() {
return x.length;
}
/** returns the length of this */
public double len() {
double res = 0;
for (int i=0;i<x.length;i++) {
res += x[i]*x[i];
}
return Math.sqrt(res);
}
/** scalar product of this and b, no change of this */
public double sc(Point b) {
double res = 0;
for (int d=0;d<x.length;d++) {
res += x[d]*b.x[d];
}
return res;
}
/** faster sc(b.clone().subtract(a)) */
public double sc(Point a, Point b) {
double res = 0;
for (int d=0;d<x.length;d++) {
res += x[d]*(b.x[d]-a.x[d]);
}
return res;
}
/** subtracts b from this */
public Point subtract(Point b) {
for (int d=0;d<this.x.length;d++) {
x[d] -= b.x[d];
}
return this;
}
// /** the copy version of subtract */
// public Point minus(Point b) {
// Point res = clone();
// res.subtract(b);
// return res;
// }
/** adds d to this */
public Point add(Point d) {
for (int i=0;i<x.length;i++) {
x[i]+=d.x[i];
}
return this;
}
// /** the copy version of add */
// public Point plus(Point b) {
// Point res = clone();
// res.add(b);
// return res;
// }
/** multiplies this by f */
public Point multiply(double f) {
for (int i=0;i<x.length;i++) {
x[i] *= f;
}
return this;
}
// /** the copy version of multiply */
// public Point times(double f) {
// Point res = clone();
// res.multiply(f);
// return res;
//}
/** Faster add(d.clone().multiply(dist))
*/
public Point addby(Point d,double dist) {
for (int i=0;i<d.x.length;i++) {
x[i]+=d.x[i]*dist;
}
return this;
}
/* Rotates this by the angle ph in the plane spanned from a and b
* into the direction from a towards b
* a and b must be orthogonal and each must be normal
*/
public Point rotate(double ph,Point a, Point b) {
assert AOP.isZero(a.sc(b)) : a.sc(b);
assert AOP.eq(a.len(), 1) : a;
assert AOP.eq(b.len(), 1) : b;
double as = a.sc(this);
double bs = b.sc(this);
addby(a,-as);
addby(b,-bs);
// newthis + as*a2 + bs*b2 = oldthis
Point a2 = a.clone();
Point b2 = b.clone();
AOP.rotate(ph,a2,b2);
add(a2.multiply(as));
add(b2.multiply(bs));
return this;
}
/** angle from this to p!=0, 0<al<pi */
public double arc(Point p) {
return Math.acos(sc(p)/(len()*p.len()));
}
/** rotates this by the rotation from vector a to vector b */
public Point rotate(Point a, Point b) {
double assertLength = len();
double ph = a.arc(b);
if (AOP.eq(ph, 0)) return this;
Point a0 = a.clone();
Point b0 = b.clone();
AOP.orthoNormalize(a0,b0);
rotate(a.arc(b),a0,b0);
assert AOP.eq(assertLength, len()) : assertLength + "!=" + len();
return this;
}
/** rotates this with center p from direction a to direction b */
public Point rotate(double ph,Point a, Point b, Point p) {
subtract(p);
rotate(ph,a,b);
add(p);
return this;
}
/** returns the projection of Point p to this Point, this Point remains unmodified */
public Point proj(Point p) {
return clone().multiply(sc(p)/sc(this));
}
/** returns 1 if the first non-zero coordinate is positive
* returns 0 if the this is 0
* return -1 otherwise (if the first non-zero coordinate is negative)
* */
public int positivity() {
for (int i=0;i<x.length;i++) {
if (-AOP.ERR < x[i] && x[i]<AOP.ERR) { continue; }
if (x[i]>0) { return 1; }
if (x[i]<0) { return -1; }
}
return 0;
}
/** scales this Point to having length 1 */
public Point normalize() {
double l = len();
if (l >= AOP.ERR) {
for (int i=0;i<x.length;i++) {
x[i] /= l;
}
}
else {
for (int i=0;i< x.length;i++) {
x[i]=0;
}
}
assert Math.abs(len()-1) < AOP.ERR || len() < AOP.ERR : this;
return this;
}
public boolean isNormal() {
return Math.abs(len()-1) < AOP.ERR;
}
public String toString() {
String res = "(";
for (int i=0;i<x.length;i++) {
res += x[i] + ",";
}
res += ")";
return res;
}
public boolean equals(Object o) {
Point p = (Point) o;
if (x.length!=p.x.length) { return false; }
return clone().subtract(p).len() < AOP.ERR;
// for (int i=0;i<x.length;i++) {
// if (Math.abs(x[i]-p.x[i])>Main.opt.ERR) { return false; }
// }
// return true;
}
public int compareTo(Point o) {
for (int i=0;i<x.length;i++) {
if (x[i]<o.x[i]) return -1;
if (x[i]>o.x[i]) return 1;
}
return 0;
}
}