/** * H2GIS is a library that brings spatial support to the H2 Database Engine * <http://www.h2database.com>. H2GIS is developed by CNRS * <http://www.cnrs.fr/>. * * This code is part of the H2GIS project. H2GIS is free software; * you can redistribute it and/or modify it under the terms of the GNU * Lesser General Public License as published by the Free Software Foundation; * version 3.0 of the License. * * H2GIS 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 Lesser General Public License * for more details <http://www.gnu.org/licenses/>. * * * For more information, please consult: <http://www.h2gis.org/> * or contact directly: info_at_h2gis.org */ package org.h2gis.utilities.jts_utils; import com.vividsolutions.jts.algorithm.CGAlgorithms; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Triangle; import com.vividsolutions.jts.math.Vector2D; import com.vividsolutions.jts.math.Vector3D; /** * Used by TriangleContouring. * Add the constraint of CCW orientation * Store also three double values, one fore each vertices * * ANR EvalPDU * IFSTTAR 11_05_2011 * @author Nicolas FORTIN, Judicaƫl PICAUT */ public class TriMarkers extends Triangle { /** * Default constructor */ public TriMarkers() { super(new Coordinate(), new Coordinate(), new Coordinate()); this.m1 = 0; this.m2 = 0; this.m3 = 0; } @Override public String toString() { return "TriMarkers{" + "p1=" + p0 + ", p2=" + p1 + ", p3=" + p2 + " m1=" + m1 + ", m2=" + m2 + ", m3=" + m3 + "}"; } /** * Constructor * @param p0 First vertex * @param p1 Second vertex * @param p2 Third vertex * @param m1 First vertex attribute * @param m2 Second vertex attribute * @param m3 Third vertex attribute */ public TriMarkers(Coordinate p0, Coordinate p1, Coordinate p2, double m1, double m2, double m3) { super(p0, p1, p2); if (!CGAlgorithms.isCCW(this.getRing())) { this.setCoordinates(p2, p1, p0); this.m1 = m3; this.m3 = m1; } else { this.m1 = m1; this.m3 = m3; } this.m2 = m2; } double m1, m2, m3; void setMarkers(double m1, double m2, double m3) { this.m1 = m1; this.m2 = m2; this.m3 = m3; } void setAll(Coordinate p0, Coordinate p1, Coordinate p2, double m1, double m2, double m3) { setCoordinates(p0, p1, p2); setMarkers(m1, m2, m3); if (!CGAlgorithms.isCCW(this.getRing())) { this.setCoordinates(p2, p1, p0); this.m1 = m3; this.m3 = m1; } } double getMinMarker() { return getMinMarker((short) -1); } double getMinMarker(int exception) { double minval = Double.POSITIVE_INFINITY; if (exception != 0) { minval = Math.min(minval, this.m1); } if (exception != 1) { minval = Math.min(minval, this.m2); } if (exception != 2) { minval = Math.min(minval, this.m3); } return minval; } double getMaxMarker() { return getMaxMarker((short) -1); } double getMaxMarker(int exception) { double maxval = Double.NEGATIVE_INFINITY; if (exception != 0) { maxval = Math.max(maxval, this.m1); } if (exception != 1) { maxval = Math.max(maxval, this.m2); } if (exception != 2) { maxval = Math.max(maxval, this.m3); } return maxval; } void setCoordinates(Coordinate p0, Coordinate p1, Coordinate p2) { this.p0 = p0; this.p1 = p1; this.p2 = p2; } Coordinate[] getRing() { return new Coordinate[] { p0, p1, p2, p0 }; } Coordinate getVertice(int idvert) { if (idvert == 0) { return p0; } else if (idvert == 1) { return p1; } else { return p2; } } double getMarker(int idvert) { if (idvert == 0) { return m1; } else if (idvert == 1) { return m2; } else { return m3; } } /** * 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(); } /** * 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(); } /** * * @param normal Plane normal * @param epsilon Epsilon value ex:1e-12 * @return The steepest slope of this plane in degree. */ public static double getSlopeInPercent(final Vector3D normal, final double epsilon) { Vector3D vector = getSteepestVector(normal, epsilon); if(Math.abs(vector.getZ()) < epsilon) { return 0; } else { return (Math.abs(vector.getZ()) / new Vector2D(vector.getX(), vector.getY()).length()) * 100; } } }