Beispiel #1
0
SoPickedPoint* ViewProvider::getPointOnRay(const SbVec2s& pos, const View3DInventorViewer* viewer) const
{
    //first get the path to this node and calculate the current transformation
    SoSearchAction sa;
    sa.setNode(pcRoot);
    sa.setSearchingAll(true);
    sa.apply(viewer->getSoRenderManager()->getSceneGraph());
    if (!sa.getPath())
        return nullptr;
    SoGetMatrixAction gm(viewer->getSoRenderManager()->getViewportRegion());
    gm.apply(sa.getPath());

    SoTransform* trans = new SoTransform;
    trans->setMatrix(gm.getMatrix());
    trans->ref();
    
    // build a temporary scenegraph only keeping this viewproviders nodes and the accumulated 
    // transformation
    SoSeparator* root = new SoSeparator;
    root->ref();
    root->addChild(viewer->getSoRenderManager()->getCamera());
    root->addChild(trans);
    root->addChild(pcRoot);

    //get the picked point
    SoRayPickAction rp(viewer->getSoRenderManager()->getViewportRegion());
    rp.setPoint(pos);
    rp.setRadius(viewer->getPickRadius());
    rp.apply(root);
    root->unref();
    trans->unref();

    SoPickedPoint* pick = rp.getPickedPoint();
    return (pick ? new SoPickedPoint(*pick) : 0);
}
Beispiel #2
0
void
IfWeeder::weedMaterial(SoNode *root, IfWeederMaterialEntry *entry)
{
    // If the material affects no shapes at all, get rid of it. This
    // can happen when vertex property nodes are used.
    if (entry->shapes.getLength() == 0) {
	SoSearchAction sa;
	sa.setNode(entry->material);
	sa.setInterest(SoSearchAction::ALL);
	sa.apply(root);
	for (int i = 0; i < sa.getPaths().getLength(); i++) {
	    SoPath *path = sa.getPaths()[i];
	    SoSeparator *parent = (SoSeparator *) path->getNodeFromTail(1);
	    int index = path->getIndexFromTail(0);
	    ASSERT(parent->isOfType(SoSeparator::getClassTypeId()));
	    ASSERT(parent->getChild(index) == entry->material);
	    parent->removeChild(index);
	}
    }

    // Remove all material values from the material node that are
    // not used by any dependent shapes. Adjust the indices in the
    // dependent shapes accordingly.
    removeDuplicateMaterials(entry);

    // Now remove all material values that are not used by any
    // dependent shapes. Again, adjust the indices in the dependent
    // shapes.
    removeUnusedMaterials(entry);
}
Beispiel #3
0
bool Item::ContainsIvNode(SoNode *pNode)
{
    SoSearchAction search;
    search.setNode(pNode);
    search.apply(_ivGeom);

    if (search.getPath())
        return true;

    return false;
}
Beispiel #4
0
SoPath* TSceneKit::GetSoPath(SoNode * theNode )
{
	TSeparatorKit* sunNode = static_cast< TSeparatorKit* > (getPart( "childList[0]", false ) );
	if( !sunNode )	return NULL;

	TSeparatorKit* rootNode = static_cast< TSeparatorKit* > ( sunNode->getPart( "childList[0]", false ) );
	if( !rootNode )	return NULL;

	SoSearchAction* coinSearch = new SoSearchAction();
	coinSearch->setNode( theNode );
	coinSearch->setInterest( SoSearchAction::FIRST );
	coinSearch->apply( rootNode );
	SoPath* nodePath = coinSearch->getPath( );
	return nodePath;
}
Beispiel #5
0
void IvDragger::_GetMatrix(SbMatrix &matrix, SoNode *root, SoNode *node)
{
    SoGetMatrixAction getXform(_viewer.lock()->GetViewer()->getViewportRegion());

    // get a path from the root to the node

    SoSearchAction mySearchAction;
    mySearchAction.setNode(node);
    mySearchAction.setInterest(SoSearchAction::FIRST);
    mySearchAction.apply(root);

    // get the transformation matrix

    getXform.apply(mySearchAction.getPath());
    matrix = getXform.getMatrix();
}
Beispiel #6
0
SbMatrix ManipWidget::localToParentMatrix(SoNode *local)
{
	SoNode *localRoot = local ? local : this->root;
	SoSearchAction sa;
	sa.setNode(localRoot);
	sa.setInterest(SoSearchAction::FIRST);
	sa.apply(inst->getPostCumulativeRoot());

	SoPath *p = sa.getPath();
	if (p) {
		SoGetMatrixAction gma(viewer->getViewportRegion());
		gma.apply(p);
		return gma.getMatrix();
	} else {
		throw "ManipWidget::localToParentMatrix -- no path found?";
	}
}
Beispiel #7
0
			void
			Shape::getTransform(::rl::math::Transform& transform)
			{
				SoSearchAction searchAction;
				searchAction.setNode(this->shape);
				searchAction.apply(this->root);
				
				SbViewportRegion viewportRegion;
				SoGetMatrixAction getMatrixAction(viewportRegion);
				getMatrixAction.apply(searchAction.getPath());
				SbMatrix matrix = getMatrixAction.getMatrix();
				
				for (int i = 0; i < 4; ++i)
				{
					for (int j = 0; j < 4; ++j)
					{
						transform(i, j) = matrix[j][i];
					}
				}
			}
