package org.mt4jx.util.extension3D; import org.mt4j.components.MTComponent; import org.mt4j.components.PickInfo; import org.mt4j.components.PickResult; import org.mt4j.components.PickResult.PickEntry; import org.mt4j.components.clipping.Clip; import org.mt4j.components.interfaces.IMTComponent3D; import org.mt4j.util.math.Ray; import org.mt4j.util.math.Tools3D; import org.mt4j.util.math.Vector3D; import processing.core.PApplet; public class ComponentHelper { /** * this is a different version of pickRecursive of MTComponent used to get the correct object when dealing with the Cluster 3D techniques * Checks which object lies under the specified screen coordinates. * The the results are stored in the returned PickResult object. This component and * its children will be checked. * * @param x the x * @param y the y * @param onlyPickables check the only pickable components * * @return the pick result */ public static PickResult pick(MTComponent comp,float x, float y, boolean onlyPickables){ //ADDTOMT4J change name PickResult pickResult = new PickResult(); PickInfo pickInfo = new PickInfo(x,y, Tools3D.getCameraPickRay(comp.getRenderer(), comp, x, y)); pickRecursive(comp,pickInfo, pickResult, Float.MAX_VALUE, pickInfo.getPickRay(), onlyPickables); // pickResult.printList(); return pickResult; } /** * this is a different version of pickRecursive of MTComponent used to get the correct object when dealing with the Cluster 3D techniques * @param comp * @param pickInfo * @param pickResult * @param currObjDist * @param currentRay * @param onlyPickables * @return */ private static float pickRecursive(MTComponent comp,PickInfo pickInfo, PickResult pickResult, float currObjDist, Ray currentRay, boolean onlyPickables){//ADDTOMT4J change name Vector3D interSP = null; float objDistance = 0; //TEST, Wenns probleme gibt das wieder aktivieren // currObjDist = pickResult.getDistanceNearestPickObj(); // System.out.println("At: " + comp.getName() + " Current Distance: " + currObjDist); if (comp.isVisible() && ((onlyPickables && comp.isPickable()) || !onlyPickables) ){ //Get the real ray for comp obj, takes the viewing camera and viewport of comp obj into account //-> changes rayStartPoint and point in ray direction if (comp.getAttachedCamera() != null){ currentRay = getChangedCameraPickRay(comp.getRenderer(), comp, pickInfo); } Ray invertedRay; if (comp.getGlobalInverseMatrix().isIdentity()){ invertedRay = currentRay; }else{ invertedRay = comp.globalToLocal(currentRay); } /* //FIXME REMOVE!!!!! //comp adds lines indicating the world ray and the local object ray used for ray-test MTLine l1 = new MTLine(comp.getRenderer(), new Vertex(currentRay.getRayStartPoint()), new Vertex(currentRay.getPointInRayDirection())); comp.getAncestor().addChild(l1); MTLine l2 = new MTLine(comp.getRenderer(), new Vertex(invertedRay.getRayStartPoint()), new Vertex(invertedRay.getPointInRayDirection())); l2.setStrokeColor(255, 10, 10, 255); comp.getAncestor().addChild(l2); */ //Check if component is clipped and only proceed if the ray intersects the clip shape Clip clip = comp.getClip(); if (clip == null || (clip != null && clip.getClipShapeIntersectionLocal(invertedRay) != null)){ interSP = comp.getIntersectionLocal(invertedRay); if (interSP != null){ //FIXME TRIAL - muss f�r die distance messung der world ray genommen //werden oder geht der invertierte ray? -> musss wohl der world ray sein interSP.transform(comp.getGlobalMatrix()); // Get distance from raystart to the intersecting point objDistance = interSP.getSubtracted(currentRay.getRayStartPoint()).length(); //System.out.println("Pick found: " + comp.getName() + " InterSP: " + interSP + " ObjDist: " + objDistance + " Mouse Pos: " + pickInfo.getScreenXCoordinate() + "," + pickInfo.getScreenYCoordinate() + " InvRay RS:" + invertedRay.getRayStartPoint() + ",RE: " + invertedRay.getPointInRayDirection()); // //If the distance is the smallest yet = closest to the raystart: replace the returnObject and current distanceFrom // if ( (objDistance - HIT_TOLERANCE) <= currObjDist /*|| comp.isAlwaysDrawnOnTop()*/){//take isDrawnOnTop into account here?? -> OBJDistance auf 0 setzen? // currObjDist = objDistance; // pickResult.addPickedObject(comp, interSP, objDistance); //// System.out.println("-> Now nearest: " + comp.getName()); // } //FIXME TEST - ADD ALL PICKED OBJECTS - SORT LATER pickResult.addPickedObject(comp, interSP, objDistance); } } //Check for child clipping shape intersection, if not intersecting -> dont try to pick children Clip childClip = comp.getChildClip(); if (childClip != null && childClip.getClipShapeIntersectionLocal(invertedRay) == null){ return currObjDist; } } /* recursively check all children now */ MTComponent[] childComponents = comp.getChildren(); for (int i = 0; i < childComponents.length; i++) { MTComponent child = childComponents[i]; if (child.isVisible()) { if (comp.isComposite()){ //Start a new picking with a new Pickresult obj from here PickResult compositePickRes = new PickResult(); float compDistance = pickRecursive(child,pickInfo, compositePickRes, Float.MAX_VALUE, currentRay, onlyPickables); //Add the composites picks to the overall picks if (compositePickRes.getNearestPickResult() != null){ // System.out.println("In: " + comp.getName() + " Composites child picked, pick resultDistance: " + compDistance); /*//TODO m�sste diese hier nach distanz geordnet in insgesamt pickresult einf�gen.. ArrayList<MTBaseComponent> pickList = compositePickRes.getPickList(); for(MTBaseComponent comp : pickList){ pickResult.addPickedObject(comp, compositePickRes.getInterSectionPointOfPickedObj(comp), compositePickRes.getDistanceOfPickedObj(comp)); } */ //Add comp composite as the last one picked with the distance of the last one picked in the composite pick // pickResult.addPickedObjects(compositePickRes.getPickList()); // pickResult.addPickedObject(comp, compositePickRes.getInterSectionPointNearestPickedObj(), compositePickRes.getDistanceNearestPickObj()); // if (//compDistance <= currObjDist // (compDistance - HIT_TOLERANCE) <= currObjDist // ){ //// System.out.println("Composites child picked and now nearest: " + comp.getName()+ " dist: " + compDistance); // pickResult.addPickedObject(comp, compositePickRes.getInterSectionPointNearestPickedObj(), compositePickRes.getDistanceNearestPickObj()); // currObjDist = compDistance; // } //FIXME TEST - ADD ALL PICKED OBJECTS - SORT LATER PickEntry nearestPickEntry = compositePickRes.getNearestPickEntry(); pickResult.addPickedObject(nearestPickEntry.hitObj, nearestPickEntry.intersectionPoint, nearestPickEntry.cameraDistance); } }else{ currObjDist = pickRecursive(child,pickInfo, pickResult, currObjDist, currentRay, onlyPickables); } } } return currObjDist; } /** * Calculates the "real" picking ray for the object. * <br>If the obj has a custom camera attached to it, this camera's position is the new ray origin and * the point in the ray direction is the unprojected x,y, coordinates while this camera is active. * * @param pa the papplet * @param obj the obj * @param ray the ray * * @return the real pick ray * * the new calculated ray, or the original ray, if the obj has no custom camera attached to it. */ private static Ray getChangedCameraPickRay(PApplet pa, IMTComponent3D obj, Ray ray){ Vector3D pointInRayDirection = ray.getPointInRayDirection(); Vector3D projected = Tools3D.project(pa, obj.getViewingCamera(), pointInRayDirection); // Vector3D projected = Tools3D.project(pa, pointInRayDirection); return getChangedCameraPickRay(pa, obj, new PickInfo( projected.x, projected.y, ray)); } /** * Calculates the "real" pickray for the object. * <br>If the obj has a custom camera attached to it, this cameras position is the new ray origin and * the point in the ray direction is the unprojected x,y, coordinates while this camera is active. * * @param pa the pa * @param obj the obj * @param pickInfo the pick info * @return the real pick ray * * the new calculated ray, or the original ray, if the obj has no custom camera attached to it. */ private static Ray getChangedCameraPickRay(PApplet pa, IMTComponent3D obj, PickInfo pickInfo){ if (obj.getViewingCamera() != null){ //FIXME TEST //Re-Project unprojected world coords to projected viewport screen coords (Tuio INput) float x = pickInfo.getScreenXCoordinate(); float y = pickInfo.getScreenYCoordinate(); return Tools3D.getCameraPickRay(pa, obj, x, y); }else{ return pickInfo.getPickRay(); } /*//FIXME disabled for performance for now! if (obj.hasCustomViewPort()){ //Take VIEWPORT changes into account, too ViewportSetting customViewPort = obj.getCustomViewportSetting(); ViewportSetting defaultViewPortSetting = obj.getDefaultViewportSetting(); rayStartPoint.setX(customViewPort.getStartX() + (rayStartPoint.getX() * (customViewPort.getWidth()/defaultViewPortSetting.getWidth()))); rayStartPoint.setY(customViewPort.getStartY() + (rayStartPoint.getY() * (customViewPort.getHeight()/defaultViewPortSetting.getHeight()))); pointInRayDirection.setX(customViewPort.getStartX() + (pointInRayDirection.getX() * (customViewPort.getWidth()/defaultViewPortSetting.getWidth()))); pointInRayDirection.setY(customViewPort.getStartY() + (pointInRayDirection.getY() * (customViewPort.getHeight()/defaultViewPortSetting.getHeight()))); ///// } */ // return new Ray(rayStartPoint, pointInRayDirection); } /* (non-Javadoc) * this is a different version of getIntersectionGlobal of MTComponent used to deal with collision engine * @see org.mt4j.components.interfaces.IMTComponent3D#getIntersectionGlobalSpace(util.math.Ray) */ public static Vector3D getIntersectionGlobal(MTComponent comp,Ray ray){ //ADDTOMT4J Chris fragen, wegen pickable { float currentDistance = Float.MAX_VALUE; //high value so that the first time a object is found comp distance is exchanged with his float objDistance = 0; Vector3D returnPoint = null; Vector3D interSP = null; if (comp.isVisible()) { //Get the real ray for comp obj, takes the custom camera and viewport of comp obj into account //-> changes rayStartPoint and point in ray direction if (comp.getAttachedCamera() != null){ ray = getChangedCameraPickRay(comp.getRenderer(), comp, ray); } //Transforms the ray into local object space Ray invertedRay = comp.globalToLocal(ray); //Check if component is clipped and only proceed if the ray intersects the clip shape Clip clip = comp.getClip(); if (clip == null || (clip != null && clip.getClipShapeIntersectionLocal(invertedRay) != null)){ interSP = comp.getIntersectionLocal(invertedRay); if (interSP != null){ //FIXME TRIAL - muss f�r die distance messung der world ray genommen //werden oder geht der invertierte ray? interSP.transform(comp.getGlobalMatrix()); //Get distance from raystart to the intersecting point objDistance = interSP.getSubtracted(ray.getRayStartPoint()).length(); //If the distance is the smalles yet = closest to the raystart replace the returnObject and current distanceFrom if ((objDistance - PickResult.HIT_TOLERANCE) < currentDistance ){ returnPoint = interSP; currentDistance = objDistance; } } } //Check for child clip intersection, if not intersecting, dont try to pick children Clip childClip = comp.getChildClip(); if (childClip != null && childClip.getClipShapeIntersectionLocal(invertedRay) == null){ return returnPoint; } } /* Go through all Children */ // for (int i = childComponents.size()-1; i >= 0; i--) { MTComponent[] childComponents = comp.getChildren(); for (int i = 0; i < childComponents.length; i++) { MTComponent child = childComponents[i]; //Get the intersectionpoint ray/object if there is one interSP = getIntersectionGlobal(child,ray); if (interSP != null ){ //if ray intersects object at a point //System.out.println("Intersection at: " + interSP); //Get distance from raystart to the intersecting point objDistance = interSP.getSubtracted(ray.getRayStartPoint()).length(); //If the distance is the smalles yet = closest to the raystart replace the returnObject and current distanceFrom if (objDistance < currentDistance ){ returnPoint = interSP; currentDistance = objDistance; } }//if intersection!=null }// for return returnPoint; } public static Vector3D getCenterPointGlobal(MTComponent comp) { MTComponent[] children = comp.getChildren(); if(children.length==0) { if(comp.hasBounds()) { return comp.getBounds().getCenterPointGlobal(); }else { return null; } }else { //float massSum = 0.0f; Vector3D vecSum = new Vector3D(); for(MTComponent compChild : children) { if(getCenterPointGlobal(compChild)!=null) { Vector3D vec = getCenterPointGlobal(compChild); vecSum.addLocal(vec); //massSum += compChild.getMass(); } } return vecSum.getScaled(1.f/children.length); } } }