| /******************************************************************************* |
| * 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: |
| * Pierre Allard - initial API and implementation |
| * Regent L'Archeveque |
| * SPDX-License-Identifier: EPL-1.0 |
| *******************************************************************************/ |
| |
| package org.eclipse.apogy.addons.geometry.paths; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import javax.media.j3d.Transform3D; |
| import javax.vecmath.Matrix4d; |
| import javax.vecmath.Point3d; |
| import javax.vecmath.Vector3d; |
| |
| import org.eclipse.apogy.common.geometry.data3d.ApogyCommonGeometryData3DFacade; |
| import org.eclipse.apogy.common.geometry.data3d.CartesianAxis; |
| import org.eclipse.apogy.common.geometry.data3d.CartesianPositionCoordinates; |
| import org.eclipse.apogy.common.geometry.data3d.Geometry3DUtilities; |
| |
| public class PathUtilities { |
| /** |
| * Appends two paths to form one. |
| * |
| * @param path1 The first path. |
| * @param path2 The second path. |
| * @return |
| */ |
| public static WayPointPath append(WayPointPath path1, WayPointPath path2, boolean removeDuplicateAtEnds) { |
| List<WayPointPath> paths = new ArrayList<WayPointPath>(); |
| |
| // Creates a list of WayPointPath. |
| paths.add(path1); |
| paths.add(path2); |
| |
| // Appends the paths. |
| return append(paths, removeDuplicateAtEnds); |
| } |
| |
| /** |
| * Appends a list of WayPointPath to create a single WayPointPath. |
| * |
| * @param paths The list of paths to append together. |
| * @param removeDuplicateAtEnds True removes duplicates point at the end points |
| * of paths appended, false does not. |
| * @return The appended WayPointPath. |
| */ |
| public static WayPointPath append(List<WayPointPath> paths, boolean removeDuplicateAtEnds) { |
| WayPointPath path = ApogyAddonsGeometryPathsFactory.eINSTANCE.createWayPointPath(); |
| |
| Iterator<WayPointPath> pathsIt = paths.iterator(); |
| while (pathsIt.hasNext()) { |
| WayPointPath currentPath = pathsIt.next(); |
| |
| // Appends the description. |
| String newDescription = path.getDescription() + "\n\n" + currentPath.getDescription(); |
| path.setDescription(newDescription); |
| |
| // Appends the way points. |
| for (int i = 0; i < currentPath.getPoints().size(); i++) { |
| CartesianPositionCoordinates currentWayPoint = currentPath.getPoints().get(i); |
| |
| // Check if the first point of the next WayPointPath is equal to the current |
| // tail of the path. |
| if (removeDuplicateAtEnds && (i == 0) && (path.getPoints().size() > 0)) { |
| CartesianPositionCoordinates currentEndPoint = path.getPoints().get(path.getPoints().size() - 1); |
| if (!currentWayPoint.equals(currentEndPoint)) { |
| path.getPoints().add(ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(currentWayPoint)); |
| } |
| } else { |
| path.getPoints().add(ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(currentWayPoint)); |
| } |
| } |
| } |
| |
| return path; |
| } |
| |
| /** |
| * Returns the sum of the absolute angular deltas of the path about a specified |
| * axis. |
| * |
| * @param axis The axis around which to sum the angular motion. |
| * @param wayPointPath The WayPointPath. |
| * @return The sum of the absolute angular deltas of the path about the |
| * specified axis, in radians. |
| */ |
| public static double getAngularMotion(CartesianAxis axis, WayPointPath wayPointPath) { |
| double angularMotion = 0.0; |
| |
| if (wayPointPath.getPoints().size() > 2) { |
| Vector3d u = null; |
| Vector3d v = null; |
| |
| // Gets the flatten coordinates on the plane perpendicular to the specified |
| // axis. |
| List<CartesianPositionCoordinates> flattenCoord = Geometry3DUtilities |
| .getFlattenCoordinates(Geometry3DUtilities.getPerpendicularPlane(axis), wayPointPath.getPoints()); |
| |
| for (int i = 0; i < flattenCoord.size() - 2; i++) { |
| CartesianPositionCoordinates p1 = flattenCoord.get(i); |
| CartesianPositionCoordinates p2 = flattenCoord.get(i + 1); |
| CartesianPositionCoordinates p3 = flattenCoord.get(i + 2); |
| |
| u = new Vector3d(p2.getX() - p1.getX(), p2.getY() - p1.getY(), p2.getZ() - p1.getZ()); |
| v = new Vector3d(p3.getX() - p2.getX(), p3.getY() - p2.getY(), p3.getZ() - p2.getZ()); |
| |
| // Adds angular motion only if the vector are non-zero length. |
| if (u.length() > 0 && v.length() > 0) { |
| angularMotion += u.angle(v); |
| } |
| } |
| } |
| |
| return angularMotion; |
| } |
| |
| /** |
| * Returns the two CartesianPositionCoordinates that defines the longest segment |
| * in a specified WayPointPath. |
| * |
| * @param wayPointPath The WayPointPath. |
| * @return A list containing the two CartesianPositionCoordinates that defines |
| * the longest segment, or empty if the WayPointPath contains less than |
| * 2 points. If many segments have the same maximum length, the last one |
| * is returned. |
| */ |
| public static List<CartesianPositionCoordinates> getLongestSegment(WayPointPath wayPointPath) { |
| List<CartesianPositionCoordinates> longestSegment = new ArrayList<CartesianPositionCoordinates>(); |
| |
| double maxLength = 0; |
| |
| if (wayPointPath.getPoints().size() > 1) { |
| for (int i = 0; i < wayPointPath.getPoints().size() - 1; i++) { |
| CartesianPositionCoordinates p1 = wayPointPath.getPoints().get(i); |
| CartesianPositionCoordinates p2 = wayPointPath.getPoints().get(i + 1); |
| |
| double segmentLength = Geometry3DUtilities.getDistance(p1, p2); |
| if (segmentLength >= maxLength) { |
| maxLength = segmentLength; |
| longestSegment.clear(); |
| longestSegment.add(p1); |
| longestSegment.add(p2); |
| } |
| } |
| } |
| |
| return longestSegment; |
| } |
| |
| /** |
| * Returns the length of the longest segment of a specified WayPointPath. |
| * |
| * @param wayPointPath The WayPointPath. |
| * @return The length of the longest segment, zero if the WayPointPath contains |
| * less than 2 points. |
| */ |
| public static double getLongestSegmentLength(WayPointPath wayPointPath) { |
| double maximumLength = 0.0; |
| |
| List<CartesianPositionCoordinates> longestSegment = getLongestSegment(wayPointPath); |
| if (longestSegment.size() == 2) { |
| maximumLength = Geometry3DUtilities.getDistance(longestSegment.get(0), longestSegment.get(1)); |
| } |
| |
| return maximumLength; |
| } |
| |
| /** |
| * Returns the two CartesianPositionCoordinates that defines the shortest |
| * segment in a specified WayPointPath. |
| * |
| * @param wayPointPath The WayPointPath. |
| * @return A list containing the two CartesianPositionCoordinates that defines |
| * the shortest segment, or empty if the WayPointPath contains less than |
| * 2 points. If many segments have the same minimum length, the last one |
| * is returned. |
| */ |
| public static List<CartesianPositionCoordinates> getShortestSegment(WayPointPath wayPointPath) { |
| List<CartesianPositionCoordinates> shortestSegment = new ArrayList<CartesianPositionCoordinates>(); |
| |
| double minLength = Double.POSITIVE_INFINITY; |
| |
| if (wayPointPath.getPoints().size() > 1) { |
| for (int i = 0; i < wayPointPath.getPoints().size() - 1; i++) { |
| CartesianPositionCoordinates p1 = wayPointPath.getPoints().get(i); |
| CartesianPositionCoordinates p2 = wayPointPath.getPoints().get(i + 1); |
| |
| double segmentLength = Geometry3DUtilities.getDistance(p1, p2); |
| if (segmentLength <= minLength) { |
| minLength = segmentLength; |
| shortestSegment.clear(); |
| shortestSegment.add(p1); |
| shortestSegment.add(p2); |
| } |
| } |
| } |
| |
| return shortestSegment; |
| } |
| |
| /** |
| * Returns the length of the shortest segment of a specified WayPointPath. |
| * |
| * @param wayPointPath The WayPointPath. |
| * @return The length of the shortest segment, zero if the WayPointPath contains |
| * less than 2 points. |
| */ |
| public static double getShortestSegmentLength(WayPointPath wayPointPath) { |
| double minimumLength = 0.0; |
| |
| List<CartesianPositionCoordinates> shortestSegment = getShortestSegment(wayPointPath); |
| if (shortestSegment.size() == 2) { |
| minimumLength = Geometry3DUtilities.getDistance(shortestSegment.get(0), shortestSegment.get(1)); |
| } |
| |
| return minimumLength; |
| } |
| |
| /** |
| * Applies a transformation to a path. |
| * |
| * @param path The original path |
| * @param transform The transform to apply |
| * @return A new WayPointPath with each point transformed. |
| */ |
| public static WayPointPath applyTransform(final WayPointPath path, final Matrix4d transform) { |
| WayPointPath transformedPath = ApogyAddonsGeometryPathsFactory.eINSTANCE.createWayPointPath(); |
| Transform3D transform3d = new Transform3D(transform); |
| |
| List<CartesianPositionCoordinates> points = new ArrayList<CartesianPositionCoordinates>(); |
| for (CartesianPositionCoordinates point : path.getPoints()) { |
| Point3d p = new Point3d(point.getX(), point.getY(), point.getZ()); |
| transform3d.transform(p); |
| |
| CartesianPositionCoordinates newPoint = ApogyCommonGeometryData3DFacade.INSTANCE |
| .createCartesianPositionCoordinates(p.x, p.y, p.z); |
| points.add(newPoint); |
| } |
| transformedPath.getPoints().addAll(points); |
| |
| return transformedPath; |
| } |
| } |