at.uni_salzburg.cs.ckgroup.cscpp.mapper.PolygonZone.java Source code

Java tutorial

Introduction

Here is the source code for at.uni_salzburg.cs.ckgroup.cscpp.mapper.PolygonZone.java

Source

/*
 * @(#) PolygonZone.java
 *
 * This code is part of the CPCC project.
 * Copyright (c) 2012  Clemens Krainer
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package at.uni_salzburg.cs.ckgroup.cscpp.mapper;

import java.math.BigDecimal;
import java.util.Locale;

import org.json.simple.JSONArray;
import org.json.simple.JSONAware;
import org.json.simple.JSONObject;

import at.uni_salzburg.cs.ckgroup.course.PolarCoordinate;

public class PolygonZone extends AbstractZone {

    private static final double epsilon = 1E-9;

    private TwoTuple[] vertices;
    private double maxLat = Double.NEGATIVE_INFINITY;
    private double minLat = Double.POSITIVE_INFINITY;
    private double maxLon = Double.NEGATIVE_INFINITY;
    private double minLon = Double.POSITIVE_INFINITY;

    public PolygonZone(PolarCoordinate[] v) {

        vertices = new TwoTuple[v.length];

        for (int k = 0, l = v.length; k < l; ++k) {
            double x = v[k].getLatitude();
            double y = v[k].getLongitude();
            vertices[k] = new TwoTuple(x, y);
        }

        findBoundingBox();
    }

    public PolygonZone(TwoTuple[] vertices) {
        this.vertices = vertices;
        findBoundingBox();
    }

    private void findBoundingBox() {
        for (int k = 0, l = vertices.length; k < l; ++k) {
            if (vertices[k].x < minLat)
                minLat = vertices[k].x;
            if (vertices[k].x > maxLat)
                maxLat = vertices[k].x;
            if (vertices[k].y < minLon)
                minLon = vertices[k].y;
            if (vertices[k].y > maxLon)
                maxLon = vertices[k].y;
        }

        setDepotPosition(getCenterOfGravity());
    }

    @Override
    public boolean isInside(PolarCoordinate p) {
        if (p == null) {
            return false;
        }
        return isInside(p.getLatitude(), p.getLongitude());
    }

    public boolean isInside(double cx, double cy) {

        if (cx < minLat || cx > maxLat || cy < minLon || cy > maxLon)
            return false;

        int right = 0;
        int left = 0;
        for (int i = 0, l = vertices.length; i < l; ++i) {
            double ax = vertices[i].x;
            double ay = vertices[i].y;
            double bx = i + 1 == l ? vertices[0].x : vertices[i + 1].x;
            double by = i + 1 == l ? vertices[0].y : vertices[i + 1].y;

            if (cx == ax && cy == ay)
                return true;

            if (cy == ay)
                ay += epsilon;
            if (cy == by)
                by += epsilon;

            if ((cy < ay && cy < by) || (cy > ay && cy > by))
                continue;

            if (cx <= ax && cx <= bx) {
                ++right;
                continue;
            }

            if (cx >= ax && cx >= bx) {
                ++left;
                continue;
            }

            double k = (by - ay) / (bx - ax);
            double x = ax + (cy - ay) / k;
            if (cx <= x)
                ++right;
            else
                ++left;
        }

        if (right != 0)
            return right % 2 == 1;

        return left % 2 == 1;
    }

    //   public PolarCoordinate getCenterOfGravity () {
    //      double x = 0, y = 0;
    //      double doubleArea = 0;
    //      
    //      for (int k=0, l=vertices.length-1; k < l; ++k) {
    //         TwoTuple a = vertices[k];
    //         TwoTuple b = vertices[k+1];
    //         double t = (a.x * b.y - b.x * a.y);
    //         x += (a.x + b.x) * t;
    //         y += (a.y + b.y) * t;
    //         doubleArea += (a.x * b.y - b.x * a.y);
    //      }
    //      
    //      double sixTimesArea = 3.0 * doubleArea;
    //      return new PolarCoordinate(x/sixTimesArea, y/sixTimesArea, 0);
    //   }

    public PolarCoordinate getCenterOfGravity() {
        BigDecimal x = new BigDecimal(0), y = new BigDecimal(0);
        BigDecimal doubleArea = new BigDecimal(0);

        for (int k = 0, l = vertices.length - 1; k < l; ++k) {
            BigDecimal ax = new BigDecimal(vertices[k].x);
            BigDecimal ay = new BigDecimal(vertices[k].y);
            BigDecimal bx = new BigDecimal(vertices[k + 1].x);
            BigDecimal by = new BigDecimal(vertices[k + 1].y);
            BigDecimal t = ax.multiply(by).subtract(bx.multiply(ay));
            x = x.add(ax.add(bx).multiply(t));
            y = y.add(ay.add(by).multiply(t));
            doubleArea = doubleArea.add(ax.multiply(by).subtract(bx.multiply(ay)));
        }

        double sixTimesArea = 3.0 * doubleArea.doubleValue();
        return new PolarCoordinate(x.doubleValue() / sixTimesArea, y.doubleValue() / sixTimesArea, 0);
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder();
        boolean first = true;
        for (TwoTuple t : vertices) {
            if (first) {
                first = false;
            } else {
                b.append(", ");
            }
            b.append(t);
        }

        return String.format(Locale.US, "vertices: %s", b.toString());
    }

    @SuppressWarnings("unchecked")
    @Override
    public String toJSONString() {

        JSONObject o = new JSONObject();
        JSONArray a = new JSONArray();
        for (TwoTuple t : vertices) {
            a.add(t);
        }
        o.put("type", "polygon");
        o.put("vertices", a);
        o.put("depot", new TwoTuple(getDepotPosition().getLatitude(), getDepotPosition().getLongitude()));
        return o.toJSONString();
    }

    public static class TwoTuple implements JSONAware {
        public double x;
        public double y;

        public TwoTuple(double x, double y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return String.format(Locale.US, "(%.8f, %.8f)", x, y);
        }

        @SuppressWarnings("unchecked")
        @Override
        public String toJSONString() {
            JSONObject o = new JSONObject();
            o.put("lat", new Double(x));
            o.put("lon", new Double(y));
            return o.toJSONString();
        }
    }
}