| /******************************************************************************* |
| * 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.core.impl; |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.FileReader; |
| import java.io.FileWriter; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.vecmath.Matrix4d; |
| |
| import org.eclipse.apogy.common.emf.transaction.ApogyCommonTransactionFacade; |
| import org.eclipse.apogy.common.math.ApogyCommonMathFacade; |
| import org.eclipse.apogy.common.math.Matrix4x4; |
| import org.eclipse.apogy.common.math.Tuple3d; |
| import org.eclipse.apogy.common.topology.ApogyCommonTopologyFacade; |
| import org.eclipse.apogy.common.topology.Node; |
| import org.eclipse.apogy.common.topology.ReferencedContentNode; |
| import org.eclipse.apogy.common.topology.TransformNode; |
| import org.eclipse.apogy.core.ApogyCoreFactory; |
| import org.eclipse.apogy.core.ApogySystem; |
| import org.eclipse.apogy.core.ApogySystemApiAdapter; |
| import org.eclipse.apogy.core.FeatureOfInterest; |
| import org.eclipse.apogy.core.PositionedResult; |
| import org.eclipse.apogy.core.ResultNode; |
| import org.eclipse.apogy.core.invocator.AbstractTypeImplementation; |
| import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorFacade; |
| import org.eclipse.apogy.core.invocator.AttributeResultValue; |
| import org.eclipse.apogy.core.invocator.Environment; |
| import org.eclipse.apogy.core.invocator.ReferenceResultValue; |
| import org.eclipse.apogy.core.invocator.TypeApiAdapter; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; |
| import org.eclipse.emf.edit.command.AddCommand; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| |
| public class ApogyCoreFacadeCustomImpl extends ApogyCoreFacadeImpl { |
| |
| @Override |
| public Matrix4x4 computeAbsolutePoseMatrix(ApogySystem apogySystem, Matrix4x4 relativePose) { |
| // Gets system pose. |
| Node root = ApogyCommonTopologyFacade.INSTANCE.findRoot(apogySystem.getTopologyRoot().getOriginNode()); |
| |
| Matrix4d systemPose = ApogyCommonTopologyFacade.INSTANCE |
| .expressInFrame(apogySystem.getTopologyRoot().getOriginNode(), root); |
| |
| // Gets the system centric result. |
| Matrix4x4 pose = relativePose; |
| Matrix4d matrix = new Matrix4d(); |
| matrix.setIdentity(); |
| if (pose != null) |
| matrix = pose.asMatrix4d(); |
| |
| // Create the absolute position result. |
| Matrix4d m = new Matrix4d(); |
| m.setIdentity(); |
| m.mul(systemPose, matrix); |
| |
| return ApogyCommonMathFacade.INSTANCE.createMatrix4x4(m); |
| } |
| |
| public ResultNode createResultNode(PositionedResult result) { |
| // Creates the ResultNode. |
| ResultNode resultNode = ApogyCoreFactory.eINSTANCE.createResultNode(); |
| resultNode.setResult(result); |
| |
| // Sets the time as the ID |
| Date time = result.getTime(); |
| if (time == null) |
| time = new Date(); |
| |
| resultNode.setNodeId(createNodeID(result)); |
| resultNode.setDescription(result.getDescription()); |
| |
| // Attaches the result itself to the ResultNode. |
| if (result.getResultValue() instanceof AttributeResultValue) { |
| AttributeResultValue attributeResultValue = (AttributeResultValue) result.getResultValue(); |
| |
| if (attributeResultValue.getValue() != null) { |
| // TODO : Adds a marker in the topology ? |
| } |
| } else if (result.getResultValue() instanceof ReferenceResultValue) { |
| ReferenceResultValue referenceResultValue = (ReferenceResultValue) result.getResultValue(); |
| if (referenceResultValue.getValue() != null) { |
| if (referenceResultValue.getValue() instanceof Node) { |
| // TODO : Do not copy the Node when bug#1429 in Link and |
| // ReferenceGroupNode is fixed. |
| Node node = EcoreUtil.copy((Node) referenceResultValue.getValue()); |
| resultNode.getChildren().add(node); |
| } else { |
| // Creates and adds a ReferencedContentNode with the result |
| // as its content. |
| EObject content = referenceResultValue.getValue(); |
| ReferencedContentNode<EObject> contentNode = ApogyCommonTopologyFacade.INSTANCE |
| .createReferencedContentNode(content); |
| |
| // Adds a the node via a ReferenceNode under the |
| // DataProductNode. |
| resultNode.getChildren().add(contentNode); |
| } |
| } |
| } |
| |
| return resultNode; |
| } |
| |
| @Override |
| public ApogySystem getApogySystem(Environment environment, String fullyQualifiedName) { |
| ApogySystem result = null; |
| AbstractTypeImplementation typeImplementation = ApogyCoreInvocatorFacade.INSTANCE |
| .getTypeImplementation(environment, fullyQualifiedName); |
| |
| if (typeImplementation != null) { |
| TypeApiAdapter typeApiAdapter = typeImplementation.getAdapterInstance(); |
| |
| if (typeApiAdapter instanceof ApogySystemApiAdapter) { |
| ApogySystemApiAdapter apogySystemApiAdapter = (ApogySystemApiAdapter) typeApiAdapter; |
| result = apogySystemApiAdapter.getApogySystem(); |
| } |
| } |
| |
| return result; |
| } |
| |
| public ApogySystem getApogySystem(Environment environment, EObject instance) { |
| ApogySystem result = null; |
| |
| AbstractTypeImplementation abstractTypeImplementation = ApogyCoreInvocatorFacade.INSTANCE |
| .findAbstractTypeImplementation(instance); |
| if (abstractTypeImplementation != null |
| && abstractTypeImplementation.getAdapterInstance() instanceof ApogySystemApiAdapter) { |
| ApogySystemApiAdapter apogySystemApiAdapter = (ApogySystemApiAdapter) abstractTypeImplementation |
| .getAdapterInstance(); |
| result = apogySystemApiAdapter.getApogySystem(); |
| } |
| |
| return result; |
| } |
| |
| public ApogySystem loadApogySystemFromFile(String apogySystemFileAbsolutePath) throws Exception { |
| Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; |
| Map<String, Object> m = reg.getExtensionToFactoryMap(); |
| m.put("key", new XMIResourceFactoryImpl()); |
| |
| // Create a resource set to hold the resources. |
| TransactionalEditingDomain domain = ApogyCommonTransactionFacade.INSTANCE.getDefaultEditingDomain(); |
| |
| ResourceSet resSet = domain.getResourceSet(); |
| |
| Resource resource = resSet.createResource(URI.createFileURI(apogySystemFileAbsolutePath)); |
| resource.load(m); |
| ApogySystem apogySystem = (ApogySystem) resource.getContents().get(0); |
| |
| return apogySystem; |
| } |
| |
| public void saveApogySystemToFile(ApogySystem apogySystem, String apogySystemFileAbsolutePath) throws Exception { |
| // Create a resource set to hold the resources. |
| TransactionalEditingDomain domain = ApogyCommonTransactionFacade.INSTANCE |
| .getTransactionalEditingDomain(apogySystem); |
| if (domain == null) { |
| domain = ApogyCommonTransactionFacade.INSTANCE.getDefaultEditingDomain(); |
| } |
| |
| ResourceSet resourceSet = domain.getResourceSet(); |
| Resource resource = resourceSet.createResource(URI.createFileURI(apogySystemFileAbsolutePath)); |
| |
| domain.getCommandStack().execute(new AddCommand(domain, resource.getContents(), apogySystem)); |
| |
| resource.save(Collections.EMPTY_MAP); |
| } |
| |
| @Override |
| public List<FeatureOfInterest> loadFeatureOfInterestFromFile(String urlString) throws Exception { |
| List<FeatureOfInterest> foiList = new ArrayList<FeatureOfInterest>(); |
| |
| URL url = new URL(urlString); |
| File tempFile = copyURLContent(url); |
| BufferedReader reader = new BufferedReader(new FileReader(tempFile)); |
| |
| String line = null; |
| while ((line = reader.readLine()) != null) { |
| line = line.trim(); |
| FeatureOfInterest foi = parserCSVLine(line); |
| if (foi != null) { |
| foiList.add(foi); |
| } |
| } |
| |
| reader.close(); |
| |
| return foiList; |
| } |
| |
| private FeatureOfInterest parserCSVLine(String line) throws Exception { |
| FeatureOfInterest foi = null; |
| |
| String[] entries = line.split(","); |
| |
| if (entries.length < 8) { |
| throw new Exception("Line <" + line + "> contains too few entries !"); |
| } |
| |
| String name = entries[0]; |
| String description = entries[1]; |
| double x = Double.parseDouble(entries[2]); |
| double y = Double.parseDouble(entries[3]); |
| double z = Double.parseDouble(entries[4]); |
| |
| double rx = Double.parseDouble(entries[5]); |
| double ry = Double.parseDouble(entries[6]); |
| double rz = Double.parseDouble(entries[7]); |
| |
| foi = ApogyCoreFactory.eINSTANCE.createFeatureOfInterest(); |
| foi.setName(name); |
| foi.setDescription(description); |
| |
| // Sets pose. |
| TransformNode tmp = ApogyCommonTopologyFacade.INSTANCE.createTransformNodeXYZ(x, y, z, rx, ry, rz); |
| Matrix4d m = tmp.asMatrix4d(); |
| foi.setPose(ApogyCommonMathFacade.INSTANCE.createMatrix4x4(m)); |
| |
| return foi; |
| } |
| |
| @Override |
| public void saveFeatureOfInterestToFile(String path, List<FeatureOfInterest> foiList) throws Exception { |
| // Converts the FOI to CSV format |
| String cvsData = convertToCSV(foiList); |
| |
| // Write data to the file. |
| BufferedWriter writer = new BufferedWriter(new FileWriter(path)); |
| writer.write(cvsData); |
| writer.close(); |
| } |
| |
| private String convertToCSV(List<FeatureOfInterest> foiList) { |
| String csvString = new String(); |
| |
| for (FeatureOfInterest foi : foiList) { |
| if (foi.getName() != null) { |
| // Replace comma by space |
| csvString += foi.getName().replaceAll(",", ";") + ","; |
| } else { |
| csvString += ","; |
| } |
| |
| if (foi.getDescription() != null) { |
| // Replace comma by space |
| csvString += foi.getDescription().replaceAll(",", ";") + ","; |
| } else { |
| csvString += ","; |
| } |
| |
| Tuple3d position = ApogyCommonMathFacade.INSTANCE.extractPosition(foi.getPose()); |
| |
| csvString += position.getX() + ","; |
| csvString += position.getY() + ","; |
| csvString += position.getZ() + ","; |
| |
| Tuple3d orientation = ApogyCommonMathFacade.INSTANCE.extractOrientation(foi.getPose()); |
| csvString += orientation.getX() + ","; |
| csvString += orientation.getY() + ","; |
| csvString += orientation.getZ() + "\n"; |
| |
| } |
| |
| return csvString; |
| } |
| |
| // FIXME Not used. |
| // private List<TimeSource> getAllAvaibleTimeSource() { |
| // List<TimeSource> timeSources = new ArrayList<TimeSource>(); |
| // |
| // List<EClass> timeSourceEClass = ApogyCommonEMFFacade.INSTANCE |
| // .getAllSubEClasses(ApogyCommonEMFPackage.Literals.TIME_SOURCE); |
| // |
| // for (EClass eClass : timeSourceEClass) { |
| // try { |
| // EObject eObject = EcoreUtil.create(eClass); |
| // if (eObject instanceof TimeSource) { |
| // timeSources.add((TimeSource) eObject); |
| // } |
| // } catch (Throwable t) { |
| // Logger.error(t.getMessage(), t); |
| // } |
| // } |
| // |
| // return timeSources; |
| // } |
| |
| // FIXME Not used. |
| // private CurrentTimeSource getCurrentTimeSource(Collection<TimeSource> timeSources) { |
| // CurrentTimeSource currentTimeSource = null; |
| // |
| // Iterator<TimeSource> it = timeSources.iterator(); |
| // while (it.hasNext() && currentTimeSource == null) { |
| // TimeSource timeSource = it.next(); |
| // if (timeSource instanceof CurrentTimeSource) { |
| // currentTimeSource = (CurrentTimeSource) timeSource; |
| // } |
| // } |
| // |
| // return currentTimeSource; |
| // } |
| // FIXME Move under Common Facade. |
| private File copyURLContent(URL url) throws Exception { |
| File tempFile = null; |
| |
| String fileName = getFileName(url); |
| String fileExtension = getFileExtension(url); |
| |
| tempFile = File.createTempFile(fileName, fileExtension); |
| |
| url.openConnection(); |
| InputStream reader = url.openStream(); |
| |
| FileOutputStream writer = new FileOutputStream(tempFile); |
| byte[] buffer = new byte[153600]; |
| int bytesRead = 0; |
| while ((bytesRead = reader.read(buffer)) > 0) { |
| writer.write(buffer, 0, bytesRead); |
| buffer = new byte[153600]; |
| } |
| writer.close(); |
| reader.close(); |
| |
| if (tempFile != null) { |
| tempFile.deleteOnExit(); |
| } |
| |
| return tempFile; |
| } |
| |
| // FIXME Move under Common Facade. |
| private String getFileName(URL url) { |
| String fileName = url.getFile(); |
| |
| int startIndex = fileName.lastIndexOf(File.separator); |
| int endIndex = fileName.lastIndexOf("."); |
| if (startIndex > 0 && endIndex > 0) { |
| fileName = fileName.substring(startIndex + 1, endIndex); |
| } |
| |
| return fileName; |
| } |
| |
| private String getFileExtension(URL url) { |
| String fileExtension = url.getFile(); |
| |
| int index = fileExtension.lastIndexOf("."); |
| if (index > 0) { |
| fileExtension = fileExtension.substring(index); |
| } |
| |
| return fileExtension; |
| } |
| |
| private String createNodeID(PositionedResult positionedResult) { |
| String nodeId = positionedResult.eClass().getName(); |
| |
| Date date = positionedResult.getTime(); |
| if (date != null) { |
| nodeId += " - " + date.toString(); |
| } |
| |
| return nodeId; |
| } |
| } // ApogyCoreFacadeImpl |