blob: a9e05fcda1ac0be2f6e0debb518939f2feae1e12 [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,
* Sebastien Gemme - initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.common.topology.impl;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import javax.vecmath.Matrix3d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Vector3d;
import org.eclipse.apogy.common.math.ApogyCommonMathFacade;
import org.eclipse.apogy.common.math.ApogyCommonMathFactory;
import org.eclipse.apogy.common.math.GeometricUtils;
import org.eclipse.apogy.common.math.Matrix3x3;
import org.eclipse.apogy.common.math.Tuple3d;
import org.eclipse.apogy.common.topology.AbstractNodeVisitor;
import org.eclipse.apogy.common.topology.AggregateContentNode;
import org.eclipse.apogy.common.topology.ApogyCommonTopologyFacade;
import org.eclipse.apogy.common.topology.ApogyCommonTopologyFactory;
import org.eclipse.apogy.common.topology.AttachedViewPoint;
import org.eclipse.apogy.common.topology.ContentNode;
import org.eclipse.apogy.common.topology.GroupNode;
import org.eclipse.apogy.common.topology.INodeVisitor;
import org.eclipse.apogy.common.topology.Link;
import org.eclipse.apogy.common.topology.Node;
import org.eclipse.apogy.common.topology.NodeFilter;
import org.eclipse.apogy.common.topology.NodePath;
import org.eclipse.apogy.common.topology.PickAndPlaceNode;
import org.eclipse.apogy.common.topology.PositionNode;
import org.eclipse.apogy.common.topology.ReferencedContentNode;
import org.eclipse.apogy.common.topology.RotationNode;
import org.eclipse.apogy.common.topology.TransformNode;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
public class ApogyCommonTopologyFacadeCustomImpl extends ApogyCommonTopologyFacadeImpl {
private static final String NULL_NODE_ID_STRING = "NULL";
public <T> ContentNode<T> createContentNode(T content) {
return createAggregateContentNode(content);
}
@Override
public PositionNode createPositionNode(double x, double y, double z) {
PositionNode node = ApogyCommonTopologyFactory.eINSTANCE.createPositionNode();
Tuple3d position = ApogyCommonMathFactory.eINSTANCE.createTuple3d();
node.setPosition(position);
node.getPosition().setX(x);
node.getPosition().setY(y);
node.getPosition().setZ(z);
return node;
}
@Override
public RotationNode createRotationNodeXYZ(double x, double y, double z) {
RotationNode node = ApogyCommonTopologyFactory.eINSTANCE.createRotationNode();
Matrix3d rotationMatrix = GeometricUtils.packXYZ(x, y, z);
Matrix3x3 matrix = ApogyCommonMathFacade.INSTANCE.createMatrix3x3(rotationMatrix);
node.setRotationMatrix(matrix);
return node;
}
@Override
public Matrix4d expressRootInNodeFrame(Node node) {
Matrix4d mat = expressNodeInRootFrame(node);
mat.invert();
return mat;
}
public Matrix4d expressInFrame(Node sourceFrame, Node targetFrame) {
Matrix4d sourceFrameToRoot = expressNodeInRootFrame(sourceFrame);
Matrix4d rootToTargetFrame = expressNodeInRootFrame(targetFrame);
rootToTargetFrame.invert();
rootToTargetFrame.mul(sourceFrameToRoot);
return rootToTargetFrame;
}
@Override
public RotationNode createRotationNodeYZX(double x, double y, double z) {
RotationNode node = ApogyCommonTopologyFactory.eINSTANCE.createRotationNode();
Matrix3d rotationMatrix = GeometricUtils.packYZX(x, y, z);
Matrix3x3 matrix = ApogyCommonMathFacade.INSTANCE.createMatrix3x3(rotationMatrix);
node.setRotationMatrix(matrix);
return node;
}
@Override
public RotationNode createRotationNodeZYX(double x, double y, double z) {
RotationNode node = ApogyCommonTopologyFactory.eINSTANCE.createRotationNode();
Matrix3d rotationMatrix = GeometricUtils.packZYX(x, y, z);
Matrix3x3 matrix = ApogyCommonMathFacade.INSTANCE.createMatrix3x3(rotationMatrix);
node.setRotationMatrix(matrix);
return node;
}
public TransformNode createTransformNodeXYZ(double tx, double ty, double tz, double rx, double ry, double rz) {
RotationNode rotationNode = createRotationNodeXYZ(rx, ry, rz);
Tuple3d translation = ApogyCommonMathFactory.eINSTANCE.createTuple3d();
translation.setX(tx);
translation.setY(ty);
translation.setZ(tz);
TransformNode trNode = ApogyCommonTopologyFactory.eINSTANCE.createTransformNode();
trNode.setRotationMatrix(rotationNode.getRotationMatrix());
trNode.setPosition(translation);
return trNode;
}
public TransformNode createTransformNodeYZX(double tx, double ty, double tz, double rx, double ry, double rz) {
RotationNode rotationNode = createRotationNodeYZX(rx, ry, rz);
Tuple3d translation = ApogyCommonMathFactory.eINSTANCE.createTuple3d();
translation.setX(tx);
translation.setY(ty);
translation.setZ(tz);
TransformNode trNode = ApogyCommonTopologyFactory.eINSTANCE.createTransformNode();
trNode.setRotationMatrix(rotationNode.getRotationMatrix());
trNode.setPosition(translation);
return trNode;
}
public TransformNode createTransformNodeZYX(double tx, double ty, double tz, double rx, double ry, double rz) {
RotationNode rotationNode = createRotationNodeZYX(rx, ry, rz);
Tuple3d translation = ApogyCommonMathFactory.eINSTANCE.createTuple3d();
translation.setX(tx);
translation.setY(ty);
translation.setZ(tz);
TransformNode trNode = ApogyCommonTopologyFactory.eINSTANCE.createTransformNode();
trNode.setRotationMatrix(rotationNode.getRotationMatrix());
trNode.setPosition(translation);
return trNode;
}
@Override
public TransformNode createTransformNode(Matrix4d matrix) {
TransformNode tn = ApogyCommonTopologyFactory.eINSTANCE.createTransformNode();
tn.setTransformation(matrix);
return tn;
}
@Override
public PickAndPlaceNode createPickAndPlaceNode(Matrix4d matrix) {
PickAndPlaceNode pnpn = ApogyCommonTopologyFactory.eINSTANCE.createPickAndPlaceNode();
pnpn.setTransformation(matrix);
return pnpn;
}
public AttachedViewPoint createAttachedViewPoint(Node attachmentNode) {
AttachedViewPoint attachedViewPoint = ApogyCommonTopologyFactory.eINSTANCE.createAttachedViewPoint();
if (attachmentNode != null) {
Node root = ApogyCommonTopologyFacade.INSTANCE.findRoot(attachmentNode);
NodePath nodePath = ApogyCommonTopologyFacade.INSTANCE.createNodePath(root, attachmentNode);
attachedViewPoint.setNodePath(nodePath);
}
return attachedViewPoint;
}
@Override
public void printTopology(Node node) {
System.out.println("graph G {");
printTopology(node, null);
System.out.println("}");
}
public Collection<Node> filter(NodeFilter filter, Collection<Node> nodes) {
List<Node> matches = new ArrayList<Node>();
for (Node node : nodes) {
if (filter.matches(node)) {
matches.add(node);
}
}
return matches;
}
@Override
public <T> ReferencedContentNode<T> createReferencedContentNode(T content) {
ReferencedContentNode<T> contentNode = ApogyCommonTopologyFactory.eINSTANCE.createReferencedContentNode();
contentNode.setContent(content);
return contentNode;
}
@Override
public <T> AggregateContentNode<T> createAggregateContentNode(T content) {
AggregateContentNode<T> contentNode = ApogyCommonTopologyFactory.eINSTANCE.createAggregateContentNode();
contentNode.setContent(content);
return contentNode;
}
@Override
public Link createLink(Node node) {
Link link = ApogyCommonTopologyFactory.eINSTANCE.createLink();
link.setNode(node);
return link;
}
@Override
public EList<Node> findNodesByDescription(String description, Node topology) {
final String fDescription = description;
final EList<Node> matches = new BasicEList<Node>();
INodeVisitor visitor = new AbstractNodeVisitor() {
@Override
public void visit(Node node) {
// Special case: description is null
if (node.getDescription() == null && fDescription == null) {
matches.add(node);
} else if (node.getDescription() != null && node.getDescription().equals(fDescription)) {
matches.add(node);
}
}
};
topology.accept(visitor);
return matches;
}
@Override
public EList<Node> findNodesByID(String id, Node topology) {
final String fId = id;
final EList<Node> matches = new BasicEList<Node>();
INodeVisitor visitor = new AbstractNodeVisitor() {
@Override
public void visit(Node node) {
// Special case: ID is null
if (node.getNodeId() == null && fId == null) {
matches.add(node);
} else if (node.getNodeId() != null && node.getNodeId().equals(fId)) {
matches.add(node);
}
}
};
topology.accept(visitor);
return matches;
}
@Override
public EList<Node> findNodesByType(final EClass clazz, Node topology) {
final EList<Node> matches = new BasicEList<Node>();
INodeVisitor visitor = new AbstractNodeVisitor() {
@Override
public void visit(Node node) {
if (clazz.isSuperTypeOf(node.eClass())) {
matches.add(node);
}
}
};
topology.accept(visitor);
return matches;
}
@Override
public Node findRoot(Node node) {
Node current = node;
Node root = node;
while (current != null) {
root = current;
current = current.getParent();
}
return root;
}
public boolean doNodesShareTopologyTree(Node node1, Node node2) {
Node root1 = findRoot(node1);
Node root2 = findRoot(node2);
return root1 == root2;
}
public double getEuclideanDistance(Node fromNode, Node toNode) {
if (fromNode == toNode) {
return 0.0;
} else {
if (doNodesShareTopologyTree(fromNode, toNode)) {
Matrix4d m = expressInFrame(fromNode, toNode);
Vector3d v = new Vector3d();
m.get(v);
return v.length();
} else {
return Double.NaN;
}
}
}
public double getGeodesicDistance(Node fromNode, Node toNode) {
if (fromNode == toNode) {
return 0.0;
} else {
if (doNodesShareTopologyTree(fromNode, toNode)) {
List<Node> nodePath = findNodePath(fromNode, toNode);
double distance = 0.0;
Node currentNode = null;
Node previousNode = null;
for (int i = 0; i < nodePath.size(); i++) {
currentNode = nodePath.get(i);
if (previousNode != null && currentNode != null) {
distance += getEuclideanDistance(previousNode, currentNode);
}
previousNode = currentNode;
}
return distance;
} else {
return Double.NaN;
}
}
}
public List<Node> findNodePath(Node fromNode, Node toNode) {
if (doNodesShareTopologyTree(fromNode, toNode)) {
// Return path with from node if from and to are the same node.
if (fromNode == toNode) {
List<Node> nodePath = new ArrayList<Node>();
nodePath.add(fromNode);
return nodePath;
}
// Traverses the topology from fromNode to root.
Node current = fromNode;
List<Node> fromToRootList = new ArrayList<Node>();
while (current != null) {
fromToRootList.add(current);
// Move up the tree.
current = current.getParent();
}
// Traverses the topology from toNode to root.
current = toNode;
List<Node> toToRootList = new ArrayList<Node>();
while (current != null) {
toToRootList.add(current);
// Move up the tree.
current = current.getParent();
}
// Finds the intersection of both path.
Node intersectionNode = null;
Iterator<Node> iterator = fromToRootList.iterator();
while (intersectionNode == null && iterator.hasNext()) {
Node node = iterator.next();
if (toToRootList.contains(node)) {
intersectionNode = node;
}
}
// If no intersection is found.
if (intersectionNode == null) {
return new ArrayList<Node>();
} else {
List<Node> nodePath = new ArrayList<Node>();
// Gets the from items up to intersectionNode.
int index = 0;
boolean stop = false;
while (!stop && index < fromToRootList.size()) {
Node node = fromToRootList.get(index);
if (node == intersectionNode) {
stop = true;
} else {
nodePath.add(node);
}
index++;
}
// Gets the to items from intersectionNode to to.
index = toToRootList.indexOf(intersectionNode);
while (index >= 0) {
Node node = toToRootList.get(index);
nodePath.add(node);
index--;
}
return nodePath;
}
} else {
return new ArrayList<Node>();
}
}
public NodePath createNodePath(Node fromNode, Node toNode) {
NodePath nodePath = null;
// Traverses the topology from toNode to fromNode.
Node current = toNode;
List<Node> toToFromList = new ArrayList<Node>();
toToFromList.add(current);
while (current != null && current != fromNode) {
current = current.getParent();
if (current != null) {
toToFromList.add(current);
}
}
// Check if the last item in the list is the fromNode
if (toToFromList.size() > 0) {
if (toToFromList.get(toToFromList.size() - 1) == fromNode) {
nodePath = ApogyCommonTopologyFactory.eINSTANCE.createNodePath();
for (int i = toToFromList.size() - 1; i >= 0; i--) {
Node node = toToFromList.get(i);
if (node.getNodeId() == null) {
nodePath.getNodeIds().add(NULL_NODE_ID_STRING);
} else {
nodePath.getNodeIds().add(node.getNodeId());
}
}
} else {
return null;
}
} else {
// Returns an empty path.
nodePath = ApogyCommonTopologyFactory.eINSTANCE.createNodePath();
}
return nodePath;
}
public Node resolveNode(Node root, NodePath nodePath) {
// Do a Breadth-First search of the topology tree.
Node result = null;
int level = 0;
Set<Node> s = new HashSet<Node>();
Queue<Node> q = new ArrayDeque<Node>();
s.add(root);
q.add(root);
Node current = null;
while (!q.isEmpty() && result == null && level < nodePath.getNodeIds().size()) {
current = q.poll();
String nodeId = current.getNodeId();
if (nodeId == null)
nodeId = NULL_NODE_ID_STRING;
if (nodeId.compareTo(nodePath.getNodeIds().get(level)) == 0) {
if (current instanceof GroupNode) {
level++;
GroupNode groupNode = (GroupNode) current;
for (Node child : groupNode.getChildren()) {
// Check if the child has an ID that fits the NodePath.
nodeId = child.getNodeId();
if (nodeId == null)
nodeId = NULL_NODE_ID_STRING;
if (nodeId.compareTo(nodePath.getNodeIds().get(level)) == 0) {
// Check to see if we have reached the end of the
// search.
if (level == (nodePath.getNodeIds().size() - 1)) {
return child;
}
if (!s.contains(child)) {
s.add(child);
q.add(child);
}
}
}
}
}
}
return null;
}
private void printTopology(Node currentNode, Node parentNode) {
if (parentNode == null && !(currentNode instanceof GroupNode)) {
System.out.println(currentNode.getNodeId());
} else if (parentNode != null) {
System.out.println("\"" + parentNode.getNodeId() + "\" -- \"" + currentNode.getNodeId() + "\"");
}
if (currentNode instanceof GroupNode) {
GroupNode groupNode = (GroupNode) currentNode;
for (Node node : groupNode.getChildren()) {
printTopology(node, currentNode);
}
}
}
@Override
public Matrix4d expressNodeInRootFrame(Node node) {
List<Matrix4d> matrices = computeMatrixList(node);
return computeMatrix(matrices, true);
}
private List<Matrix4d> computeMatrixList(Node node) {
Matrix4d transformationMatrix = new Matrix4d();
transformationMatrix.setIdentity();
Stack<Matrix4d> matrices = new Stack<Matrix4d>();
Node currentNode = node;
// We get the parent of the node until we get to the root,
// i.e. when the parent is null.
while (currentNode != null) {
Matrix4d nodeMatrix = null;
if (currentNode instanceof TransformNode) {
TransformNode tnode = (TransformNode) currentNode;
nodeMatrix = tnode.asMatrix4d();
} else if (currentNode instanceof PositionNode) {
PositionNode pNode = (PositionNode) currentNode;
nodeMatrix = new Matrix4d();
nodeMatrix.setIdentity();
nodeMatrix.setTranslation(new Vector3d(pNode.getPosition().asTuple3d()));
} else if (currentNode instanceof RotationNode) {
RotationNode rNode = (RotationNode) currentNode;
nodeMatrix = new Matrix4d();
nodeMatrix.setIdentity();
nodeMatrix.setRotation(rNode.getRotationMatrix().asMatrix3d());
}
if (nodeMatrix != null) {
matrices.push(nodeMatrix);
}
currentNode = currentNode.getParent();
}
return matrices;
}
private Matrix4d computeMatrix(List<Matrix4d> matrices, boolean reverse) {
Matrix4d result = new Matrix4d();
result.setIdentity();
while (!matrices.isEmpty()) {
Matrix4d matrix = null;
if (reverse) {
matrix = matrices.remove(matrices.size() - 1);
} else {
matrix = matrices.remove(0);
}
result.mul(matrix);
}
return result;
}
} // ApogyCommonTopologyFacadeImpl