Beispiel #8
0
SoPickedPoint* ViewProvider::getPointOnRay(const SbVec3f& pos,const SbVec3f& dir, const View3DInventorViewer* viewer) const
{
    // Note: There seems to be a  bug with setRay() which causes SoRayPickAction
    // to fail to get intersections between the ray and a line
    
    //first get the path to this node and calculate the current setTransformation
    SoSearchAction sa;
    sa.setNode(pcRoot);
    sa.setSearchingAll(true);
    sa.apply(viewer->getSoRenderManager()->getSceneGraph());
    SoGetMatrixAction gm(viewer->getSoRenderManager()->getViewportRegion());
    gm.apply(sa.getPath());
    
    // build a temporary scenegraph only keeping this viewproviders nodes and the accumulated 
    // transformation
    SoTransform* trans = new SoTransform;
    trans->ref();
    trans->setMatrix(gm.getMatrix());
    
    SoSeparator* root = new SoSeparator;
    root->ref();
    root->addChild(viewer->getSoRenderManager()->getCamera());
    root->addChild(trans);
    root->addChild(pcRoot);
    
    //get the picked point
    SoRayPickAction rp(viewer->getSoRenderManager()->getViewportRegion());
    rp.setRay(pos,dir);
    rp.setRadius(viewer->getPickRadius());
    rp.apply(root);
    root->unref();
    trans->unref();

    // returns a copy of the point
    SoPickedPoint* pick = rp.getPickedPoint();
    //return (pick ? pick->copy() : 0); // needs the same instance of CRT under MS Windows
    return (pick ? new SoPickedPoint(*pick) : 0);
}
bool ViewProviderMirror::setEdit(int ModNum)
{
    if (ModNum == ViewProvider::Default) {
        // get the properties from the mirror feature
        Part::Mirroring* mf = static_cast<Part::Mirroring*>(getObject());
        Base::BoundBox3d bbox = mf->Shape.getBoundingBox();
        float len = (float)bbox.CalcDiagonalLength();
        Base::Vector3d base = mf->Base.getValue();
        Base::Vector3d norm = mf->Normal.getValue();
        Base::Vector3d cent = bbox.GetCenter();
        base = cent.ProjToPlane(base, norm);

        // setup the graph for editing the mirror plane
        SoTransform* trans = new SoTransform;
        SbRotation rot(SbVec3f(0,0,1), SbVec3f(norm.x,norm.y,norm.z));
        trans->rotation.setValue(rot);
        trans->translation.setValue(base.x,base.y,base.z);
        trans->center.setValue(0.0f,0.0f,0.0f);

        SoMaterial* color = new SoMaterial();
        color->diffuseColor.setValue(0,0,1);
        color->transparency.setValue(0.5);
        SoCoordinate3* points = new SoCoordinate3();
        points->point.setNum(4);
        points->point.set1Value(0, -len/2,-len/2,0);
        points->point.set1Value(1,  len/2,-len/2,0);
        points->point.set1Value(2,  len/2, len/2,0);
        points->point.set1Value(3, -len/2, len/2,0);
        SoFaceSet* face = new SoFaceSet();
        pcEditNode->addChild(trans);
        pcEditNode->addChild(color);
        pcEditNode->addChild(points);
        pcEditNode->addChild(face);

        // Now we replace the SoTransform node by a manipulator
        // Note: Even SoCenterballManip inherits from SoTransform
        // we cannot use it directly (in above code) because the
        // translation and center fields are overridden.
        SoSearchAction sa;
        sa.setInterest(SoSearchAction::FIRST);
        sa.setSearchingAll(FALSE);
        sa.setNode(trans);
        sa.apply(pcEditNode);
        SoPath * path = sa.getPath();
        if (path) {
            SoCenterballManip * manip = new SoCenterballManip;
            manip->replaceNode(path);

            SoDragger* dragger = manip->getDragger();
            dragger->addStartCallback(dragStartCallback, this);
            dragger->addFinishCallback(dragFinishCallback, this);
            dragger->addMotionCallback(dragMotionCallback, this);
        }
        pcRoot->addChild(pcEditNode);
    }
    else {
        ViewProviderPart::setEdit(ModNum);
    }

    return true;
}
// doc from parent
void
SoFCUnifiedSelection::handleEvent(SoHandleEventAction * action)
{
    // If off then don't handle this event
    if (!selectionRole.getValue()) {
        inherited::handleEvent(action);
        return;
    }

    static char buf[513];
    HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
    const SoEvent * event = action->getEvent();

    // If we don't need to pick for locate highlighting,
    // then just behave as separator and return.
    // NOTE: we still have to pick for ON even though we don't have
    // to re-render, because the app needs to be notified as the mouse
    // goes over locate highlight nodes.
    //if (highlightMode.getValue() == OFF) {
    //    inherited::handleEvent( action );
    //    return;
    //}

    
    //
    // If this is a mouseMotion event, then check for locate highlighting
    //
    if (event->isOfType(SoLocation2Event::getClassTypeId())) {
        // NOTE: If preselection is off then we do not check for a picked point because otherwise this search may slow
        // down extremely the system on really big data sets. In this case we just check for a picked point if the data
        // set has been selected.
        if (mymode == AUTO || mymode == ON) {
            // check to see if the mouse is over our geometry...
            const SoPickedPoint * pp = this->getPickedPoint(action);
            SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL;
            ViewProvider *vp = 0;
            ViewProviderDocumentObject* vpd = 0;
            if (pPath && pPath->containsPath(action->getCurPath()))
                vp = viewer->getViewProviderByPathFromTail(pPath);
            if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
                vpd = static_cast<ViewProviderDocumentObject*>(vp);

            SbBool old_state = highlighted;
            highlighted = FALSE;
            if (vpd && vpd->useNewSelectionModel() && vpd->isSelectable()) {
                std::string documentName = vpd->getObject()->getDocument()->getName();
                std::string objectName = vpd->getObject()->getNameInDocument();
                std::string subElementName = vpd->getElement(pp ? pp->getDetail() : 0);

                static char buf[513];
                snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",documentName.c_str()
                                           ,objectName.c_str()
                                           ,subElementName.c_str()
                                           ,pp->getPoint()[0]
                                           ,pp->getPoint()[1]
                                           ,pp->getPoint()[2]);

                getMainWindow()->showMessage(QString::fromAscii(buf),3000);

                if (Gui::Selection().setPreselect(documentName.c_str()
                                       ,objectName.c_str()
                                       ,subElementName.c_str()
                                       ,pp->getPoint()[0]
                                       ,pp->getPoint()[1]
                                       ,pp->getPoint()[2])){

                    SoSearchAction sa;
                    sa.setNode(vp->getRoot());
                    sa.apply(vp->getRoot());
                    if (sa.getPath()) {
                        highlighted = TRUE;
                        if (currenthighlight && currenthighlight->getTail() != sa.getPath()->getTail()) {
                            SoHighlightElementAction action;
                            action.setHighlighted(FALSE);
                            action.apply(currenthighlight);
                            currenthighlight->unref();
                            currenthighlight = 0;
                            old_state = !highlighted;
                        }

                        currenthighlight = static_cast<SoFullPath*>(sa.getPath()->copy());
                        currenthighlight->ref();
                    }
                }
            }

            if (currenthighlight/* && old_state != highlighted*/) {
                SoHighlightElementAction action;
                action.setHighlighted(highlighted);
                action.setColor(this->colorHighlight.getValue());
                action.setElement(pp ? pp->getDetail() : 0);
                action.apply(currenthighlight);
                if (!highlighted) {
                    currenthighlight->unref();
                    currenthighlight = 0;
                }
                this->touch();
            }
        }
    }
    // key press events
    else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) {
        SoKeyboardEvent  * const e = (SoKeyboardEvent  *) event;
        if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT)     ||
            SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT)     )
            bShift = true;
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT)   ||
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT)   )
            bShift = false;
        if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL)   ||
            SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL)   )
            bCtrl = true;
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
            bCtrl = false;
    }
    // mouse press events for (de)selection
    else if (event->isOfType(SoMouseButtonEvent::getClassTypeId()) && 
             selectionMode.getValue() == SoFCUnifiedSelection::ON) {
        const SoMouseButtonEvent* e = static_cast<const SoMouseButtonEvent *>(event);
        if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
            // check to see if the mouse is over a geometry...
            const SoPickedPoint * pp = this->getPickedPoint(action);
            SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL;
            ViewProvider *vp = 0;
            ViewProviderDocumentObject* vpd = 0;
            if (pPath && pPath->containsPath(action->getCurPath()))
                vp = viewer->getViewProviderByPathFromTail(pPath);
            if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
                vpd = static_cast<ViewProviderDocumentObject*>(vp);
            if (vpd && vpd->useNewSelectionModel() && vpd->isSelectable()) {
                SoSelectionElementAction::Type type = SoSelectionElementAction::None;
                std::string documentName = vpd->getObject()->getDocument()->getName();
                std::string objectName = vpd->getObject()->getNameInDocument();
                std::string subElementName = vpd->getElement(pp ? pp->getDetail() : 0);
                if (bCtrl) {
                    if (Gui::Selection().isSelected(documentName.c_str()
                                         ,objectName.c_str()
                                         ,subElementName.c_str())) {
                        Gui::Selection().rmvSelection(documentName.c_str()
                                          ,objectName.c_str()
                                          ,subElementName.c_str());
                        type = SoSelectionElementAction::Remove;
                    }
                    else {
                        bool ok = Gui::Selection().addSelection(documentName.c_str()
                                          ,objectName.c_str()
                                          ,subElementName.c_str()
                                          ,pp->getPoint()[0]
                                          ,pp->getPoint()[1]
                                          ,pp->getPoint()[2]);
                        if (ok)
                            type = SoSelectionElementAction::Append;
                        if (mymode == OFF) {
                            snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.c_str()
                                                       ,objectName.c_str()
                                                       ,subElementName.c_str()
                                                       ,pp->getPoint()[0]
                                                       ,pp->getPoint()[1]
                                                       ,pp->getPoint()[2]);

                            getMainWindow()->showMessage(QString::fromAscii(buf),3000);
                        }
                    }
                }
                else { // Ctrl
                    if (!Gui::Selection().isSelected(documentName.c_str()
                                         ,objectName.c_str()
                                         ,subElementName.c_str())) {
                        Gui::Selection().clearSelection(documentName.c_str());
                        bool ok = Gui::Selection().addSelection(documentName.c_str()
                                              ,objectName.c_str()
                                              ,subElementName.c_str()
                                              ,pp->getPoint()[0]
                                              ,pp->getPoint()[1]
                                              ,pp->getPoint()[2]);
                        if (ok)
                            type = SoSelectionElementAction::Append;
                    }
                    else {
                        Gui::Selection().clearSelection(documentName.c_str());
                        bool ok = Gui::Selection().addSelection(documentName.c_str()
                                              ,objectName.c_str()
                                              ,0
                                              ,pp->getPoint()[0]
                                              ,pp->getPoint()[1]
                                              ,pp->getPoint()[2]);
                        if (ok)
                            type = SoSelectionElementAction::All;
                    }

                    if (mymode == OFF) {
                        snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.c_str()
                                                   ,objectName.c_str()
                                                   ,subElementName.c_str()
                                                   ,pp->getPoint()[0]
                                                   ,pp->getPoint()[1]
                                                   ,pp->getPoint()[2]);

                        getMainWindow()->showMessage(QString::fromAscii(buf),3000);
                    }
                }

                action->setHandled(); 
                if (currenthighlight) {
                    SoSelectionElementAction action(type);
                    action.setColor(this->colorSelection.getValue());
                    action.setElement(pp ? pp->getDetail() : 0);
                    action.apply(currenthighlight);
                    this->touch();
                }
            } // picked point
        } // mouse release
    }

    inherited::handleEvent(action);
}
Beispiel #11
0
		void
		Scene::load(const ::std::string& filename, const bool& doBoundingBoxPoints, const bool& doPoints)
		{
			::rl::xml::DomParser parser;
			
			::rl::xml::Document doc = parser.readFile(filename, "", XML_PARSE_NOENT | XML_PARSE_XINCLUDE);
			
			doc.substitute(XML_PARSE_NOENT | XML_PARSE_XINCLUDE);
			
			::rl::xml::Path path(doc);
			
			::rl::xml::Object scenes = path.eval("//scene");
			
			for (int i = 0; i < ::std::min(1, scenes.getNodeNr()); ++i)
			{
				SoInput input;
				
				if (!input.openFile(scenes.getNodeTab(i).getLocalPath(scenes.getNodeTab(i).getAttribute("href").getValue()).c_str() ,true))
				{
					throw Exception("::rl::sg::Scene::load() - failed to open file");
				}
				
				SoVRMLGroup* root = SoDB::readAllVRML(&input);
				
				if (NULL == root)
				{
					throw Exception("::rl::sg::Scene::load() - failed to read file");
				}
				
				SbViewportRegion viewportRegion;
				
				root->ref();
				
				// model
				
				::rl::xml::Object models = path.eval("model", scenes.getNodeTab(i));
				
				for (int j = 0; j < models.getNodeNr(); ++j)
				{
					SoSearchAction modelSearchAction;
					modelSearchAction.setName(models.getNodeTab(j).getAttribute("name").getValue().c_str());
					modelSearchAction.apply(root);
					
					if (NULL == modelSearchAction.getPath())
					{
						continue;
					}
					
					Model* model = this->create();
					
					model->setName(models.getNodeTab(j).getAttribute("name").getValue());
					
					// body
					
					::rl::xml::Object bodies = path.eval("body", models.getNodeTab(j));
					
					for (int k = 0; k < bodies.getNodeNr(); ++k)
					{
						SoSearchAction bodySearchAction;
						bodySearchAction.setName(bodies.getNodeTab(k).getAttribute("name").getValue().c_str());
						bodySearchAction.apply(static_cast< SoFullPath* >(modelSearchAction.getPath())->getTail());
						
						if (NULL == bodySearchAction.getPath())
						{
							continue;
						}
						
						Body* body = model->create();
						
						body->setName(bodies.getNodeTab(k).getAttribute("name").getValue());
						
						SoSearchAction pathSearchAction;
						pathSearchAction.setNode(static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail());
						pathSearchAction.apply(root);
						
						SoGetMatrixAction bodyGetMatrixAction(viewportRegion);
						bodyGetMatrixAction.apply(static_cast< SoFullPath* >(pathSearchAction.getPath()));
						SbMatrix bodyMatrix = bodyGetMatrixAction.getMatrix();
						
						if (!this->isScalingSupported)
						{
							SbVec3f bodyTranslation;
							SbRotation bodyRotation;
							SbVec3f bodyScaleFactor;
							SbRotation bodyScaleOrientation;
							SbVec3f bodyCenter;
							bodyMatrix.getTransform(bodyTranslation, bodyRotation, bodyScaleFactor, bodyScaleOrientation, bodyCenter);
							
							for (int l = 0; l < 3; ++l)
							{
								if (::std::abs(bodyScaleFactor[l] - 1.0f) > 1.0e-6f)
								{
									throw Exception("::rl::sg::Scene::load() - bodyScaleFactor not supported");
								}
							}
						}
						
						::rl::math::Transform frame;
						
						for (int m = 0; m < 4; ++m)
						{
							for (int n = 0; n < 4; ++n)
							{
								frame(m, n) = bodyMatrix[n][m];
							}
						}
						
						body->setFrame(frame);
						
						if (static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail()->isOfType(SoVRMLTransform::getClassTypeId()))
						{
							SoVRMLTransform* bodyVrmlTransform = static_cast< SoVRMLTransform* >(static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail());
							
							for (int l = 0; l < 3; ++l)
							{
								body->center(l) = bodyVrmlTransform->center.getValue()[l];
							}
						}
						
						SoPathList pathList;
						
						// shape
						
						SoSearchAction shapeSearchAction;
						shapeSearchAction.setInterest(SoSearchAction::ALL);
						shapeSearchAction.setType(SoVRMLShape::getClassTypeId());
						shapeSearchAction.apply(static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail());
						
						for (int l = 0; l < shapeSearchAction.getPaths().getLength(); ++l)
						{
							SoFullPath* path = static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l]);
							
							if (path->getLength() > 1)
							{
								path = static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l]->copy(1, static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l])->getLength() - 1));
							}
							
							pathList.append(path);
							
							SoGetMatrixAction shapeGetMatrixAction(viewportRegion);
							shapeGetMatrixAction.apply(path);
							SbMatrix shapeMatrix = shapeGetMatrixAction.getMatrix();
							
							if (!this->isScalingSupported)
							{
								SbVec3f shapeTranslation;
								SbRotation shapeRotation;
								SbVec3f shapeScaleFactor;
								SbRotation shapeScaleOrientation;
								SbVec3f shapeCenter;
								shapeMatrix.getTransform(shapeTranslation, shapeRotation, shapeScaleFactor, shapeScaleOrientation, shapeCenter);
								
								for (int m = 0; m < 3; ++m)
								{
									if (::std::abs(shapeScaleFactor[m] - 1.0f) > 1.0e-6f)
									{
										throw Exception("::rl::sg::Scene::load() - shapeScaleFactor not supported");
									}
								}
							}
							
							SoVRMLShape* shapeVrmlShape = static_cast< SoVRMLShape* >(static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l])->getTail());
							
							Shape* shape = body->create(shapeVrmlShape);
							
							shape->setName(shapeVrmlShape->getName().getString());
							
							::rl::math::Transform transform;
							
							for (int m = 0; m < 4; ++m)
							{
								for (int n = 0; n < 4; ++n)
								{
									transform(m, n) = shapeMatrix[n][m];
								}
							}
							
							shape->setTransform(transform);
						}
						
						// bounding box
						
						if (doBoundingBoxPoints)
						{
							SoGetBoundingBoxAction getBoundingBoxAction(viewportRegion);
							getBoundingBoxAction.apply(pathList);
							SbBox3f boundingBox = getBoundingBoxAction.getBoundingBox();
							
							for (int l = 0; l < 3; ++l)
							{
								body->max(l) = boundingBox.getMax()[l];
								body->min(l) = boundingBox.getMin()[l];
							}
						}
						
						// convex hull
						
						if (doPoints)
						{
							SoCallbackAction callbackAction;
							callbackAction.addTriangleCallback(SoVRMLGeometry::getClassTypeId(), Scene::triangleCallback, &body->points);
							callbackAction.apply(pathList);
						}
					}
				}
				
				root->unref();
			}
		}
    virtual void apply(SoNode* node)
    {
        if (!headlightRot) {
            SoSearchAction sa;
            sa.setNode(viewer->getHeadlight());
            sa.apply(viewer->getSceneRoot());
            SoFullPath* fullPath = (SoFullPath*) sa.getPath();
            if (fullPath) {
                SoGroup *group = (SoGroup*) fullPath->getNodeFromTail(1);
                headlightRot = (SoRotation*) group->getChild(0);
                if (!headlightRot->isOfType(SoRotation::getClassTypeId()))
                    headlightRot = 0;
            }
        }

        const SbViewportRegion vpr = getViewportRegion();
        const SbVec2s & size = vpr.getViewportSizePixels();

        const int width = size[0];
        const int height = size[1];

        const int vpsize = width / 2;

        SoCamera * camera = viewer->getCamera();

        const SbVec3f position = camera->position.getValue();
        const SbRotation orientation = camera->orientation.getValue();
        const float nearplane = camera->nearDistance.getValue();
        const float farplane = camera->farDistance.getValue();

        camera->enableNotify(false);

        // Front View
        rotateCamera(SbRotation(SbVec3f(0,0,1), M_PI));

        SbViewportRegion vp;
        vp.setViewportPixels(SbVec2s(0, height-width/2), SbVec2s(width, width/2) );
        setViewportRegion(vp);

        SoGLRenderAction::apply(node);

        // Left View
        SbRotation r1(SbVec3f(0,0,1), -M_PI/2);

        rotateCamera(r1*SbRotation(SbVec3f(0,1,0), -M_PI/2));
        
        vp.setViewportPixels(SbVec2s(0, height-width), SbVec2s(width/2, width) );
        setViewportRegion(vp);

        SoGLRenderAction::apply(node);

        // Right View
        rotateCamera(SbRotation(SbVec3f(0,1,0), -M_PI));

        vp.setViewportPixels(SbVec2s(width/2, height-width), SbVec2s(width/2, width) );
        setViewportRegion(vp);

        SoGLRenderAction::apply(node);

        setViewportRegion(vpr);

        camera->position = position;
        camera->orientation = orientation;
        camera->enableNotify(true);

        // Restore original viewport region
        setViewportRegion(vpr);
    }