/* * __ .__ .__ ._____. * _/ |_ _______ __|__| ____ | | |__\_ |__ ______ * \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/ * | | ( <_> > <| \ \___| |_| || \_\ \\___ \ * |__| \____/__/\_ \__|\___ >____/__||___ /____ > * \/ \/ \/ \/ * * Copyright (c) 2006-2011 Karsten Schmidt * * This library 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 2.1 of the License, or (at your option) any later version. * * http://creativecommons.org/licenses/LGPL/2.1/ * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ package spimedb.util.geom; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class PointCloud3D implements Iterable<Vec3D> { protected List<Vec3D> points; protected Vec3D min, max; protected Vec3D centroid; protected float radiusSquared; public PointCloud3D() { this(100); } public PointCloud3D(int numPoints) { points = new ArrayList(numPoints); clear(); } public PointCloud3D addAll(List<? extends Vec3D> plist) { for (Vec3D p : plist) { addPoint(p); } return this; } public PointCloud3D addPoint(Vec3D p) { points.add(p); min.minSelf(p); max.maxSelf(p); centroid.set(min.plus(max).scaleSelf(0.5f)); radiusSquared = Math.max(radiusSquared, p.distanceToSquared(centroid)); return this; } /** * Applies the given transformation matrix to all points in the cloud. * * @param m * transformation matrix * @return itself */ public PointCloud3D applyMatrix(Matrix4x4 m) { for (Vec3D p : points) { p.set(m.applyTo(p)); } updateBounds(); return this; } /** * Updates all points in the cloud so that their new centroid is at the * origin. * * @return itself */ public PointCloud3D center() { return center(null); } /** * Updates all points in the cloud so that their new centroid is at the * given point. * * @param origin * new centroid * @return itself */ public PointCloud3D center(roVec3D origin) { getCentroid(); Vec3D delta = origin != null ? origin.sub(centroid) : centroid .getInverted(); for (Vec3D p : points) { p.addSelf(delta); } min.addSelf(delta); max.addSelf(delta); centroid.addSelf(delta); return this; } /** * Removes all points from the cloud and resets the bounds and centroid. * * @return itself */ public PointCloud3D clear() { points.clear(); min = Vec3D.MAX_VALUE.copy(); max = Vec3D.NEG_MAX_VALUE.copy(); centroid = new Vec3D(); return this; } /** * Creates a deep copy of the cloud * * @return copied instance */ public PointCloud3D copy() { PointCloud3D c = new PointCloud3D(points.size()); for (roVec3D p : points) { c.addPoint(p.copy()); } return c; } public BB getBoundingBox() { return BB.fromMinMax(min, max); } public Sphere getBoundingSphere() { return new Sphere(getCentroid(), (float) Math.sqrt(radiusSquared)); } /** * @return the cloud centroid */ public Vec3D getCentroid() { return centroid; } /** * @return an iterator for the backing point collection. * * @see Iterable#iterator() */ public Iterator<Vec3D> iterator() { return points.iterator(); } /** * Removes the point from the cloud, but doesn't update the bounds * automatically. * * @param p * @return true, if point has been removed. */ public boolean removePoint(roVec3D p) { return points.remove(p); } /** * @return the current number of points in the cloud */ public int size() { return points.size(); } /** * Recalculates the bounding box, bounding sphere and centroid of the cloud. * * @return itself */ public PointCloud3D updateBounds() { min = Vec3D.MAX_VALUE.copy(); max = Vec3D.NEG_MAX_VALUE.copy(); for (Vec3D p : points) { min.minSelf(p); max.maxSelf(p); } centroid.set(min.plus(max).scaleSelf(0.5f)); radiusSquared = 0; for (roVec3D p : points) { radiusSquared = Math.max(radiusSquared, p.distanceToSquared(centroid)); } return this; } }