Click or drag to resize

Ellipsoid Surface Regions

The need to define surface regions on a planetary body is common in many domains and applications. In this topic, we'll show you how to create and use EllipsoidSurfaceRegions, which are created using builder classes derived from EllipsoidSurfaceRegionBuilders. Surface regions are used in many areas in STK Components, including:

  • Defining a surface region for use with an access constraint, which can be a basic membership test, an azimuth-elevation constraint, or a sensor volume constraint.

  • Visualizing topographical regions or geopolitical regions of interest.

  • Gridding a surface region for use with Coverage.

  • Visualizing coverage metrics on the surface of a planet.

  • Defining a search area for the Route Design Library.

EllipsoidSurfaceRegion in South America
Ellipsoid Surface Region Builders

STK Components includes four techniques for creating surface regions on an ellipsoid, each provided by a different builder class. Because EllipsoidSurfaceRegions are immutable after construction, the builders allow configuration of inputs and options for creating a surface region or surface region hole (a surface region with inverted point membership). After fully configuring a builder, call getEllipsoidSurfaceRegion or getEllipsoidSurfaceRegionHole to obtain an immutable region or hole. The builder can then be reconfigured and used to create additional regions or holes. Since each builder has unique features, we will discuss them individually.

First, SpecifiedNodesEllipsoidSurfaceRegionBuilder creates a region based on specified "nodes" or vertices that define the boundary of the surface region. The connection between each vertex of the surface boundary can be either a geodesic curve (minimum distance) or a rhumb line (constant heading).

Java
// First we choose our reference surface, which will be the ellipsoid that defines Earth's surface.
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
Ellipsoid referenceSurface = earth.getShape();

// We specify the boundary in terms of nodes connected by geodesics
Cartographic[] nodes = {
        new Cartographic(Trig.degreesToRadians(-72.9947), Trig.degreesToRadians(11.3181), 0),
        new Cartographic(Trig.degreesToRadians(-35.4977), Trig.degreesToRadians(-6.29148), 0),
        new Cartographic(Trig.degreesToRadians(-48.902), Trig.degreesToRadians(-13.6507), 0),
        new Cartographic(Trig.degreesToRadians(-63.9708), Trig.degreesToRadians(-0.859671), 0),
        new Cartographic(Trig.degreesToRadians(-64.5841), Trig.degreesToRadians(-21.9736), 0),
        new Cartographic(Trig.degreesToRadians(-77.9884), Trig.degreesToRadians(-9.44543), 0),
};

// With the boundary nodes specified and the reference surface chosen,
// we now decide on the granularity of the interconnecting curves.
double granularity = Trig.degreesToRadians(0.5);
SpecifiedNodesEllipsoidSurfaceRegionBuilder builder =
        new SpecifiedNodesEllipsoidSurfaceRegionBuilder(referenceSurface, granularity, Arrays.asList(nodes));
// The default connection type is geodesic, but rhumb lines could be used instead if desired.
builder.setConnectionType(EllipsoidSurfaceRegionCurveConnectionType.GEODESIC);

// The region is ready to be built!
EllipsoidSurfaceRegion region = builder.getEllipsoidSurfaceRegion();

SpecifiedExtentEllipsoidSurfaceRegionBuilder takes an input CartographicExtent and produces a surface region. This builder is best suited for situations where an approximate boundary for your region is desired, or a quick estimate based upon input north/south and east/west bounds will suffice for your analysis. This builder has a configurable granularity for the output region, as this region discretizes the border to create the final boundary as a series of connected rhumb lines.

Java
// First we choose our reference surface, which will be the ellipsoid that defines Earth's surface.
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
Ellipsoid referenceSurface = earth.getShape();

// Here we specify a simple boundary for our extent
CartographicExtent extent = new CartographicExtent(Trig.degreesToRadians(-70), // west
                                                   Trig.degreesToRadians(20), // south
                                                   Trig.degreesToRadians(-60), // east
                                                   Trig.degreesToRadians(40)); // north

