Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update ProductType vocab with current DataLink terms #177

Merged
merged 8 commits into from
May 3, 2024
Merged
2 changes: 1 addition & 1 deletion caom2-compute/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ sourceCompatibility = 1.8

group = 'org.opencadc'

version = '2.4.10'
version = '2.4.11'

description = 'OpenCADC CAOM compute library'
def git_url = 'https://github.com/opencadc/caom2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import ca.nrc.cadc.caom2.types.Point;
import ca.nrc.cadc.caom2.types.Polygon;
import ca.nrc.cadc.caom2.types.SegmentType;
import ca.nrc.cadc.caom2.types.Shape;
import ca.nrc.cadc.caom2.types.Vertex;
import ca.nrc.cadc.caom2.wcs.CoordAxis2D;
import ca.nrc.cadc.caom2.wcs.CoordBounds2D;
Expand Down Expand Up @@ -126,11 +127,10 @@ public static Position compute(Set<Artifact> artifacts)

Position p = new Position();
if (productType != null) {
Polygon poly = computeBounds(artifacts, productType);
p.bounds = poly;
p.bounds = computeBounds(artifacts, productType);
p.dimension = computeDimensionsFromRange(artifacts, productType);
if (p.dimension == null) {
p.dimension = computeDimensionsFromWCS(poly, artifacts, productType);
p.dimension = computeDimensionsFromWCS(p.bounds, artifacts, productType);
}
p.resolution = computeResolution(artifacts, productType);
p.sampleSize = computeSampleSize(artifacts, productType);
Expand All @@ -140,6 +140,48 @@ public static Position compute(Set<Artifact> artifacts)
return p;
}

public static Shape generateShape(Set<Artifact> artifacts, ProductType productType)
throws NoSuchKeywordException {
int num = 0;
Chunk chunk = null;
for (Artifact a : artifacts) {
log.debug("generatePolygons: " + a.getURI());
for (Part p : a.getParts()) {
log.debug("generatePolygons: " + a.getURI() + " " + p.getName());
for (Chunk c : p.getChunks()) {
log.debug("generatePolygons: " + a.getURI() + " " + p.getName() + " " + c.getID());
if (Util.useChunk(a.getProductType(), p.productType, c.productType, productType)) {
log.debug("generatePolygons: " + a.getURI() + " "
+ a.getProductType() + " " + p.productType + " " + c.productType);
if (c.position != null) {
num++;
chunk = c;
}
} else {
log.debug("generatePolygons SKIP: " + a.getURI() + " "
+ a.getProductType() + " " + p.productType + " " + c.productType);
}
}
}
}
if (chunk == null) {
// no spatial
return null;
}
if (num > 1) {
// multiple, assume mosaic w/ polygons
return null;
}
if (chunk.position.getAxis().bounds != null) {
if (chunk.position.getAxis().bounds instanceof CoordCircle2D) {
CoordCircle2D cc = (CoordCircle2D) chunk.position.getAxis().bounds;
return new Circle(new Point(cc.getCenter().coord1, cc.getCenter().coord2), cc.getRadius());
}
// handle CoordPolygon2D in generatePolygons
}
return null;
}

