/*- * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * * This file is part of CityDoctor2. * * CityDoctor2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CityDoctor2 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CityDoctor2. If not, see . */ package de.hft.stuttgart.citydoctor2.math; import java.util.ArrayList; import java.util.Collections; import java.util.List; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Vertex; /** * A two dimensional polygon. Has an 2d exterior ring and interior rings * * @author Matthias Betz * */ public class Polygon2d { private Ring2d exterior; private List innerRings; public static Polygon2d withProjection(Polygon poly) { Vector3d normal = poly.calculateNormalNormalized(); int[] axis = getProjectionAxis(normal); return projectTo2D(poly, axis); } public static Polygon2d withProjection(MovedPolygon poly, int[] projectionAxis) { return projectTo2D(poly, projectionAxis); } public static Polygon2d withProjection(Polygon poly, int[] projectionAxis) { return projectTo2D(poly, projectionAxis); } private static Polygon2d projectTo2D(Polygon p, int[] axis) { List interior = new ArrayList<>(); Ring2d exterior = projectRing(p.getExteriorRing(), axis); for (LinearRing innerRing : p.getInnerRings()) { interior.add(projectRing(innerRing, axis)); } return new Polygon2d(exterior, interior); } private static Polygon2d projectTo2D(MovedPolygon p, int[] axis) { List interior = new ArrayList<>(); Ring2d exterior = projectRing(p.getExteriorRing(), axis); for (MovedRing innerRing : p.getInnerRings()) { interior.add(projectRing(innerRing, axis)); } return new Polygon2d(exterior, interior); } public static int[] getProjectionAxis(Vector3d normal) { double nx = Math.abs(normal.getX()); double ny = Math.abs(normal.getY()); double nz = Math.abs(normal.getZ()); int[] axis; if (nx >= ny && nx >= nz) { axis = new int[] { 1, 2 }; } else if (ny >= nx && ny >= nz) { axis = new int[] { 0, 2 }; } else { axis = new int[] { 0, 1 }; } return axis; } private static Ring2d projectRing(LinearRing r, int[] axis) { List projectedVertices = new ArrayList<>(); for (Vertex v : r.getVertices()) { projectedVertices.add(new Vector2d(v.getCoordinate(axis[0]), v.getCoordinate(axis[1]))); } return new Ring2d(projectedVertices, r); } private static Ring2d projectRing(MovedRing r, int[] axis) { List projectedVertices = new ArrayList<>(); for (Vector3d v : r.getVertices()) { projectedVertices.add(new Vector2d(v.getCoordinate(axis[0]), v.getCoordinate(axis[1]))); } return new Ring2d(projectedVertices, r.getOriginal()); } public static Polygon2d withRotationMatrix(Polygon poly) { Matrix3x3d rotMatrix = PolygonUtils.calculateRotationMatrix(poly); LinearRing lr = poly.getExteriorRing(); Ring2d exterior = createRing2d(rotMatrix, lr); List innerRings = new ArrayList<>(); for (LinearRing innerRing : poly.getInnerRings()) { innerRings.add(createRing2d(rotMatrix, innerRing)); } return new Polygon2d(exterior, innerRings); } /** * Converts a Polygon to a 2d polygon. This will change the area of the polygon. * * @param ring a linear ring */ private Polygon2d(Ring2d exterior, List interior) { if (interior == null) { interior = Collections.emptyList(); } this.exterior = exterior; this.innerRings = interior; } private static Ring2d createRing2d(Matrix3x3d rotMatrix, LinearRing lr) { List ringVertices = new ArrayList<>(); for (Vertex v : lr.getVertices()) { Vector3d rotated = rotMatrix.mult(v); Vector2d v2d = new Vector2d(rotated.getX(), rotated.getY()); ringVertices.add(v2d); } return new Ring2d(ringVertices, lr); } public Ring2d getExterior() { return exterior; } public List getInteriorRings() { if (innerRings == null) { return Collections.emptyList(); } return innerRings; } }