/** * Computes the oriented distance from a point to the plane. * The distance is: * <ul> * <li><b>positive</b> if the point lies above the plane (relative to the plane normal) * <li><b>zero</b> if the point is on the plane * <li><b>negative</b> if the point lies below the plane (relative to the plane normal) * </ul> * * @param p the point to compute the distance for * @return the oriented distance to the plane */ public double orientedDistance(Coordinate p) { Vector3D pb = new Vector3D(p, basePt); double pbdDotNormal = pb.dot(normal); if (Double.isNaN(pbdDotNormal)) throw new IllegalArgumentException("3D Coordinate has NaN ordinate"); double d = pbdDotNormal / normal.length(); return d; }
/** * Computes the axis plane that this plane lies closest to. * <p> * Geometries lying in this plane undergo least distortion * (and have maximum area) * when projected to the closest axis plane. * This provides optimal conditioning for * computing a Point-in-Polygon test. * * @return the index of the closest axis plane. */ public int closestAxisPlane() { double xmag = Math.abs(normal.getX()); double ymag = Math.abs(normal.getY()); double zmag = Math.abs(normal.getZ()); if (xmag > ymag) { if (xmag > zmag) return YZ_PLANE; else return XY_PLANE; } // y >= x else if (zmag > ymag) { return XY_PLANE; } // y >= z return XZ_PLANE; }
/** * Computes an average normal vector from a list of polygon coordinates. * Uses Newell's method, which is based * on the fact that the vector with components * equal to the areas of the projection of the polygon onto * the Cartesian axis planes is normal. * * @param seq the sequence of coordinates for the polygon * @return a normal vector */ private Vector3D averageNormal(CoordinateSequence seq) { int n = seq.size(); Coordinate sum = new Coordinate(0,0,0); Coordinate p1 = new Coordinate(0,0,0); Coordinate p2 = new Coordinate(0,0,0); for (int i = 0; i < n - 1; i++) { seq.getCoordinate(i, p1); seq.getCoordinate(i+1, p2); sum.x += (p1.y - p2.y)*(p1.z + p2.z); sum.y += (p1.z - p2.z)*(p1.x + p2.x); sum.z += (p1.x - p2.x)*(p1.y + p2.y); } sum.x /= n; sum.y /= n; sum.z /= n; Vector3D norm = Vector3D.create(sum).normalize(); return norm; }
/** * Get the vector with the highest down slope in the plan. * @param normal * @param epsilon * @return the steepest vector. */ public static Vector3D getSteepestVector(final Vector3D normal, final double epsilon) { if (Math.abs(normal.getX()) < epsilon && Math.abs(normal.getY()) < epsilon) { return new Vector3D(0, 0, 0); } Vector3D slope; if (Math.abs(normal.getX()) < epsilon) { slope = new Vector3D(0, 1, -normal.getY() / normal.getZ()); } else if (Math.abs(normal.getY()) < epsilon) { slope = new Vector3D(1, 0, -normal.getX() / normal.getZ()); } else { slope = new Vector3D(normal.getX() / normal.getY(), 1, -1 / normal.getZ() * (normal.getX() * normal.getX() / normal.getY() + normal.getY())); } //We want the vector to be low-oriented. if (slope.getZ() > epsilon) { slope = new Vector3D(-slope.getX(), -slope.getY(), -slope.getZ()); } //We normalize it return slope.normalize(); }
/** * Compute the aspect in degree. The geometry must be a triangle. * @param geometry Polygon triangle * @return aspect in degree * @throws IllegalArgumentException ST_TriangleAspect accept only triangles */ public static Double computeAspect(Geometry geometry) throws IllegalArgumentException { if (geometry == null) { return null; } Vector3D vector = TriMarkers.getSteepestVector(TriMarkers.getNormalVector(TINFeatureFactory.createTriangle(geometry)), TINFeatureFactory.EPSILON); if (vector.length() < TINFeatureFactory.EPSILON) { return 0d; } else { Vector2D v = new Vector2D(vector.getX(), vector.getY()); return measureFromNorth(Math.toDegrees(v.angle())); } }
/** * Creates a vector from a {@link Coordinate}. * * @param coord * the Coordinate to copy * @return a new vector */ public static Vector3D create(Coordinate coord) { return new Vector3D(coord); }
public static Coordinate normalize(Coordinate v) { double len = length(v); return new Coordinate(v.x / len, v.y / len, v.z / len); } /**
private Vector3D divide(double d) { return create(x / d, y / d, z / d); }
/** * Get the vector with the highest down slope in the plan. * @param normal * @param epsilon * @return the steepest vector. */ public static Vector3D getSteepestVector(final Vector3D normal, final double epsilon) { if (Math.abs(normal.getX()) < epsilon && Math.abs(normal.getY()) < epsilon) { return new Vector3D(0, 0, 0); } Vector3D slope; if (Math.abs(normal.getX()) < epsilon) { slope = new Vector3D(0, 1, -normal.getY() / normal.getZ()); } else if (Math.abs(normal.getY()) < epsilon) { slope = new Vector3D(1, 0, -normal.getX() / normal.getZ()); } else { slope = new Vector3D(normal.getX() / normal.getY(), 1, -1 / normal.getZ() * (normal.getX() * normal.getX() / normal.getY() + normal.getY())); } //We want the vector to be low-oriented. if (slope.getZ() > epsilon) { slope = new Vector3D(-slope.getX(), -slope.getY(), -slope.getZ()); } //We normalize it return slope.normalize(); }
/** * Compute the aspect in degree. The geometry must be a triangle. * @param geometry Polygon triangle * @return aspect in degree * @throws IllegalArgumentException ST_TriangleAspect accept only triangles */ public static Double computeAspect(Geometry geometry) throws IllegalArgumentException { if (geometry == null) { return null; } Vector3D vector = TriMarkers.getSteepestVector(TriMarkers.getNormalVector(TINFeatureFactory.createTriangle(geometry)), TINFeatureFactory.EPSILON); if (vector.length() < TINFeatureFactory.EPSILON) { return 0d; } else { Vector2D v = new Vector2D(vector.getX(), vector.getY()); return measureFromNorth(Math.toDegrees(v.angle())); } }
/** * Creates a new vector with given X and Y components. * * @param x * the x component * @param y * the y component * @param z * the z component * @return a new vector */ public static Vector3D create(double x, double y, double z) { return new Vector3D(x, y, z); }
public static Coordinate normalize(Coordinate v) { double len = length(v); return new Coordinate(v.x / len, v.y / len, v.z / len); } /**
private Vector3D divide(double d) { return create(x / d, y / d, z / d); }
Vector3D vector = new Vector3D(normal.getX(), normal.getY(), 0).normalize(); for(LineSegment side : sides) { Coordinate intersection = CoordinateUtils.vectorIntersection(inCenter, vector, side.p0, new Vector3D(side.p0,side.p1).normalize()); double distInters = intersection == null ? Double.MAX_VALUE : side.distance(intersection); if(intersection != null && distInters < nearestIntersection) {
/** * Computes the axis plane that this plane lies closest to. * <p> * Geometries lying in this plane undergo least distortion * (and have maximum area) * when projected to the closest axis plane. * This provides optimal conditioning for * computing a Point-in-Polygon test. * * @return the index of the closest axis plane. */ public int closestAxisPlane() { double xmag = Math.abs(normal.getX()); double ymag = Math.abs(normal.getY()); double zmag = Math.abs(normal.getZ()); if (xmag > ymag) { if (xmag > zmag) return YZ_PLANE; else return XY_PLANE; } // y >= x else if (zmag > ymag) { return XY_PLANE; } // y >= z return XZ_PLANE; }
/** * Get the normal vector to this triangle, of length 1. * @param t input triangle * @return vector normal to the triangle. */ public static Vector3D getNormalVector(Triangle t) throws IllegalArgumentException { if(Double.isNaN(t.p0.z) || Double.isNaN(t.p1.z) || Double.isNaN(t.p2.z)) { throw new IllegalArgumentException("Z is required, cannot compute triangle normal of "+t); } double dx1 = t.p0.x - t.p1.x; double dy1 = t.p0.y - t.p1.y; double dz1 = t.p0.z - t.p1.z; double dx2 = t.p1.x - t.p2.x; double dy2 = t.p1.y - t.p2.y; double dz2 = t.p1.z - t.p2.z; return Vector3D.create(dy1*dz2 - dz1*dy2, dz1 * dx2 - dx1 * dz2, dx1 * dy2 - dy1 * dx2).normalize(); }