blob: 75803e10f14b3a9430a2692aefcddbf30f266d6c [file] [log] [blame]
/*******************************************************************************
* 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,
* Regent L'Archeveque - initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.addons.vehicle.impl;
import javax.vecmath.Matrix4d;
import javax.vecmath.Vector3d;
import org.eclipse.apogy.addons.ApogyAddonsPackage;
import org.eclipse.apogy.addons.geometry.paths.WayPointPath;
import org.eclipse.apogy.addons.mobility.pathplanners.ApogyAddonsMobilityPathplannersPackage;
import org.eclipse.apogy.addons.mobility.pathplanners.MeshWayPointPathPlanner;
import org.eclipse.apogy.addons.mobility.pathplanners.graph.ApogyAddonsMobilityPathplannersGraphFactory;
import org.eclipse.apogy.addons.mobility.pathplanners.graph.DistanceAndSlopesCostFunction;
import org.eclipse.apogy.addons.mobility.pathplanners.graph.SimpleDirectedWeightedGraphBasedMeshWayPointPathPlanner;
import org.eclipse.apogy.addons.vehicle.ApogyAddonsVehicleFactory;
import org.eclipse.apogy.addons.vehicle.ApogyAddonsVehiclePackage;
import org.eclipse.apogy.addons.vehicle.PathPlannerToolNode;
import org.eclipse.apogy.common.emf.ApogyCommonEMFFacade;
import org.eclipse.apogy.common.emf.transaction.ApogyCommonTransactionFacade;
import org.eclipse.apogy.common.geometry.data3d.ApogyCommonGeometryData3DFacade;
import org.eclipse.apogy.common.geometry.data3d.CartesianAxis;
import org.eclipse.apogy.common.geometry.data3d.CartesianPolygon;
import org.eclipse.apogy.common.geometry.data3d.CartesianPositionCoordinates;
import org.eclipse.apogy.common.math.ApogyCommonMathFacade;
import org.eclipse.apogy.common.math.Tuple3d;
import org.eclipse.apogy.common.processors.ApogyCommonProcessorsPackage;
import org.eclipse.apogy.common.topology.GroupNode;
import org.eclipse.apogy.common.topology.Node;
import org.eclipse.apogy.common.topology.ui.NodeSelection;
import org.eclipse.apogy.core.environment.surface.CartesianTriangularMeshMapLayer;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PathPlannerToolCustomImpl extends PathPlannerToolImpl {
private static final Logger Logger = LoggerFactory.getLogger(PathPlannerToolImpl.class);
public static int FROM_NODE_INDEX = 0;
public static int TO_NODE_INDEX = 1;
private int nextNode = FROM_NODE_INDEX;
@Override
public void setMeshLayer(CartesianTriangularMeshMapLayer newMeshLayer) {
super.setMeshLayer(newMeshLayer);
if (getPathPlanner() != null && newMeshLayer != null) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(getPathPlanner(),
ApogyAddonsMobilityPathplannersPackage.Literals.MESH_WAY_POINT_PATH_PLANNER__MESH,
newMeshLayer.getCurrentMesh());
// getPathPlanner().setMesh(newMeshLayer.getCurrentMesh());
}
}
@Override
@SuppressWarnings({ "rawtypes" })
public MeshWayPointPathPlanner getPathPlanner() {
if (this.pathPlanner == null) {
SimpleDirectedWeightedGraphBasedMeshWayPointPathPlanner<CartesianPolygon> tmp = ApogyAddonsMobilityPathplannersGraphFactory.eINSTANCE
.createSimpleDirectedWeightedGraphBasedMeshWayPointPathPlanner();
DistanceAndSlopesCostFunction das = ApogyAddonsMobilityPathplannersGraphFactory.eINSTANCE
.createDistanceAndSlopesCostFunction();
das.setGravityAxis(CartesianAxis.Z);
tmp.getCostFunctions().add(das);
tmp.setEnablePathSimplification(false);
setPathPlanner(tmp);
}
return this.pathPlanner;
}
@Override
public PathPlannerToolNode getPathPlannerToolNode() {
PathPlannerToolNode node = super.getPathPlannerToolNode();
if (node == null) {
node = ApogyAddonsVehicleFactory.eINSTANCE.createPathPlannerToolNode();
String nodeID = "PathPlannerToolNode_";
if (getName() != null) {
nodeID += getName() + "_" + ApogyCommonEMFFacade.INSTANCE.getID(this);
} else {
nodeID += ApogyCommonEMFFacade.INSTANCE.getID(this);
}
node.setNodeId(nodeID);
String description = "Node representing the tool named <" + getName() + ">";
if (getDescription() != null) {
description += ": " + getDescription();
}
node.setDescription(description);
setPathPlannerToolNode(node);
}
return node;
}
@Override
public void setRootNode(Node newRootNode) {
if (newRootNode instanceof GroupNode) {
((GroupNode) newRootNode).getChildren().add(getPathPlannerToolNode());
} else {
if (getPathPlannerToolNode().getParent() instanceof GroupNode) {
((GroupNode) getPathPlannerToolNode().getParent()).getChildren().remove(getPathPlannerToolNode());
}
}
super.setRootNode(newRootNode);
}
@Override
public void dispose() {
// Detach the PathPlannerToolNode from the topology if applicable.
if (getPathPlannerToolNode() != null) {
if (getPathPlannerToolNode().getParent() instanceof GroupNode) {
GroupNode parent = (GroupNode) getPathPlannerToolNode().getParent();
parent.getChildren().remove(getPathPlannerToolNode());
}
}
super.dispose();
}
@Override
public void selectionChanged(NodeSelection nodeSelection) {
if (!isDisposed()) {
Node node = nodeSelection.getSelectedNode();
Tuple3d relativePosition = null;
if (nodeSelection.getRelativeIntersectionPoint() != null) {
relativePosition = ApogyCommonMathFacade.INSTANCE
.createTuple3d(nodeSelection.getRelativeIntersectionPoint());
}
Tuple3d normal = null;
if (nodeSelection.getAbsoluteIntersectionNormal() != null) {
normal = ApogyCommonMathFacade.INSTANCE.createTuple3d(nodeSelection.getAbsoluteIntersectionNormal().x,
nodeSelection.getAbsoluteIntersectionNormal().y,
nodeSelection.getAbsoluteIntersectionNormal().z);
}
if (this.nextNode == TO_NODE_INDEX) {
if (!isFromNodeLock()) {
updateFromNode(node, relativePosition, normal);
} else if (!isToNodeLock()) {
updateToNode(node, relativePosition, normal);
}
this.nextNode = FROM_NODE_INDEX;
} else if (this.nextNode == FROM_NODE_INDEX) {
if (!isToNodeLock()) {
updateToNode(node, relativePosition, normal);
} else if (!isFromNodeLock()) {
updateFromNode(node, relativePosition, normal);
}
this.nextNode = TO_NODE_INDEX;
}
}
}
@Override
public void pointsRelativePoseChanged(Matrix4d newPose) {
if (getPathPlanner() != null) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsVehiclePackage.Literals.PATH_PLANNER_TOOL__PLANNED_PATH, null);
// setPlannedPath(null);
planPathInternal();
}
}
@Override
public boolean planPath() {
boolean success = false;
ApogyCommonTransactionFacade.INSTANCE.basicSet(this, ApogyAddonsVehiclePackage.Literals.PATH_PLANNER_TOOL__BUSY,
true);
// setBusy(true);
try {
if (getPathPlanner() != null && getMeshLayer() != null) {
CartesianPositionCoordinates from = getFromCartesianPositionCoordinates();
CartesianPositionCoordinates to = getToCartesianPositionCoordinates();
// If both current location and destination are defined.
if (from != null && to != null) {
Logger.info("Planning path from " + from.asPoint3d() + " to " + to.asPoint3d() + "...");
// Sets the mesh if not already done
if (getPathPlanner().getMesh() != getMeshLayer().getCurrentMesh()) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(getPathPlanner(),
ApogyAddonsMobilityPathplannersPackage.Literals.MESH_WAY_POINT_PATH_PLANNER__MESH,
getMeshLayer().getCurrentMesh());
// getPathPlanner().setMesh(getMeshLayer().getCurrentMesh());
}
// Plans a new path.
WayPointPath newPath = getPathPlanner().plan(from, to);
newPath.setNodeId(getName() + " Plan Path");
newPath.setDescription("Planned Path");
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsVehiclePackage.Literals.PATH_PLANNER_TOOL__PLANNED_PATH, newPath);
// setPlannedPath(newPath);
if (newPath != null) {
success = true;
Logger.info("Path planning sucessfully completed.");
}
} else {
String message = "Failed to plan path : ";
if (from == null)
message += "Current location is undefined.";
if (to == null)
message += " Destination is undefined.";
Logger.error(message);
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsVehiclePackage.Literals.PATH_PLANNER_TOOL__PLANNED_PATH, null);
}
}
} catch (Throwable t) {
Logger.error(t.getMessage(), t);
}
ApogyCommonTransactionFacade.INSTANCE.basicSet(this, ApogyAddonsVehiclePackage.Literals.PATH_PLANNER_TOOL__BUSY,
false);
return success;
}
protected void updateFromNode(Node node, Tuple3d relativePosition, Tuple3d normal) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsPackage.Literals.ABSTRACT_TWO_POINTS3_DTOOL__FROM_NODE, node);
// setFromNode(node);
if (relativePosition != null) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsPackage.Literals.ABSTRACT_TWO_POINTS3_DTOOL__FROM_RELATIVE_POSITION,
EcoreUtil.copy(relativePosition));
// setFromRelativePosition(EcoreUtil.copy(relativePosition));
if (isAutoPathPlanEnabled() && getPathPlanner() != null) {
planPathInternal();
}
}
}
protected void updateToNode(Node node, Tuple3d relativePosition, Tuple3d normal) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsPackage.Literals.ABSTRACT_TWO_POINTS3_DTOOL__TO_NODE, node);
// setToNode(node);
if (relativePosition != null) {
ApogyCommonTransactionFacade.INSTANCE.basicSet(this,
ApogyAddonsPackage.Literals.ABSTRACT_TWO_POINTS3_DTOOL__TO_RELATIVE_POSITION,
EcoreUtil.copy(relativePosition));
// setToRelativePosition(EcoreUtil.copy(relativePosition));
if (isAutoPathPlanEnabled() && getPathPlanner() != null) {
planPathInternal();
}
}
}
private void planPathInternal() {
if (!isBusy()) {
Job job = new Job("Planning Path") {
@Override
protected IStatus run(final IProgressMonitor monitor) {
try {
ApogyCommonTransactionFacade.INSTANCE.basicSet(getPathPlanner(),
ApogyCommonProcessorsPackage.Literals.MONITORABLE__PROGRESS_MONITOR, monitor);
// getPathPlanner().setProgressMonitor(monitor);
planPath();
} catch (Throwable t) {
Logger.error(t.getMessage(), t);
}
return Status.OK_STATUS;
}
};
job.schedule();
} else {
Logger.warn("Path Planner is busy.");
}
}
private CartesianPositionCoordinates getFromCartesianPositionCoordinates() {
CartesianPositionCoordinates from = null;
if (getFromAbsolutePosition() != null && getMeshLayer() != null) {
// Express to in the mesh coordinate system.
Matrix4d meshToWorld = getMeshLayer().getMap().getTransformation().asMatrix4d();
Vector3d fromVector = new Vector3d(getFromAbsolutePosition().asTuple3d());
meshToWorld.transform(fromVector);
from = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(fromVector.x,
fromVector.y, fromVector.z);
}
return from;
}
private CartesianPositionCoordinates getToCartesianPositionCoordinates() {
CartesianPositionCoordinates to = null;
if (getToAbsolutePosition() != null && getMeshLayer() != null) {
// Express to in the mesh coordinate system.
Matrix4d meshToWorld = getMeshLayer().getMap().getTransformation().asMatrix4d();
Vector3d toVector = new Vector3d(getToAbsolutePosition().asTuple3d());
meshToWorld.transform(toVector);
to = ApogyCommonGeometryData3DFacade.INSTANCE.createCartesianPositionCoordinates(toVector.x, toVector.y,
toVector.z);
}
return to;
}
} // PathPlannerToolImpl