Package org.geoscript.js.geom

Source Code of org.geoscript.js.geom.Geometry$ConstructiveFunction1

package org.geoscript.js.geom;

import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

import org.geoscript.js.GeoObject;
import org.geoscript.js.proj.Projection;
import org.geotools.geometry.jts.GeometryCoordinateSequenceTransformer;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeJavaMethod;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Wrapper;
import org.mozilla.javascript.annotations.JSFunction;
import org.mozilla.javascript.annotations.JSGetter;
import org.mozilla.javascript.annotations.JSSetter;
import org.mozilla.javascript.annotations.JSStaticFunction;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.operation.buffer.BufferOp;
import com.vividsolutions.jts.operation.buffer.BufferParameters;
import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier;

public class Geometry extends GeoObject implements Wrapper {

    /** serialVersionUID */
    private static final long serialVersionUID = 8771743870215086281L;

    private com.vividsolutions.jts.geom.Geometry geometry;
   
    protected static GeometryFactory factory = new GeometryFactory();
   
    private Projection projection;

    /**
     * Geometry prototype constructor.
     */
    public Geometry() {
    }
   
    com.vividsolutions.jts.geom.Geometry getGeometry() {
        return geometry;
    }
   
    void setGeometry(com.vividsolutions.jts.geom.Geometry geometry) {
        this.geometry = geometry;
    }
   
    @Override
    public Object get(String name, Scriptable start) {
        Object member = null;
        if (geometry != null) {
            member = getNativeMethod(name);
        }
        if (member == null) {
            member = super.get(name, start);
        }
        return member;
    }
   

    /**
     * Convert the provided object into an acceptable geometry config object.
     * @param context
     * @param configObj
     * @return
     */
    protected static NativeObject prepConfig(Context context, Scriptable configObj) {
        Scriptable scope = configObj.getParentScope();
        NativeObject config = null;
        if (configObj instanceof NativeObject) {
            getRequiredMember(configObj, "coordinates", NativeArray.class, "Array");
            config = (NativeObject) configObj;
        } else if (configObj instanceof NativeArray) {
            NativeArray array = (NativeArray) configObj;
            config = (NativeObject) context.newObject(scope);
            config.put("coordinates", config, array);
        } else {
            throw ScriptRuntime.constructError("Error",
                    "Geometry config must be an array or an object with a coordinates member");
        }
        return config;
    }
   
    /**
     * Create a JavaScript method from an underlying JTS Geometry method where
     * possible.
     * @param name Method name
     * @return
     */
    Object getNativeMethod(String name) {
        NativeJavaMethod nativeMethod = null;
        Method method = null;

        List<String> unary = Arrays.asList(
                "isEmpty", "isRectangle", "isSimple", "isValid");

        if (unary.contains(name)) {
            try {
                method = geometry.getClass().getMethod(name);
            } catch (Exception e) {
                throw new RuntimeException("Unable to find method: " + name, e);
            }
            return new NativeJavaMethod(method, name);
        }
       
        List<String> binary = Arrays.asList(
                "contains", "coveredBy", "covers", "crosses", "disjoint",
                "equals", "equalsExact", "overlaps", "intersects", "touches",
                "within");
       
        if (binary.contains(name)) {
            try {
                method = geometry.getClass().getMethod(name, com.vividsolutions.jts.geom.Geometry.class);
            } catch (Exception e) {
                throw new RuntimeException("Unable to find method: " + name, e);
            }
            try {
                return new BinaryFunction(name, method, getParentScope(), this);
            } catch (Exception e) {
                throw new RuntimeException("Failed to create binary method for " + name, e);
            }
        }
       
        List<String> constructive0 = Arrays.asList(
                "clone", "convexHull", "getBoundary", "getEnvelope");

        if (constructive0.contains(name)) {
            try {
                method = geometry.getClass().getMethod(name);
            } catch (Exception e) {
                throw new RuntimeException("Unable to find method: " + name, e);
            }
            try {
                return new ConstructiveFunction0(name, method, getParentScope(), this);
            } catch (Exception e) {
                throw new RuntimeException("Failed to create constructive method for " + name, e);
            }
        }
       
        List<String> constructive1 = Arrays.asList(
                "difference", "intersection", "symDifference", "union");

        if (constructive1.contains(name)) {
            try {
                method = geometry.getClass().getMethod(name, com.vividsolutions.jts.geom.Geometry.class);
            } catch (Exception e) {
                throw new RuntimeException("Unable to find method: " + name, e);
            }
            try {
                return new ConstructiveFunction1(name, method, getParentScope(), this);
            } catch (Exception e) {
                throw new RuntimeException("Failed to create constructive method for " + name, e);
            }
        }

        return nativeMethod;
    }
   
    @JSGetter
    public Bounds getBounds() {
        Envelope env = geometry.getEnvelopeInternal();
        CoordinateReferenceSystem crs = null;
        if (projection != null) {
            crs = projection.unwrap();
        }
        ReferencedEnvelope refEnv = new ReferencedEnvelope(env, crs);
        return new Bounds(getParentScope(), refEnv);
    }
   
    @JSGetter
    public Point getCentroid() {
        Geometry geom = (Geometry) GeometryWrapper.wrap(getParentScope(), geometry.getCentroid());
        if (projection != null) {
            geom.projection = projection;
        }
        return (Point) geom;
    }
   
    @JSFunction
    public Geometry transform(Object projObj) {
        Projection fromProj = projection;
        if (fromProj == null) {
            throw new RuntimeException("Geometry must have a projection before transforming.");
        }
        Projection toProj = null;
        if (projObj instanceof Projection) {
            toProj = (Projection) projObj;
        } else if (projObj instanceof String) {
            toProj = new Projection(getParentScope(), (String) projObj);
        } else {
            throw new RuntimeException("Argument must be a Projection instance or string identifier.");
        }
        GeometryCoordinateSequenceTransformer gt = new GeometryCoordinateSequenceTransformer();
        try {
            gt.setMathTransform(CRS.findMathTransform(fromProj.unwrap(), toProj.unwrap()));
        } catch (FactoryException e) {
            throw new RuntimeException("Failed to find transform.", e);
        }
        com.vividsolutions.jts.geom.Geometry transGeom;
        try {
            transGeom = gt.transform((com.vividsolutions.jts.geom.Geometry) this.unwrap());
        } catch (TransformException e) {
            throw new RuntimeException("Failed to transform.", e);
        }
        Geometry transformed = (Geometry) GeometryWrapper.wrap(getParentScope(), transGeom);
        transformed.projection = toProj;
        return transformed;
    }
   
    @JSFunction
    public double distance(Geometry other) {
        other = sameProjection(this, other);
        return geometry.distance((com.vividsolutions.jts.geom.Geometry) other.unwrap());
    }
   
    @JSFunction
    public Geometry buffer(double distance, NativeObject options) {
        BufferParameters params = new BufferParameters();
        if (options != null) {
            Object segsObj = options.get("segs", options);
            if (segsObj instanceof Integer) {
                params.setQuadrantSegments((Integer) segsObj);
            }
            Object singleObj = options.get("single", options);
            if (singleObj instanceof Boolean) {
                params.setSingleSided((Boolean) singleObj);
            }
            Object capsObj = options.get("caps", options);
            if (capsObj instanceof Integer) {
                params.setEndCapStyle((Integer) capsObj);
            }
        }
        com.vividsolutions.jts.geom.Geometry buffered = BufferOp.bufferOp(getGeometry(), distance, params);
        Geometry wrapped = (Geometry) GeometryWrapper.wrap(getParentScope(), buffered);
        if (projection != null) {
            wrapped.projection = projection;
        }
        return wrapped;
    }

    @JSGetter
    public Projection getProjection() {
        return projection;
    }
   
    @JSSetter
    public void setProjection(Object projObj) {
        Projection projection = null;
        if (projObj != null) {
            if (projObj instanceof Projection) {
                projection = (Projection) projObj;
            } else if (projObj instanceof String) {
                projection = new Projection(getParentScope(), (String) projObj);
            } else {
                throw ScriptRuntime.constructError("Error", "Set projection with Projection object or string identifier.");
            }
            if (this.projection != null && !projection.equals(this.projection)) {
                throw ScriptRuntime.constructError("Error", "Geometry projection already set.  Use the transform method to transform coordinates.");
            }
        }
        this.projection = projection;
    }
   
    @JSGetter
    public double getArea() {
        double area = 0;
        if (geometry != null) {
            area = geometry.getArea();
        }
        return area;
    }
   
    @JSFunction
    public ScriptableObject simplify(double tolerance) {
        com.vividsolutions.jts.geom.Geometry geom = DouglasPeuckerSimplifier.simplify(geometry, tolerance);
        ScriptableObject simplified = GeometryWrapper.wrap(getParentScope(), geom);
        ((Geometry) simplified).projection = projection;
        return simplified;
    }
   
    @JSFunction
    public String getGeometryType() {
        return geometry.getGeometryType();
    }

    @JSGetter
    public double getLength() {
        double length = 0;
        if (geometry != null) {
            length = geometry.getLength();
        }
        return length;
    }

    @JSGetter
    public int getDimension() {
        int dimension = 0;
        if (geometry != null) {
            dimension = geometry.getDimension();
        }
        return dimension;
    }
   
    @JSGetter
    public Scriptable getConfig() {
        Scriptable obj = super.getConfig();
        obj.put("coordinates", obj, getCoordinates());
        if (projection != null) {
            obj.put("projection", obj, projection.getId());
        }
        return obj;
    }

    @JSGetter
    public NativeArray getCoordinates() {
        return null;
    }

    public Object unwrap() {
        return geometry;
    }

    /**
     * Convert a JavaScript array to an array of JTS Coordinates.
     * @param array An array of 2 or 3 element arrays.
     * @return
     */
    protected Coordinate[] arrayToCoords(NativeArray array) {
        int size = array.size();
        Coordinate[] coords = new Coordinate[size];
        for (int i=0; i<size; ++i) {
            Object item = array.get(i);
            if (item instanceof NativeArray) {
                coords[i] = arrayToCoord((NativeArray) item);
            } else if (item instanceof com.vividsolutions.jts.geom.Point) {
                coords[i] = ((com.vividsolutions.jts.geom.Point) item).getCoordinate();
            } else {
                throw new RuntimeException("Must provide array of numbers or array of points");
            }
        }
        return coords;
    }
   
    /**
     * Convert a JavaScript array to a JTS Coordinate.
     * @param array An array of length 2 or 3
     * @return Coordinate with x, y, and optional z value from array
     */
    protected Coordinate arrayToCoord(NativeArray array) {
        double x = Double.NaN;
        double y = Double.NaN;
        double z = Double.NaN;
        if (array.size() >= 2) {
            Object xObj = array.get(0);
            if (xObj instanceof Number) {
                x = ((Number) xObj).doubleValue();
            }
            Object yObj = array.get(1);
            if (yObj instanceof Number) {
                y = ((Number) yObj).doubleValue();
            }
        }
        if (array.size() > 2) {
            Object zObj = array.get(2);
            if (zObj instanceof Number) {
                z = ((Number) zObj).doubleValue();
            }
        }
        Coordinate coord = new Coordinate(x, y, z);
        return coord;
    }
   
    /**
     * Convert a JTS Coordinate into a JavaScript array.
     * @param cx
     * @param scope
     * @param coord
     * @return
     */
    protected NativeArray coordToArray(Coordinate coord) {
        Scriptable scope = getParentScope();
        Context cx = getCurrentContext();
        Object[] elements = new Object[] {
                coord.x, coord.y
        };
        NativeArray array = (NativeArray) cx.newArray(scope, elements);
        double z = coord.z;
        if (!Double.isNaN(z)) {
            array.put(2, array, z);
        }
        return array;
    }
   
    /**
     * Convert a JTS Coordinate array into a JavaScript array.
     * @param scope
     * @param coords
     * @return
     */
    protected NativeArray coordsToArray(Coordinate[] coords) {
        Scriptable scope = getParentScope();
        Context cx = getCurrentContext();
        int length = coords.length;
        NativeArray array = (NativeArray) cx.newArray(scope, length);
        for (int i=0; i<length; ++i) {
            array.put(i, array, coordToArray(coords[i]));
        }
        return array;
    }

    private class BinaryFunction extends FunctionObject {

        /** serialVersionUID */
        private static final long serialVersionUID = 2395795118963401426L;
   
        Geometry geometry;
        Method trueMethod;
       
        public BinaryFunction(String name, Member methodOrConstructor,
                Scriptable scope) {
            super(name, methodOrConstructor, scope);
        }
       
        @SuppressWarnings("unused")
        public boolean nop(Geometry geometry) {
            return true;
        }
   
        BinaryFunction(String name, Method method, Scriptable scope, Geometry geometry) throws SecurityException, NoSuchMethodException {
            this(name, BinaryFunction.class.getMethod("nop", Geometry.class), scope);
            this.trueMethod = method;
            this.geometry = geometry;
        }
       
        @Override
        public Object call(Context cx, Scriptable scope, Scriptable thisObj,
                Object[] args) {
           
            Object otherObj = args[0];
            Geometry other;
            if (otherObj instanceof Geometry) {
                other = (Geometry) otherObj;
            } else {
                throw new RuntimeException("Must provide a geometry");
            }
            other = sameProjection(geometry, other);
            Boolean result;
            try {
                result = (Boolean) trueMethod.invoke(geometry.unwrap(), other.unwrap());
            } catch (Exception e) {
                throw new RuntimeException("Failed to invoke method", e);
            }
            return result;
        }
    }
   
    private class ConstructiveFunction0 extends FunctionObject {

        /** serialVersionUID */
        private static final long serialVersionUID = -96486854506406979L;

        Geometry geometry;
        Method trueMethod;
       
        public ConstructiveFunction0(String name, Member methodOrConstructor,
                Scriptable scope) {
            super(name, methodOrConstructor, scope);
        }
       
        @SuppressWarnings("unused")
        public com.vividsolutions.jts.geom.Geometry nop() {
            return null;
        }
   
        ConstructiveFunction0(String name, Method method, Scriptable scope, Geometry geometry) throws SecurityException, NoSuchMethodException {
            this(name, ConstructiveFunction0.class.getMethod("nop"), scope);
            this.trueMethod = method;
            this.geometry = geometry;
        }
       
        @Override
        public Object call(Context cx, Scriptable scope, Scriptable thisObj,
                Object[] args) {
           
            com.vividsolutions.jts.geom.Geometry result;
            try {
                result = (com.vividsolutions.jts.geom.Geometry) trueMethod.invoke(geometry.unwrap());
            } catch (Exception e) {
                throw new RuntimeException("Failed to invoke method", e);
            }
            ScriptableObject wrapped = GeometryWrapper.wrap(scope, result);
            if (geometry.projection != null) {
                ((Geometry) wrapped).projection = geometry.projection;
            }
            return wrapped;
        }
    }
   
    private class ConstructiveFunction1 extends FunctionObject {

        /** serialVersionUID */
        private static final long serialVersionUID = 7249580667784196575L;
   
        Geometry geometry;
        Method trueMethod;
       
        public ConstructiveFunction1(String name, Member methodOrConstructor,
                Scriptable scope) {
            super(name, methodOrConstructor, scope);
        }
       
        @SuppressWarnings("unused")
        public com.vividsolutions.jts.geom.Geometry nop(Geometry geometry) {
            return null;
        }
   
        ConstructiveFunction1(String name, Method method, Scriptable scope, Geometry geometry) throws SecurityException, NoSuchMethodException {
            this(name, ConstructiveFunction1.class.getMethod("nop", Geometry.class), scope);
            this.trueMethod = method;
            this.geometry = geometry;
        }
       
        @Override
        public Object call(Context cx, Scriptable scope, Scriptable thisObj,
                Object[] args) {
           
            Object otherObj = args[0];
            Geometry other;
            if (otherObj instanceof Geometry) {
                other = (Geometry) otherObj;
            } else {
                throw new RuntimeException("Must provide a geometry");
            }
            other = sameProjection(geometry, other);
            com.vividsolutions.jts.geom.Geometry result;
            try {
                result = (com.vividsolutions.jts.geom.Geometry) trueMethod.invoke(geometry.unwrap(), other.unwrap());
            } catch (Exception e) {
                throw new RuntimeException("Failed to invoke method", e);
            }
            ScriptableObject wrapped = GeometryWrapper.wrap(scope, result);
            if (geometry.projection != null) {
                ((Geometry) wrapped).projection = geometry.projection;
            }
            return wrapped;
        }
    }

    private Geometry sameProjection(Geometry thisGeom, Geometry otherGeom) {
        Projection thisProj = thisGeom.projection;
        if (thisProj != null) {
            Projection otherProj = otherGeom.projection;
            if (otherProj != null) {
                if (!thisProj.equals(otherProj)) {
                    otherGeom = otherGeom.transform(thisProj);
                }
            }
        }
        return otherGeom;
    }
   
    @JSStaticFunction
    public static Geometry from_(Scriptable geometryObj) {
        com.vividsolutions.jts.geom.Geometry geometry = null;
        if (geometryObj instanceof Wrapper) {
            Object obj = ((Wrapper) geometryObj).unwrap();
            if (obj instanceof com.vividsolutions.jts.geom.Geometry) {
                geometry = (com.vividsolutions.jts.geom.Geometry) obj;
            }
        }
        if (geometry == null) {
            throw ScriptRuntime.constructError("Error", "Cannot create geometry from " + Context.toString(geometryObj));
        }
        return (Geometry) GeometryWrapper.wrap(getTopLevelScope(geometryObj), geometry);
    }
   
    /**
     * Descriptive string representation of this object.
     * @return
     */
    public String toFullString() {
        return arrayRepr(getCoordinates());
    }

}
TOP

Related Classes of org.geoscript.js.geom.Geometry$ConstructiveFunction1

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.