/*********************************************************************** * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved. * * 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 3 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, see <http://www.gnu.org/licenses/>. * ***********************************************************************/ package org.mt4j.components.bounds; import org.mt4j.components.MTComponent; import org.mt4j.components.TransformSpace; import org.mt4j.util.camera.IFrustum; import org.mt4j.util.math.Matrix; import org.mt4j.util.math.Ray; import org.mt4j.util.math.ToolsGeometry; import org.mt4j.util.math.Vector3D; import processing.core.PGraphics; /** * The Class BoundsArbitraryPlanarPolygon. * @author Christopher Ruff */ public class BoundsArbitraryPlanarPolygon implements IBoundingShape { /** The peer component. */ private MTComponent peerComponent; /** The bounding points local. */ private Vector3D[] boundingPointsLocal; /** The xy bounds rect. */ private BoundsZPlaneRectangle xyBoundsRect; private Vector3D[] worldVecs; private boolean worldVecsDirty; private Vector3D centerPointWorld; private boolean centerWorldDirty; /** * A 2D bounding polygon that is defined by the specified vectors. * This bounding shape is only suitable for objects that lie entirely in the z=0 plane. * * @param peerComponent the peer component * @param boundingPoints the bounding points */ public BoundsArbitraryPlanarPolygon(MTComponent peerComponent, Vector3D[] boundingPoints) { super(); this.peerComponent = peerComponent; this.boundingPointsLocal = boundingPoints; if (boundingPointsLocal.length < 3){ throw new RuntimeException("Bounds have to have at least 3 vertices!"); } //Calc bounding rect in xy-plane for width/height this.xyBoundsRect = new BoundsZPlaneRectangle(peerComponent, boundingPoints); this.worldVecsDirty = true; this.centerWorldDirty = true; // this.worldVecs = this.getVectorsGlobal(); // this.centerPointWorld = this.getCenterPointGlobal(); } public void drawBounds(PGraphics g) { g.pushMatrix(); g.fill(150,180); g.beginShape(); Vector3D[] vectors = this.getVectorsLocal(); for (int i = 0; i < vectors.length; i++) { g.vertex(vectors[i].x, vectors[i].y, vectors[i].z); } g.endShape(); g.popMatrix(); } public void setGlobalBoundsChanged(){ this.worldVecsDirty = true; this.centerWorldDirty = true; xyBoundsRect.setGlobalBoundsChanged(); } public Vector3D getCenterPointLocal() { //TODO check if entierely in x,y plane and use this, else create bounding box/sphere and get the center return ToolsGeometry.getPolygonCenterOfMass2D(this.boundingPointsLocal); } public Vector3D getCenterPointGlobal() { if (centerWorldDirty){ Vector3D tmp = this.getCenterPointLocal().getCopy(); tmp.transform(this.peerComponent.getGlobalMatrix()); this.centerPointWorld = tmp; this.centerWorldDirty = false; return this.centerPointWorld; } else{ return this.centerPointWorld; } } public Vector3D getIntersectionLocal(Ray ray) { Vector3D[] verts = this.boundingPointsLocal; Vector3D polyNormal = this.getNormalLocal(); Vector3D testPoint = ToolsGeometry.getRayPlaneIntersection(ray, polyNormal, verts[0]); if (testPoint == null) return null; return (ToolsGeometry.isPoint3DInPlanarPolygon(verts, testPoint, polyNormal)? testPoint : null); } /** * Gets the normal local. * * @return the normal local */ private Vector3D getNormalLocal() { return ToolsGeometry.getNormal(this.boundingPointsLocal[0], this.boundingPointsLocal[1], this.boundingPointsLocal[2], true); } public Vector3D[] getVectorsLocal() { return this.boundingPointsLocal; } public Vector3D[] getVectorsGlobal() { if (this.worldVecsDirty){ Vector3D[] vecs = Vector3D.getDeepVertexArrayCopy(this.boundingPointsLocal); Vector3D.transFormArrayLocal(this.peerComponent.getGlobalMatrix(), vecs); this.worldVecs = vecs; this.worldVecsDirty = false; return this.worldVecs; }else{ return this.worldVecs; } } public boolean containsPointLocal(Vector3D testPoint) { return ToolsGeometry.isPolygonContainsPoint(this.getVectorsLocal(), testPoint); } public float getHeightXY(TransformSpace transformSpace) { switch (transformSpace) { case LOCAL: return this.getHeightXYObjSpace(); case RELATIVE_TO_PARENT: return this.getHeightXYRelativeToParent(); case GLOBAL: return this.getHeightXYGlobal(); default: return -1; } } /** * Gets the height xy obj space. * * @return the height xy obj space */ private float getHeightXYObjSpace() { return this.getHeightXYVectLocal().length(); } /** * Gets the "height vector" and transforms it to parent relative space, then calculates * its length. * * @return the height xy relative to parent * * the height relative to its peer components parent frame of reference */ private float getHeightXYRelativeToParent() { Vector3D p = this.getHeightXYVectLocal(); Matrix m = new Matrix(this.peerComponent.getLocalMatrix()); m.removeTranslationFromMatrix(); p.transform(m); return p.length(); // Vector3D[] v = xyBoundsRect.getVectorsRelativeToParent(); // float[] minMax = ToolsGeometry.getMinXYMaxXY(v); // return minMax[3] - minMax[1]; } /** * Gets the "height vector" and transforms it to world space, then calculates * its length. * * @return the height xy global * * the height relative to the world space */ private float getHeightXYGlobal() { Vector3D p = this.getHeightXYVectLocal(); Matrix m = new Matrix(this.peerComponent.getGlobalMatrix()); m.removeTranslationFromMatrix(); p.transform(m); return p.length(); // Vector3D[] v = xyBoundsRect.getVectorsGlobal(); // float[] minMax = ToolsGeometry.getMinXYMaxXY(v); // return minMax[3] - minMax[1]; } /** * Gets the "height vector". The vector is calculated from the bounds vectors, * representing a vector with the height as its length in object space. * * @return the height xy vect obj space * * vector representing the height of the boundingshape of the shape */ public Vector3D getHeightXYVectLocal() { return this.xyBoundsRect.getHeightXYVectLocal(); } public float getWidthXY(TransformSpace transformSpace) { switch (transformSpace) { case LOCAL: return this.getWidthXYObjSpace(); case RELATIVE_TO_PARENT: return this.getWidthXYRealtiveToParent(); case GLOBAL: return this.getWidthXYGlobal(); default: return -1; } } /** * Gets the width xy obj space. * * @return the width xy obj space */ private float getWidthXYObjSpace() { return this.getWidthXYVectLocal().length(); } /** * Calculates the width of this shape, by using the * bounding shapes vectors. * Uses the objects local transform. So the width will be * relative to the parent only - not the whole world * * @return the width xy realtive to parent * * the width */ private float getWidthXYRealtiveToParent() { Vector3D p = this.getWidthXYVectLocal(); Matrix m = new Matrix(this.peerComponent.getLocalMatrix()); m.removeTranslationFromMatrix(); p.transform(m); return p.length(); // Vector3D[] v = xyBoundsRect.getVectorsRelativeToParent(); // float[] minMax = ToolsGeometry.getMinXYMaxXY(v); // return minMax[2] - minMax[0]; } /** * Gets the "Width vector" and transforms it to world space, then calculates * its length. * * @return the width xy global * * the Width relative to the world space */ private float getWidthXYGlobal() { Vector3D p = this.getWidthXYVectLocal(); Matrix m = new Matrix(this.peerComponent.getGlobalMatrix()); m.removeTranslationFromMatrix(); p.transform(m); return p.length(); // Vector3D[] v = xyBoundsRect.getVectorsGlobal(); // float[] minMax = ToolsGeometry.getMinXYMaxXY(v); // return minMax[2] - minMax[0]; } /** * Gets the "Width vector". The vector is calculated from the bounds vectors, * representing a vector with the Width as its length in object space. * * @return the width xy vect obj space * * vector representing the Width of the boundingshape of the shape */ public Vector3D getWidthXYVectLocal() { return this.xyBoundsRect.getWidthXYVectLocal(); } //@Override public boolean isContainedInFrustum(IFrustum frustum) { Vector3D[] points = this.getVectorsGlobal(); for (int i = 0; i < points.length; i++) { Vector3D vector3D = points[i]; int test = frustum.isPointInFrustum(vector3D); if ( test == IFrustum.INSIDE || test == IFrustum.INTERSECT ){ return true; } } return false; } }