All Downloads are FREE. Search and download functionalities are using the official Maven repository.

grails.mongodb.geo.Polygon.groovy Maven / Gradle / Ivy

/* Copyright (C) 2014 SpringSource
 *
 * 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 grails.mongodb.geo

import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import org.springframework.util.Assert

/**
 * Represents a GeoJSON polygon for use in Geo data models.
 * See http://geojson.org/geojson-spec.html#polygon
 */
@CompileStatic
@EqualsAndHashCode
class Polygon extends Shape implements GeoJSON{

    /**
     * The {@link Point} instances that constitute the Polygon
     */
    final List> points

    /**
     * Constructs a Polygon for the given {@link Point} instances
     *
     * @param x The x {@link Point}
     * @param y The y {@link Point}
     * @param z The z {@link Point}
     * @param others The remaining {@link Point} instances
     */
    Polygon(Point x, Point y, Point z, Point...others) {
        Assert.notNull(x, "Point x is required")
        Assert.notNull(y, "Point y is required")
        Assert.notNull(z, "Point z is required")
        Assert.notNull(others, "Point others is required")

        def list = []
        list.addAll Arrays.asList(x, y, z)
        list.addAll others
        this.points = [list]
    }

    private Polygon(List> points){
        this.points = points
    }

    /**
     * Converts the Polygon to a multi-dimensional list of coordinates.
     * Example: [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
     *
     * @return The list
     */
    public List>> asList() {
         points.collect() { List ring ->
            ring.collect { Point p -> 
                p.asList()
            }
        }
    }

    @Override
    String toString() {
        points.toString()
    }
/**
     * The inverse of {@link Polygon#asList()}, constructs a Polygon from a coordinate list
     *
     * @param coords The coordinate list
     * @return A Polygon
     */
    static Polygon valueOf(List coords) {
        Assert.notNull(coords, "Argument coords cannot be null")

        

        /*
         * Search for list type - it could be 
         * (1) List  - a single ring polygon
         * (2) List> - a single ring with list as long/lat/alt
         * (3) List - a multi-ring polygon
         * (4) List - a multi-ring polygon with list as long/lat/alt
         */
         try 
         {
            if(coords[0] instanceof Point){
                return new Polygon( [fromSingleCoordsList(coords)] ) // case (1) above
             }
             else if(coords[0] instanceof List )
             {
                if( ((List)coords[0])[0] instanceof Number) {
                    return new Polygon( [fromSingleCoordsList(coords)] ) // case (2) above
                }
                else if( ((List)coords[0])[0] instanceof Point){
                    return new Polygon( coords.collect { poly_ring ->
                        // each is a List
                        return fromSingleCoordsList((List)poly_ring)
                    }) // case (3) above
                }
                else if( ((List)coords[0])[0] instanceof List && ((List)((List)coords[0])[0])[0] instanceof Number ){
                    return new Polygon( coords.collect { poly_ring ->
                        // each is a List
                        return fromSingleCoordsList((List>)poly_ring)
                    } ) // case (4) above
                }
                else {
                    throw new IllegalArgumentException("Coordinate list must be Points or number-lists")
                }
             }
             else {
                throw new IllegalArgumentException("Coordinate list must be Points or number-lists")
             }
         }
         catch(IndexOutOfBoundsException ioobe){
            throw new IllegalArgumentException("Coordinate lists cannot be empty")
         }
         
    }

    /**
     *  A single ring.  This could be a list of Point objects or a List points as number lists.
     *   E.g. List or List> 
     */
    private static List fromSingleCoordsList(List coords) {
        Assert.notNull(coords, "Argument coords cannot be null")

        if(coords.size() < 4) throw new IllegalArgumentException("Coordinates should contain at least 4 entries for a Polygon")

        return coords.collect {
            if(it instanceof Point) {
                return (Point)it
            }
            else if(it instanceof List) {
                return Point.valueOf((List)it)
            }
            else {
                throw new IllegalArgumentException("Invalid coordinates: $coords")
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy