msi.gama.util.path.GamaSpatialPath.java Source code

Java tutorial

Introduction

Here is the source code for msi.gama.util.path.GamaSpatialPath.java

Source

/*******************************************************************************************************
 *
 * msi.gama.util.path.GamaSpatialPath.java, in plugin msi.gama.core, is part of the source code of the GAMA modeling and
 * simulation platform (v. 1.8)
 * 
 * (c) 2007-2018 UMI 209 UMMISCO IRD/SU & Partners
 *
 * Visit https://github.com/gama-platform/gama for license information and contacts.
 * 
 ********************************************************************************************************/
package msi.gama.util.path;

import static java.lang.Math.min;
import static msi.gama.common.geometry.GeometryUtils.GEOMETRY_FACTORY;
import static msi.gama.common.geometry.GeometryUtils.getContourCoordinates;
import static msi.gama.common.geometry.GeometryUtils.getPointsOf;
import static msi.gama.common.geometry.GeometryUtils.split_at;
import static msi.gaml.operators.Spatial.Punctal._closest_point_to;

import org.apache.commons.lang.ArrayUtils;
import org.jgrapht.Graph;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;

import gnu.trove.map.hash.THashMap;
import msi.gama.common.geometry.GeometryUtils;
import msi.gama.common.geometry.ICoordinates;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.shape.GamaPoint;
import msi.gama.metamodel.shape.GamaShape;
import msi.gama.metamodel.shape.ILocation;
import msi.gama.metamodel.shape.IShape;
import msi.gama.metamodel.topology.ITopology;
import msi.gama.metamodel.topology.graph.GamaSpatialGraph;
import msi.gama.runtime.IScope;
import msi.gama.util.GamaListFactory;
import msi.gama.util.IList;
import msi.gama.util.graph.IGraph;
import msi.gaml.operators.Cast;
import msi.gaml.operators.Spatial.Punctal;
import msi.gaml.types.GamaGeometryType;
import msi.gaml.types.Types;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class GamaSpatialPath extends GamaPath<IShape, IShape, IGraph<IShape, IShape>> {

    IList<IShape> segments;
    IShape shape = null;
    THashMap<IShape, IShape> realObjects; // key = part of the geometry

    public GamaSpatialPath(final GamaSpatialGraph g, final IShape start, final IShape target,
            final IList<IShape> _edges) {
        super(g, start, target, _edges);
    }

    public GamaSpatialPath(final GamaSpatialGraph g, final IShape start, final IShape target,
            final IList<IShape> _edges, final boolean modify_edges) {
        super(g, start, target, _edges, modify_edges);
    }

    public GamaSpatialPath(final IShape start, final IShape target, final IList<? extends IShape> edges) {
        super(null, start, target, edges, false);
    }

    public GamaSpatialPath(final IShape start, final IShape target, final IList<? extends IShape> edges,
            final boolean modify_edges) {
        super(null, start, target, edges, modify_edges);
    }

    public GamaSpatialPath(final IList<IShape> nodes) {
        super(nodes);
    }

    @Override
    protected IShape createEdge(final IShape v, final IShape v2) {
        return GamaGeometryType.buildLine(v.getLocation(), v2.getLocation());
    }

    @Override
    public void init(final IGraph<IShape, IShape> g, final IShape start, final IShape target,
            final IList<? extends IShape> _edges, final boolean modify_edges) {
        super.init(g, start, target, _edges, modify_edges);
        source = start;
        this.target = target;
        this.graph = g;
        this.segments = GamaListFactory.create(Types.GEOMETRY);
        realObjects = new THashMap<>();
        graphVersion = 0;

        final Geometry firstLine = _edges == null || _edges.isEmpty() ? null : _edges.get(0).getInnerGeometry();
        GamaPoint pt = null, pt0 = null, pt1 = null;
        if (firstLine != null) {
            final GamaPoint[] firstLinePoints = GeometryUtils.getPointsOf(firstLine);
            pt0 = firstLinePoints[0];
            pt1 = firstLinePoints[firstLinePoints.length - 1];
        }
        if (firstLine != null && _edges != null && pt0 != null && pt1 != null) {
            if (_edges.size() > 1) {
                final IShape secondLine = _edges.get(1).getGeometry();
                pt = pt0.euclidianDistanceTo(secondLine) > pt1.euclidianDistanceTo(secondLine) ? pt0 : pt1;
            } else {
                final IShape lineEnd = edges.get(edges.size() - 1);
                final GamaPoint falseTarget = (GamaPoint) _closest_point_to(getEndVertex().getLocation(), lineEnd);
                pt = start.euclidianDistanceTo(pt0) < falseTarget.euclidianDistanceTo(pt0) ? pt0 : pt1;
            }
            if (graph != null) {
                graphVersion = graph.getVersion();
            }
            int cpt = 0;
            for (final IShape edge : _edges) {
                if (modify_edges) {
                    final IAgent ag = edge instanceof IAgent ? (IAgent) edge : null;
                    final GamaPoint[] points = getPointsOf(edge);
                    final Geometry geom = edge.getInnerGeometry();
                    Geometry geom2;
                    final GamaPoint c0 = points[0];
                    final GamaPoint c1 = points[points.length - 1];
                    IShape edge2 = null;
                    final GamaPoint[] coords = getContourCoordinates(geom).toCoordinateArray().clone();
                    if ((g == null || !g.isDirected()) && pt.distance(c0) > pt.distance(c1)) {
                        ArrayUtils.reverse(coords);
                        pt = c0;
                    } else {
                        pt = c1;
                    }
                    final ICoordinates cc = GEOMETRY_FACTORY.getCoordinateSequenceFactory().create(coords, false);
                    geom2 = GEOMETRY_FACTORY.createLineString(cc);
                    // geom2 = geom.reverse();
                    edge2 = new GamaShape(geom2);
                    if (cpt == 0 && !source.equals(pt)) {
                        GamaPoint falseSource = source.getLocation().toGamaPoint();
                        if (source.euclidianDistanceTo(edge2) > min(0.01, edge2.getPerimeter() / 1000)) {
                            falseSource = (GamaPoint) _closest_point_to(source, edge2);
                            falseSource.z = zVal(falseSource, edge2);
                        }
                        edge2 = split_at(edge2, falseSource).get(1);
                    }
                    if (cpt == _edges.size() - 1 && !target.equals(edge2.getInnerGeometry()
                            .getCoordinates()[edge2.getInnerGeometry().getNumPoints() - 1])) {

                        GamaPoint falseTarget = target.getLocation().toGamaPoint();
                        if (target.euclidianDistanceTo(edge2) > Math.min(0.01, edge2.getPerimeter() / 1000)) {
                            falseTarget = (GamaPoint) Punctal._closest_point_to(target, edge2);
                            falseTarget.z = zVal(falseTarget, edge2);
                        }
                        edge2 = split_at(edge2, falseTarget).get(0);
                    }
                    if (ag != null) {
                        realObjects.put(edge2.getGeometry(), ag);
                    } else {
                        realObjects.put(edge2.getGeometry(), edge);
                    }
                    segments.add(edge2.getGeometry());

                } else {
                    segments.add(edge.getGeometry());
                }
                cpt++;
                // segmentsInGraph.put(agents, agents);
            }
        }
    }

    protected double zVal(final GamaPoint point, final IShape edge) {
        double z = 0.0;
        final int nbSp = getPointsOf(edge).length;
        final Coordinate[] temp = new Coordinate[2];
        final Point pointGeom = (Point) point.getInnerGeometry();
        double distanceS = Double.MAX_VALUE;
        final GamaPoint[] edgePoints = GeometryUtils.getPointsOf(edge);
        for (int i = 0; i < nbSp - 1; i++) {
            temp[0] = edgePoints[i];
            temp[1] = edgePoints[i + 1];
            final LineString segment = GeometryUtils.GEOMETRY_FACTORY.createLineString(temp);
            final double distS = segment.distance(pointGeom);
            if (distS < distanceS) {
                distanceS = distS;
                final GamaPoint pt0 = new GamaPoint(temp[0]);
                final GamaPoint pt1 = new GamaPoint(temp[1]);
                z = pt0.z + (pt1.z - pt0.z) * point.distance(pt0) / segment.getLength();
            }
        }
        return z;
    }

    public GamaSpatialPath(final GamaSpatialGraph g, final IList<? extends IShape> nodes) {
        // FIXME call super super(param...);
        // DEBUG.OUT("GamaSpatialPath nodes: " + nodes);
        if (nodes.isEmpty()) {
            source = new GamaPoint(0, 0);
            target = source;
        } else {
            source = nodes.get(0);
            target = nodes.get(nodes.size() - 1);
        }
        segments = GamaListFactory.<IShape>create(Types.GEOMETRY);
        realObjects = new THashMap<>();
        graph = g;

        for (int i = 0, n = nodes.size(); i < n - 1; i++) {
            final IShape geom = GamaGeometryType.buildLine(nodes.get(i).getLocation(),
                    nodes.get(i + 1).getLocation());
            segments.add(geom);

            final IAgent ag = nodes.get(i).getAgent();
            if (ag != null) {
                // MODIF: put?
                realObjects.put(nodes.get(i).getGeometry(), ag);
            }
        }
        final IAgent ag = nodes.isEmpty() ? null : nodes.get(nodes.size() - 1).getAgent();
        if (ag != null) {
            // MODIF: put?
            realObjects.put(nodes.get(nodes.size() - 1).getGeometry(), ag);
        }
    }

    // /////////////////////////////////////////////////
    // Implements methods from IValue

    @Override
    public GamaSpatialPath copy(final IScope scope) {
        return new GamaSpatialPath(getGraph(), source, target, edges);
    }

    @Override
    public GamaSpatialGraph getGraph() {
        return (GamaSpatialGraph) graph;
    }

    // /////////////////////////////////////////////////
    // Implements methods from IPath
    //
    // @Override
    // public IList<IShape> getAgentList() {
    // GamaList<IShape> ags = GamaListFactory.create(Types.GEOMETRY);
    // ags.addAll(new HashSet<IShape>(realObjects.values()));
    // return ags;
    // }

    @Override
    public IList getEdgeGeometry() {
        // GamaList<IShape> ags = GamaListFactory.create(Types.GEOMETRY);
        // ags.addAll(new HashSet<IShape>(realObjects.values()));
        // return ags;
        return segments;
    }

    @Override
    public void acceptVisitor(final IAgent agent) {
        agent.setAttribute("current_path", this); // ???
    }

    @Override
    public void forgetVisitor(final IAgent agent) {
        agent.setAttribute("current_path", null); // ???
    }

    @Override
    public int indexOf(final IAgent a) {
        return Cast.asInt(null, a.getAttribute("index_on_path")); // ???
    }

    @Override
    public int indexSegmentOf(final IAgent a) {
        return Cast.asInt(null, a.getAttribute("index_on_path_segment")); // ???
    }

    @Override
    public boolean isVisitor(final IAgent a) {
        return a.getAttribute("current_path") == this;
    }

    @Override
    public void setIndexOf(final IAgent a, final int index) {
        a.setAttribute("index_on_path", index);
    }

    @Override
    public void setIndexSegementOf(final IAgent a, final int indexSegement) {
        a.setAttribute("index_on_path_segment", indexSegement);
    }

    @Override
    public double getDistance(final IScope scope) {
        if (segments == null || segments.isEmpty()) {
            return Double.MAX_VALUE;
        }
        final Coordinate[] coordsSource = segments.get(0).getInnerGeometry().getCoordinates();
        final Coordinate[] coordsTarget = segments.get(getEdgeList().size() - 1).getInnerGeometry()
                .getCoordinates();
        if (coordsSource.length == 0 || coordsTarget.length == 0) {
            return Double.MAX_VALUE;
        }
        final GamaPoint sourceEdges = new GamaPoint(coordsSource[0]);
        final GamaPoint targetEdges = new GamaPoint(coordsTarget[coordsTarget.length - 1]);
        final boolean keepSource = source.getLocation().equals(sourceEdges);
        final boolean keepTarget = target.getLocation().equals(targetEdges);
        if (keepSource && keepTarget) {
            double d = 0d;
            for (final IShape g : segments) {
                d += g.getInnerGeometry().getLength();
            }
            return d;
        }
        return getDistanceComplex(scope, keepSource, keepTarget);
    }

    private double getDistanceComplex(final IScope scope, final boolean keepSource, final boolean keepTarget) {
        double distance = 0;
        int index = 0;
        int indexSegment = 0;
        ILocation currentLocation = source.getLocation().copy(scope);
        final int nb = segments.size();
        if (!keepSource) {
            double distanceS = Double.MAX_VALUE;
            IShape line = null;
            for (int i = 0; i < nb; i++) {
                line = segments.get(i);
                final double distS = line.euclidianDistanceTo(currentLocation);
                if (distS < distanceS) {
                    distanceS = distS;
                    index = i;
                }
            }
            line = segments.get(index);
            currentLocation = Punctal._closest_point_to(currentLocation, line);
            final Point pointGeom = (Point) currentLocation.getInnerGeometry();
            if (line.getInnerGeometry().getNumPoints() >= 3) {
                distanceS = Double.MAX_VALUE;
                final Coordinate coords[] = line.getInnerGeometry().getCoordinates();
                final int nbSp = coords.length;
                final Coordinate[] temp = new Coordinate[2];
                for (int i = 0; i < nbSp - 1; i++) {
                    temp[0] = coords[i];
                    temp[1] = coords[i + 1];
                    final LineString segment = GeometryUtils.GEOMETRY_FACTORY.createLineString(temp);
                    final double distS = segment.distance(pointGeom);
                    if (distS < distanceS) {
                        distanceS = distS;
                        indexSegment = i + 1;
                    }
                }
            }
        }
        final IShape lineEnd = segments.get(nb - 1);
        int endIndexSegment = lineEnd.getInnerGeometry().getNumPoints();
        GamaPoint falseTarget = target.getLocation().toGamaPoint();
        if (!keepTarget) {
            falseTarget = (GamaPoint) Punctal._closest_point_to(getEndVertex(), lineEnd);
            endIndexSegment = 1;
            final Point pointGeom = (Point) falseTarget.getInnerGeometry();
            if (lineEnd.getInnerGeometry().getNumPoints() >= 3) {
                double distanceT = Double.MAX_VALUE;
                final Coordinate coords[] = lineEnd.getInnerGeometry().getCoordinates();
                final int nbSp = coords.length;
                final Coordinate[] temp = new Coordinate[2];
                for (int i = 0; i < nbSp - 1; i++) {
                    temp[0] = coords[i];
                    temp[1] = coords[i + 1];
                    final LineString segment = GeometryUtils.GEOMETRY_FACTORY.createLineString(temp);
                    final double distT = segment.distance(pointGeom);
                    if (distT < distanceT) {
                        distanceT = distT;
                        endIndexSegment = i + 1;
                    }
                }
            }
        }
        for (int i = index; i < nb; i++) {
            final IShape line = segments.get(i);
            final Coordinate coords[] = line.getInnerGeometry().getCoordinates();

            for (int j = indexSegment; j < coords.length; j++) {
                GamaPoint pt = null;
                if (i == nb - 1 && j == endIndexSegment) {
                    pt = falseTarget;
                } else {
                    pt = new GamaPoint(coords[j]);
                }
                final double dist = currentLocation.euclidianDistanceTo(pt);
                currentLocation = pt;
                distance = distance + dist;
                if (i == nb - 1 && j == endIndexSegment) {
                    break;
                }
                indexSegment++;
            }
            indexSegment = 1;
            index++;
        }
        return distance;
    }

    @Override
    public ITopology getTopology(final IScope scope) {
        if (graph == null) {
            return null;
        }
        return ((GamaSpatialGraph) graph).getTopology(scope);
    }

    @Override
    public void setRealObjects(final THashMap<IShape, IShape> realObjects) {
        this.realObjects = realObjects;
    }

    @Override
    public IShape getRealObject(final Object obj) {
        return realObjects.get(obj);
    }

    @Override
    public IShape getGeometry() {

        if (shape == null && segments.size() > 0) {
            if (segments.size() == 1) {
                shape = new GamaShape(segments.get(0));
            } else {
                final IList<IShape> pts = GamaListFactory.create(Types.POINT);
                for (final IShape ent : segments) {
                    for (final GamaPoint p : GeometryUtils.getPointsOf(ent)) {
                        if (!pts.contains(p)) {
                            pts.add(p);
                        }
                    }
                }
                if (pts.size() > 0) {
                    shape = GamaGeometryType.buildPolyline(pts);
                }
            }

        }
        return shape;
    }

    @Override
    public void setGraph(final IGraph<IShape, IShape> graph) {
        this.graph = graph;
        graphVersion = graph.getVersion();

        for (final IShape edge : edges) {
            final IAgent ag = edge.getAgent();
            if (ag != null) {
                realObjects.put(edge.getGeometry(), ag);
            } else {
                realObjects.put(edge.getGeometry(), edge);
            }
        }

    }

    @Override
    public IList<IShape> getEdgeList() {
        if (edges == null) {
            return segments;
        }
        return edges;
    }

    @Override
    public IList<IShape> getVertexList() {
        if (graph == null) {
            final IList<IShape> vertices = GamaListFactory.create();
            IShape g = null;
            for (final Object ed : getEdgeList()) {
                g = (IShape) ed;
                vertices.add(GeometryUtils.getFirstPointOf(g));
            }
            if (g != null) {
                vertices.add(GeometryUtils.getLastPointOf(g));
            }
            return vertices;
        }
        return getPathVertexList();
    }

    public IList<IShape> getPathVertexList() {
        final Graph<IShape, IShape> g = getGraph();
        final IList<IShape> list = GamaListFactory.create();
        IShape v = getStartVertex();
        list.add(v);
        IShape vPrev = null;
        for (final IShape e : getEdgeList()) {
            vPrev = v;
            v = getOppositeVertex(g, e, v);
            if (!v.equals(vPrev)) {
                list.add(v);
            }
        }
        return list;
    }

    public static IShape getOppositeVertex(final Graph<IShape, IShape> g, final IShape e, final IShape v) {
        final IShape source = g.getEdgeSource(e);
        final IShape target = g.getEdgeTarget(e);
        if (v.equals(source)) {
            return target;
        } else if (v.equals(target)) {
            return source;
        } else {
            return v.euclidianDistanceTo(source) > v.euclidianDistanceTo(target) ? target : source;
        }
    }
}