/* * Copyright Inria and Bordeaux University. * Author Jeremy Laviole. jeremy.laviole@inria.fr * PapAR project is the open-source version of the * PapARt project. License is LGPLv3, distributed with the sources. * This project can also distributed with standard commercial * licence for closed-sources projects. */ package fr.inria.papart.calibration; import processing.core.PApplet; import processing.core.PMatrix3D; import processing.core.PVector; import processing.data.XML; import toxi.geom.Plane; import toxi.geom.Triangle3D; import toxi.geom.Vec3D; import toxi.math.MathUtils; /** * * @author Jeremy Laviole <jeremy.laviole@inria.fr> */ public class PlaneCalibration extends Calibration { public static final float HEIGHT_NOT_SET = -1; static final String PLANE_XML_NAME = "Plane"; static final String PLANE_POS_XML_NAME = "Position"; static final String PLANE_NORMAL_XML_NAME = "Normal"; static final String PLANE_HEIGHT_XML_NAME = "Height"; static final String X_XML_NAME = "x"; static final String Y_XML_NAME = "y"; static final String Z_XML_NAME = "z"; private float height = HEIGHT_NOT_SET; private Plane plane; public boolean orientation(Vec3D point, float value) { return plane.classifyPoint(point, 0.05f) == Plane.Classifier.BACK; } public boolean orientation(Vec3D p) { float d = plane.sub(p).dot(plane.normal); if (d < -MathUtils.EPS) { return false; } else if (d > MathUtils.EPS) { return true; } return true; //ON_PLANE; } public boolean hasGoodOrientationAndDistance(Vec3D point) { return orientation(point) && plane.getDistanceToPoint(point) <= height; } public boolean isUnderPlane(Vec3D point) { return !orientation(point) && plane.getDistanceToPoint(point) <= height; } public boolean hasGoodDistance(Vec3D point) { return plane.getDistanceToPoint(point) <= height; } public boolean hasGoodOrientation(Vec3D point) { return orientation(point); } public float distanceTo(Vec3D point) { return plane.getDistanceToPoint(point); } public float distanceTo(PVector point) { return plane.getDistanceToPoint(new Vec3D(point.x, point.y, point.z)); } public void flipNormal() { plane.normal = plane.normal.invert(); } public void moveAlongNormal(float value) { plane.x = plane.x + value * plane.normal.x; plane.y = plane.y + value * plane.normal.y; plane.z = plane.z + value * plane.normal.z; } public float getHeight() { return height; } public void setHeight(float planeHeight) { this.height = planeHeight; } protected void setPlane(Plane plane) { this.plane = plane; } public Plane getPlane() { assert (isValid()); return plane; } public boolean isValid() { return this.plane != null && this.height != HEIGHT_NOT_SET; } @Override public void replaceIn(XML xml) { XML planeNode = xml.getChild(PLANE_XML_NAME); setVectorIn(planeNode.getChild(PLANE_POS_XML_NAME), (Vec3D) plane); setVectorIn(planeNode.getChild(PLANE_NORMAL_XML_NAME), plane.normal); planeNode.getChild(PLANE_HEIGHT_XML_NAME).setFloat(PLANE_HEIGHT_XML_NAME, height); } @Override public void addTo(XML xml) { XML root = new XML(PLANE_XML_NAME); XML pos = createXML(PLANE_POS_XML_NAME, (Vec3D) plane); XML normal = createXML(PLANE_NORMAL_XML_NAME, plane.normal); XML height = new XML(PLANE_HEIGHT_XML_NAME); height.setFloat(PLANE_HEIGHT_XML_NAME, this.height); root.addChild(pos); root.addChild(normal); root.addChild(height); xml.addChild(root); } private XML createXML(String name, Vec3D v) { XML node = new XML(name); this.setVectorIn(node, v); return node; } private void setVectorIn(XML node, Vec3D v) { node.setFloat(X_XML_NAME, v.x); node.setFloat(Y_XML_NAME, v.y); node.setFloat(Z_XML_NAME, v.z); } private Vec3D getVectorFrom(XML node) { Vec3D v = new Vec3D(); v.x = node.getFloat(X_XML_NAME); v.y = node.getFloat(Y_XML_NAME); v.z = node.getFloat(Z_XML_NAME); return v; } @Override public void loadFrom(PApplet parent, String fileName) { XML root = parent.loadXML(fileName); XML planeNode = root.getChild(PLANE_XML_NAME); XML posNode = planeNode.getChild(PLANE_POS_XML_NAME); XML normalNode = planeNode.getChild(PLANE_NORMAL_XML_NAME); XML heightNode = planeNode.getChild(PLANE_HEIGHT_XML_NAME); Vec3D position = getVectorFrom(posNode); Vec3D normal = getVectorFrom(normalNode); float h = heightNode.getFloat(PLANE_HEIGHT_XML_NAME); this.plane = new Plane(); plane.set(position); plane.normal.set(normal); setHeight(h); } @Override public String toString() { return this.plane.toString() + " " + this.height; } public static float DEFAULT_PLANE_SHIFT = -8f; public static float DEFAULT_PLANE_HEIGHT = 15f; /** * Get a plane from a 3D matrix. * Here the size is not that important, might be removed. * @param mat * @param size * @return */ public static PlaneCalibration CreatePlaneCalibrationFrom(PMatrix3D mat, PVector size) { PlaneCreator planeCreator = new PlaneCreator(); planeCreator.addPoint(new Vec3D(mat.m03, mat.m13, mat.m23)); mat.translate(size.x, 0, 0); planeCreator.addPoint(new Vec3D(mat.m03, mat.m13, mat.m23)); mat.translate(0, size.y, 0); planeCreator.addPoint(new Vec3D(mat.m03, mat.m13, mat.m23)); planeCreator.setHeight(DEFAULT_PLANE_HEIGHT); assert (planeCreator.isComputed()); PlaneCalibration planeCalibration = planeCreator.getPlaneCalibration(); planeCalibration.flipNormal(); // planeCalibration.moveAlongNormal(DEFAULT_PLANE_SHIFT); assert (planeCalibration.isValid()); return planeCalibration; } }