// compute object space ray and test for intersection static SbBool ray_intersect(SoRayPickAction * action, const SbBox3f & box) { if (box.isEmpty()) return FALSE; action->setObjectSpace(); return action->intersect(box, TRUE); }
void rotateCamera(const SbRotation &rot) { SoCamera * camera = viewer->getCamera(); // get center of rotation const float radius = camera->focalDistance.getValue(); SbVec3f forward; camera->orientation.getValue().multVec(SbVec3f(0,0,-1), forward); const SbVec3f center = camera->position.getValue() + radius * forward; // apply new rotation to the camera camera->orientation = rot * camera->orientation.getValue(); // reposition camera to look at pt of interest camera->orientation.getValue().multVec(SbVec3f(0,0,-1), forward); camera->position = center - radius * forward; headlightRot->rotation = camera->orientation.getValue(); // Adjust clipping planes SoGetBoundingBoxAction clipbox_action(getViewportRegion()); clipbox_action.apply(viewer->getSceneRoot()); SbBox3f bbox = clipbox_action.getBoundingBox(); if (bbox.isEmpty()) return; SbSphere bSphere; bSphere.circumscribe(bbox); float denumerator = forward.length(); float numerator = (bSphere.getCenter() - camera->position.getValue()).dot(forward); float distToCenter = (forward * (numerator / denumerator)).length(); float farplane = distToCenter + bSphere.getRadius(); // if scene is behind the camera, don't change the planes if (farplane < 0) return; float nearplane = distToCenter - bSphere.getRadius(); if (nearplane < (0.001 * farplane)) nearplane = 0.001 * farplane; camera->nearDistance = nearplane; camera->farDistance = farplane; }
// Doc in superclass. void SoOrthographicCamera::viewBoundingBox(const SbBox3f & box, float aspect, float slack) { #if COIN_DEBUG if (box.isEmpty()) { SoDebugError::postWarning("SoOrthographicCamera::viewBoundingBox", "bounding box empty"); return; } #endif // COIN_DEBUG // Get the radius of the bounding sphere. SbSphere bs; bs.circumscribe(box); float radius = bs.getRadius(); // We want to move the camera in such a way that it is pointing // straight at the center of the scene bounding box -- but without // modifiying the rotation value (so we can't use SoCamera::pointAt()), // and positioned at the edge of the bounding sphere. SbVec3f cameradirection; this->orientation.getValue().multVec(SbVec3f(0, 0, -1), cameradirection); this->position.setValue(box.getCenter() + cameradirection * -radius); // Set up the clipping planes tangent to the bounding sphere of the scene. this->nearDistance = radius * ( -slack + 1); this->farDistance = radius * ( slack + 1); // The focal distance is simply the distance from the camera to the // scene midpoint. This field is not used in rendering, its just // provided to make it easier for the user to do calculations based // on the distance between the camera and the scene. this->focalDistance = radius; // Make sure that everything will still be inside the viewing volume // even if the aspect ratio "favorizes" width over height, and take the // slack factor into account. if (aspect < 1.0f) this->height = 2 * radius / aspect; else this->height = 2 * radius; }
void Command::adjustCameraPosition() { Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(doc->getActiveView()); Gui::View3DInventorViewer* viewer = view->getViewer(); SoCamera* camera = viewer->getSoRenderManager()->getCamera(); if (!camera || !camera->isOfType(SoOrthographicCamera::getClassTypeId())) return; // get scene bounding box SoGetBoundingBoxAction action(viewer->getSoRenderManager()->getViewportRegion()); action.apply(viewer->getSceneGraph()); SbBox3f box = action.getBoundingBox(); if (box.isEmpty()) return; // get cirumscribing sphere and check if camera is inside SbVec3f cam_pos = camera->position.getValue(); SbVec3f box_cnt = box.getCenter(); SbSphere bs; bs.circumscribe(box); float radius = bs.getRadius(); float distance_to_midpoint = (box_cnt-cam_pos).length(); if (radius >= distance_to_midpoint) { // Move the camera to the edge of the bounding sphere, while still // pointing at the scene. SbVec3f direction = cam_pos - box_cnt; (void) direction.normalize(); // we know this is not a null vector camera->position.setValue(box_cnt + direction * radius); // New distance to mid point distance_to_midpoint = (camera->position.getValue() - box.getCenter()).length(); camera->nearDistance = distance_to_midpoint - radius; camera->farDistance = distance_to_midpoint + radius; camera->focalDistance = distance_to_midpoint; } } }
/// Override original method since it seems to adjust the clipping planes in a weird manner. /// Maybe using a screen-space projection or whatever. virtual void adjustCameraClippingPlanes() { SoCamera * camera = getCamera(); if (!camera) return; SoGetBoundingBoxAction clipbox_action(getViewportRegion()); clipbox_action.apply(getSceneRoot()); SbBox3f bbox = clipbox_action.getBoundingBox(); if (bbox.isEmpty()) return; SbSphere bSphere; bSphere.circumscribe(bbox); SbVec3f forward; camera->orientation.getValue().multVec(SbVec3f(0,0,-1), forward); float denumerator = forward.length(); float numerator = (bSphere.getCenter() - camera->position.getValue()).dot(forward); float distToCenter = (forward * (numerator / denumerator)).length(); float farplane = distToCenter + bSphere.getRadius(); // if scene is behind the camera, don't change the planes if (farplane < 0) return; float nearplane = distToCenter - bSphere.getRadius(); if (nearplane < (0.001 * farplane)) nearplane = 0.001 * farplane; camera->nearDistance = nearplane; camera->farDistance = farplane; }
void SoSurroundScale::updateMySurroundParams(SoAction *action, const SbMatrix &myInv ) // //////////////////////////////////////////////////////////////////////// { const SoFullPath *curPath = (const SoFullPath *) action->getCurPath(); int curPathLength = curPath->getLength(); // If the container node is out of range, just return. int numUpCon = (int) numNodesUpToContainer.getValue(); if ( (numUpCon <= 0) || (numUpCon > (curPathLength - 1)) ){ cachedScale.setValue(1,1,1); cachedInvScale.setValue(1,1,1); cachedTranslation.setValue(0,0,0); cacheOK = FALSE; return; } // CHECK TO SEE IF OUR CACHED VALUES ARE OKAY // IF SO, JUST RETURN if ( cacheOK ) return; // Find the path to apply the bounding box action to. It should end // 'numUpCon' above this one. SoPath *applyPath = curPath->copy(0, (curPathLength - numUpCon)); applyPath->ref(); // See if there is a node to do a reset at. If so, build a resetPath SoPath *resetPath = NULL; int numUpReset = (int) numNodesUpToReset.getValue(); if (numUpReset >= 0 && (numUpReset < numUpCon) ) { // Build a path ending at the reset node. resetPath = curPath->copy(0, curPathLength - numUpReset ); resetPath->ref(); } SoFullPath *fullResetPath = (SoFullPath *) resetPath; // Create a getBoundingBox action // Set the reset path if we have one. // Apply the bounding box action and find out how big the box was. // Temporarily set the ignoreInBbox flag TRUE, so we don't infinite loop! SbViewportRegion vpRegion(0,0); SoState *state = action->getState(); vpRegion = SoViewportRegionElement::get(state); static SoGetBoundingBoxAction *boundingBoxAction = NULL; if (boundingBoxAction == NULL) boundingBoxAction = new SoGetBoundingBoxAction(vpRegion); else boundingBoxAction->setViewportRegion(vpRegion); if (fullResetPath) boundingBoxAction->setResetPath( fullResetPath, FALSE, SoGetBoundingBoxAction::BBOX); SbBool oldFlag = isIgnoreInBbox(); setIgnoreInBbox( TRUE ); boundingBoxAction->apply( applyPath ); setIgnoreInBbox( oldFlag ); SbXfBox3f &myXfBox = boundingBoxAction->getXfBoundingBox(); // Transform the box into our local space, then project it. myXfBox.transform( myInv ); SbBox3f myBox = myXfBox.project(); // Get the scale for this node to add to the ctm. if (myBox.isEmpty()) { cachedScale.setValue(1,1,1); cachedInvScale.setValue(1,1,1); cachedTranslation.setValue(0,0,0); cacheOK = TRUE; return; } else { float x, y, z; myBox.getSize(x,y,z); cachedScale.setValue( .5*x, .5*y, .5*z ); float minLength = .01 * cachedScale.length(); // Macro defined just before beginning of this method. FUDGE(cachedScale[0],minLength); FUDGE(cachedScale[1],minLength); FUDGE(cachedScale[2],minLength); // Find the inverse values for (int j = 0; j < 3; j++ ) cachedInvScale[j] = 1.0 / cachedScale[j]; } // Get the translation for this node to add to the ctm. // This will get the cube centered about the bbox center. // If the bounding box is not centered at the origin, we have to // move the cube to the correct place. if (doTranslations) cachedTranslation = 0.5 * ( myBox.getMin() + myBox.getMax() ); else cachedTranslation.setValue(0,0,0); // Establish the cached values to save us some time later... cacheOK = TRUE; if (resetPath) resetPath->unref(); if (applyPath) applyPath->unref(); }
/* * Fun flux analysis */ void FluxAnalysis::RunFluxAnalysis( QString nodeURL, QString surfaceSide, unsigned long nOfRays, bool increasePhotonMap, int heightDivisions, int widthDivisions ) { m_surfaceURL = nodeURL; m_surfaceSide = surfaceSide; //Delete a photonCounts if( m_photonCounts && m_photonCounts != 0 ) { for( int h = 0; h < m_heightDivisions; h++ ) { delete[] m_photonCounts[h]; } delete[] m_photonCounts; } m_photonCounts = 0; m_heightDivisions = heightDivisions; m_widthDivisions = widthDivisions; //Check if there is a scene if ( !m_pCurrentScene ) return; //Check if there is a transmissivity defined TTransmissivity* transmissivity = 0; if ( !m_pCurrentScene->getPart( "transmissivity", false ) ) transmissivity = 0; else transmissivity = static_cast< TTransmissivity* > ( m_pCurrentScene->getPart( "transmissivity", false ) ); //Check if there is a rootSeparator InstanceNode if( !m_pRootSeparatorInstance ) return; InstanceNode* sceneInstance = m_pRootSeparatorInstance->GetParent(); if ( !sceneInstance ) return; //Check if there is a light and is properly configured if ( !m_pCurrentScene->getPart( "lightList[0]", false ) )return; TLightKit* lightKit = static_cast< TLightKit* >( m_pCurrentScene->getPart( "lightList[0]", false ) ); InstanceNode* lightInstance = sceneInstance->children[0]; if ( !lightInstance ) return; if( !lightKit->getPart( "tsunshape", false ) ) return; TSunShape* sunShape = static_cast< TSunShape * >( lightKit->getPart( "tsunshape", false ) ); if( !lightKit->getPart( "icon", false ) ) return; TLightShape* raycastingSurface = static_cast< TLightShape * >( lightKit->getPart( "icon", false ) ); if( !lightKit->getPart( "transform" ,false ) ) return; SoTransform* lightTransform = static_cast< SoTransform * >( lightKit->getPart( "transform" ,false ) ); //Check if there is a random generator is defined. if( !m_pRandomDeviate || m_pRandomDeviate== 0 ) return; //Check if the surface and the surface side defined is suitable if( CheckSurface() == false || CheckSurfaceSide() == false ) return; //Create the photon map where photons are going to be stored if( !m_pPhotonMap || !increasePhotonMap ) { if( m_pPhotonMap ) m_pPhotonMap->EndStore( -1 ); delete m_pPhotonMap; m_pPhotonMap = new TPhotonMap(); m_pPhotonMap->SetBufferSize( HUGE_VAL ); m_tracedRays = 0; m_wPhoton = 0; m_totalPower = 0; } QVector< InstanceNode* > exportSuraceList; QModelIndex nodeIndex = m_pCurrentSceneModel->IndexFromNodeUrl( m_surfaceURL ); if( !nodeIndex.isValid() ) return; InstanceNode* surfaceNode = m_pCurrentSceneModel->NodeFromIndex( nodeIndex ); if( !surfaceNode || surfaceNode == 0 ) return; exportSuraceList.push_back( surfaceNode ); //UpdateLightSize(); TSeparatorKit* concentratorRoot = static_cast< TSeparatorKit* >( m_pCurrentScene->getPart( "childList[0]", false ) ); if ( !concentratorRoot ) return; SoGetBoundingBoxAction* bbAction = new SoGetBoundingBoxAction( SbViewportRegion() ) ; concentratorRoot->getBoundingBox( bbAction ); SbBox3f box = bbAction->getXfBoundingBox().project(); delete bbAction; bbAction = 0; BBox sceneBox; if( !box.isEmpty() ) { sceneBox.pMin = Point3D( box.getMin()[0], box.getMin()[1], box.getMin()[2] ); sceneBox.pMax = Point3D( box.getMax()[0], box.getMax()[1], box.getMax()[2] ); if( lightKit ) lightKit->Update( sceneBox ); } m_pCurrentSceneModel->UpdateSceneModel(); //Compute bounding boxes and world to object transforms trf::ComputeSceneTreeMap( m_pRootSeparatorInstance, Transform( new Matrix4x4 ), true ); m_pPhotonMap->SetConcentratorToWorld( m_pRootSeparatorInstance->GetIntersectionTransform() ); QStringList disabledNodes = QString( lightKit->disabledNodes.getValue().getString() ).split( ";", QString::SkipEmptyParts ); QVector< QPair< TShapeKit*, Transform > > surfacesList; trf::ComputeFistStageSurfaceList( m_pRootSeparatorInstance, disabledNodes, &surfacesList ); lightKit->ComputeLightSourceArea( m_sunWidthDivisions, m_sunHeightDivisions, surfacesList ); if( surfacesList.count() < 1 ) return; QVector< long > raysPerThread; int maximumValueProgressScale = 100; unsigned long t1 = nOfRays/ maximumValueProgressScale; for( int progressCount = 0; progressCount < maximumValueProgressScale; ++ progressCount ) raysPerThread<< t1; if( ( t1 * maximumValueProgressScale ) < nOfRays ) raysPerThread<< ( nOfRays - ( t1* maximumValueProgressScale) ); Transform lightToWorld = tgf::TransformFromSoTransform( lightTransform ); lightInstance->SetIntersectionTransform( lightToWorld.GetInverse() ); // Create a progress dialog. QProgressDialog dialog; dialog.setLabelText( QString("Progressing using %1 thread(s)..." ).arg( QThread::idealThreadCount() ) ); // Create a QFutureWatcher and conncect signals and slots. QFutureWatcher< void > futureWatcher; QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset())); QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel())); QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int, int)), &dialog, SLOT(setRange(int, int))); QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int))); QMutex mutex; QMutex mutexPhotonMap; QFuture< void > photonMap; if( transmissivity ) photonMap = QtConcurrent::map( raysPerThread, RayTracer( m_pRootSeparatorInstance, lightInstance, raycastingSurface, sunShape, lightToWorld, transmissivity, *m_pRandomDeviate, &mutex, m_pPhotonMap, &mutexPhotonMap, exportSuraceList ) ); else photonMap = QtConcurrent::map( raysPerThread, RayTracerNoTr( m_pRootSeparatorInstance, lightInstance, raycastingSurface, sunShape, lightToWorld, *m_pRandomDeviate, &mutex, m_pPhotonMap, &mutexPhotonMap, exportSuraceList ) ); futureWatcher.setFuture( photonMap ); // Display the dialog and start the event loop. dialog.exec(); futureWatcher.waitForFinished(); m_tracedRays += nOfRays; double irradiance = sunShape->GetIrradiance(); double inputAperture = raycastingSurface->GetValidArea(); m_wPhoton = double ( inputAperture * irradiance ) / m_tracedRays; UpdatePhotonCounts(); }