| /******************************************************************************* |
| * Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| <<<<<<< HEAD |
| * Pierre Allard - initial API and implementation |
| * Regent L'Archeveque |
| * |
| ======= |
| * Pierre Allard, |
| * Regent L'Archeveque - initial API and implementation |
| * |
| >>>>>>> refs/heads/eclipse_pa |
| * SPDX-License-Identifier: EPL-1.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.apogy.common.geometry.data3d; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| import javax.vecmath.Matrix4d; |
| import javax.vecmath.Point3d; |
| import javax.vecmath.Vector2d; |
| import javax.vecmath.Vector3d; |
| |
| import org.eclipse.apogy.common.geometry.data.Coordinates; |
| import org.eclipse.apogy.common.geometry.data.CoordinatesSet; |
| import org.eclipse.apogy.common.geometry.data.Mesh; |
| import org.eclipse.apogy.common.geometry.data.Polygon; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| |
| /** |
| * Utilities Class providing basic 3D data manipulations. |
| * |
| * @author pallard |
| */ |
| // FIXME Move under XCore. |
| public class Geometry3DUtilities { |
| |
| /** |
| * Returns the axis that is perpendicular to the specified reference plane. |
| * |
| * @param plane The reference plane. |
| * @return The reference axis perpendicular to the specified plane. |
| */ |
| public static CartesianAxis getPerpendicularAxis(CartesianPlane plane) { |
| CartesianAxis axis = null; |
| |
| switch (plane.getValue()) { |
| case CartesianPlane.XY_VALUE: |
| axis = CartesianAxis.Z; |
| break; |
| case CartesianPlane.XZ_VALUE: |
| axis = CartesianAxis.Y; |
| break; |
| case CartesianPlane.YZ_VALUE: |
| axis = CartesianAxis.X; |
| break; |
| } |
| |
| return axis; |
| } |
| |
| /** |
| * Returns the plane that is perpendicular to the specified reference axis. |
| * |
| * @param axis The reference axis. |
| * @return The reference plane perpendicular to the specified axis. |
| */ |
| public static CartesianPlane getPerpendicularPlane(CartesianAxis axis) { |
| CartesianPlane plane = null; |
| |
| switch (axis.getValue()) { |
| case CartesianAxis.X_VALUE: |
| plane = CartesianPlane.YZ; |
| break; |
| case CartesianAxis.Y_VALUE: |
| plane = CartesianPlane.XZ; |
| break; |
| case CartesianAxis.Z_VALUE: |
| plane = CartesianPlane.XY; |
| break; |
| } |
| |
| return plane; |
| } |
| |
| /** |
| * Return the spherical coordinates associated with a given Cartesian position. |
| * |
| * @param cartesianCoordinates The Cartesian position. |
| * @return The SphericalCoordinates representing the |
| * CartesianPositionCoordinates. |
| * @see http://en.wikipedia.org/wiki/Spherical_coordinate_system |
| */ |
| public static SphericalCoordinates getSphericalCoordinates(CartesianPositionCoordinates cartesianCoordinates) { |
| |
| double x2y2 = cartesianCoordinates.getX() * cartesianCoordinates.getX() |
| + cartesianCoordinates.getY() * cartesianCoordinates.getY(); |
| double r = Math.sqrt(x2y2 + (cartesianCoordinates.getZ() * cartesianCoordinates.getZ())); |
| double phi = 0.0; |
| |
| if (r != 0) { |
| phi = Math.acos(cartesianCoordinates.getZ() / r); |
| } else { |
| phi = Math.toRadians(90.0); |
| } |
| |
| double theta = Math.atan2(cartesianCoordinates.getY(), cartesianCoordinates.getX()); |
| |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createSphericalCoordinates(phi, theta, r); |
| } |
| |
| /** |
| * Return the Cartesian coordinates associated with a given spherical position. |
| * |
| * @param sphericalCoordinates The spherical position |
| * @return The CartesianPositionCoordinates representing the |
| * SphericalCoordinates. |
| * @see http://en.wikipedia.org/wiki/Spherical_coordinate_system |
| */ |
| public static CartesianPositionCoordinates getCartesianPositionCoordinates( |
| SphericalCoordinates sphericalCoordinates) { |
| |
| double x = sphericalCoordinates.getR() * Math.sin(sphericalCoordinates.getPhi()) |
| * Math.cos(sphericalCoordinates.getTheta()); |
| double y = sphericalCoordinates.getR() * Math.sin(sphericalCoordinates.getPhi()) |
| * Math.sin(sphericalCoordinates.getTheta()); |
| double z = sphericalCoordinates.getR() * Math.cos(sphericalCoordinates.getPhi()); |
| |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(x, y, z); |
| } |
| |
| /** |
| * Returns the centroid of a list of Cartesian positions. |
| * |
| * @param coordinates The list of Cartesian positions. |
| * @return The Cartesian position of the centroid. Returns (0,0,0) if the list |
| * of position is empty. |
| * @see http://en.wikipedia.org/wiki/Centroid |
| */ |
| public static CartesianPositionCoordinates getCentroid(List<CartesianPositionCoordinates> coordinates) { |
| return getCentroid(coordinates, null); |
| } |
| |
| /** |
| * Return the flatten position (i.e. projected onto one plane). |
| * |
| * @param plane The plane on which to flatten the position |
| * @param point The Point3d coordinates |
| * @return The flattened Point3d coordinates. |
| */ |
| public static Point3d getFlattenCoordinate(final CartesianPlane plane, final Point3d point) { |
| Point3d flattenPoint = null; |
| switch (plane.getValue()) { |
| case CartesianPlane.XY_VALUE: |
| flattenPoint = new Point3d(point.x, point.y, 0); |
| break; |
| case CartesianPlane.XZ_VALUE: |
| flattenPoint = new Point3d(point.x, 0, point.z); |
| break; |
| case CartesianPlane.YZ_VALUE: |
| flattenPoint = new Point3d(0, point.y, point.z); |
| break; |
| } |
| return flattenPoint; |
| } |
| |
| /** |
| * Return the flatten position (i.e. projected onto one plane). |
| * |
| * @param plane The plane on which to flatten the position |
| * @param point The Cartesian coordinates |
| * @return The flattened Cartesian coordinates. |
| */ |
| public static CartesianPositionCoordinates getFlattenCoordinate(final CartesianPlane plane, |
| final CartesianPositionCoordinates point) { |
| Point3d flattenPoint = getFlattenCoordinate(plane, point.asPoint3d()); |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(flattenPoint.x, |
| flattenPoint.y, flattenPoint.z); |
| } |
| |
| /** |
| * Return the flatten position (i.e. projected onto one plane). |
| * |
| * @param plane The plane on which to flatten the position, |
| * @param coordinates The list of Cartesian positions. |
| * @return The list of flattened Cartesian positions. |
| */ |
| public static List<Point3d> getPoint3dFlattenCoordinates(CartesianPlane plane, List<Point3d> coordinates) { |
| List<Point3d> flattenCoordinates = new ArrayList<Point3d>(); |
| |
| Iterator<Point3d> it = coordinates.iterator(); |
| while (it.hasNext()) { |
| Point3d p = it.next(); |
| Point3d flattenP = getFlattenCoordinate(plane, p); |
| flattenCoordinates.add(flattenP); |
| } |
| |
| return flattenCoordinates; |
| } |
| |
| /** |
| * Return the flatten position (i.e. projected onto one plane). |
| * |
| * @param plane The plane on which to flatten the position, |
| * @param coordinates The list of Cartesian positions. |
| * @return The list of flattened Cartesian positions. |
| */ |
| public static List<CartesianPositionCoordinates> getFlattenCoordinates(CartesianPlane plane, |
| List<CartesianPositionCoordinates> coordinates) { |
| List<CartesianPositionCoordinates> flattenCoordinates = new ArrayList<CartesianPositionCoordinates>(); |
| |
| Iterator<CartesianPositionCoordinates> it = coordinates.iterator(); |
| while (it.hasNext()) { |
| CartesianPositionCoordinates p = it.next(); |
| CartesianPositionCoordinates flattenP = getFlattenCoordinate(plane, p); |
| flattenCoordinates.add(flattenP); |
| } |
| |
| return flattenCoordinates; |
| } |
| |
| /** |
| * Returns the centroid of a list of Cartesian positions. |
| * |
| * @param coordinates The list of Cartesian positions. |
| * @param monitor Progress monitor to provide feedback on the operation. Can |
| * be null. |
| * @return The Cartesian position of the centroid. Returns (0,0,0) if the list |
| * of position is empty. |
| * @see http://en.wikipedia.org/wiki/Centroid |
| */ |
| public static CartesianPositionCoordinates getCentroid(List<CartesianPositionCoordinates> coordinates, |
| final IProgressMonitor monitor) { |
| |
| // Gets a valid IProgressMonitor. |
| IProgressMonitor internalMonitor = monitor; |
| if (internalMonitor == null) |
| internalMonitor = new NullProgressMonitor(); |
| |
| double x = 0.0; |
| double y = 0.0; |
| double z = 0.0; |
| |
| try { |
| internalMonitor.beginTask(Geometry3DUtilities.class.getSimpleName() + ".getCentroid", coordinates.size()); |
| |
| Iterator<CartesianPositionCoordinates> it = coordinates.iterator(); |
| while (it.hasNext()) { |
| CartesianPositionCoordinates coord = it.next(); |
| if (coord != null) { |
| x += coord.getX(); |
| y += coord.getY(); |
| z += coord.getZ(); |
| } |
| |
| internalMonitor.worked(1); |
| } |
| |
| if (coordinates.size() > 0) { |
| x = x / coordinates.size(); |
| y = y / coordinates.size(); |
| z = z / coordinates.size(); |
| } |
| } finally { |
| internalMonitor.done(); |
| } |
| |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(x, y, z); |
| } |
| |
| /** |
| * Returns the surface of the polygon defined by a list of |
| * CartesianPositionCoordinates. |
| * |
| * @param vertices The list of vertices composing the polygon. |
| * @return The surface. Returns zero if the list contains less than 3 vertices. |
| */ |
| public static double getPolygonSurface(List<CartesianPositionCoordinates> vertices) { |
| |
| double area = 0.0; |
| |
| if (vertices.size() == 3) { |
| CartesianPositionCoordinates p1 = vertices.get(0); |
| CartesianPositionCoordinates p2 = vertices.get(1); |
| CartesianPositionCoordinates p3 = vertices.get(2); |
| |
| // Creates a vector u (p1-p2) and a vector v (p1-p3) |
| Vector3d u = new Vector3d(p2.getX() - p1.getX(), p2.getY() - p1.getY(), p2.getZ() - p1.getZ()); |
| Vector3d v = new Vector3d(p3.getX() - p1.getX(), p3.getY() - p1.getY(), p3.getZ() - p1.getZ()); |
| Vector3d normal = new Vector3d(); |
| |
| // Area = ||u x v|| /2 |
| normal.cross(u, v); |
| area += normal.length() / 2.0; |
| } else if (vertices.size() > 3) { |
| throw new UnsupportedOperationException( |
| "getPolygonSurface() for polygons with more that 3 vertices is not implemented yet."); |
| } |
| |
| return area; |
| } |
| |
| /** |
| * Return the normal of a polygon defined by a list of |
| * CartesianPositionCoordinates; |
| * |
| * @param vertices The list of CartesianPositionCoordinates. |
| * @return The polygon normal, null if the list less than 3 points. |
| */ |
| public static Vector3d getPolygonNormal(List<CartesianPositionCoordinates> vertices) { |
| Vector3d normal = null; |
| |
| if (vertices.size() == 3) { |
| CartesianPositionCoordinates p1 = vertices.get(0); |
| CartesianPositionCoordinates p2 = vertices.get(1); |
| CartesianPositionCoordinates p3 = vertices.get(2); |
| |
| Vector3d u = new Vector3d(p2.getX() - p1.getX(), p2.getY() - p1.getY(), p2.getZ() - p1.getZ()); |
| Vector3d v = new Vector3d(p3.getX() - p1.getX(), p3.getY() - p1.getY(), p3.getZ() - p1.getZ()); |
| normal = new Vector3d(); |
| normal.cross(u, v); |
| } else if (vertices.size() > 3) { |
| throw new UnsupportedOperationException( |
| "getPolygonNormal() for polygons with more that 3 vertices is not implemented yet."); |
| } |
| |
| /* Normalize the normal. */ |
| normal.normalize(); |
| |
| return normal; |
| } |
| |
| /** |
| * Returns the projection of a point onto a polygon. |
| * |
| * @param point The point to project. |
| * @param polygon The polygon to project the point onto. |
| * @return The CartesianPositionCoordinates of the intersection point onto the |
| * polygon plane. |
| */ |
| public static CartesianPositionCoordinates getProjectionInPolygonPlane(CartesianPositionCoordinates point, |
| CartesianPolygon polygon) { |
| if (polygon.getVertices().size() == 3) { |
| // Gets the projection Q' of the point Q in the plane of the polygon |
| // using the following : |
| // Q' = Q - rN |
| // r = N dot (Q-P) where P is a point on the plane. |
| |
| // Gets the plane normal |
| Vector3d N = getPolygonNormal(polygon.getVertices()); |
| N.normalize(); |
| |
| Vector3d Q = new Vector3d(point.getX(), point.getY(), point.getZ()); |
| Vector3d P = new Vector3d(polygon.getVertices().get(0).getX(), polygon.getVertices().get(0).getY(), |
| polygon.getVertices().get(0).getZ()); |
| |
| Vector3d PQ = new Vector3d(); |
| PQ.sub(Q, P); |
| |
| double r = N.dot(PQ); |
| Vector3d Qprime = new Vector3d(Q); |
| N.scale(r); |
| Qprime.sub(Q, N); |
| |
| CartesianPositionCoordinates projection = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(Qprime.x, Qprime.y, Qprime.z); |
| |
| return projection; |
| } else if (polygon.getVertices().size() > 3) { |
| throw new UnsupportedOperationException( |
| "getProjection() for polygons with more that 3 vertices is not implemented yet."); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the projection of a point onto a polygon. |
| * |
| * @param point The point to project. |
| * @param polygon The polygon to project the point onto. |
| * @return The CartesianPositionCoordinates of the intersection point, null if |
| * the projection does not fall on the polygon. |
| */ |
| public static CartesianPositionCoordinates getProjectionOnPolygon(CartesianPositionCoordinates point, |
| CartesianPolygon polygon) { |
| if (polygon.getVertices().size() == 3) { |
| CartesianPositionCoordinates projection = getProjectionInPolygonPlane(point, polygon); |
| |
| // Finds if the projection fits inside the polygon boundaries. |
| if (isInsidePolygon(projection, polygon)) { |
| return projection; |
| } else { |
| return null; |
| } |
| } else if (polygon.getVertices().size() > 3) { |
| throw new UnsupportedOperationException( |
| "getProjection() for polygons with more that 3 vertices is not implemented yet."); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the projection of a point on a polygon along a specified axis. |
| * |
| * @param axis The axis along which to project the point. |
| * @param point The point to project. |
| * @param polygon The polygon onto which to project. |
| * @return The point of intersection, null if the intersection point falls |
| * outside the projected polygon. |
| * @see Geometrics Tools for Computer Graphics, pp. 482-484. |
| */ |
| public static CartesianPositionCoordinates getProjectionAlongAxisOnToPolygon(CartesianAxis axis, Point3d point, |
| CartesianPolygon polygon) { |
| if (polygon.getVertices().size() == 3) { |
| // Gets the polygon normal. |
| Point3d lineOrigin = null; |
| Vector3d lineDirection = null; |
| |
| switch (axis.getValue()) { |
| case CartesianAxis.X_VALUE: { |
| lineOrigin = new Point3d(Float.MIN_VALUE, point.getY(), point.getZ()); |
| lineDirection = new Vector3d(1, 0, 0); |
| } |
| break; |
| case CartesianAxis.Y_VALUE: { |
| lineOrigin = new Point3d(point.getX(), Float.MIN_VALUE, point.getZ()); |
| lineDirection = new Vector3d(0, 1, 0); |
| } |
| break; |
| case CartesianAxis.Z_VALUE: { |
| lineOrigin = new Point3d(point.getX(), point.getY(), Float.MIN_VALUE); |
| lineDirection = new Vector3d(0, 0, 1); |
| } |
| break; |
| |
| } |
| |
| // Extracts the plane parametrized form. |
| Vector3d n = polygon.getNormal(); |
| n.normalize(); |
| double a = n.x; |
| double b = n.y; |
| double c = n.z; |
| |
| Vector3d vertex = new Vector3d(polygon.getVertices().get(0).asPoint3d()); |
| double d = -n.dot(vertex); |
| |
| // Computes the equation denominator. |
| double denominator = lineDirection.dot(n); |
| if (Math.abs(denominator) == 0) { |
| return null; |
| } |
| |
| // Computes the t parameters. |
| double t = -(a * lineOrigin.x + b * lineOrigin.y + c * lineOrigin.z + d); |
| t = t / denominator; |
| |
| // Computes the intersection point. |
| lineDirection.scale(t); |
| lineOrigin.add(lineDirection); |
| |
| // Check to see if the projected point falls inside the projected polygon. |
| Point3d flattenedPoint = getFlattenCoordinate(getPerpendicularPlane(axis), point); |
| |
| List<CartesianPositionCoordinates> flattenedVertices = getFlattenCoordinates(getPerpendicularPlane(axis), |
| polygon.getVertices()); |
| |
| CartesianPolygon flattenPolygon = ApogyCommonGeometryData3DFactory.eINSTANCE.createCartesianPolygon(); |
| flattenPolygon.getVertices().addAll(flattenedVertices); |
| |
| if (isInsidePolygon(flattenedPoint, flattenPolygon)) { |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(lineOrigin.x, |
| lineOrigin.y, lineOrigin.z); |
| } else { |
| return null; |
| } |
| } else if (polygon.getVertices().size() > 3) { |
| throw new UnsupportedOperationException( |
| "getProjection() for polygons with more that 3 vertices is not implemented yet."); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the projection of a point on a polygon along a specified axis. |
| * |
| * @param axis The axis along which to project the point. |
| * @param point The point to project. |
| * @param polygon The polygon onto which to project. |
| * @return The point of intersection, null if the intersection point falls |
| * outside the projected polygon. |
| * @see Geometrics Tools for Computer Graphics, pp. 482-484. |
| */ |
| public static CartesianPositionCoordinates getProjectionAlongAxisOnToPolygon(CartesianAxis axis, |
| CartesianPositionCoordinates point, CartesianPolygon polygon) { |
| if (polygon.getVertices().size() == 3) { |
| // Gets the polygon normal. |
| Point3d lineOrigin = null; |
| Vector3d lineDirection = null; |
| |
| switch (axis.getValue()) { |
| case CartesianAxis.X_VALUE: { |
| lineOrigin = new Point3d(Float.MIN_VALUE, point.getY(), point.getZ()); |
| lineDirection = new Vector3d(1, 0, 0); |
| } |
| break; |
| case CartesianAxis.Y_VALUE: { |
| lineOrigin = new Point3d(point.getX(), Float.MIN_VALUE, point.getZ()); |
| lineDirection = new Vector3d(0, 1, 0); |
| } |
| break; |
| case CartesianAxis.Z_VALUE: { |
| lineOrigin = new Point3d(point.getX(), point.getY(), Float.MIN_VALUE); |
| lineDirection = new Vector3d(0, 0, 1); |
| } |
| break; |
| |
| } |
| |
| // Extracts the plane parametrized form. |
| Vector3d n = polygon.getNormal(); |
| n.normalize(); |
| double a = n.x; |
| double b = n.y; |
| double c = n.z; |
| |
| Vector3d vertex = new Vector3d(polygon.getVertices().get(0).asPoint3d()); |
| double d = -n.dot(vertex); |
| |
| // Computes the equation denominator. |
| double denominator = lineDirection.dot(n); |
| if (Math.abs(denominator) == 0) { |
| return null; |
| } |
| |
| // Computes the t parameters. |
| double t = -(a * lineOrigin.x + b * lineOrigin.y + c * lineOrigin.z + d); |
| t = t / denominator; |
| |
| // Computes the intersection point. |
| lineDirection.scale(t); |
| lineOrigin.add(lineDirection); |
| |
| // Check to see if the projected point falls inside the projected polygon. |
| CartesianPositionCoordinates flattenedPoint = getFlattenCoordinate(getPerpendicularPlane(axis), point); |
| List<CartesianPositionCoordinates> flattenedVertices = getFlattenCoordinates(getPerpendicularPlane(axis), |
| polygon.getVertices()); |
| |
| CartesianPolygon flattenPolygon = ApogyCommonGeometryData3DFactory.eINSTANCE.createCartesianPolygon(); |
| flattenPolygon.getVertices().addAll(flattenedVertices); |
| |
| if (isInsidePolygon(flattenedPoint, flattenPolygon)) { |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(lineOrigin.x, |
| lineOrigin.y, lineOrigin.z); |
| } else { |
| return null; |
| } |
| } else if (polygon.getVertices().size() > 3) { |
| throw new UnsupportedOperationException( |
| "getProjection() for polygons with more that 3 vertices is not implemented yet."); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the projection of a list of points on a list of polygons along a |
| * specified axis. |
| * |
| * @param axis The axis along which to project the point. |
| * @param points The list of points. |
| * @param polygons The list of polygons. |
| * @return The array containing the projection of the point. |
| */ |
| public static <T extends CartesianPolygon> CartesianPositionCoordinates[] getProjectionAlongAxisOnToPolygon( |
| CartesianAxis axis, List<CartesianPositionCoordinates> points, List<T> polygons) { |
| // Finds the centroid of the points. |
| CartesianPositionCoordinates centroid = getCentroid(points); |
| |
| // Sorts the polygon according to the distance to the centroid. |
| SortedSet<CartesianPolygon> sortedPolygons = Geometry3DUtilities.sortCartesianPolygonByDistance(centroid, |
| polygons); |
| |
| // For each of the point, tries to find a projection. |
| CartesianPositionCoordinates[] intersections = new CartesianPositionCoordinates[points.size()]; |
| |
| for (int i = 0; i < points.size(); i++) { |
| // System.out.println("i " + i); |
| CartesianPositionCoordinates point = points.get(i); |
| |
| CartesianPositionCoordinates projection = null; |
| |
| Iterator<CartesianPolygon> it = sortedPolygons.iterator(); |
| while ((projection == null) && (it.hasNext())) { |
| CartesianPolygon polygon = it.next(); |
| projection = Geometry3DUtilities.getProjectionAlongAxisOnToPolygon(CartesianAxis.Z, point, polygon); |
| } |
| intersections[i] = projection; |
| } |
| |
| return intersections; |
| } |
| |
| /** |
| * Projects all of the points of a mesh on the plane defined by a polygon. |
| * |
| * @param mesh The mesh to project. |
| * @param projectionPlanePolygon The polygon defining the plane. |
| * @return A new mesh representing the projection. |
| */ |
| public static CartesianCoordinatesMesh getProjectedCartesianCoordinatesMeshOnPlane(CartesianCoordinatesMesh mesh, |
| CartesianPolygon projectionPlanePolygon) { |
| CartesianCoordinatesMesh newMesh = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianCoordinatesMesh(mesh); |
| Iterator<CartesianPositionCoordinates> iterator = newMesh.getPoints().iterator(); |
| /* Project each points on the plane */ |
| while (iterator.hasNext()) { |
| CartesianPositionCoordinates vMesh = iterator.next(); |
| CartesianPositionCoordinates vProj = Geometry3DUtilities.getProjectionInPolygonPlane(vMesh, |
| projectionPlanePolygon); |
| vMesh.setX(vProj.getX()); |
| vMesh.setY(vProj.getY()); |
| vMesh.setZ(vProj.getZ()); |
| } |
| |
| return newMesh; |
| } |
| |
| /** |
| * Projects all of the points of a mesh on the plane defined by a polygon. |
| * |
| * @param mesh The mesh to project. |
| * @param projectionPlanePolygon The polygon defining the plane. |
| * @return A new mesh representing the projection. |
| */ |
| public static CartesianTriangularMesh getProjectedCartesianTriangularMeshOnPlane(CartesianTriangularMesh mesh, |
| CartesianPolygon projectionPlanePolygon) { |
| CartesianTriangularMesh newMesh = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianTriangularMesh(mesh.getPolygons()); |
| |
| Iterator<CartesianPositionCoordinates> iterator = newMesh.getPoints().iterator(); |
| /* Project each points on the plane */ |
| while (iterator.hasNext()) { |
| CartesianPositionCoordinates vMesh = iterator.next(); |
| CartesianPositionCoordinates vProj = Geometry3DUtilities.getProjectionInPolygonPlane(vMesh, |
| projectionPlanePolygon); |
| vMesh.setX(vProj.getX()); |
| vMesh.setY(vProj.getY()); |
| vMesh.setZ(vProj.getZ()); |
| } |
| |
| return newMesh; |
| } |
| |
| /** |
| * Returns whether or not a point falls within the boundary of a polygon. |
| * |
| * @param point The point. |
| * @param polygon The polygon |
| * @return True if the point falls inside the polygon, false otherwise. |
| */ |
| public static boolean isInsidePolygon(Point3d point, CartesianPolygon polygon) { |
| boolean isInside = true; |
| |
| // For each of the edges of the polygon check on which side of the edge the |
| // point fall. |
| CartesianPositionCoordinates[] vertices = new CartesianPositionCoordinates[polygon.getVertices().size() + 1]; |
| polygon.getVertices().toArray(vertices); |
| |
| int i = 0; |
| int vertexCount = vertices.length - 1; |
| |
| /* |
| * Add the first point of the polygon at the end of the array in order to test |
| * the last polygon segment |
| */ |
| vertices[vertexCount] = vertices[0]; |
| |
| Vector3d polygonNormal = getPolygonNormal(polygon.getVertices()); |
| |
| Point3d c = new Point3d(point.x, point.y, point.z); |
| while ((i < vertexCount) && isInside) { |
| Point3d a = new Point3d(vertices[i].getX(), vertices[i].getY(), vertices[i].getZ()); |
| Point3d b = new Point3d(vertices[i + 1].getX(), vertices[i + 1].getY(), vertices[i + 1].getZ()); |
| |
| if (getSide(a, b, c, polygonNormal) < 0) { |
| isInside = false; |
| } |
| i++; |
| } |
| |
| return isInside; |
| } |
| |
| /** |
| * Returns whether or not a point falls within the boundary of a polygon. |
| * |
| * @param point The point. |
| * @param polygon The polygon |
| * @return True if the point falls inside the polygon, false otherwise. |
| */ |
| public static boolean isInsidePolygon(CartesianPositionCoordinates point, CartesianPolygon polygon) { |
| return isInsidePolygon(point.asPoint3d(), polygon); |
| } |
| |
| /** |
| * Returns whether a sphere intersects with a polygon. |
| * |
| * @param center The center of the sphere. |
| * @param radius The radius of the sphere. |
| * @param includeZeroOverlap Enable to consider zero-overlap (just touching) to |
| * be considered. |
| * @param polygon The polygon. |
| * @return True if the sphere touches the polygon, false otherwise. |
| */ |
| public static <T extends CartesianPolygon> boolean isSphereIntersectsPolygon( |
| final CartesianPositionCoordinates center, double radius, final boolean includeZeroOverlap, |
| final T polygon) { |
| boolean isInside = false; |
| |
| // First checks if the center point falls inside the polygon. |
| if (isInsidePolygon(center, polygon)) { |
| isInside = true; |
| } |
| |
| // Check to see if at least on of the polygon vertex falls inside the sphere. |
| if (!isInside) { |
| int i = 0; |
| while (i < polygon.getVertices().size() && !isInside) { |
| CartesianPositionCoordinates point = polygon.getVertices().get(i); |
| Vector3d tmp = new Vector3d(); |
| tmp.sub(point.asPoint3d(), center.asPoint3d()); |
| double length = tmp.length(); |
| if (length <= radius) { |
| if (includeZeroOverlap) { |
| isInside = true; |
| } else if (length < radius) { |
| isInside = true; |
| } |
| } |
| i++; |
| } |
| } |
| |
| // Checks if part of the polygon lies inside. |
| if (!isInside) { |
| // Gets the list of polygon edges. |
| CartesianPositionCoordinates[] vertices = new CartesianPositionCoordinates[polygon.getVertices().size() |
| + 1]; |
| polygon.getVertices().toArray(vertices); |
| |
| int i = 0; |
| int vertexCount = vertices.length - 1; |
| |
| /* |
| * Add the first point of the polygon at the end of the array in order to test |
| * the last polygon segment |
| */ |
| vertices[vertexCount] = vertices[0]; |
| |
| Vector3d c = new Vector3d(center.getX(), center.getY(), center.getZ()); |
| while ((i < vertexCount) && (!isInside)) { |
| Vector3d a = new Vector3d(vertices[i].getX(), vertices[i].getY(), vertices[i].getZ()); |
| Vector3d b = new Vector3d(vertices[i + 1].getX(), vertices[i + 1].getY(), vertices[i + 1].getZ()); |
| Vector3d centerProjectionOnEdge = getProjectionOfPointOntoLineSegment(c, a, b); |
| |
| if (centerProjectionOnEdge != null) { |
| Vector3d tmp = new Vector3d(c); |
| tmp.sub(centerProjectionOnEdge); |
| |
| if (tmp.length() <= radius) { |
| if (includeZeroOverlap) { |
| isInside = true; |
| } else if (tmp.length() < radius) { |
| isInside = true; |
| } |
| } |
| } |
| i++; |
| } |
| } |
| return isInside; |
| } |
| |
| /** |
| * Gets the distance between a point and a infinite line. |
| * |
| * @param point The point. |
| * @param p1 The first point defining the infinite line. |
| * @param p2 The second point defining the infinite line. |
| * @return The distance between the point and the infinite line. Note that the |
| * line extends beyond the points used to define it. |
| */ |
| public static double getPointToLineDistance(final CartesianPositionCoordinates point, |
| final CartesianPositionCoordinates p1, final CartesianPositionCoordinates p2) { |
| return getPointToLineDistance(new Vector3d(point.asPoint3d()), new Vector3d(p1.asPoint3d()), |
| new Vector3d(p2.asPoint3d())); |
| } |
| |
| /** |
| * Gets the distance between a point and an infinite line. |
| * |
| * @param point The point. |
| * @param p1 The first point defining the infinite line. |
| * @param p2 The second point defining the infinite line. |
| * @return The distance between the point and the line. Note that the line |
| * extends beyond the points used to define it. |
| * @see "Geometric Tools for Computer Graphics", pp.366-367. |
| */ |
| public static double getPointToLineDistance(final Vector3d point, final Vector3d p1, final Vector3d p2) { |
| Vector3d projectionOntoLine = getProjectionOfPointOntoLine(point, p1, p2); |
| projectionOntoLine.sub(point); |
| return projectionOntoLine.length(); |
| } |
| |
| /** |
| * Returns the projection of a point onto an infinite line. |
| * |
| * @param point The point. |
| * @param p1 The first point defining the infinite line. |
| * @param p2 The second point defining the infinite line. |
| * @return The projection of the point onto the infinite line. |
| * @see "Geometric Tools for Computer Graphics", pp.366-367. |
| */ |
| public static CartesianPositionCoordinates getProjectionOfPointOntoLine(final CartesianPositionCoordinates point, |
| final CartesianPositionCoordinates p1, final CartesianPositionCoordinates p2) { |
| Vector3d q = getProjectionOfPointOntoLine(new Vector3d(point.asPoint3d()), new Vector3d(p1.asPoint3d()), |
| new Vector3d(p2.asPoint3d())); |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(q.x, q.y, q.z); |
| } |
| |
| /** |
| * Returns the projection of a point onto an infinite line. |
| * |
| * @param point The point. |
| * @param p1 The first point defining the infinite line. |
| * @param p2 The second point defining the infinite line. |
| * @return The projection of the point onto the infinite line. |
| * @see "Geometric Tools for Computer Graphics", pp.366-367. |
| */ |
| public static Vector3d getProjectionOfPointOntoLine(final Vector3d point, final Vector3d p1, final Vector3d p2) { |
| Vector3d direction = new Vector3d(); |
| direction.sub(p2, p1); |
| |
| Vector3d qp = new Vector3d(); |
| qp.sub(point, p1); |
| |
| double t = direction.dot(qp); |
| |
| Vector3d qPrime = new Vector3d(); |
| |
| direction.scale(t); |
| qPrime.add(p1, direction); |
| |
| return qPrime; |
| } |
| |
| /** |
| * Returns the projection of a point onto an line segment. |
| * |
| * @param point The point. |
| * @param p1 The first point defining the line segment. |
| * @param p2 The first point defining the line segment. |
| * @return The projection of the point onto the line segment, null if the |
| * projection of the point does not fall onto the line segment. |
| * @see "Geometric Tools for Computer Graphics", pp.366-368. |
| */ |
| public static CartesianPositionCoordinates getProjectionOfPointOntoLineSegment( |
| final CartesianPositionCoordinates point, final CartesianPositionCoordinates p1, |
| final CartesianPositionCoordinates p2) { |
| Vector3d q = getProjectionOfPointOntoLine(new Vector3d(point.asPoint3d()), new Vector3d(p1.asPoint3d()), |
| new Vector3d(p2.asPoint3d())); |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(q.x, q.y, q.z); |
| } |
| |
| /** |
| * Returns the projection of a point onto an line segment. |
| * |
| * @param point The point. |
| * @param p1 The first point defining the line segment. |
| * @param p2 The first point defining the line segment. |
| * @return The projection of the point onto the line segment, null if the |
| * projection of the point does not fall onto the line segment. |
| * @see "Geometric Tools for Computer Graphics", pp.366-368. |
| */ |
| public static Vector3d getProjectionOfPointOntoLineSegment(final Vector3d point, final Vector3d p1, |
| final Vector3d p2) { |
| Vector3d direction = new Vector3d(); |
| direction.sub(p2, p1); |
| |
| Vector3d qp = new Vector3d(); |
| qp.sub(point, p1); |
| |
| double t = direction.dot(qp); |
| |
| // If the projection falls onto the segment. |
| if ((0 <= t) && (t <= 1)) { |
| Vector3d qPrime = new Vector3d(); |
| direction.scale(t); |
| qPrime.add(p1, direction); |
| |
| return qPrime; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Tells whether or not a line intersect with all the polygons. |
| * |
| * @param <T> |
| * @param plane The plane onto which to project both line and polygons. |
| * @param p1 The first point defining the line. |
| * @param p2 The second point defining the line. |
| * @param polygons The list of polygon. |
| * @return True if the line intersect ALL polygon, false othwerwise; |
| */ |
| public static <T extends CartesianPolygon> boolean isLineIntersectsAllPolygons(final CartesianPlane plane, |
| final CartesianPositionCoordinates p1, final CartesianPositionCoordinates p2, final List<T> polygons) { |
| boolean intersect = true; |
| int i = 0; |
| while (intersect && (i < polygons.size())) { |
| T polygon = polygons.get(i); |
| |
| if (!isLineIntersectsPolygon(plane, p1, p2, polygon)) { |
| intersect = false; |
| } else { |
| } |
| i++; |
| } |
| |
| return intersect; |
| } |
| |
| /** |
| * Tells whether or not a line intersect a polygon. |
| * |
| * @param <T> |
| * @param plane The plane onto which to project both line and polygon. |
| * @param p1 The first point defining the line. |
| * @param p2 The second point defining the line. |
| * @param polygon The polygon. |
| * @return True if the line intersect at least one of the polygon edge, false |
| * otherwise. |
| */ |
| public static <T extends CartesianPolygon> boolean isLineIntersectsPolygon(final CartesianPlane plane, |
| final CartesianPositionCoordinates p1, final CartesianPositionCoordinates p2, final T polygon) { |
| if (polygon.getVertices().size() > 2) { |
| Vector2d u1 = getVector2D(plane, p1); |
| Vector2d u2 = getVector2D(plane, p2); |
| |
| // Check to see if the line intersect at least one edge of the polygon. |
| int i = 0; |
| while (i < polygon.getVertices().size()) { |
| CartesianPositionCoordinates e1 = null; |
| CartesianPositionCoordinates e2 = null; |
| |
| // Test all edges. |
| if (i < (polygon.getVertices().size() - 1)) { |
| e1 = polygon.getVertices().get(i); |
| e2 = polygon.getVertices().get(i + 1); |
| } else { |
| e1 = polygon.getVertices().get(polygon.getVertices().size() - 1); |
| e2 = polygon.getVertices().get(0); |
| } |
| |
| Vector2d v1 = getVector2D(plane, e1); |
| Vector2d v2 = getVector2D(plane, e2); |
| |
| // Find the intersection point between the line and the edge. |
| Vector2d intersect = getLineIntersectionPoint(u1, u2, v1, v2); |
| |
| // Checks is the intersection point falls on the edge segment and the line |
| // segment. |
| if (intersect != null) { |
| double edgeLength = getDistance(v1, v2); |
| double lineLength = getDistance(u1, u2); |
| |
| if ((getDistance(intersect, v1) < edgeLength) && (getDistance(intersect, v1) > 0) |
| && (getDistance(intersect, v2) < edgeLength) && (getDistance(intersect, v2) > 0) |
| && (getDistance(intersect, u1) < lineLength) && (getDistance(intersect, u1) > 0) |
| && (getDistance(intersect, u2) < lineLength) && (getDistance(intersect, u2) > 0)) |
| return true; |
| } |
| i++; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Computes the Euclidian distance separating two Vector2d. |
| * |
| * @param v1 The first Vector2d. |
| * @param v2 The second Vector2d. |
| * @return The distance. |
| */ |
| public static double getDistance(Vector2d v1, Vector2d v2) { |
| return Math.sqrt((v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y - v2.y)); |
| } |
| |
| /** |
| * Converts a CartesianPositionCoordinates to a Vector2d by flattening it on a |
| * specified plane. |
| * |
| * @param plane The plane to flatten onto. |
| * @param point The CartesianPositionCoordinates to convert. |
| * @return The vector2d. |
| */ |
| public static Vector2d getVector2D(final CartesianPlane plane, CartesianPositionCoordinates point) { |
| Vector2d vector2d = null; |
| |
| switch (plane.getValue()) { |
| case CartesianPlane.XY_VALUE: { |
| vector2d = new Vector2d(point.getX(), point.getY()); |
| break; |
| } |
| case CartesianPlane.XZ_VALUE: { |
| vector2d = new Vector2d(point.getX(), point.getZ()); |
| break; |
| } |
| case CartesianPlane.YZ_VALUE: { |
| vector2d = new Vector2d(point.getY(), point.getZ()); |
| break; |
| } |
| } |
| |
| return vector2d; |
| } |
| |
| /** |
| * Return the point of intersection between a line and a polygon. |
| * |
| * @param u The first point (origin) defining the line. |
| * @param v The second point defining the line. |
| * @param polygon The polygon |
| * @return The intersection point, null if none is found. |
| * @see http://en.wikipedia.org/wiki/Line-plane_intersection |
| */ |
| public static Point3d getLineAndPolygonIntersectionPoint(final Vector3d u, final Vector3d v, |
| final CartesianPolygon polygon) { |
| // First, find the normal of the polygon. |
| Vector3d n = polygon.getNormal(); |
| n.normalize(); |
| |
| // Define a point p0 that lies on the plane. |
| Point3d p0 = polygon.getVertices().get(0).asPoint3d(); |
| |
| // Define point l0 as being the origin of the line. |
| Vector3d l0 = new Vector3d(u); |
| |
| // Defines l as a vector in the direction of the line. |
| Vector3d l = new Vector3d(v); |
| l.sub(u); |
| |
| // Defines l dot n as the numerator |
| Vector3d lDotn = new Vector3d(l); |
| double numerator = lDotn.dot(n); |
| |
| // Defines the denominator |
| Vector3d p0l0 = new Vector3d(p0); |
| p0l0.sub(l0); |
| double denominator = p0l0.dot(n); |
| |
| if (numerator == 0) { |
| // Both numerator and denominator are 0 -> line lies in the plane. |
| if (denominator == 0) { |
| return new Point3d(u); |
| } else { |
| // Numerator only is zero -> no intersection. |
| return null; |
| } |
| } |
| |
| // Defines the distance d along the line where the line intersects the plane. |
| double d = denominator / numerator; |
| |
| // If the distance falls within the line boundary |
| if ((d >= 0.0) && (d <= 1.0)) { |
| // Finds the intersection by moving by distance d along the line. |
| Vector3d line = new Vector3d(l); |
| // line.normalize(); |
| line.scale(d); |
| line.add(u); |
| Point3d intersection = new Point3d(line); |
| |
| // Checks that the line projection falls within the polygon. |
| CartesianPositionCoordinates p = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(intersection.x, intersection.y, intersection.z); |
| if (isInsidePolygon(p, polygon)) { |
| return intersection; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the intersection point between two lines defines by points. |
| * |
| * @param u1 The first point defining the first line. |
| * @param u2 The second point defining the first line. |
| * @param v1 The first point defining the second line. |
| * @param v2 The second point defining the second line. |
| * @return The intersection, null if lines are parallel or the same. |
| * @see http://www.ahristov.com/tutorial/geometry-games/intersection-lines.html |
| */ |
| public static Vector2d getLineIntersectionPoint(Vector2d u1, Vector2d u2, Vector2d v1, Vector2d v2) { |
| double d = (u1.x - u2.x) * (v1.y - v2.y) - (u1.y - u2.y) * (v1.x - v2.x); |
| |
| if (d == 0.0) |
| return null; |
| |
| double xi = ((v1.x - v2.x) * (u1.x * u2.y - u1.y * u2.x) - (u1.x - u2.x) * (v1.x * v2.y - v1.y * v2.x)) / d; |
| double yi = ((v1.y - v2.y) * (u1.x * u2.y - u1.y * u2.x) - (u1.y - u2.y) * (v1.x * v2.y - v1.y * v2.x)) / d; |
| |
| return new Vector2d(xi, yi); |
| } |
| |
| /** |
| * Computes on which side of an edge defined by two points a specified point |
| * falls. |
| * |
| * @param a First point defining the edge. |
| * @param b Second point defining the edge. |
| * @param point The specified point. |
| * @param polygonNormal The normal of the polygon. |
| * @return -1 if c is on the right of a-b, 0 if c is on a-b or -1 if c is left |
| * of a-c |
| */ |
| private static int getSide(Point3d a, Point3d b, Point3d point, Vector3d polygonNormal) { |
| int result = 0; |
| |
| Vector3d ab = new Vector3d(); |
| ab.sub(b, a); |
| |
| Vector3d ac = new Vector3d(); |
| ac.sub(point, a); |
| |
| // Finds the cross product of a->b and a->point |
| Vector3d normal = new Vector3d(); |
| normal.cross(ab, ac); |
| |
| // Find the angle between the normal computed and the one from the |
| // polygon. |
| double angle = normal.angle(polygonNormal); |
| if (angle == 0.0) { |
| result = 0; |
| } else if (angle < Math.toRadians(90)) { |
| result = 1; |
| } else if (angle > Math.toRadians(90)) { |
| result = -1; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Sorts a list of CartesianPositionCoordinates by order of proximity to a given |
| * CartesianPositionCoordinates. |
| * |
| * @param centerPoint The point to sort relative to. |
| * @param points List of CartesianPositionCoordinates to be sorted. |
| * @return Sorted set of points, closest point first. |
| */ |
| public static SortedSet<CartesianPositionCoordinates> sortCartesianPositionCoordinatesByDistance( |
| CartesianPositionCoordinates centerPoint, List<CartesianPositionCoordinates> points) { |
| |
| TreeSet<CartesianPositionCoordinates> sortedPoints = new TreeSet<CartesianPositionCoordinates>( |
| new CartesianPositionCoordinatesDistanceComparator(centerPoint)); |
| sortedPoints.addAll(points); |
| |
| return sortedPoints; |
| } |
| |
| /** |
| * Returns the list of polygons sorted by their distance to a specified point. |
| * The centroid of the polygon is used to compute the distance. |
| * |
| * @param centerPoint The center point. |
| * @param polygons The list of polygons. |
| * @return The list of polygons, sorted by distance. |
| */ |
| public static SortedSet<CartesianPolygon> sortCartesianPolygonByDistance(CartesianPositionCoordinates centerPoint, |
| Collection<? extends CartesianPolygon> polygons) { |
| TreeSet<CartesianPolygon> sortedPolygons = new TreeSet<CartesianPolygon>( |
| new CartesianPolygonCoordinatesDistanceComparator(centerPoint)); |
| sortedPolygons.addAll(polygons); |
| |
| return sortedPolygons; |
| } |
| |
| /** |
| * Computes the average normal of a set of polygons weighted by the polygon |
| * area. |
| * |
| * @param <T> |
| * @param polygons The list of polygons. |
| * @return The average normal. |
| */ |
| public static <T extends CartesianPolygon> Vector3d getAverageNormal(Collection<T> polygons) { |
| Vector3d averageNormal = new Vector3d(0.0, 0.0, 0.0); |
| |
| Iterator<T> it = polygons.iterator(); |
| while (it.hasNext()) { |
| T polygon = it.next(); |
| Vector3d polygonNormal = polygon.getNormal(); |
| double polygonArea = polygon.getSurface(); |
| averageNormal.set(averageNormal.x + polygonArea * polygonNormal.x, |
| averageNormal.y + polygonArea * polygonNormal.y, averageNormal.z + polygonArea * polygonNormal.z); |
| } |
| |
| return averageNormal; |
| } |
| |
| /** |
| * Computes a roughness index for a set of polygons. |
| * |
| * @param <T> |
| * @param polygons The list of polygons. |
| * @param averageNormal |
| * @param polygon The polygon around which the computation is based. |
| * @param radius The radius of the footprint to test. |
| * @return A double giving an indication of the roughness terrain in the list of |
| * polygon based on the dot product of the neighbouring polygon. |
| */ |
| public static <T extends CartesianPolygon> double getSurfaceRoughnessIndex(Collection<T> polygons, |
| Vector3d averageNormal, T polygon, double radius) { |
| Point3d centre = polygon.getCentroid().asPoint3d(); |
| double maxRoughnessIndex = 0.0; |
| double roughnessIndex = 0.0; |
| Vector3d toVertex = new Vector3d(); |
| Iterator<T> it = polygons.iterator(); |
| |
| // For each vertex compute the distance from the plane defined by the |
| // centre of the polygon and the average normal. |
| while (it.hasNext()) { |
| T currentPolygon = it.next(); |
| Point3d currentVertex = currentPolygon.getCentroid().asPoint3d(); |
| |
| // Check that the vertex is within the radius of the footprint |
| // It could belong to a polygon touching the footprint, yet be outside of it. |
| if (currentVertex.distance(centre) <= radius) { |
| toVertex.set(currentVertex.x - centre.x, currentVertex.y - centre.y, currentVertex.z - centre.z); |
| roughnessIndex = Math.abs(toVertex.dot(averageNormal)); |
| |
| // If the value is larger than the maximum roughness found so far, keep this |
| // value. |
| // If this value is smaller than the minimum found so far, assign it to the |
| // minimum. |
| if (roughnessIndex > maxRoughnessIndex) { |
| maxRoughnessIndex = roughnessIndex; |
| } |
| } |
| } |
| |
| return maxRoughnessIndex; |
| } |
| |
| /** |
| * Returns the Euclidean distance separating two CartesianPositionCoordinates. |
| * |
| * @param from First CartesianPositionCoordinates. |
| * @param to Second CartesianPositionCoordinates. |
| * @return The Euclidean distance between the two position. |
| */ |
| public static double getDistance(CartesianPositionCoordinates from, CartesianPositionCoordinates to) { |
| Point3d p1 = new Point3d(from.getX(), from.getY(), from.getZ()); |
| Point3d p2 = new Point3d(to.getX(), to.getY(), to.getZ()); |
| |
| return p1.distance(p2); |
| } |
| |
| /** |
| * Returns the distance between a point and a line defined by two points. |
| * |
| * @param point The point. |
| * @param u1 The first point defining the line. |
| * @param u2 The second point defining the line. |
| * @return The distance between the point and the specified line. |
| */ |
| public static double getDistance(CartesianPositionCoordinates point, CartesianPositionCoordinates u1, |
| CartesianPositionCoordinates u2) { |
| CartesianPositionCoordinates projectedPoint = getProjection(point, u1, u2); |
| return getDistance(projectedPoint, point); |
| } |
| |
| /** |
| * Returns the projection of a point on a line defined by two points. |
| * |
| * @param point The point. |
| * @param u1 The first point defining the line. |
| * @param u2 The second point defining the line. |
| * @return The projection of the point onto the line. |
| */ |
| public static CartesianPositionCoordinates getProjection(CartesianPositionCoordinates point, |
| CartesianPositionCoordinates u1, CartesianPositionCoordinates u2) { |
| // Defines the vectors. |
| Vector3d u1point = new Vector3d(point.getX() - u1.getX(), point.getY() - u1.getY(), point.getZ() - u1.getZ()); |
| Vector3d u1u2 = new Vector3d(u2.getX() - u1.getX(), u2.getY() - u1.getY(), u2.getZ() - u1.getZ()); |
| |
| // Computes the projection of u1->point on u1->u2 |
| double scale = (u1point.dot(u1u2)) / u1u2.lengthSquared(); |
| Vector3d projOnu1u2 = new Vector3d(u1u2); |
| projOnu1u2.scale(scale); |
| |
| Vector3d u1Vector = new Vector3d(u1.getX(), u1.getY(), u1.getZ()); |
| projOnu1u2.add(u1Vector); |
| |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(projOnu1u2.x, projOnu1u2.y, |
| projOnu1u2.z); |
| } |
| |
| /** |
| * Returns the CartesianPositionCoordinates from a list that has the maximum |
| * coordinate along a specified axis. |
| * |
| * @param axis The specified axis. |
| * @param points The list of CartesianPositionCoordinates. |
| * @return The CartesianPositionCoordinates. Returns (0,0,0) if the list is |
| * empty. |
| */ |
| public static CartesianPositionCoordinates getMaximumPosition(CartesianAxis axis, |
| List<CartesianPositionCoordinates> points) { |
| return getMaximumPosition(axis, points, null); |
| } |
| |
| /** |
| * Returns the CartesianPositionCoordinates from a list that has the maximum |
| * coordinate along a specified axis. |
| * |
| * @param axis The specified axis. |
| * @param points The list of CartesianPositionCoordinates. |
| * @param monitor Progress monitor to provide feedback on the operation. Can be |
| * null. |
| * @return The CartesianPositionCoordinates. Returns (0,0,0) if the list is |
| * empty. |
| */ |
| public static CartesianPositionCoordinates getMaximumPosition(CartesianAxis axis, |
| List<CartesianPositionCoordinates> points, final IProgressMonitor monitor) { |
| // Gets a valid IProgressMonitor. |
| IProgressMonitor internalMonitor = monitor; |
| if (internalMonitor == null) |
| internalMonitor = new NullProgressMonitor(); |
| |
| CartesianPositionCoordinates coord = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(0, 0, 0); |
| double max = Double.NEGATIVE_INFINITY; |
| |
| try { |
| internalMonitor.beginTask(Geometry3DUtilities.class.getSimpleName() + ".getMaximumPosition", points.size()); |
| |
| Iterator<CartesianPositionCoordinates> it = points.iterator(); |
| while (it.hasNext()) { |
| CartesianPositionCoordinates p = it.next(); |
| |
| double value = 0.0; |
| switch (axis.getValue()) { |
| case CartesianAxis.X_VALUE: |
| value = p.getX(); |
| break; |
| case CartesianAxis.Y_VALUE: |
| value = p.getY(); |
| break; |
| case CartesianAxis.Z_VALUE: |
| value = p.getZ(); |
| break; |
| } |
| |
| if (value > max) { |
| max = value; |
| coord = p; |
| } |
| |
| internalMonitor.worked(1); |
| } |
| } finally { |
| internalMonitor.done(); |
| } |
| |
| return coord; |
| } |
| |
| /** |
| * Returns the CartesianPositionCoordinates from a list that has the maximum |
| * coordinate along a specified axis. |
| * |
| * @param axis The specified axis. |
| * @param points The list of CartesianPositionCoordinates. |
| * @return The CartesianPositionCoordinates. Returns (0,0,0) if the list is |
| * empty. |
| */ |
| public static CartesianPositionCoordinates getMinimumPosition(CartesianAxis axis, |
| List<CartesianPositionCoordinates> points) { |
| return getMinimumPosition(axis, points, null); |
| } |
| |
| /** |
| * Returns the CartesianPositionCoordinates from a list that has the maximum |
| * coordinate along a specified axis. |
| * |
| * @param axis The specified axis. |
| * @param points The list of CartesianPositionCoordinates. |
| * @param monitor Progress monitor to provide feedback on the operation. Can be |
| * null. |
| * @return The CartesianPositionCoordinates. Returns (0,0,0) if the list is |
| * empty. |
| */ |
| public static CartesianPositionCoordinates getMinimumPosition(CartesianAxis axis, |
| List<CartesianPositionCoordinates> points, final IProgressMonitor monitor) { |
| // Gets a valid IProgressMonitor. |
| IProgressMonitor internalMonitor = monitor; |
| if (internalMonitor == null) |
| internalMonitor = new NullProgressMonitor(); |
| |
| CartesianPositionCoordinates coord = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(0, 0, 0); |
| double min = Double.POSITIVE_INFINITY; |
| |
| try { |
| internalMonitor.beginTask(Geometry3DUtilities.class.getSimpleName() + ".getMinimumPosition", points.size()); |
| |
| Iterator<CartesianPositionCoordinates> it = points.iterator(); |
| while (it.hasNext()) { |
| CartesianPositionCoordinates p = it.next(); |
| |
| double value = 0.0; |
| switch (axis.getValue()) { |
| case CartesianAxis.X_VALUE: |
| value = p.getX(); |
| break; |
| case CartesianAxis.Y_VALUE: |
| value = p.getY(); |
| break; |
| case CartesianAxis.Z_VALUE: |
| value = p.getZ(); |
| break; |
| } |
| |
| if (value < min) { |
| min = value; |
| coord = p; |
| } |
| |
| internalMonitor.worked(1); |
| } |
| } finally { |
| internalMonitor.done(); |
| } |
| return coord; |
| } |
| |
| /** |
| * Returns the angle of the normal of a polygon defined by a list of |
| * CartesianPositionCoordinates with respect to a specified axis. |
| * |
| * @param axis The specified axis. |
| * @param vertices The list of of CartesianPositionCoordinates defining the |
| * polygon. |
| * @return The angle, between 0 and PI/2. Zero if points contains less than 3 |
| * points. |
| */ |
| public static double getAngle(CartesianAxis axis, List<CartesianPositionCoordinates> vertices) { |
| double slope = 0.0; |
| |
| if (vertices.size() > 2) { |
| // Vector used to represent the axis. |
| Vector3d axisVector = null; |
| |
| switch (axis.getValue()) { |
| case CartesianAxis.X_VALUE: |
| axisVector = new Vector3d(1, 0, 0); |
| break; |
| case CartesianAxis.Y_VALUE: |
| axisVector = new Vector3d(0, 1, 0); |
| break; |
| case CartesianAxis.Z_VALUE: |
| axisVector = new Vector3d(0, 0, 1); |
| break; |
| } |
| |
| Vector3d normal = getPolygonNormal(vertices); |
| slope = normal.angle(axisVector); |
| |
| if (slope > Math.PI / 2) { |
| slope = slope - Math.PI / 2; |
| } |
| } |
| |
| return slope; |
| } |
| |
| /** |
| * Returns the angle between a vector (specified by two points) and a specified |
| * cartesian plane. |
| * |
| * @param plane The cartesian plane. |
| * @param v1 The starts point of the vector. |
| * @param v2 The end point of the vector. |
| * @return The angle, between -PI/2 and PI/2. Zero if the vector is zero-length. |
| */ |
| public static double getAngle(CartesianPlane plane, CartesianPositionCoordinates v1, |
| CartesianPositionCoordinates v2) { |
| double angle = 0.0; |
| if (getDistance(v1, v2) != 0.0) { |
| Vector3d axisVector = null; |
| switch (plane.getValue()) { |
| case CartesianPlane.XY_VALUE: |
| axisVector = new Vector3d(0, 0, 1); |
| break; |
| case CartesianPlane.XZ_VALUE: |
| axisVector = new Vector3d(0, 1, 0); |
| break; |
| case CartesianPlane.YZ_VALUE: |
| axisVector = new Vector3d(1, 0, 0); |
| break; |
| } |
| |
| Vector3d v = new Vector3d(v2.getX() - v1.getX(), v2.getY() - v1.getY(), v2.getZ() - v1.getZ()); |
| |
| angle = Math.PI / 2 - v.angle(axisVector); |
| } |
| return angle; |
| } |
| |
| /** |
| * Returns the list of CartesianPositionCoordinates that are within a specified |
| * radius of a center point. |
| * |
| * @param centerPoint The center point. |
| * @param radius The radius. |
| * @param points The list of points. |
| * @return The list of CartesianPositionCoordinates that at a distance equal or |
| * smaller than the specified radius. |
| */ |
| public static List<CartesianPositionCoordinates> getCartesianCoordinatesWithinRadius( |
| CartesianPositionCoordinates centerPoint, double radius, List<CartesianPositionCoordinates> points) { |
| List<CartesianPositionCoordinates> pointsWithinRadius = new ArrayList<CartesianPositionCoordinates>(); |
| |
| if (points.size() > 0) { |
| // First creates a sorted set of the point by distance to the center |
| // point. |
| SortedSet<CartesianPositionCoordinates> sortedPoints = sortCartesianPositionCoordinatesByDistance( |
| centerPoint, points); |
| |
| // Finds where a point exactly at r from the center would be |
| // inserted. |
| CartesianPositionCoordinates pointOnSurface = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(centerPoint.getX() + radius, centerPoint.getY(), |
| centerPoint.getZ()); |
| pointsWithinRadius.addAll(sortedPoints.headSet(pointOnSurface)); |
| |
| // If pointOnSurface is already in the list of point, we need to add |
| // it since the headSet(pointOnSurface) excludes pointOnSurface. |
| if (sortedPoints.contains(pointOnSurface)) { |
| pointsWithinRadius.add(sortedPoints.tailSet(pointOnSurface).first()); |
| } |
| } |
| |
| return pointsWithinRadius; |
| } |
| |
| /** |
| * Returns all the polygons that are at least partially within a specified |
| * radius from the center of a specified polygon. |
| * |
| * @param <T> |
| * @param centerPolygon The specified polygon. |
| * @param radius The radius. |
| * @param mesh The mesh to search. |
| * @return The list of polygons, including centerPolygon (if radius > 0). |
| */ |
| public static <T extends CartesianPolygon> Set<T> getCartesianPolygonsPartiallyWithinRadius(T centerPolygon, |
| double radius, Mesh<CartesianPositionCoordinates, T> mesh) { |
| Set<T> polys = new HashSet<T>(); |
| |
| // Include center polygon if the radius is non-zero. |
| if (radius > 0) { |
| polys.add(centerPolygon); |
| } |
| |
| List<T> neighbours = mesh.getPolygonNeighbours(centerPolygon); |
| recursiveGetCartesianPolygonsPartiallyWithinRadius(polys, centerPolygon.getCentroid(), radius, mesh, |
| neighbours); |
| |
| return polys; |
| } |
| |
| private static <T extends CartesianPolygon> void recursiveGetCartesianPolygonsPartiallyWithinRadius( |
| Set<T> polygonsFound, CartesianPositionCoordinates center, double radius, |
| Mesh<CartesianPositionCoordinates, T> mesh, List<T> polygons) { |
| // Checks all of the polygon in the list. |
| for (int i = 0; i < polygons.size(); i++) { |
| T polygon = polygons.get(i); |
| if (!polygonsFound.contains(polygon) && isPolygonPartiallyWithinRadius(center, radius, polygon)) { |
| polygonsFound.add(polygon); |
| List<T> neighbours = mesh.getPolygonNeighbours(polygon); |
| recursiveGetCartesianPolygonsPartiallyWithinRadius(polygonsFound, center, radius, mesh, neighbours); |
| } |
| } |
| } |
| |
| public static <T extends CartesianPolygon> boolean isPolygonPartiallyWithinRadius( |
| CartesianPositionCoordinates centerPoint, double radius, T polygon) { |
| // First check if at least one of the polygon vertex falls within the specified |
| // radius. |
| // This test is done first as it is simpler to perform. |
| Point3d center = centerPoint.asPoint3d(); |
| for (int i = 0; i < polygon.getVertices().size(); i++) { |
| if (polygon.getVertices().get(i).asPoint3d().distance(center) < radius) { |
| return true; |
| } |
| } |
| |
| // If the polygon contains at least one edge, checks for intersecting edges. |
| if (polygon.getVertices().size() > 1) { |
| // Goes through each edge of the polygon and checks if its projection |
| // is at a distance shorter than radius. |
| for (int i = 0; i < polygon.getVertices().size(); i++) { |
| CartesianPositionCoordinates p1 = null; |
| CartesianPositionCoordinates p2 = null; |
| |
| // Ensure we go all around the edges. |
| if (i < (polygon.getVertices().size() - 1)) { |
| p1 = polygon.getVertices().get(i); |
| p2 = polygon.getVertices().get(i + 1); |
| } else { |
| p1 = polygon.getVertices().get(i); |
| p2 = polygon.getVertices().get(0); |
| } |
| |
| // Checks if the line defined by the edge intersects the edge. |
| Point3d pIntersection = getProjection(centerPoint, p1, p2).asPoint3d(); |
| if (pIntersection.distance(centerPoint.asPoint3d()) <= radius) { |
| Point3d p1Point = p1.asPoint3d(); |
| Point3d p2Point = p2.asPoint3d(); |
| |
| double p1p2Distance = p1Point.distance(p2Point); |
| double p1pIntersectionDistance = p1Point.distance(pIntersection); |
| double p2pIntersectionDistance = p2Point.distance(pIntersection); |
| |
| // If the Edge line intersects with the radius, we need to check if the |
| // intersection point |
| // is on the polygon edge itself (i.e. between p1 and p2). |
| if ((p1pIntersectionDistance < p1p2Distance) && (p2pIntersectionDistance < p1p2Distance)) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Tells wheter or not all the vertex of a polygon falls within the specified |
| * radius from a specified center point. |
| * |
| * @param <T> |
| * @param centerPoint The center point. |
| * @param radius The radius. |
| * @param polygon The polygon. |
| * @return True if all the vertex fall within the radius, false otherwise. |
| */ |
| public static <T extends CartesianPolygon> boolean isPolygonWithinRadius(CartesianPositionCoordinates centerPoint, |
| double radius, T polygon) { |
| boolean isInside = true; |
| |
| Point3d center = centerPoint.asPoint3d(); |
| int i = 0; |
| while (i < polygon.getVertices().size() && isInside) { |
| CartesianPositionCoordinates vertex = polygon.getVertices().get(i); |
| if (center.distance(vertex.asPoint3d()) > radius) { |
| isInside = false; |
| } else { |
| i++; |
| } |
| } |
| |
| return isInside; |
| } |
| |
| /** |
| * Creates a Map that map vertex to list of polygon that contain them. |
| * |
| * @param mesh The mesh to use. |
| * @param monitor Progress monitor to provide feedback on the operation. Can be |
| * null. |
| * @return The Map that map vertex to list of polygons. |
| */ |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| public static <T1 extends Coordinates, T2 extends Polygon> Map<T1, List<T2>> getVertexToPolygonMapping( |
| List<T2> polygons, final IProgressMonitor monitor) { |
| // Gets a valid IProgressMonitor. |
| IProgressMonitor internalMonitor = monitor; |
| if (internalMonitor == null) |
| internalMonitor = new NullProgressMonitor(); |
| |
| HashMap<T1, List<T2>> vertexToPolygonMap = new HashMap<T1, List<T2>>(); |
| |
| try { |
| // Goes through the list of polygons and adds the vertices in the map. |
| internalMonitor.beginTask(Geometry3DUtilities.class.getSimpleName() + ".getVertexToPolygonMapping", |
| polygons.size()); |
| |
| Iterator<T2> polygonIt = polygons.iterator(); |
| while (polygonIt.hasNext()) { |
| T2 polygon = polygonIt.next(); |
| |
| // Go through the list of vertices of the polygon. |
| Iterator<T1> verticeIt = polygon.getVertices().iterator(); |
| |
| while (verticeIt.hasNext()) { |
| T1 vertex = verticeIt.next(); |
| |
| // If no key exist yet for the specified vertex, creates it. |
| if (!vertexToPolygonMap.containsKey(vertex)) { |
| vertexToPolygonMap.put(vertex, new ArrayList<T2>()); |
| } |
| |
| // Adds the polygon to the list if it is not already there. |
| if (!vertexToPolygonMap.get(vertex).contains(polygon)) { |
| vertexToPolygonMap.get(vertex).add(polygon); |
| } |
| } |
| internalMonitor.worked(1); |
| } |
| } finally { |
| internalMonitor.done(); |
| } |
| |
| return vertexToPolygonMap; |
| } |
| |
| /** |
| * Returns the set of CartesianPositionCoordinates that are shared by a list of |
| * CartesianPolygons. |
| * |
| * @param polygons The list of polygons. |
| * @return The set of shared CartesianPositionCoordinates. |
| */ |
| public static Set<CartesianPositionCoordinates> getSharedVertices(List<CartesianPolygon> polygons) { |
| Set<CartesianPositionCoordinates> sharedVertices = new HashSet<CartesianPositionCoordinates>(); |
| |
| TreeMap<CartesianPositionCoordinates, Integer> vertexToPolygonCount = new TreeMap<CartesianPositionCoordinates, Integer>( |
| new CartesianPositionCoordinatesDistanceComparator()); |
| |
| // Goes through the list of all the vertex from all polygons and builds |
| // a map of vertex -> polygon count. |
| Iterator<CartesianPolygon> polygonIt = polygons.iterator(); |
| while (polygonIt.hasNext()) { |
| CartesianPolygon polygon = polygonIt.next(); |
| Iterator<CartesianPositionCoordinates> verticesIt = polygon.getVertices().iterator(); |
| while (verticesIt.hasNext()) { |
| CartesianPositionCoordinates vertex = verticesIt.next(); |
| if (vertexToPolygonCount.get(vertex) == null) { |
| vertexToPolygonCount.put(vertex, 0); |
| } |
| |
| Integer count = new Integer(vertexToPolygonCount.get(vertex).intValue() + 1); |
| vertexToPolygonCount.put(vertex, count); |
| } |
| } |
| |
| // Retains only the vertex that have a count equal to the number of |
| // polygons specified. |
| Iterator<CartesianPositionCoordinates> keyIt = vertexToPolygonCount.keySet().iterator(); |
| while (keyIt.hasNext()) { |
| CartesianPositionCoordinates vertex = keyIt.next(); |
| Integer count = vertexToPolygonCount.get(vertex); |
| |
| if (count == polygons.size()) { |
| sharedVertices.add(vertex); |
| } |
| } |
| |
| return sharedVertices; |
| } |
| |
| /** |
| * Returns the set of CartesianPositionCoordinates that are shared by two |
| * CartesianPolygons. |
| * |
| * @param p1 First CartesianPolygon. |
| * @param p2 Second CartesianPolygon. |
| * @return The set of shared CartesianPositionCoordinates. |
| */ |
| public static Set<CartesianPositionCoordinates> getSharedVertices(CartesianPolygon p1, CartesianPolygon p2) { |
| List<CartesianPolygon> polygons = new ArrayList<CartesianPolygon>(); |
| |
| polygons.add(p1); |
| polygons.add(p2); |
| |
| return getSharedVertices(polygons); |
| } |
| |
| /** |
| * Returns a list of list of point duplicates found in a list of |
| * CartesianPositionCoordinates. For example, if the list of coordinates is (v1, |
| * v2, v3, v4, v5, v6, v7) where v1 = v3, v4 =v5 =v6, the result will be a list |
| * of the following list : (v1, v3), (v4,v5,v6). |
| * |
| * @param coordinates The list of CartesianPositionCoordinates. |
| * @return The list of list of duplicates. TODO : Faster implementation |
| * required. |
| */ |
| public static List<List<CartesianPositionCoordinates>> getDuplicateCartesianCoordinates( |
| List<CartesianPositionCoordinates> coordinates) { |
| List<List<CartesianPositionCoordinates>> duplicates = new ArrayList<List<CartesianPositionCoordinates>>(); |
| Map<CartesianPositionCoordinates, List<CartesianPositionCoordinates>> pointToEquivalent = new HashMap<CartesianPositionCoordinates, List<CartesianPositionCoordinates>>(); |
| |
| // Goes through the list of vertices. |
| Iterator<CartesianPositionCoordinates> pointsIt = coordinates.iterator(); |
| while (pointsIt.hasNext()) { |
| CartesianPositionCoordinates point = pointsIt.next(); |
| |
| boolean duplicateDetected = false; |
| int i = 0; |
| CartesianPositionCoordinates key = null; |
| |
| // Looks to see if a equivalent point is already in the map as a key. |
| while ((!duplicateDetected) && (i < pointToEquivalent.keySet().size())) { |
| key = (CartesianPositionCoordinates) (pointToEquivalent.keySet().toArray()[i]); |
| if (getDistance(point, key) == 0.0) { |
| duplicateDetected = true; |
| } |
| i++; |
| } |
| |
| if (duplicateDetected) { |
| // Point is a duplicate, add it the to equivalent. |
| pointToEquivalent.get(key).add(point); |
| } else { |
| // Point has no equivalent in the map, add it as a key. |
| List<CartesianPositionCoordinates> list = new ArrayList<CartesianPositionCoordinates>(); |
| list.add(point); |
| pointToEquivalent.put(point, list); |
| } |
| } |
| |
| // Creates the list of duplicates. |
| Iterator<List<CartesianPositionCoordinates>> duplicateListIt = pointToEquivalent.values().iterator(); |
| while (duplicateListIt.hasNext()) { |
| List<CartesianPositionCoordinates> duplicatesList = duplicateListIt.next(); |
| if (duplicatesList.size() > 1) { |
| duplicates.add(duplicatesList); |
| } |
| } |
| |
| return duplicates; |
| } |
| |
| /** |
| * Removes from a mesh vertices that are at the exact same position. Polygons |
| * vertex lists are also updated. |
| * |
| * @param mesh The mesh. |
| * @return A new mesh where CartesianPositionCoordinates duplicate have been |
| * removed. |
| */ |
| public static CartesianCoordinatesMesh removeDuplicateVertex(final CartesianCoordinatesMesh mesh) { |
| CartesianCoordinatesMesh newMesh = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianCoordinatesMesh(mesh); |
| |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap = Geometry3DUtilities |
| .getVertexToPolygonMapping(newMesh.getPolygons(), null); |
| |
| // Gets a list of duplicate list. |
| List<List<CartesianPositionCoordinates>> duplicatesVertex = getDuplicateCartesianCoordinates( |
| newMesh.getPoints()); |
| |
| Iterator<List<CartesianPositionCoordinates>> itDuplicateLists = duplicatesVertex.iterator(); |
| while (itDuplicateLists.hasNext()) { |
| List<CartesianPositionCoordinates> duplicates = itDuplicateLists.next(); |
| |
| // For each of the duplicate, keep only the first "incarnation". |
| CartesianPositionCoordinates goodIncarnation = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(duplicates.get(0)); |
| newMesh.getPoints().add(goodIncarnation); |
| |
| // Updates all polygon reference to point to the good incarnation. |
| Iterator<CartesianPositionCoordinates> duplicatesIt = duplicates.iterator(); |
| while (duplicatesIt.hasNext()) { |
| CartesianPositionCoordinates badPoint = duplicatesIt.next(); |
| |
| // Gets the list of polygons that refer to the bad point. |
| List<CartesianPolygon> polygons = vertexToPolygonMap.get(badPoint); |
| |
| if (polygons != null) { |
| for (int i = 0; i < polygons.size(); i++) { |
| // Remove the bad point, replace it with the good one. |
| CartesianPolygon polygon = polygons.get(i); |
| int indexBadPoint = polygon.getVertices().indexOf(badPoint); |
| polygon.getVertices().add(indexBadPoint, goodIncarnation); |
| polygon.getVertices().remove(badPoint); |
| |
| // Remove and add the polygon to force update of the mesh mapping of |
| // points->polygon. |
| newMesh.getPolygons().remove(polygon); |
| newMesh.getPolygons().add(polygon); |
| } |
| } |
| } |
| |
| // Delete the bad points |
| Iterator<CartesianPositionCoordinates> badIt = duplicates.iterator(); |
| while (badIt.hasNext()) { |
| newMesh.getPoints().remove(badIt.next()); |
| } |
| } |
| |
| return newMesh; |
| } |
| |
| /** |
| * Returns the list of immediate neighbors polygons (i.e. polygon that share at |
| * least one vertex) for a specified polygon in a mesh. |
| * |
| * @param polygon The specified polygon. |
| * @param vertexToPolygonMap The Map that map vertex to list of polygons. |
| * @return The list of polygon sharing at least a vertex with the specified |
| * polygon. |
| */ |
| public static Set<CartesianPolygon> getPolygonVertexNeighbors(CartesianPolygon polygon, |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap) { |
| Set<CartesianPolygon> neighbours = new HashSet<CartesianPolygon>(); |
| |
| // Explores the list of vertices of the polygon. |
| Iterator<CartesianPositionCoordinates> verticeIt = polygon.getVertices().iterator(); |
| while (verticeIt.hasNext()) { |
| CartesianPositionCoordinates vertex = verticeIt.next(); |
| |
| // Adds the polygon that share that vertex. |
| neighbours.addAll(vertexToPolygonMap.get(vertex)); |
| } |
| |
| // Remove the specified polygon from the list |
| neighbours.remove(polygon); |
| |
| return neighbours; |
| } |
| |
| /** |
| * Returns the list of polygons connected directly or indirectly by at least on |
| * vertex to specified polygon. |
| * |
| * @param polygon The specified polygon. |
| * @param vertexToPolygonMap The Map that maps vertex to list of polygons. |
| * @return The list of polygon connected directly or indirectly by at least on |
| * vertex to the specified polygon. |
| */ |
| public static Set<CartesianPolygon> getPolygonVertexExtendedNeighbors(CartesianPolygon polygon, |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap) { |
| Set<CartesianPolygon> neighbours = new HashSet<CartesianPolygon>(); |
| Set<CartesianPolygon> processedPolygons = new HashSet<CartesianPolygon>(); |
| |
| neighbours = recursiveGetPolygonVertexExtendedNeighbors(processedPolygons, polygon, vertexToPolygonMap); |
| neighbours.remove(polygon); |
| |
| return neighbours; |
| } |
| |
| private static Set<CartesianPolygon> recursiveGetPolygonVertexExtendedNeighbors( |
| Set<CartesianPolygon> processedPolygons, CartesianPolygon polygon, |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap) { |
| Set<CartesianPolygon> neighbours = new HashSet<CartesianPolygon>(); |
| |
| // Gets the polygon's vertex neighbors. |
| Set<CartesianPolygon> immediateNeighbors = getPolygonVertexNeighbors(polygon, vertexToPolygonMap); |
| neighbours.addAll(immediateNeighbors); |
| |
| // Adds the specified polygon to the list of processed polygon. |
| processedPolygons.add(polygon); |
| |
| Iterator<CartesianPolygon> it = immediateNeighbors.iterator(); |
| while (it.hasNext()) { |
| CartesianPolygon p = it.next(); |
| if (!processedPolygons.contains(p)) { |
| processedPolygons.add(p); |
| neighbours.addAll(recursiveGetPolygonVertexExtendedNeighbors(processedPolygons, p, vertexToPolygonMap)); |
| } |
| } |
| |
| return neighbours; |
| } |
| |
| /** |
| * Returns the list of immediate neighbors polygons (i.e. polygon that share at |
| * least an edge) for a specified polygon. |
| * |
| * @param polygon The specified polygon. |
| * @param vertexToPolygonMap The Map that maps vertex to list of polygons. |
| * @return The list of polygon sharing at least an edge with the specified |
| * polygon. |
| */ |
| public static Set<CartesianPolygon> getPolygonEdgeNeighbors(CartesianPolygon polygon, |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap) { |
| Set<CartesianPolygon> neighbours = new HashSet<CartesianPolygon>(); |
| |
| // Explores the list of vertices of the polygon. |
| Iterator<CartesianPositionCoordinates> verticeIt = polygon.getVertices().iterator(); |
| while (verticeIt.hasNext()) { |
| CartesianPositionCoordinates vertex = verticeIt.next(); |
| |
| // Gets the list of polygon that share that vertex. |
| List<CartesianPolygon> potentialNeighbors = vertexToPolygonMap.get(vertex); |
| |
| // Check each of the potentialNeighbors to see if they contain two |
| // or more vertex of the specified polygon. |
| Iterator<CartesianPolygon> polygonIt = potentialNeighbors.iterator(); |
| while (polygonIt.hasNext()) { |
| CartesianPolygon potentialNeighbor = polygonIt.next(); |
| |
| // Verifies the potential neighbor is not the polygon itself. |
| if (potentialNeighbor != polygon) { |
| // Verifies if polygons shared more than one vertex. |
| if (getSharedVertices(polygon, potentialNeighbor).size() > 1) { |
| neighbours.add(potentialNeighbor); |
| } |
| } |
| } |
| } |
| |
| return neighbours; |
| } |
| |
| /** |
| * Returns the list of polygons connected directly or indirectly by at least one |
| * edge to specified polygon. |
| * |
| * @param polygon The specified polygon. |
| * @param vertexToPolygonMap The Map that maps vertex to list of polygons. |
| * @return The list of polygon connected directly or indirectly by at least on |
| * edge to the specified polygon. |
| */ |
| public static Set<CartesianPolygon> getPolygonEdgeExtendedNeighbors(CartesianPolygon polygon, |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap) { |
| Set<CartesianPolygon> neighbours = new HashSet<CartesianPolygon>(); |
| Set<CartesianPolygon> processedPolygons = new HashSet<CartesianPolygon>(); |
| |
| neighbours = recursiveGetPolygonEdgeExtendedNeighbors(processedPolygons, polygon, vertexToPolygonMap); |
| neighbours.remove(polygon); |
| |
| return neighbours; |
| } |
| |
| private static Set<CartesianPolygon> recursiveGetPolygonEdgeExtendedNeighbors( |
| Set<CartesianPolygon> processedPolygons, CartesianPolygon polygon, |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> vertexToPolygonMap) { |
| Set<CartesianPolygon> neighbours = new HashSet<CartesianPolygon>(); |
| |
| // Gets the polygon's edge neighbors. |
| Set<CartesianPolygon> immediateNeighbors = getPolygonEdgeNeighbors(polygon, vertexToPolygonMap); |
| neighbours.addAll(immediateNeighbors); |
| |
| // Adds the specified polygon to the list of processed polygon. |
| processedPolygons.add(polygon); |
| |
| Iterator<CartesianPolygon> it = immediateNeighbors.iterator(); |
| while (it.hasNext()) { |
| CartesianPolygon p = it.next(); |
| if (!processedPolygons.contains(p)) { |
| processedPolygons.add(p); |
| neighbours.addAll(recursiveGetPolygonEdgeExtendedNeighbors(processedPolygons, p, vertexToPolygonMap)); |
| } |
| } |
| |
| return neighbours; |
| } |
| |
| /** |
| * Returns the list of groups of polygons connected by at least one vertex. |
| * |
| * @param polygons List of polygons. |
| * @param monitor Progress monitor to provide feedback on the operation. Can be |
| * null. |
| * @return The list of group of polygons. |
| */ |
| public static Set<Set<CartesianPolygon>> getCartesianPolygonGroupConnectedByVertex(List<CartesianPolygon> polygons, |
| IProgressMonitor monitor) { |
| // Gets a valid IProgressMonitor. |
| IProgressMonitor internalMonitor = monitor; |
| if (internalMonitor == null) |
| internalMonitor = new NullProgressMonitor(); |
| |
| Set<Set<CartesianPolygon>> groups = new HashSet<Set<CartesianPolygon>>(); |
| |
| try { |
| internalMonitor.beginTask( |
| Geometry3DUtilities.class.getSimpleName() + ".getCartesianPolygonGroupConnectedByVertex", |
| polygons.size()); |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> map = getVertexToPolygonMapping(polygons, |
| monitor); |
| |
| Iterator<CartesianPolygon> polygonIt = polygons.iterator(); |
| while (polygonIt.hasNext()) { |
| CartesianPolygon polygon = polygonIt.next(); |
| |
| // If the polygon is not already part of a group. |
| if (getPolygonGroupForPolygon(groups, polygon) == null) { |
| // Creates a new group. |
| Set<CartesianPolygon> group = new HashSet<CartesianPolygon>(); |
| |
| // Adds the polygon's vertex Neighbors |
| group.addAll(getPolygonVertexExtendedNeighbors(polygon, map)); |
| |
| // Adds the polygon itself to the group. |
| group.add(polygon); |
| |
| // Adds the group to the set of groups. |
| groups.add(group); |
| } |
| |
| internalMonitor.worked(1); |
| } |
| } finally { |
| internalMonitor.done(); |
| } |
| |
| return groups; |
| } |
| |
| /** |
| * Returns the list of groups of polygon connected by at least one edge. |
| * |
| * @param polygons List of polygons. |
| * @param monitor Progress monitor to provide feedback on the operation. Can be |
| * null. |
| * @return The list of group of polygons. |
| */ |
| public static Set<Set<CartesianPolygon>> getCartesianPolygonGroupsConnectedByEdge(List<CartesianPolygon> polygons, |
| IProgressMonitor monitor) { |
| // Gets a valid IProgressMonitor. |
| IProgressMonitor internalMonitor = monitor; |
| if (internalMonitor == null) |
| internalMonitor = new NullProgressMonitor(); |
| |
| Set<Set<CartesianPolygon>> groups = new HashSet<Set<CartesianPolygon>>(); |
| |
| try { |
| internalMonitor.beginTask( |
| Geometry3DUtilities.class.getSimpleName() + ".getCartesianPolygonGroupConnectedByEdge", |
| polygons.size()); |
| Map<CartesianPositionCoordinates, List<CartesianPolygon>> map = getVertexToPolygonMapping(polygons, |
| monitor); |
| |
| Iterator<CartesianPolygon> polygonIt = polygons.iterator(); |
| while (polygonIt.hasNext()) { |
| CartesianPolygon polygon = polygonIt.next(); |
| |
| // If the polygon is not already part of a group. |
| if (getPolygonGroupForPolygon(groups, polygon) == null) { |
| // Creates a new group. |
| Set<CartesianPolygon> group = new HashSet<CartesianPolygon>(); |
| |
| // Adds the polygon's edge Neighbors |
| group.addAll(getPolygonEdgeExtendedNeighbors(polygon, map)); |
| |
| // Adds the polygon itself to the group. |
| group.add(polygon); |
| |
| // Adds the group to the set of groups. |
| groups.add(group); |
| } |
| |
| internalMonitor.worked(1); |
| } |
| } finally { |
| internalMonitor.done(); |
| } |
| |
| return groups; |
| } |
| |
| /** |
| * Returns the group in which a specified polygon is found. |
| * |
| * @param groups The list of polygon group. |
| * @param polygon The specified polygon. |
| * @return The group containing the polygon, null if none is found. |
| */ |
| public static Set<CartesianPolygon> getPolygonGroupForPolygon(Set<Set<CartesianPolygon>> groups, |
| CartesianPolygon polygon) { |
| Set<CartesianPolygon> group = null; |
| |
| Iterator<Set<CartesianPolygon>> groupIt = groups.iterator(); |
| while (groupIt.hasNext() && (group == null)) { |
| Set<CartesianPolygon> g = groupIt.next(); |
| if (g.contains(polygon)) { |
| group = g; |
| } |
| } |
| |
| return group; |
| } |
| |
| /** |
| * Converts a list of CartesianPositionCoordinates into a list of Point3d. |
| * |
| * @param points list of CartesianPositionCoordinates. |
| * @return The list of Point3d. |
| */ |
| public static List<Point3d> getPoint3dList(List<CartesianPositionCoordinates> points) { |
| List<Point3d> pointList = new ArrayList<Point3d>(); |
| |
| Iterator<CartesianPositionCoordinates> it = points.iterator(); |
| while (it.hasNext()) { |
| CartesianPositionCoordinates p = it.next(); |
| Point3d point = new Point3d(p.getX(), p.getY(), p.getZ()); |
| pointList.add(point); |
| } |
| |
| return pointList; |
| } |
| |
| /** |
| * Converts a list of Point3d into a list of CartesianPositionCoordinates. |
| * |
| * @param points list of Point3d. |
| * @return The list of CartesianPositionCoordinates. |
| */ |
| public static List<CartesianPositionCoordinates> getCartesianPositionCoordinates(List<Point3d> points) { |
| List<CartesianPositionCoordinates> pointList = new ArrayList<CartesianPositionCoordinates>(); |
| |
| Iterator<Point3d> it = points.iterator(); |
| while (it.hasNext()) { |
| Point3d p = it.next(); |
| CartesianPositionCoordinates point = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(p.x, p.y, p.z); |
| pointList.add(point); |
| } |
| |
| return pointList; |
| } |
| |
| /** |
| * Returns a transformed CartesianPolygon Poly(b) = T(ba) * Poly(a). |
| * |
| * @param transformationMatrix The transformation matrix to be applied. |
| * @param polygon The CartesianPolygon to be transformed. |
| * @return The transformed CartesianPolygon. |
| */ |
| public static CartesianPolygon createTransformedPolygon(Matrix4d transformationMatrix, CartesianPolygon polygon) { |
| /* Create an empty polygon */ |
| CartesianPolygon transformedData = ApogyCommonGeometryData3DFactory.eINSTANCE.createCartesianPolygon(); |
| |
| /* Create a copy of the CartesianPositionCoordinates as a Point3d list */ |
| List<Point3d> points = getPoint3dList(polygon.getVertices()); |
| |
| /* Apply the transformation on the Point3d list */ |
| applyTransformation(transformationMatrix, points); |
| |
| /* Create a List of CartesianPositionCoordinates using the transformed points */ |
| transformedData.getVertices().addAll(getCartesianPositionCoordinates(points)); |
| |
| return transformedData; |
| } |
| |
| /** |
| * Returns a transformed CartesianCoordinatesMesh Mesh(b) = T(ba) * Mesh(a). |
| * |
| * @param transformationMatrix The transformation matrix to be applied. |
| * @param mesh The CartesianCoordinatesMesh to be transformed. |
| * @return The transformed CartesianCoordinatesMesh. |
| */ |
| public static CartesianCoordinatesMesh createTransformedCartesianCoordinateMesh(Matrix4d transformationMatrix, |
| CartesianCoordinatesMesh mesh) { |
| /* Create a copy of the mesh */ |
| CartesianCoordinatesMesh transformedMesh = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianCoordinatesMesh(mesh); |
| |
| /* Create a copy of the CartesianPositionCoordinates as a Point3d list */ |
| List<Point3d> points = getPoint3dList(mesh.getPoints()); |
| |
| /* Apply the transformation on the Point3d list */ |
| applyTransformation(transformationMatrix, points); |
| |
| /* |
| * Modify the CartesianPositionCoordinates of the copied mesh to reflect the |
| * transformation |
| */ |
| CartesianPositionCoordinates pos = null; |
| Point3d point = null; |
| int NP = points.size(); |
| for (int i = 0; i < NP; i++) { |
| pos = transformedMesh.getPoints().get(i); |
| point = points.get(i); |
| pos.setX(point.x); |
| pos.setY(point.y); |
| pos.setZ(point.z); |
| } |
| |
| return transformedMesh; |
| } |
| |
| public static CartesianCoordinatesSet createTransformedCartesianCoordinatesSet(Matrix4d transformationMatrix, |
| CartesianCoordinatesSet cartesianCoordinatesSet) { |
| CartesianCoordinatesSet result = ApogyCommonGeometryData3DFactory.eINSTANCE.createCartesianCoordinatesSet(); |
| |
| // Creates a list of point on which the transformation will be applied. |
| List<Point3d> points = Geometry3DUtilities.getPoint3dList(cartesianCoordinatesSet.getPoints()); |
| |
| // Applies the transformation. |
| Geometry3DUtilities.applyTransformation(transformationMatrix, points); |
| |
| // Filld the result with the transformed points. |
| for (Point3d point : points) { |
| CartesianPositionCoordinates coord = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(point.x, point.y, point.z); |
| result.getPoints().add(coord); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns a transformed CartesianCoordinatesMesh Mesh(b) = T(ba) * Mesh(a). |
| * |
| * @param transformationMatrix The transformation matrix to be applied. |
| * @param mesh The CartesianCoordinatesMesh to be transformed. |
| * @return The transformed CartesianCoordinatesMesh. |
| */ |
| public static CartesianTriangularMesh createTransformedCartesianTriangularMesh(Matrix4d transformationMatrix, |
| CartesianTriangularMesh mesh) { |
| /* Create a copy of the mesh */ |
| CartesianTriangularMesh transformedMesh = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianTriangularMesh(mesh); |
| |
| /* Create a copy of the CartesianPositionCoordinates as a Point3d list */ |
| List<Point3d> points = getPoint3dList(mesh.getPoints()); |
| |
| /* Apply the transformation on the Point3d list */ |
| applyTransformation(transformationMatrix, points); |
| |
| /* |
| * Modify the CartesianPositionCoordinates of the copied mesh to reflect the |
| * transformation |
| */ |
| CartesianPositionCoordinates pos = null; |
| Point3d point = null; |
| int NP = points.size(); |
| for (int i = 0; i < NP; i++) { |
| pos = transformedMesh.getPoints().get(i); |
| point = points.get(i); |
| pos.setX(point.x); |
| pos.setY(point.y); |
| pos.setZ(point.z); |
| } |
| |
| return transformedMesh; |
| } |
| |
| /** |
| * Returns a transformed CartesianPositionCoordinates Coord(b) = T(ba) * |
| * Coord(a). |
| * |
| * @param transformationMatrix The transformation matrix to be applied. |
| * @param coord The CartesianPositionCoordinates to be |
| * transformed. |
| * @return The transformed CartesianPositionCoordinates. |
| */ |
| public static CartesianPositionCoordinates createTransformedCartesianPositionCoordinates( |
| Matrix4d transformationMatrix, CartesianPositionCoordinates coord) { |
| Point3d point = new Point3d(coord.getX(), coord.getY(), coord.getZ()); |
| transformationMatrix.transform(point); |
| return ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(point.x, point.y, point.z); |
| } |
| |
| /** |
| * Modify the Point3d listed elements by applying to them the provided |
| * transformation such that Point(b) = T(ba) * Point(a). |
| * |
| * @param transformationMatrix The transformation matrix to be applied. |
| * @param points The list of Point3d to be modified by the |
| * transformation. |
| */ |
| public static void applyTransformation(Matrix4d transformationMatrix, List<Point3d> points) { |
| Iterator<Point3d> iterator = points.iterator(); |
| |
| Point3d point = null; |
| while (iterator.hasNext()) { |
| point = iterator.next(); |
| transformationMatrix.transform(point); |
| } |
| |
| return; |
| } |
| |
| /** |
| * Creates a polygon (a triangle) that lays on the specified cartesian plane. |
| * |
| * @param plane The cartesian plane. |
| * @return The polygon. |
| */ |
| public static CartesianPolygon createNormalizedPolygonOfPlane(CartesianPlane plane) { |
| CartesianAxis axis = Geometry3DUtilities.getPerpendicularAxis(plane); |
| |
| CartesianPositionCoordinates vO = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(0, |
| 0, 0); |
| CartesianPositionCoordinates vX = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(1, |
| 0, 0); |
| CartesianPositionCoordinates vY = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(0, |
| 1, 0); |
| CartesianPositionCoordinates vZ = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(0, |
| 0, 1); |
| |
| CartesianPolygon polygon = null; |
| |
| switch (axis) { |
| case X: |
| polygon = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPolygon(vO, vY, vZ); |
| break; |
| case Y: |
| polygon = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPolygon(vO, vZ, vX); |
| break; |
| case Z: |
| polygon = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPolygon(vO, vX, vY); |
| break; |
| default: |
| break; |
| } |
| |
| return polygon; |
| } |
| |
| /** |
| * Return the extent of a list of points. |
| * |
| * @param points The list of points |
| * @return The CartesianCoordinatesSetExtent of the list of points. |
| */ |
| public static CartesianCoordinatesSetExtent getCartesianCoordinatesSetExtent( |
| List<CartesianPositionCoordinates> points) { |
| double xMin = Double.POSITIVE_INFINITY; |
| double xMax = Double.NEGATIVE_INFINITY; |
| double yMin = Double.POSITIVE_INFINITY; |
| double yMax = Double.NEGATIVE_INFINITY; |
| double zMin = Double.POSITIVE_INFINITY; |
| double zMax = Double.NEGATIVE_INFINITY; |
| |
| for (CartesianPositionCoordinates p : points) { |
| if (p.getX() < xMin) |
| xMin = p.getX(); |
| if (p.getX() > xMax) |
| xMax = p.getX(); |
| |
| if (p.getY() < yMin) |
| yMin = p.getY(); |
| if (p.getY() > yMax) |
| yMax = p.getY(); |
| |
| if (p.getZ() < zMin) |
| zMin = p.getZ(); |
| if (p.getZ() > zMax) |
| zMax = p.getZ(); |
| } |
| |
| CartesianCoordinatesSetExtent extent = ApogyCommonGeometryData3DFactory.eINSTANCE |
| .createCartesianCoordinatesSetExtent(); |
| extent.setXMin(xMin); |
| extent.setXMax(xMax); |
| extent.setYMin(yMin); |
| extent.setYMax(yMax); |
| extent.setZMin(zMin); |
| extent.setZMax(zMax); |
| |
| return extent; |
| } |
| |
| /** |
| * Return an area weighted average normal of a list of triangles. |
| * |
| * @param triangles The list of triangles. |
| * @return The average normal (normalized). |
| */ |
| public static Vector3d getAreaWeightedAverageNormal(List<CartesianTriangle> triangles) { |
| Vector3d normal = new Vector3d(); |
| for (CartesianTriangle triangle : triangles) { |
| Vector3d triangleEffectiveNormal = triangle.getNormal(); |
| triangleEffectiveNormal.scale(triangle.getSurface()); |
| normal.add(triangleEffectiveNormal); |
| } |
| normal.normalize(); |
| |
| return normal; |
| } |
| |
| /** |
| * Creates a map that associates a point to a point identifier for the list of |
| * points contained in a CoordinatesSet. |
| * |
| * @param coordinateSet The coordinates set. |
| * @return The map. |
| */ |
| public static <T extends Coordinates> Map<T, Integer> createPointIdMap(final CoordinatesSet<T> coordinateSet) { |
| Map<T, Integer> map = new HashMap<T, Integer>(); |
| |
| for (int i = 0; i < coordinateSet.getPoints().size(); i++) { |
| map.put(coordinateSet.getPoints().get(i), new Integer(i)); |
| } |
| |
| return map; |
| } |
| |
| public static class CartesianPositionCoordinatesDistanceComparator |
| implements Comparator<CartesianPositionCoordinates> { |
| private CartesianPositionCoordinates centerPoint = null; |
| private final CoordinatesComparator coordinatesComparator = new CoordinatesComparator(); |
| |
| public CartesianPositionCoordinatesDistanceComparator() { |
| this(ApogyCommonGeometryData3DFactory.eINSTANCE.createCartesianPositionCoordinates()); |
| } |
| |
| public CartesianPositionCoordinatesDistanceComparator(CartesianPositionCoordinates centerPoint) { |
| this.centerPoint = centerPoint; |
| } |
| |
| /** |
| * Compares two CartesianPositionCoordinates based on smallest distance to a |
| * center point. |
| */ |
| @Override |
| public int compare(CartesianPositionCoordinates o1, CartesianPositionCoordinates o2) { |
| double d1 = getDistance(o1, this.centerPoint); |
| double d2 = getDistance(o2, this.centerPoint); |
| |
| if (d1 > d2) { |
| return 1; |
| } else if (d1 < d2) { |
| return -1; |
| } else { |
| // If distance is the same, return order by coordinates. |
| return this.coordinatesComparator.compare(o1, o2); |
| } |
| } |
| } |
| |
| public static class CartesianPolygonCoordinatesDistanceComparator implements Comparator<CartesianPolygon> { |
| private CartesianPositionCoordinates centerPoint = null; |
| private final CoordinatesComparator coordinatesComparator = new CoordinatesComparator(); |
| |
| public CartesianPolygonCoordinatesDistanceComparator(CartesianPositionCoordinates centerPoint) { |
| this.centerPoint = centerPoint; |
| } |
| |
| @Override |
| public int compare(CartesianPolygon o1, CartesianPolygon o2) { |
| CartesianPositionCoordinates c1 = getCentroid(o1.getVertices()); |
| double d1 = getDistance(c1, this.centerPoint); |
| |
| CartesianPositionCoordinates c2 = getCentroid(o2.getVertices()); |
| double d2 = getDistance(c2, this.centerPoint); |
| |
| if (d1 > d2) { |
| return 1; |
| } else if (d1 < d2) { |
| return -1; |
| } else { |
| // If distance is the same, return order by coordinates. |
| return this.coordinatesComparator.compare(c1, c2); |
| } |
| } |
| } |
| |
| /** |
| * Comparator that compares two position based on their x, than y, than z |
| * coordinates. |
| * |
| * @author pallard |
| * |
| */ |
| private static class CoordinatesComparator implements Comparator<CartesianPositionCoordinates> { |
| @Override |
| public int compare(CartesianPositionCoordinates o1, CartesianPositionCoordinates o2) { |
| double deltax = o1.getX() - o2.getX(); |
| if (deltax > 0) { |
| return 1; |
| } else if (deltax < 0) { |
| return -1; |
| } else { |
| double deltay = o1.getY() - o2.getY(); |
| if (deltay > 0) { |
| return 1; |
| } else if (deltay < 0) { |
| return -1; |
| } else { |
| double deltaz = o1.getZ() - o2.getZ(); |
| if (deltaz > 0) { |
| return 1; |
| } else if (deltaz < 0) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| } |
| } |
| } |
| } // Geometry3DUtilities |