// With the extent specified and the reference surface chosen, we can decide on the granularity of the
// boundary curve that is created based upon the extent. In this case we choose the default granularity.
EllipsoidSurfaceRegionBuilder builder = new SpecifiedExtentEllipsoidSurfaceRegionBuilder(referenceSurface, extent);

// The region is ready to be built!
EllipsoidSurfaceRegion region = builder.getEllipsoidSurfaceRegion();

SpecifiedCurveEllipsoidSurfaceRegionBuilder creates a surface region based upon an input EllipsoidSurfaceCurve. The boundary will be discretized based upon the input granularity settings for the purpose of computing the centroid and the planar mapping (see below for more information about the mapping and centroid).

Java
// First we choose our reference surface, which will be the ellipsoid that defines Earth's surface.
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
Ellipsoid referenceSurface = earth.getShape();

// We specify the boundary curve.
EllipsoidGeodesic first = new EllipsoidGeodesic(referenceSurface, one, two);
EllipsoidGeodesic second = new EllipsoidGeodesic(referenceSurface, two, three);
EllipsoidGeodesic third = new EllipsoidGeodesic(referenceSurface, three, one);
EllipsoidComplexSurfaceCurve boundary = EllipsoidComplexSurfaceCurve.createCurve(first, second, third);

// With the boundary curve specified and the reference surface chosen, we can decide on the granularity of the
// boundary curve. In this case we choose the default granularity.
EllipsoidSurfaceRegionBuilder builder = new SpecifiedCurveEllipsoidSurfaceRegionBuilder(referenceSurface, boundary);

// The region is ready to be built!
EllipsoidSurfaceRegion region = builder.getEllipsoidSurfaceRegion();

Finally, ConvexBoundaryEllipsoidSurfaceRegionBuilder creates a surface region by taking the input unorganized points and projecting them on to the tangent plane defined by the centroid of the input points. It then computes the 2D convex hull on this projection and extracts the final set of boundary vertices from this construction. An example of using this builder would be to create a region that bounds a set of input water well locations.

Java
// First we choose our ellipsoid, which will be the ellipsoid that defines Earth's surface.
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
Ellipsoid referenceSurface = earth.getShape();

// We specify the boundary in terms of unorganized points.
// Note that these are the same points used in the specified nodes builder example.
Cartographic[] nodes = {
        new Cartographic(Trig.degreesToRadians(-72.9947), Trig.degreesToRadians(11.3181), 0),
        new Cartographic(Trig.degreesToRadians(-35.4977), Trig.degreesToRadians(-6.29148), 0),
        new Cartographic(Trig.degreesToRadians(-48.902), Trig.degreesToRadians(-13.6507), 0),
        new Cartographic(Trig.degreesToRadians(-63.9708), Trig.degreesToRadians(-0.859671), 0),
        new Cartographic(Trig.degreesToRadians(-64.5841), Trig.degreesToRadians(-21.9736), 0),
        new Cartographic(Trig.degreesToRadians(-77.9884), Trig.degreesToRadians(-9.44543), 0),
};

EllipsoidSurfaceRegionBuilder builder = 
        new ConvexBoundaryEllipsoidSurfaceRegionBuilder(referenceSurface, Arrays.asList(nodes));

// The region is ready to be built!
EllipsoidSurfaceRegion region = builder.getEllipsoidSurfaceRegion();

Each of these surface region builders allow for the definition of one or more holes. Each hole defines a region with inverted membership relative to the containing region. An example of using ellipsoid surface region holes would be to define a region that bounds the state of Minnesota, then to define a hole for each lake contained within. You could then check whether a sensor volume contains the land of Minnesota, excluding all water.

Suppose we instead wish to check whether the sensor volume contains a specific lake, such as Lake Mille Lacs. A hole defining this lake can be converted to a surface region by calling getEllipsoidSurfaceRegion on the hole to produce a region with the same boundary. Conversion between holes and regions is bidirectional, and getEllipsoidSurfaceRegionHole can be called on a region to convert it to a hole.

When creating holes, be mindful that they are not checked for validity, and it is possible to define holes that overlap or extend beyond the borders of the containing surface region.