public static List<MultiPolygon> generatePolygons(Set<Artifact> artifacts, ProductType productType)
throws NoSuchKeywordException {
List<MultiPolygon> polys = new ArrayList<MultiPolygon>();
Expand Down Expand Up @@ -178,31 +220,35 @@ public static List<MultiPolygon> generatePolygons(Set<Artifact> artifacts, Produ
}

// TODO: change return type to Shape; if we find CoordCircle2D in the SpatialWCS we should return a Circle
public static Polygon computeBounds(Set<Artifact> artifacts, ProductType productType)
public static Shape computeBounds(Set<Artifact> artifacts, ProductType productType)
throws NoSuchKeywordException {
// since we compute the union, just blindly use all the polygons
// derived from spatial wcs
List<MultiPolygon> polys = generatePolygons(artifacts, productType);
if (polys.isEmpty()) {
return null;
Shape ret = generateShape(artifacts, productType);
if (ret == null) {
// since we compute the union, just blindly use all the polygons
// derived from spatial wcs
List<MultiPolygon> polys = generatePolygons(artifacts, productType);
if (polys.isEmpty()) {
return null;
}
log.debug("[computeBounds] components: " + polys.size());
MultiPolygon mp = MultiPolygon.compose(polys);
ret = PolygonUtil.getOuterHull(mp);
}
log.debug("[computeBounds] components: " + polys.size());
MultiPolygon mp = MultiPolygon.compose(polys);
Polygon poly = PolygonUtil.getOuterHull(mp);
log.debug("[computeBounds] done: " + poly);
return poly;
log.debug("[computeBounds] done: " + ret);
return ret;
}

// this works for mosaic camera data: multiple parts with ~single scale wcs functions
static Dimension2D computeDimensionsFromWCS(Polygon poly, Set<Artifact> artifacts, ProductType productType)
static Dimension2D computeDimensionsFromWCS(Shape bounds, Set<Artifact> artifacts, ProductType productType)
throws NoSuchKeywordException {
log.debug("[computeDimensionsFromWCS] " + poly + " " + artifacts.size());
if (poly == null) {
log.debug("[computeDimensionsFromWCS] " + bounds + " " + artifacts.size());
if (bounds == null) {
return null;
}

// pick the WCS with the largest pixel size
SpatialWCS sw = null;
boolean foundCoordBounds = false;
double scale = 0.0;
int num = 0;
for (Artifact a : artifacts) {
Expand All @@ -216,6 +262,7 @@ static Dimension2D computeDimensionsFromWCS(Polygon poly, Set<Artifact> artifact
scale = ss;
sw = c.position;
}
foundCoordBounds = foundCoordBounds || c.position.getAxis().bounds != null;
}
}
}
Expand All @@ -225,12 +272,27 @@ static Dimension2D computeDimensionsFromWCS(Polygon poly, Set<Artifact> artifact
return null;
}

if (num == 1) { // single WCS solution
if (num == 1) { // single WCS solution, ASSUME CoordBounds2D mask is whole frame
// deep copy
long ix = sw.getAxis().function.getDimension().naxis1;
long iy = sw.getAxis().function.getDimension().naxis2;
return new Dimension2D(ix, iy);
}

List<Point> points = null;
if (bounds instanceof Polygon) {
Polygon poly = (Polygon) bounds;
points = poly.getPoints();
} else if (bounds instanceof Circle) {
Circle circ = (Circle) bounds;
MultiPolygon mp = toPolygon(circ);
points = new ArrayList<>();
for (Vertex v : mp.getVertices()) {
if (!SegmentType.CLOSE.equals(v.getType())) {
points.add(new Point(v.cval1, v.cval2));
}
}
}

WCSWrapper map = new WCSWrapper(sw, 1, 2);
Transform transform = new Transform(map);
Expand All @@ -241,7 +303,7 @@ static Dimension2D computeDimensionsFromWCS(Polygon poly, Set<Artifact> artifact
double y2 = -1 * y1;
CoordSys csys = inferCoordSys(sw);
List<long[]> pixv = new ArrayList<long[]>();
for (Point pt : poly.getPoints()) {
for (Point pt : points) {
double[] coords = new double[] {pt.cval1, pt.cval2};
if (csys.swappedAxes) {
double tmp = coords[0];
Expand Down Expand Up @@ -491,12 +553,13 @@ static MultiPolygon toPolygon(SpatialWCS wcs, CoordPolygon2D cp)
static MultiPolygon toPolygon(SpatialWCS wcs, CoordCircle2D cc)
throws NoSuchKeywordException {
Circle circ = new Circle(new Point(cc.getCenter().coord1, cc.getCenter().coord2), cc.getRadius());
return toPolygon(circ);
}

static MultiPolygon toPolygon(Circle circ) {
CartesianTransform trans = CartesianTransform.getTransform(circ);
List<Vertex> skyCoords = new ArrayList<Vertex>();
List<Vertex> skyCoords = new ArrayList<>();

//if (Math.abs(cc.getCenter().coord2) + cc.getRadius() > 80.0) { // near a pole
// throw new UnsupportedOperationException("cannot convert CoordCircle2D -> MultiPolygon near the pole (" + cc + ")");
//}
Point tcen = trans.transform(circ.getCenter());
double x = tcen.cval1;
double y = tcen.cval2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@
import ca.nrc.cadc.caom2.Plane;
import ca.nrc.cadc.caom2.ProductType;
import ca.nrc.cadc.caom2.ReleaseType;
import ca.nrc.cadc.caom2.types.Circle;
import ca.nrc.cadc.caom2.types.IllegalPolygonException;
import ca.nrc.cadc.caom2.types.MultiPolygon;
import ca.nrc.cadc.caom2.types.Point;
import ca.nrc.cadc.caom2.types.Polygon;
import ca.nrc.cadc.caom2.types.SegmentType;
import ca.nrc.cadc.caom2.types.Shape;
import ca.nrc.cadc.caom2.types.Vertex;
import ca.nrc.cadc.caom2.wcs.Axis;
import ca.nrc.cadc.caom2.wcs.Coord2D;
Expand Down Expand Up @@ -517,31 +519,31 @@ public void testComputeBounds() {

// coordinate range
plane = getTestSetRange(1, 2);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(2.0, poly.getArea(), 0.05);
Assert.assertEquals(21.0, poly.getCenter().cval1, 0.02);
Assert.assertEquals(10.5, poly.getCenter().cval2, 0.02);

plane = getTestSetRange(1, 2);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(2.0, poly.getArea(), 0.05);
Assert.assertEquals(21.0, poly.getCenter().cval1, 0.02);
Assert.assertEquals(10.5, poly.getCenter().cval2, 0.02);

plane = getTestSetRange(1, 3);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(3.0, poly.getArea(), 0.08);
Assert.assertEquals(21.5, poly.getCenter().cval1, 0.02);
Assert.assertEquals(10.5, poly.getCenter().cval2, 0.02);

plane = getTestSetRange(4, 1);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(4.0, poly.getArea(), 0.1);
Expand All @@ -550,15 +552,24 @@ public void testComputeBounds() {

// coordinate function
plane = getTestSetFunction(1, 1);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(1.0, poly.getArea(), 0.05);
Assert.assertEquals(20.5, poly.getCenter().cval1, 0.02);
Assert.assertEquals(10.5, poly.getCenter().cval2, 0.02);

// mask with CoordCircle2D; array is 1000x1000 at 1e-3 aka 1x1 deg
Chunk chunk = plane.getArtifacts().iterator().next().getParts().iterator().next().getChunks().iterator().next();
chunk.position.getAxis().bounds = new CoordCircle2D(new ValueCoord2D(20.5, 10.5), 0.25);
Circle circ = (Circle) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(circ);
Assert.assertEquals(20.5, circ.getCenter().cval1, 0.02);
Assert.assertEquals(10.5, circ.getCenter().cval2, 0.02);
Assert.assertEquals(0.25, circ.getRadius(), 0.02);

plane = getTestSetFunction(1, 2);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
log.debug("[testComputeBounds] getTestSetFunction union: " + poly);
//Assert.assertEquals(5, poly.getVertices().size());
Expand All @@ -567,7 +578,7 @@ public void testComputeBounds() {
Assert.assertEquals(10.5, poly.getCenter().cval2, 0.02);

plane = getTestSetFunction(1, 3);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
log.debug("[testComputeBounds] getTestSetFunction union: " + poly);
//Assert.assertEquals(5, poly.getVertices().size());
Expand All @@ -576,7 +587,7 @@ public void testComputeBounds() {
Assert.assertEquals(10.5, poly.getCenter().cval2, 0.02);

plane = getTestSetFunction(4, 1);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
log.debug("[testComputeBounds] getTestSetFunction union: " + poly);
//Assert.assertEquals(5, poly.getVertices().size());
Expand All @@ -597,17 +608,29 @@ public void testComputeDimension() {
Dimension2D dim;

plane = getTestSetFunction(1, 1);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
dim = PositionUtil.computeDimensionsFromWCS(poly, plane.getArtifacts(), ProductType.SCIENCE);
log.debug("[testComputeDimension] dim=" + dim);
Assert.assertNotNull(dim);
Assert.assertEquals(1000L, dim.naxis1, 1L);
Assert.assertEquals(1000L, dim.naxis2, 1L);

// mask with CoordCircle2D; array is 1000x1000 at 1e-3 aka 1x1 deg
Chunk chunk = plane.getArtifacts().iterator().next().getParts().iterator().next().getChunks().iterator().next();
chunk.position.getAxis().bounds = new CoordCircle2D(new ValueCoord2D(20.5, 10.5), 0.25);
Shape bounds = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(bounds);
dim = PositionUtil.computeDimensionsFromWCS(bounds, plane.getArtifacts(), ProductType.SCIENCE);
log.debug("[testComputeDimension] dim=" + dim);
Assert.assertNotNull(dim);
// TODO: need to use pixel-aligned "cutout" of circle vs array to get the right dimensions
//Assert.assertEquals(500L, dim.naxis1, 1L);
//Assert.assertEquals(500L, dim.naxis2, 1L);

// with GAL <-> ICRS transformations
plane = getTestSetFunction(1, 1, true);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
dim = PositionUtil.computeDimensionsFromWCS(poly, plane.getArtifacts(), ProductType.SCIENCE);
log.debug("[testComputeDimension] dim=" + dim);
Expand All @@ -616,7 +639,7 @@ public void testComputeDimension() {
Assert.assertEquals(1000L, dim.naxis2, 1L);

plane = getTestSetFunction(1, 2);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
dim = PositionUtil.computeDimensionsFromWCS(poly, plane.getArtifacts(), ProductType.SCIENCE);
log.debug("[testComputeDimension] dim=" + dim);
Expand All @@ -625,7 +648,7 @@ public void testComputeDimension() {
Assert.assertEquals(1000L, dim.naxis2, 1L);

plane = getTestSetRange(1, 1);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
dim = PositionUtil.computeDimensionsFromWCS(poly, plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNull(dim);
Expand All @@ -636,7 +659,7 @@ public void testComputeDimension() {
Assert.assertEquals(1000L, dim.naxis2, 1L);

plane = getTestSetRange(1, 3);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
dim = PositionUtil.computeDimensionsFromWCS(poly, plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNull(dim);
Expand All @@ -647,7 +670,7 @@ public void testComputeDimension() {
Assert.assertEquals(1000L, dim.naxis2, 1L);

plane = getTestSetRange(4, 1);
poly = PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNotNull(poly);
dim = PositionUtil.computeDimensionsFromWCS(poly, plane.getArtifacts(), ProductType.SCIENCE);
Assert.assertNull(dim);
Expand Down Expand Up @@ -752,7 +775,7 @@ public void testComputeFromCalibration() {
aux.getParts().addAll(tmpA.getParts());
plane.getArtifacts().add(aux);

poly = PositionUtil.computeBounds(plane.getArtifacts(), Util.choseProductType(plane.getArtifacts()));
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), Util.choseProductType(plane.getArtifacts()));
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(1.0, poly.getArea(), 0.02);
Expand All @@ -779,7 +802,7 @@ public void testComputeFromMixed() {
aux.getParts().addAll(tmpA.getParts());
plane.getArtifacts().add(aux);

poly = PositionUtil.computeBounds(plane.getArtifacts(), Util.choseProductType(plane.getArtifacts()));
poly = (Polygon) PositionUtil.computeBounds(plane.getArtifacts(), Util.choseProductType(plane.getArtifacts()));
Assert.assertNotNull(poly);
Assert.assertEquals(4, poly.getPoints().size());
Assert.assertEquals(1.0, poly.getArea(), 0.02);
Expand Down
Loading
Loading