blob: 7453937228052b200f56c6488c60097266676977 [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.sensors.fov.impl;
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.CartesianPolygon;
import org.eclipse.apogy.common.geometry.data3d.CartesianPositionCoordinates;
import org.eclipse.apogy.common.geometry.data3d.Geometry3DUtilities;
import org.eclipse.emf.ecore.util.EcoreUtil;
public class RectangularFrustrumFieldOfViewSamplingShapeCustomImpl<PolygonType extends CartesianPolygon>
extends RectangularFrustrumFieldOfViewSamplingShapeImpl<PolygonType> {
private static Point3d origin = new Point3d();
@Override
public boolean isPolygonInside(PolygonType polygon) {
// Checks if the centroide of the polygon falls within the FOV.
if (isInside(polygon.getCentroid()))
return true;
// Checks that at least one vertex of the polygon falls inside.
for (CartesianPositionCoordinates point : polygon.getVertices()) {
if (isInside(point)) {
return true;
}
}
// Checks whether any of the FOV edges intersects with the polygon.
Matrix4d matrix = new Matrix4d(getTransform().asMatrix4d());
matrix.invert();
// Creates a version of the polygon that is expressed in the FOV frame.
PolygonType transformedPolygon = createPolygonInFOVFrame(polygon);
Vector3d[][] edges = getFOVEdges();
for (int i = 0; i < edges.length; i++) {
Vector3d u = edges[i][0];
Vector3d v = edges[i][1];
if (Geometry3DUtilities.getLineAndPolygonIntersectionPoint(u, v, transformedPolygon) != null) {
return true;
}
}
return false;
}
private PolygonType createPolygonInFOVFrame(PolygonType polygon) {
PolygonType newPolygon = EcoreUtil.copy(polygon);
newPolygon.getVertices().clear();
Matrix4d matrix = new Matrix4d(getTransform().asMatrix4d());
matrix.invert();
for (CartesianPositionCoordinates p : polygon.getVertices()) {
Point3d point3d = new Point3d();
matrix.transform(p.asPoint3d(), point3d);
CartesianPositionCoordinates transformedP = ApogyCommonGeometryData3DFacade.INSTANCE
.createCartesianPositionCoordinates(point3d.x, point3d.y, point3d.z);
newPolygon.getVertices().add(transformedP);
}
return newPolygon;
}
private Vector3d[][] getFOVEdges() {
Vector3d[][] edges = new Vector3d[4][2];
double azimuth = getRectangularFrustrumFieldOfView().getHorizontalFieldOfViewAngle() / 2.0;
double elevation = getRectangularFrustrumFieldOfView().getVerticalFieldOfViewAngle() / 2.0;
double x = Math.sin(elevation);
double y = Math.cos(elevation) * Math.sin(azimuth);
double z = Math.cos(elevation) * Math.cos(azimuth);
double xShort = x * getRectangularFrustrumFieldOfView().getRange().getMinimumDistance();
double yShort = y * getRectangularFrustrumFieldOfView().getRange().getMinimumDistance();
double zShort = z * getRectangularFrustrumFieldOfView().getRange().getMinimumDistance();
double xLong = x * getRectangularFrustrumFieldOfView().getRange().getMaximumDistance();
double yLong = y * getRectangularFrustrumFieldOfView().getRange().getMaximumDistance();
double zLong = z * getRectangularFrustrumFieldOfView().getRange().getMaximumDistance();
edges[0][0] = new Vector3d(xShort, yShort, zShort);
edges[0][1] = new Vector3d(xLong, yLong, zLong);
edges[1][0] = new Vector3d(-xShort, yShort, zShort);
edges[1][1] = new Vector3d(-xLong, yLong, zLong);
edges[2][0] = new Vector3d(-xShort, -yShort, zShort);
edges[2][1] = new Vector3d(-xLong, -yLong, zLong);
edges[3][0] = new Vector3d(xShort, -yShort, zShort);
edges[3][1] = new Vector3d(xLong, -yLong, zLong);
return edges;
}
@Override
public boolean isInside(CartesianPositionCoordinates point) {
boolean isInside = false;
// Transform the point into the FOV coordinates system.
Matrix4d matrix = new Matrix4d(getTransform().asMatrix4d());
matrix.invert();
Point3d p = new Point3d();
matrix.transform(point.asPoint3d(), p);
double distance = p.distance(origin);
if (getRectangularFrustrumFieldOfView().getRange().isWithinRange(distance)) {
// Point is within range, check whether it is within the horizontal field of
// view.
double azimuth = Math.abs(Math.atan2(p.y, p.z));
if (azimuth <= (getRectangularFrustrumFieldOfView().getHorizontalFieldOfViewAngle() / 2.0)) {
// Checks whether is is with the vertical field of view.
double elevation = Math.abs(Math.atan2(p.x, p.z));
if (elevation <= (getRectangularFrustrumFieldOfView().getVerticalFieldOfViewAngle() / 2.0)) {
isInside = true;
}
}
}
return isInside;
}
} // RectangularFrustrumFieldOfViewSamplingShapeImpl