In addition to dealing with negative spaces (holes), EllipsoidSurfaceRegions are also designed to handle large areas. For regions built with SpecifiedCurveEllipsoidSurfaceRegionBuilder, SpecifiedNodesEllipsoidSurfaceRegionBuilder, or ConvexBoundaryEllipsoidSurfaceRegionBuilder, you have the option to configure a reference point on the ellipsoid, and indicate if that point should be considered to be inside or outside of the region. This allows creating regions that cover more than half of the ellipsoid.

Working With Surface Regions

As we discussed in the introductory text, surface regions have a wide variety of uses in STK Components. Let's explore some uses beginning with simple point membership. Using isPointInsideRegion, we can check if any point (ignoring height) is within the region. This method will return false for points that are within one of the region's holes. You can also ignore holes by calling isPointInsideRegionIgnoringHoles.

We can obtain a rough boundary for our surface region by using computeCartographicExtent. This method returns the north/south east/west bounds. Similarly, Centroid (get), BoundaryCurve (get), and ReferenceSurface (get) are available properties of EllipsoidSurfaceRegion. BoundaryCurve (get) can be used to compute the total boundary perimeter, Centroid (get) is the location of the point used to form a planar mapping of the surface region in the projected space, and ReferenceSurface (get) indicates which ellipsoid the region is defined on.

Using a surface region with an access constraint, or as a grid in the coverage system, is very straightforward. An EllipsoidSurfaceRegion can be used to create a CentralBodySurfaceRegion, which can then be used to create any of the following built-in constraints:

Constraint

Description

CentralBodySurfaceRegionConstraint

An access constraint that requires that an object be within a surface region.

CentralBodySurfaceRegionElevationAngleConstraint

An access constraint that requires that an object be between a span of elevation angles from any or all points within a surface region.

CentralBodySurfaceRegionSensorVolumeConstraint

An access constraint that requires that part of the input surface region lies within the sensor surface footprint.

The process for using a surface region as a coverage or volumetric (three-dimensional) grid is similar. Create the region (or regions) using one of the builders, decide on your grid's resolution, and then use SurfaceRegionsCoverageGrid. This grid can be extruded to make a three-dimensional grid relative to the surface region by passing the two-dimensional grid to ExtrudedCentralBodyCoverageGrid. The following example demonstrates this process:

Java
// Use the surface region to define the coverage grid. Note that this type of coverage grid
// can take multiple ellipsoid surface regions for use in a single coverage calculation.
SurfaceRegionsCoverageGrid surfaceCoverageGrid = 
        new SurfaceRegionsCoverageGrid(Trig.degreesToRadians(1.0), earth, region);

// Create the coverage definition using the grid. We will use the default coverage grid platform.
ParameterizedSpatiallyPartitionedCoverageDefinition coverage = 
        new ParameterizedSpatiallyPartitionedCoverageDefinition(surfaceCoverageGrid, true);

// Create a line-of-sight constraint between a spacecraft and the grid point.
LinkInstantaneous link = new LinkInstantaneous(spacecraft, coverage.getGridPointPlaceholder());
CentralBodyObstructionConstraint lineOfSight = new CentralBodyObstructionConstraint(link, earth);
coverage.addAsset(new AssetDefinition(spacecraft, lineOfSight, true));

// Compute the results!
agi.foundation.coverage.CoverageResults results = coverage.computeCoverageOverTheGrid(start, stop);

// Let's do the same thing, only in 3D.
SpecifiedNumberOfPointsCoverageGriddingTechnique heightGriddingTechnique = 
        new SpecifiedNumberOfPointsCoverageGriddingTechnique(10);
CentralBodyCoverageGrid grid3D = 
        new ExtrudedCentralBodyCoverageGrid(surfaceCoverageGrid, new Bounds(0.0, 1000.0), heightGriddingTechnique);
coverage.setGrid(grid3D);

// Compute the 3D results!
CoverageResults results3D = coverage.computeCoverageOverTheGrid(start, stop);