/*- * 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.utils; import java.util.List; import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Vertex; import de.hft.stuttgart.citydoctor2.math.Vector3d; /** * Utility class for calculating axis aligned bounding boxes for different * inputs. * * @author Matthias Betz * */ public class BoundingBoxCalculator { private BoundingBoxCalculator() { // only static use } /** * This will calculate two points where every other point in the geometry is * between those two. If the geometry does not contain points or is null, an * empty array is returned. This is considered an axis aligned bounding box. * Only the exterior rings of the polygons is used as inner rings should be * within the exterior or they are faulty. * * @param a list of polygons containing the vertices * @return an BoundingBox containing the two end points of the bounding box. */ public static BoundingBox calculateBoundingBox(List polygons) { double lowX = Double.MAX_VALUE; double highX = Double.NEGATIVE_INFINITY; double lowY = Double.MAX_VALUE; double highY = Double.NEGATIVE_INFINITY; double lowZ = Double.MAX_VALUE; double highZ = Double.NEGATIVE_INFINITY; for (Polygon p : polygons) { // only need to check exterior rings for (Vertex v : p.getExteriorRing().getVertices()) { if (v.getX() < lowX) { lowX = v.getX(); } else if (v.getX() > highX) { highX = v.getX(); } if (v.getY() < lowY) { lowY = v.getY(); } else if (v.getY() > highY) { highY = v.getY(); } if (v.getZ() < lowZ) { lowZ = v.getZ(); } else if (v.getZ() > highZ) { highZ = v.getZ(); } } } Vector3d[] result = new Vector3d[2]; result[0] = new Vector3d(lowX, lowY, lowZ); result[1] = new Vector3d(highX, highY, highZ); return BoundingBox.of(result); } /** * This will calculate an axis aligned bounding box for the complete GML model. * * @param model the model * @return the bounding box of the model */ public static BoundingBox calculateBoundingBox(CityDoctorModel model) { Vector3d low = new Vector3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); Vector3d high = new Vector3d(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); findMinMax(low, high, model.getBuildings()); findMinMax(low, high, model.getBridges()); findMinMax(low, high, model.getLand()); findMinMax(low, high, model.getTransportation()); findMinMax(low, high, model.getWater()); findMinMax(low, high, model.getVegetation()); Vector3d[] result = new Vector3d[2]; result[0] = low; result[1] = high; return BoundingBox.of(result); } private static void findMinMax(Vector3d low, Vector3d high, List features) { for (CityObject co : features) { findMinMax(low, high, co); } } private static void findMinMax(Vector3d low, Vector3d high, CityObject co) { for (Geometry geom : co.getGeometries()) { if (geom.getVertices() == null) { geom.updateVertices(); } for (Vertex v : geom.getVertices()) { if (v.getX() < low.getX()) { low.setX(v.getX()); } else if (v.getX() > high.getX()) { high.setX(v.getX()); } if (v.getY() < low.getY()) { low.setY(v.getY()); } else if (v.getY() > high.getY()) { high.setY(v.getY()); } if (v.getZ() < low.getZ()) { low.setZ(v.getZ()); } else if (v.getZ() > high.getZ()) { high.setZ(v.getZ()); } } } } }