Added by jgarnett, last edited by Graham Davis on Sep 05, 2007  (view change)

Labels

 
(None)

The following sections explain how to manipulate Surfaces:

Creating a Surface

As with the other geometries, Surfaces are built up from a series of other geometry pieces. Surfaces can be created directly from the GeometryBuilder, or if you only want to use GeoAPI interfaces you can also use factories:

Using GeometryBuilder

Surfaces can be built from a list of SurfacePatches or from a SurfaceBoundary. The following example shows how to create a Surface from a SurfaceBoundary using the GeometryBuilder.

GeometryBuilder builder = new GeometryBuilder( DefaultGeographicCRS.WGS84 );   	
    	
// create a list of connected positions
List<Position> dps = new ArrayList<Position>();
dps.add(builder.createDirectPosition( new double[] {20, 10} ));
dps.add(builder.createDirectPosition( new double[] {40, 10} ));
dps.add(builder.createDirectPosition( new double[] {50, 40} ));
dps.add(builder.createDirectPosition( new double[] {30, 50} ));
dps.add(builder.createDirectPosition( new double[] {10, 30} ));
dps.add(builder.createDirectPosition( new double[] {20, 10} ));

// create linestring from directpositions
LineString line = builder.createLineString(dps);

// create curvesegments from line
ArrayList<CurveSegment> segs = new ArrayList<CurveSegment>();
segs.add(line);

// Create list of OrientableCurves that make up the surface
OrientableCurve curve = builder.createCurve(segs);
List<OrientableCurve> orientableCurves = new ArrayList<OrientableCurve>();
orientableCurves.add(curve);

// create the interior ring and a list of empty interior rings (holes)
Ring extRing = builder.createRing(orientableCurves);
List<Ring> intRings = new ArrayList<Ring>();

// create the surfaceboundary from the rings
SurfaceBoundary sb = builder.createSurfaceBoundary(extRing, intRings);
    			
// create the surface
Surface surface = builder.createSurface(sb);

Using Factories

Building a surface from factories is very similar to the process of using the GeometryBuilder, but it lets you only use GeoAPI interfaces:

// create a list of connected positions
List<Position> dps = new ArrayList<Position>();
dps.add(posF.createDirectPosition( new double[] {20, 10} ));
dps.add(posF.createDirectPosition( new double[] {40, 10} ));
dps.add(posF.createDirectPosition( new double[] {50, 40} ));
dps.add(posF.createDirectPosition( new double[] {30, 50} ));
dps.add(posF.createDirectPosition( new double[] {10, 30} ));
dps.add(posF.createDirectPosition( new double[] {20, 10} ));

// create linestring from directpositions
LineString line = geomF.createLineString(dps);

// create curvesegments from line
ArrayList<CurveSegment> segs = new ArrayList<CurveSegment>();
segs.add(line);

// Create list of OrientableCurves that make up the surface
OrientableCurve curve = primF.createCurve(segs);
List<OrientableCurve> orientableCurves = new ArrayList<OrientableCurve>();
orientableCurves.add(curve);

// create the interior ring and a list of empty interior rings (holes)
Ring extRing = primF.createRing(orientableCurves);
List<Ring> intRings = new ArrayList<Ring>();

// create the surfaceboundary from the rings
SurfaceBoundary sb = primF.createSurfaceBoundary(extRing, intRings);
		
// create the surface
Surface surface = primF.createSurface(sb);

Dissecting a Surface

The list of points that build up a Surface are not a good representation of that geometry. Surfaces can have holes in them, and a simple list of points will not tell you if they belong to a hole or to the exterior of the shape. However, you can obtain the Rings for the exterior and interior (holes) of the Surface. If desired, you can also get the points that make those Rings:

SurfaceBoundary sb = (SurfaceBoundary) surface2.getBoundary();
Ring exterior = sb.getExterior();
List<Ring> interiors = sb.getInteriors();
Collection<? extends Primitive> extCurve = exterior.getElements();
Iterator<? extends Primitive> iter = extCurve.iterator();
PointArray samplePoints = null;
while (iter.hasNext()) {
	Curve curve = (Curve) iter.next();
	List<CurveSegment> segs = curve.getSegments();
	Iterator<CurveSegment> curveIter = segs.iterator();
	while (curveIter.hasNext()) {
		if (samplePoints == null) {
			samplePoints = curveIter.next().getSamplePoints();
		}
		else {
			samplePoints.addAll(curveIter.next().getSamplePoints());
		}
	}
}

Rendering the outline of a Polygon

The following are two quick examples of how you can render a Surface (Polygon):

Using Java For/Each Loops

Here is a quick example of rendering a Polygon using Java for/each syntax:

final int X = 0; // easting axis for surface.getCoordinateReferenceSystem()
final int Y = 1; // westing axis for surface.getCoordinateReferenceSystem()
for( SurfacePatch patch : surface.getPatches()){
    SurfaceBoundary boundary = patch.getBoundary();
    Ring ring = boundary.getExterior();
    for( Primitive primitive : ring.getElements() ){
        if( primitive instanceof Curve ){
            Curve curve = (Curve) primitive;
            for( CurveSegment segment : curve.getSegments() ){
                if( segment instanceof LineString){
                    LineString lines = (LineString) segment;
                    for( LineSegment line : lines.asLineSegments() ){
                        DirectPosition point1 = line.getStartPoint();
                        DirectPosition point2 = line.getEndPoint();
                        g.drawLine( point1.getOrdinate(X), point1.getOrdinate(Y),
                                    point2.getOrdinate(X), point2.getOrdinate(Y) );
                    }
                }
                else if (segment instanceof LineSegment){
                    LineSegment line = (LineSegment) segment;
                    DirectPosition point1 = line.getStartPoint();
                    DirectPosition point2 = line.getEndPoint();
                    g.drawLine( point1.getOrdinate(X), point1.getOrdinate(Y),
                                point2.getOrdinate(X), point2.getOrdinate(Y) );
                }
            }
        }
    }               
}

Please note:

  • Review your CoordianteReferenceSystem to figure out which axis is to use for X and Y
  • Surface is a deep data structure, better suited to recursion or a visitor

Using Recursive Code

You can produce less code duplication using recursion to navigate through your Surface:

protected void paint( Graphics2D g, Surface surface  ) {
    for( SurfacePatch patch : surface.getPatches()){
        SurfaceBoundary boundary = patch.getBoundary();
        Ring ring = boundary.getExterior();
        paint( g, ring );
    }            
}
protected void paint( Graphics2D g, Ring ring ) {
    for( Primitive primitive : ring.getElements() ){
        if( primitive instanceof Curve ){
            Curve curve = (Curve) primitive;
            paint( g, curve );                
        }
    }
}
protected void paint(Graphics2D g, Curve curve ) {
    for( CurveSegment segment : curve.getSegments() ){
        if( segment instanceof LineString){
            LineString lines = (LineString) segment;
            for( LineSegment line : lines.asLineSegments() ){
                paint( g, line );
            }
        }
        else if (segment instanceof LineSegment){
            LineSegment line = (LineSegment) segment;
            paint( g, line );
        }
    }
}
protected void paint(Graphics2D g, LineSegment line) {
    DirectPosition point1 = line.getStartPoint();
    DirectPosition point2 = line.getEndPoint();
    g.drawLine( point1.getOrdinate(X), point1.getOrdinate(Y),
                point2.getOrdinate(X), point2.getOrdinate(Y) ); 
}