1 /* Copyright 2002-2025 CS GROUP
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.orekit.geometry.fov;
18
19 import org.hipparchus.exception.LocalizedCoreFormats;
20 import org.hipparchus.geometry.euclidean.threed.Rotation;
21 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
22 import org.hipparchus.geometry.euclidean.threed.Vector3D;
23 import org.hipparchus.geometry.partitioning.Region;
24 import org.hipparchus.geometry.partitioning.RegionFactory;
25 import org.hipparchus.geometry.spherical.twod.Circle;
26 import org.hipparchus.geometry.spherical.twod.S2Point;
27 import org.hipparchus.geometry.spherical.twod.Sphere2D;
28 import org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet;
29 import org.hipparchus.geometry.spherical.twod.SubCircle;
30 import org.hipparchus.util.FastMath;
31 import org.orekit.errors.OrekitException;
32
33 /** Class representing a spacecraft sensor Field Of View with dihedral shape (i.e. rectangular shape).
34 * @author Luc Maisonobe
35 * @since 10.1
36 */
37 public class DoubleDihedraFieldOfView extends PolygonalFieldOfView {
38
39 /** Build a Field Of View with dihedral shape (i.e. rectangular shape).
40 * @param center Direction of the FOV center, in spacecraft frame
41 * @param axis1 FOV dihedral axis 1, in spacecraft frame
42 * @param halfAperture1 FOV dihedral half aperture angle 1,
43 * must be less than π/2, i.e. full dihedra must be smaller then
44 * an hemisphere
45 * @param axis2 FOV dihedral axis 2, in spacecraft frame
46 * @param halfAperture2 FOV dihedral half aperture angle 2,
47 * must be less than π/2, i.e. full dihedra must be smaller then
48 * an hemisphere
49 * @param margin angular margin to apply to the zone (if positive,
50 * points outside of the raw FoV but close enough to the boundary are
51 * considered visible; if negative, points inside of the raw FoV
52 * but close enough to the boundary are considered not visible)
53 */
54 public DoubleDihedraFieldOfView(final Vector3D center,
55 final Vector3D axis1, final double halfAperture1,
56 final Vector3D axis2, final double halfAperture2,
57 final double margin) {
58 super(createPolygon(center, axis1, halfAperture1, axis2, halfAperture2), margin);
59 }
60
61 /** Create polygon.
62 * @param center Direction of the FOV center, in spacecraft frame
63 * @param axis1 FOV dihedral axis 1, in spacecraft frame
64 * @param halfAperture1 FOV dihedral half aperture angle 1,
65 * must be less than π/2, i.e. full dihedra must be smaller then
66 * an hemisphere
67 * @param axis2 FOV dihedral axis 2, in spacecraft frame
68 * @param halfAperture2 FOV dihedral half aperture angle 2,
69 * must be less than π/2, i.e. full dihedra must be smaller then
70 * an hemisphere
71 * @return built polygon
72 */
73 private static SphericalPolygonsSet createPolygon(final Vector3D center,
74 final Vector3D axis1, final double halfAperture1,
75 final Vector3D axis2, final double halfAperture2) {
76 final RegionFactory<Sphere2D, S2Point, Circle, SubCircle> factory = new RegionFactory<>();
77 final double tolerance = FastMath.max(FastMath.ulp(2.0 * FastMath.PI),
78 1.0e-12 * FastMath.max(halfAperture1, halfAperture2));
79 final Region<Sphere2D, S2Point, Circle, SubCircle> dihedra1 = buildDihedra(factory, tolerance, center, axis1, halfAperture1);
80 final Region<Sphere2D, S2Point, Circle, SubCircle> dihedra2 = buildDihedra(factory, tolerance, center, axis2, halfAperture2);
81 return (SphericalPolygonsSet) factory.intersection(dihedra1, dihedra2);
82 }
83
84 /** Build a dihedra.
85 * @param factory factory for regions
86 * @param tolerance tolerance below which points are considered equal
87 * @param center Direction of the FOV center, in spacecraft frame
88 * @param axis FOV dihedral axis, in spacecraft frame
89 * @param halfAperture FOV dihedral half aperture angle,
90 * must be less than π/2, i.e. full dihedra must be smaller then
91 * an hemisphere
92 * @return dihedra
93 */
94 private static Region<Sphere2D, S2Point, Circle, SubCircle>
95 buildDihedra(final RegionFactory<Sphere2D, S2Point, Circle, SubCircle> factory,
96 final double tolerance, final Vector3D center,
97 final Vector3D axis, final double halfAperture) {
98 if (halfAperture > 0.5 * FastMath.PI) {
99 throw new OrekitException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
100 halfAperture, 0.0, 0.5 * FastMath.PI);
101 }
102
103 final Rotation r = new Rotation(axis, halfAperture, RotationConvention.VECTOR_OPERATOR);
104 final Vector3D normalCenterPlane = Vector3D.crossProduct(axis, center);
105 final Vector3D normalSidePlus = r.applyInverseTo(normalCenterPlane);
106 final Vector3D normalSideMinus = r.applyTo(normalCenterPlane.negate());
107
108 return factory.intersection(new SphericalPolygonsSet(normalSidePlus, tolerance),
109 new SphericalPolygonsSet(normalSideMinus, tolerance));
110
111 }
112
113 }