Skip to content

Commit

Permalink
Merge pull request NRCan#9 from Canadian-Wildlife-Federation/multiaoi…
Browse files Browse the repository at this point in the history
…boundary

fix for cases when aoi intersects with catchment and has multiple ter…
  • Loading branch information
egouge authored Aug 31, 2021
2 parents 6bcdaab + 01c807b commit 74daf34
Show file tree
Hide file tree
Showing 2 changed files with 303 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,18 @@ public static void doWork(IFlowpathDataSource dataSource, ChyfProperties propert

logger.info("POINT GENERATOR: " + cnt);
cnt++;


// if (toProcess.getAttribute(idAttribute).toString().equalsIgnoreCase("04445a93-e7b7-44ea-8ff2-cbe9814134bc")) {
// System.out.println("break");
// }else {
// System.out.println(toProcess.getAttribute(idAttribute).toString());
// continue;
// }

ftouch.clear();
ptouch.clear();


Polygon workingPolygon = ChyfDataSource.getPolygon(toProcess);
if (!workingPolygon.isValid()) throw new Exception("Polygon not a valid geometry. Centroid: " + workingPolygon.getCentroid().toText());

Expand Down Expand Up @@ -163,7 +171,9 @@ public static void doWork(IFlowpathDataSource dataSource, ChyfProperties propert
//write point layers
dataSource.createConstructionsPoints(generator.getPoints());
}
private static List<BoundaryEdge> getBoundary(IFlowpathDataSource dataSource, ChyfProperties properties) throws Exception{


public static List<BoundaryEdge> getBoundary(IFlowpathDataSource dataSource, ChyfProperties properties) throws Exception{

logger.info("computing boundary points");

Expand Down Expand Up @@ -312,25 +322,25 @@ private static List<BoundaryEdge> getBoundary(IFlowpathDataSource dataSource, Ch
if (x instanceof LineString) {
//find the nearest point within 0.004 units
LineString ls = (LineString)x;
Point found = null;

List<Point> found = new ArrayList<>();
for (Coordinate c : ls.getCoordinates()) {
for (Point p : inoutpoints) {
if (c.equals2D(p.getCoordinate())) {
found = p;
break;
found.add(p);
}
}
if (found != null) break;
}

FlowDirection d = FlowDirection.UNKNOWN;
if (found != null) {
if (found.getUserData() != null) {
d = (FlowDirection) found.getUserData();
if (!found.isEmpty()) {
for (Point f : found) {
if (f.getUserData() != null) {
d = (FlowDirection) f.getUserData();
}
BoundaryEdge be = new BoundaryEdge(d, (LineString)x, f);
edges.add(be);
}
BoundaryEdge be = new BoundaryEdge(d, (LineString)x, found);
edges.add(be);
}else {
BoundaryEdge be = new BoundaryEdge(d, (LineString)x, null);
edges.add(be);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*
* Copyright 2021 Canadian Wildlife Federation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.refractions.chyf.flowpathconstructor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureReader;
import org.geotools.data.Transaction;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.junit.Assert;
import org.junit.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.WKTReader;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.identity.FeatureId;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import net.refractions.chyf.datasource.ChyfAttribute;
import net.refractions.chyf.datasource.ILayer;
import net.refractions.chyf.datasource.RankType;
import net.refractions.chyf.flowpathconstructor.ChyfProperties.Property;
import net.refractions.chyf.flowpathconstructor.datasource.IFlowpathDataSource;
import net.refractions.chyf.flowpathconstructor.skeletonizer.points.BoundaryEdge;
import net.refractions.chyf.flowpathconstructor.skeletonizer.points.ConstructionPoint;
import net.refractions.chyf.flowpathconstructor.skeletonizer.points.PointEngine;
import net.refractions.chyf.flowpathconstructor.skeletonizer.voronoi.SkelLineString;


/**
* Test cases for PointEngine
* @author Emily
*
*/
public class PointEngineTest {

private ChyfProperties getChyfProperties() {
ChyfProperties prop = new ChyfProperties();
prop.setProperty(Property.PNT_VERTEX_DISTANCE, 0.0001);
return prop;
}

/**
* Test the basic case where waterbody touches aoi on line
* @throws Exception
*/
@Test
public void testGetBoundarySingle() throws Exception{
SingleDataSource ds = new SingleDataSource();

List<BoundaryEdge> edges = PointEngine.getBoundary(ds, getChyfProperties());
Assert.assertEquals("invalid number of boundary edges", 1, edges.size());

for (Point pnt : ds.getTerminalNodes()) {
boolean found = false;
for (BoundaryEdge be : edges) {
if (be.getInOut().getCoordinate().equals2D(pnt.getCoordinate())) {
found = true;
break;
}
}
if (!found) {
Assert.fail("no boundary edge found for found: " + pnt.toText());
}
}
}


/**
* Test the case where we need multiple outputs along a waterbody that touches the aoi
* boundary. This could be because of multiple single line outputs in the corresponding
* aoi.
*
* @throws Exception
*/
@Test
public void testGetBoundaryMulti() throws Exception{
MultiDataSource ds = new MultiDataSource();

List<BoundaryEdge> edges = PointEngine.getBoundary(ds, getChyfProperties());
Assert.assertEquals("invalid number of boundary edges", 3, edges.size());

for (Point pnt : ds.getTerminalNodes()) {
boolean found = false;
for (BoundaryEdge be : edges) {
if (be.getInOut().getCoordinate().equals2D(pnt.getCoordinate())) {
found = true;
break;
}
}
if (!found) {
Assert.fail("no boundary edge found for found: " + pnt.toText());
}
}

}


private class MultiDataSource implements IFlowpathDataSource{

@Override
public FeatureReader<SimpleFeatureType, SimpleFeature> query(ILayer layer) throws IOException {
return null;
}

@Override
public FeatureReader<SimpleFeatureType, SimpleFeature> query(ILayer layer, ReferencedEnvelope bounds)
throws IOException {
return null;
}

@Override
public FeatureReader<SimpleFeatureType, SimpleFeature> query(ILayer layer, Filter filter) throws IOException {
return null;
}

@Override
public FeatureReader<SimpleFeatureType, SimpleFeature> query(ILayer layer, ReferencedEnvelope bounds,
Filter filter) throws IOException {
return null;
}

@Override
public FeatureReader<SimpleFeatureType, SimpleFeature> getWaterbodies() throws IOException {

String text = "POLYGON (( 724 565, 676 653, 492 686, 338 622, 331 610, 326 595, 323 578, 321 563, 331 468, 458 394, 712 381, 724 565 ))";
Polygon wb = null;
try {
WKTReader reader = new WKTReader();
wb = (Polygon)reader.read(text);
}catch (Exception ex) {
throw new IOException(ex);
}

SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.add(ChyfAttribute.INTERNAL_ID.getFieldName(),String.class);
builder.add("geometry", Polygon.class);
builder.setName("SimpleTest");
SimpleFeatureType type = builder.buildFeatureType();

SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(type);
fbuilder.set(ChyfAttribute.INTERNAL_ID.getFieldName(), "1");
fbuilder.set("geometry", wb);

SimpleFeature sf = fbuilder.buildFeature("1");

return DataUtilities.reader(Collections.singletonList(sf));
}

@Override
public SimpleFeatureType getFeatureType(ILayer layer) throws IOException {
return null;
}

@Override
public void logError(String message, Geometry location) throws IOException {
System.out.println(message);
}

@Override
public void logWarning(String message, Geometry location) throws IOException {
System.out.println(message);
}

@Override
public void close() throws Exception {
}

@Override
public CoordinateReferenceSystem getCoordinateReferenceSystem() {
return null;
}

@Override
public List<Polygon> getAoi() throws IOException {
WKTReader reader = new WKTReader();
try {
Polygon p = (Polygon)reader.read("POLYGON (( 724 565, 676 653, 492 686, 338 622, 331 610, 326 595, 323 578, 321 563, 331 468, 458 394, 712 381, 724 565 ))");
return Collections.singletonList(p);
}catch (Exception ex) {
throw new IOException(ex);
}
}

@Override
public List<Point> getTerminalNodes() throws Exception {
WKTReader reader = new WKTReader();
try {
List<Point> points = new ArrayList<>();
Point p = (Point)reader.read("POINT ( 331 610 )");
points.add(p);
p = (Point)reader.read("POINT ( 326 595 )");
points.add(p);
p = (Point)reader.read("POINT ( 323 578 )");
points.add(p);
return points;
}catch (Exception ex) {
throw new IOException(ex);
}
}


@Override
public void updateWaterbodyGeometries(Collection<Polygon> polygons) throws IOException { }

@Override
public void updateCoastline(FeatureId fid, LineString newls, Transaction tx) throws IOException { }

@Override
public void createConstructionsPoints(List<ConstructionPoint> points) throws IOException { }

@Override
public void writeSkeletons(Collection<SkelLineString> skeletons) throws IOException { }

@Override
public void removeExistingSkeletons(boolean bankOnly) throws IOException { }

@Override
public void addRankAttribute() throws Exception { }

@Override
public void flipFlowEdges(Collection<FeatureId> pathstoflip, Collection<FeatureId> processed) throws Exception { }

@Override
public void writeRanks(Map<FeatureId, RankType> ranks) throws Exception { }

@Override
public List<ConstructionPoint> getConstructionsPoints(Object catchmentId) throws IOException {
return null;
}

@Override
public Set<Coordinate> getOutputConstructionPoints() throws Exception {
return null;
}
}

private class SingleDataSource extends MultiDataSource {


@Override
public List<Point> getTerminalNodes() throws Exception {
WKTReader reader = new WKTReader();
try {
List<Point> points = new ArrayList<>();
Point p = (Point)reader.read("POINT ( 331 610 )");
points.add(p);
return points;
}catch (Exception ex) {
throw new IOException(ex);
}
}
}
}

0 comments on commit 74daf34

Please sign in to comment.