void GeometryCollisionParticleSystemAffector::affect(ParticleSystemRefPtr System, const Time& elps) { UInt32 NumParticles(System->getNumParticles()); Line ray; IntersectAction *iAct = IntersectAction::create(); Pnt3f ParticlePos, ParticleSecPos; Real32 HitT(0.0f); for(UInt32 i(0) ; i<NumParticles ; ++i) { ParticlePos = System->getPosition(i); ParticleSecPos = System->getSecPosition(i); ray.setValue(ParticleSecPos, ParticlePos); iAct->setLine(ray); iAct->apply(getCollisionNode()); if (iAct->didHit()) { HitT = iAct->getHitT(); if(HitT > 0.0f && HitT*HitT<ParticlePos.dist2(ParticleSecPos)) { produceParticleCollision(System, i, iAct); for(UInt32 j(0) ; j<getMFCollisionAffectors()->size(); ++j) { getCollisionAffectors(i)->affect(System,i,elps); } } } } }
/* virtual */ Action::ResultE KDTreeIntersectProxyAttachment::intersectEnter(Node *node, Action *action) { Action::ResultE res = Inherited::intersectEnter(node, action); IntersectAction *iact = boost::polymorphic_downcast<IntersectAction *>(action); Real32 closestHitT = iact->didHit() ? iact->getHitT() : iact->getMaxDist(); Vec3f hitNormal; UInt32 hitTriangle; if(_mfTreeNodes.empty() == false) { UInt32 numTris = 0; bool hit = intersectIntersectKDTree(iact->getLine(), node->getVolume(), _sfGeometry.getValue(), &_mfTreeNodes, &_mfTriIndices, closestHitT, hitNormal, hitTriangle, &numTris ); if(hit == true) { iact->setHit(closestHitT, node, hitTriangle, hitNormal, 0); } iact->getStatCollector()->getElem( IntersectAction::statNTriangles)->add(numTris); } else { // tree was empty - skip this proxy and use conventional // intersect res = Action::Continue; } return res; }
int main(int argc, char *argv[]) { osgLogP->setLogLevel(LOG_NOTICE); osgInit(argc, argv); int winid = setupGLUT(&argc, argv); // create a GLUT window GLUTWindowPtr gwin = GLUTWindow::create(); gwin->setId(winid); gwin->init(); osgLogP->setLogLevel(LOG_DEBUG); // build the test scene NodePtr pRoot = Node ::create(); GroupPtr pRootCore = Group::create(); NodePtr pRayGeo = Node ::create(); NodePtr pScene = buildGraph(); GroupPtr pSceneCore = Group::create(); Time tStart; Time tStop; Time tDFTotal = 0.0; Time tDFSTotal = 0.0; Time tPTotal = 0.0; Time tOTotal = 0.0; StatCollector statP; StatCollector statDF; StatCollector statDFS; beginEditCP(pRoot, Node::CoreFieldId | Node::ChildrenFieldId); pRoot->setCore (pRootCore ); pRoot->addChild(pScene ); pRoot->addChild(pRayGeo ); endEditCP (pRoot, Node::CoreFieldId | Node::ChildrenFieldId); createRays(uiNumRays, testRays); // build the geometry to visualize the rays pPoints = GeoPositions3f::create(); beginEditCP(pPoints); pPoints->addValue(Pnt3f(0.0, 0.0, 0.0)); pPoints->addValue(Pnt3f(0.0, 0.0, 0.0)); pPoints->addValue(Pnt3f(0.0, 0.0, 0.0)); pPoints->addValue(Pnt3f(0.0, 0.0, 0.0)); pPoints->addValue(Pnt3f(0.0, 0.0, 0.0)); endEditCP (pPoints); GeoIndicesUI32Ptr pIndices = GeoIndicesUI32::create(); beginEditCP(pIndices); pIndices->addValue(0); pIndices->addValue(1); pIndices->addValue(2); pIndices->addValue(3); pIndices->addValue(4); endEditCP (pIndices); GeoPLengthsPtr pLengths = GeoPLengthsUI32::create(); beginEditCP(pLengths); pLengths->addValue(2); pLengths->addValue(3); endEditCP (pLengths); GeoPTypesPtr pTypes = GeoPTypesUI8::create(); beginEditCP(pTypes); pTypes->addValue(GL_LINES ); pTypes->addValue(GL_TRIANGLES); endEditCP (pTypes); GeoColors3fPtr pColors = GeoColors3f::create(); beginEditCP(pColors); pColors->addValue(Color3f(1.0, 1.0, 1.0)); pColors->addValue(Color3f(1.0, 0.0, 0.0)); pColors->addValue(Color3f(1.0, 0.0, 0.0)); pColors->addValue(Color3f(1.0, 0.0, 0.0)); pColors->addValue(Color3f(1.0, 0.0, 0.0)); endEditCP (pColors); SimpleMaterialPtr pMaterial = SimpleMaterial::create(); beginEditCP(pMaterial); pMaterial->setLit(false); endEditCP (pMaterial); GeometryPtr pRayGeoCore = Geometry::create(); beginEditCP(pRayGeoCore); pRayGeoCore->setPositions(pPoints ); pRayGeoCore->setIndices (pIndices ); pRayGeoCore->setLengths (pLengths ); pRayGeoCore->setTypes (pTypes ); pRayGeoCore->setColors (pColors ); pRayGeoCore->setMaterial (pMaterial); endEditCP (pRayGeoCore); beginEditCP(pRayGeo, Node::CoreFieldId); pRayGeo->setCore(pRayGeoCore); endEditCP (pRayGeo, Node::CoreFieldId); IntersectActor::regDefaultClassEnter( osgTypedFunctionFunctor2CPtr< NewActionTypes::ResultE, NodeCorePtr, ActorBase::FunctorArgumentType & >(enterDefault)); NewActionBase *pDFAction = DepthFirstAction ::create(); NewActionBase *pDFSAction = DepthFirstStateAction::create(); NewActionBase *pPAction = PriorityAction ::create(); IntersectActor *pIActorDF = IntersectActor ::create(); IntersectActor *pIActorDFS = IntersectActor ::create(); IntersectActor *pIActorP = IntersectActor ::create(); pDFAction ->setStatistics(&statDF ); pDFSAction->setStatistics(&statDFS); pPAction ->setStatistics(&statP ); // IntersectActor with DFS-Action does not need leave calls pIActorDFS->setLeaveNodeFlag(false); pDFAction ->addActor(pIActorDF ); pDFSAction->addActor(pIActorDFS); pPAction ->addActor(pIActorP ); // create old action IntersectAction *pIntAction = IntersectAction ::create(); // make sure bv are up to date pScene->updateVolume(); SINFO << "-=< Intersect >=-" << endLog; std::vector<Line>::iterator itRays = testRays.begin(); std::vector<Line>::iterator endRays = testRays.end (); for(; itRays != endRays; ++itRays) { // DepthFirst tStart = getSystemTime(); pIActorDF->setRay (*itRays); pIActorDF->setMaxDistance(10000.0); pIActorDF->reset ( ); pDFAction->apply(pScene); tStop = getSystemTime(); tDFTotal += (tStop - tStart); if(pIActorDF->getHit() == true) { IntersectResult result; result._hit = true; result._pObj = pIActorDF->getHitObject (); result._tri = pIActorDF->getHitTriangleIndex(); result._dist = pIActorDF->getHitDistance (); result._time = (tStop - tStart); resultsDF.push_back(result); } else { IntersectResult result; result._hit = false; result._pObj = NullFC; result._tri = -1; result._dist = 0.0; result._time = (tStop - tStart); resultsDF.push_back(result); } std::string strStatDF; statDF.putToString(strStatDF); //SINFO << "stat DF: " << strStatDF << endLog; // Depth First State tStart = getSystemTime(); pIActorDFS->setRay (*itRays); pIActorDFS->setMaxDistance(10000.0); pIActorDFS->reset ( ); pDFSAction->apply(pScene); tStop = getSystemTime(); tDFSTotal += (tStop - tStart); if(pIActorDFS->getHit() == true) { IntersectResult result; result._hit = true; result._pObj = pIActorDFS->getHitObject (); result._tri = pIActorDFS->getHitTriangleIndex(); result._dist = pIActorDFS->getHitDistance (); result._time = (tStop - tStart); resultsDFS.push_back(result); } else { IntersectResult result; result._hit = false; result._pObj = NullFC; result._tri = -1; result._dist = 0.0; result._time = (tStop - tStart); resultsDFS.push_back(result); } std::string strStatDFS; statDFS.putToString(strStatDFS); //SINFO << "stat DFS: " << strStatDFS << endLog; // Priority tStart = getSystemTime(); pIActorP->setRay (*itRays); pIActorP->setMaxDistance(10000.0); pIActorP->reset ( ); pPAction->apply(pScene); tStop = getSystemTime(); tPTotal += (tStop - tStart); if(pIActorP->getHit() == true) { IntersectResult result; result._hit = true; result._pObj = pIActorP->getHitObject (); result._tri = pIActorP->getHitTriangleIndex(); result._dist = pIActorP->getHitDistance (); result._time = (tStop - tStart); resultsP.push_back(result); } else { IntersectResult result; result._hit = false; result._pObj = NullFC; result._tri = -1; result._dist = 0.0; result._time = (tStop - tStart); resultsP.push_back(result); } std::string strStatP; statP.putToString(strStatP); //SINFO << "stat P: " << strStatP << endLog; // Old tStart = getSystemTime(); pIntAction->setLine(*itRays, 100000); pIntAction->apply (pScene ); tStop = getSystemTime(); tOTotal += (tStop - tStart); if(pIntAction->didHit() == true) { IntersectResult result; result._hit = true; result._pObj = pIntAction->getHitObject (); result._tri = pIntAction->getHitTriangle(); result._dist = pIntAction->getHitT (); result._time = (tStop - tStart); resultsO.push_back(result); } else { IntersectResult result; result._hit = false; result._pObj = NullFC; result._tri = -1; result._dist = 0.0; result._time = (tStop - tStart); resultsO.push_back(result); } } UInt32 DFwins = 0; UInt32 DFwinsHit = 0; UInt32 DFwinsMiss = 0; UInt32 DFSwins = 0; UInt32 DFSwinsHit = 0; UInt32 DFSwinsMiss = 0; UInt32 Pwins = 0; UInt32 PwinsHit = 0; UInt32 PwinsMiss = 0; UInt32 Owins = 0; UInt32 OwinsHit = 0; UInt32 OwinsMiss = 0; UInt32 failCount = 0; UInt32 passCount = 0; UInt32 hitCount = 0; UInt32 missCount = 0; for(UInt32 i = 0; i < uiNumRays; ++i) { bool DFfastest = ((resultsDF [i]._time <= resultsDFS[i]._time) && (resultsDF [i]._time <= resultsP [i]._time) && (resultsDF [i]._time <= resultsO [i]._time) ); bool DFSfastest = ((resultsDFS[i]._time <= resultsDF [i]._time) && (resultsDFS[i]._time <= resultsP [i]._time) && (resultsDFS[i]._time <= resultsO [i]._time) ); bool Pfastest = ((resultsP [i]._time <= resultsDF [i]._time) && (resultsP [i]._time <= resultsDFS[i]._time) && (resultsP [i]._time <= resultsO [i]._time) ); bool Ofastest = ((resultsO [i]._time <= resultsDF [i]._time) && (resultsO [i]._time <= resultsDFS[i]._time) && (resultsO [i]._time <= resultsP [i]._time) ); if((resultsDF [i]._hit == resultsDFS[i]._hit) && (resultsDFS[i]._hit == resultsP [i]._hit) && (resultsP [i]._hit == resultsO [i]._hit) ) { if((osgabs(resultsDF [i]._dist - resultsDFS[i]._dist) >= 0.001) || (osgabs(resultsDFS[i]._dist - resultsP [i]._dist) >= 0.001) || (osgabs(resultsP [i]._dist - resultsO [i]._dist) >= 0.001) || (osgabs(resultsO [i]._dist - resultsDF [i]._dist) >= 0.001) ) { ++failCount; SINFO << "FAIL: df: " << resultsDF [i]._dist << " dfs: " << resultsDFS[i]._dist << " p: " << resultsP [i]._dist << " o: " << resultsO [i]._dist << endLog; SINFO << "FAIL: df: " << resultsDF [i]._tri << " dfs: " << resultsDFS[i]._tri << " p: " << resultsP [i]._tri << " o: " << resultsO [i]._tri << endLog; } else { ++passCount; } if(resultsDF[i]._hit == true) { ++hitCount; DFwinsHit = DFfastest ? DFwinsHit + 1 : DFwinsHit; DFSwinsHit = DFSfastest ? DFSwinsHit + 1 : DFSwinsHit; PwinsHit = Pfastest ? PwinsHit + 1 : PwinsHit; OwinsHit = Ofastest ? OwinsHit + 1 : OwinsHit; } else { ++missCount; DFwinsMiss = DFfastest ? DFwinsMiss + 1 : DFwinsMiss; DFSwinsMiss = DFSfastest ? DFSwinsMiss + 1 : DFSwinsMiss; PwinsMiss = Pfastest ? PwinsMiss + 1 : PwinsMiss; OwinsMiss = Ofastest ? OwinsMiss + 1 : OwinsMiss; } DFwins = DFfastest ? DFwins + 1 : DFwins; DFSwins = DFSfastest ? DFSwins + 1 : DFSwins; Pwins = Pfastest ? Pwins + 1 : Pwins; Owins = Ofastest ? Owins + 1 : Owins; } else { ++failCount; } //SINFO << i << " \t" << (DFfastest ? "D ->" : " ") << " hit: " << resultsDF [i]._hit << " time: " << resultsDF [i]._time << endLog; //SINFO << " \t" << (DFSfastest ? "S ->" : " ") << " hit: " << resultsDFS[i]._hit << " time: " << resultsDFS[i]._time << endLog; //SINFO << " \t" << (Pfastest ? "P ->" : " ") << " hit: " << resultsP [i]._hit << " time: " << resultsP [i]._time << endLog; //SINFO << " \t" << (Ofastest ? "O ->" : " ") << " hit: " << resultsO [i]._hit << " time: " << resultsO [i]._time << endLog; } SINFO << " df total: " << tDFTotal << (tDFTotal < tDFSTotal && tDFTotal < tPTotal && tDFTotal < tOTotal ? " *" : " ") << " wins: " << DFwins << " (" << (static_cast<Real32>(DFwins) / static_cast<Real32>(passCount)) * 100.0 << "%)\t" << " wins on hit: " << DFwinsHit << " (" << (static_cast<Real32>(DFwinsHit) / static_cast<Real32>(hitCount )) * 100.0 << "%)\t" << " wins on miss: " << DFwinsMiss << " (" << (static_cast<Real32>(DFwinsMiss) / static_cast<Real32>(missCount)) * 100.0 << "%)" << endLog; SINFO << " dfs total: " << tDFSTotal << (tDFSTotal < tDFTotal && tDFSTotal < tPTotal && tDFSTotal < tOTotal ? " *" : " ") << " wins: " << DFSwins << " (" << (static_cast<Real32>(DFSwins) / static_cast<Real32>(passCount)) * 100.0 << "%)\t" << " wins on hit: " << DFSwinsHit << " (" << (static_cast<Real32>(DFSwinsHit) / static_cast<Real32>(hitCount )) * 100.0 << "%)\t" << " wins on miss: " << DFSwinsMiss << " (" << (static_cast<Real32>(DFSwinsMiss) / static_cast<Real32>(missCount)) * 100.0 << "%)" << endLog; SINFO << " p total: " << tPTotal << (tPTotal < tDFTotal && tPTotal < tDFSTotal && tPTotal < tOTotal ? " *" : " ") << " wins: " << Pwins << " (" << (static_cast<Real32>(Pwins) / static_cast<Real32>(passCount)) * 100.0 << "%)\t" << " wins on hit: " << PwinsHit << " (" << (static_cast<Real32>(PwinsHit) / static_cast<Real32>(hitCount )) * 100.0 << "%)\t" << " wins on miss: " << PwinsMiss << " (" << (static_cast<Real32>(PwinsMiss) / static_cast<Real32>(missCount)) * 100.0 << "%)" << endLog; SINFO << " o total: " << tOTotal << (tOTotal < tDFTotal && tOTotal < tDFSTotal && tOTotal < tPTotal ? " *" : " ") << " wins: " << Owins << " (" << (static_cast<Real32>(Owins) / static_cast<Real32>(passCount)) * 100.0 << "%)\t" << " wins on hit: " << OwinsHit << " (" << (static_cast<Real32>(OwinsHit) / static_cast<Real32>(hitCount )) * 100.0 << "%)\t" << " wins on miss: " << OwinsMiss << " (" << (static_cast<Real32>(OwinsMiss) / static_cast<Real32>(missCount)) * 100.0 << "%)" << endLog; SINFO << "pass: "******" fail: " << failCount << " hit: " << hitCount << " miss: " << missCount << endLog; osgLogP->setLogLevel(LOG_NOTICE); #if 0 // create the SimpleSceneManager helper mgr = new SimpleSceneManager; // tell the manager what to manage mgr->setWindow(gwin ); mgr->setRoot (pRoot); // show the whole scene mgr->showAll(); // GLUT main loop glutMainLoop(); #endif return 0; }
void SpaceNavigatorSSM::mouseButtonPress(UInt16 button, Int16 x, Int16 y) { switch (button) { case MouseLeft: // test if an object is picked if(_objectPicking) { Line ray = calcViewRay(x, y); IntersectAction *iAct = IntersectAction::create(); iAct->setLine(ray); iAct->apply(this->getRoot()); // we have a hit if(iAct->didHit()) { _pickedObjectNode = iAct->getHitObject(); #ifdef SPACENAVIGATOR_DEBUG_OUTPUT std::cout << "SpaceNavigatorSSM: Object transformation mode active ( " << getName(_pickedObjectNode) << " )" << std::endl; #endif // SPACENAVIGATOR_DEBUG_OUTPUT // go up in the graph to the next transformation while(!_pickedObjectNode->getCore()->getType().isDerivedFrom(Transform::getClassType())) { if(_pickedObjectNode->getParent() != this->getRoot()) _pickedObjectNode = _pickedObjectNode->getParent(); else { // insert a new transformation node NodePtr pickedObject = iAct->getHitObject(); TransformPtr newTransform = Transform::create(); Matrix m; m.setIdentity(); beginEditCP(newTransform, Transform::MatrixFieldMask); newTransform->setMatrix(m); endEditCP(newTransform, Transform::MatrixFieldMask); NodePtr newTransformNode = Node::create(); beginEditCP(newTransformNode, Node::CoreFieldMask); newTransformNode->setCore(newTransform); endEditCP(newTransformNode, Node::CoreFieldMask); NodePtr pickedObjectParent = pickedObject->getParent(); // add reference because reCount would be 0 and then it will // be deleted addRefCP(pickedObject); beginEditCP(pickedObjectParent); pickedObjectParent->replaceChildBy(pickedObject, newTransformNode); endEditCP(pickedObjectParent); beginEditCP(newTransformNode); newTransformNode->addChild(pickedObject); endEditCP(newTransformNode); // sub the reference which was added before subRefCP(pickedObject); _pickedObjectNode = newTransformNode; } } // a transformation was found and the objects bounding box is showed this->setHighlight(_pickedObjectNode); } } _navigator.buttonPress(Navigator::LEFT_MOUSE,x,y); break; case MouseMiddle: _navigator.buttonPress(Navigator::MIDDLE_MOUSE,x,y); break; case MouseRight: // release picked object and switch off bounding box rendering if(_objectPicking) { _pickedObjectNode = NullFC; this->setHighlight(NullFC); #ifdef SPACENAVIGATOR_DEBUG_OUTPUT std::cout << "SpaceNavigatorSSM: Camera transformation mode active" << std::endl; #endif // SPACENAVIGATOR_DEBUG_OUTPUT } _navigator.buttonPress(Navigator::RIGHT_MOUSE,x,y); break; case MouseUp: _navigator.buttonPress(Navigator::UP_MOUSE,x,y); break; case MouseDown: _navigator.buttonPress(Navigator::DOWN_MOUSE,x,y); break; } _mousebuttons |= 1 << button; _lastx = x; _lasty = y; }
void key( unsigned char key, int , int ) { switch ( key ) { case 27: exit(0); } // Intersect IntersectAction * act = IntersectAction::create(); static Pnt3f pnts[] = { Pnt3f( 0,0,1 ), Pnt3f( 1,0,1), Pnt3f( 2,0,1), Pnt3f( 3,0,1), Pnt3f( 0,0,1 ), Pnt3f( 0,0,1 ), Pnt3f( 0,0,1 ),Pnt3f( 0,0,1 ), Pnt3f( 0.9,0.9,1 ), Pnt3f(-Inf,-Inf,-Inf) }; static Vec3f dirs[] = { Vec3f( 0,0,-1), Vec3f( 0,0,-1), Vec3f( 0,0,-1), Vec3f( 0,0,-1), Vec3f( 0,-.2,-1), Vec3f( 0,.2,-1), Vec3f( -.2,-.2,-1), Vec3f( .2,.2,-1), Vec3f( 0,0,-1 ), Vec3f(-Inf,-Inf,-Inf) }; static int i = 0; act->setLine( Line( pnts[i], dirs[i]) ); act->apply( iroot ); std::cerr << "Line " << act->getLine().getPosition() << " dir " << act->getLine().getDirection() << " hit: " << act->didHit() << " "; beginEditCP(points); points->setValue( pnts[i], 0 ); points->setValue( pnts[i] + (dirs[i] * Real32(3.0)), 1 ); if ( act->didHit() ) { std::cerr << " object " << act->getHitObject() << " tri " << act->getHitTriangle() << " at " << act->getHitPoint(); TriangleIterator it( act->getHitObject() ); it.seek( act->getHitTriangle() ); Matrix m; act->getHitObject()->getToWorld(m); Pnt3f p = it.getPosition(0); m.mult(p, p); points->setValue( p, 2 ); p = it.getPosition(1); m.mult(p, p); points->setValue( p, 3 ); p = it.getPosition(2); m.mult(p, p); points->setValue( p, 4 ); } else { points->setValue( Pnt3f(0,0,0), 2 ); points->setValue( Pnt3f(0,0,0), 3 ); points->setValue( Pnt3f(0,0,0), 4 ); } endEditCP(points); std::cerr << std::endl; glutPostRedisplay(); if ( pnts[++i][0] == -Inf ) i = 0; }
// react to keys void keyboard(unsigned char k, int x, int y) { switch(k) { case 27: { OSG::osgExit(); exit(0); } break; case ' ': // send a ray through the clicked pixel /* Intersection testing for rays is done using an IntersectAction. The ray itself is calculated by the SimpleSceneManager, given the clicked pixel. It needs to be set up with the line that is to be intersected. A line is a semi-infinite ray which has a starting point and a direction, and extends in the direction to infinity. To do the actual test the Action's apply() method is used. The results can be received from the Action. The main difference is if something was hit or not, which is returned in didHit(). If an intersection did occur, the other data elements are valid, otherwise they are undefined. The information that is stored in the action is the object which was hit, the triangle of the object that was hit (in the form of its index) and the actual hit position. */ { Line l; l = mgr->calcViewRay(x, y); std::cerr << "From " << l.getPosition () << ", dir " << l.getDirection() << std::endl; IntersectAction *act = IntersectAction::create(); act->setLine(l); act->apply(fileroot); beginEditCP(isectPoints); isectPoints->setValue(l.getPosition(), 0); isectPoints->setValue(l.getPosition() + l.getDirection(), 1); // did we hit something? if (act->didHit()) { // yes!! print and highlight it std::cerr << " object " << act->getHitObject () << " tri " << act->getHitTriangle() << " at " << act->getHitPoint (); mgr->setHighlight(act->getHitObject()); // stop the ray on the hit surface Pnt3f is = l.getPosition() + l.getDirection() * act->getHitT(); isectPoints->setValue(is, 1); // find the triangle that was hit TriangleIterator it(act->getHitObject()); it.seek(act->getHitTriangle()); // Draw its normal at the intersection point isectPoints->setValue(is, 2); isectPoints->setValue(is + act->getHitNormal() * 5, 3); // calculate its vertex positions in world space Matrix m; act->getHitObject()->getToWorld(m); // and turn them into a triangle Pnt3f p = it.getPosition(0); m.mult(p, p); isectPoints->setValue(p, 4); p = it.getPosition(1); m.mult(p, p); isectPoints->setValue(p, 5); p = it.getPosition(2); m.mult(p, p); isectPoints->setValue(p, 6); } else { // no, get rid of the triangle and highlight. isectPoints->setValue(Pnt3f(0,0,0), 2); isectPoints->setValue(Pnt3f(0,0,0), 3); isectPoints->setValue(Pnt3f(0,0,0), 4); mgr->setHighlight(NullFC); } endEditCP(isectPoints); // free the action delete act; // the geometry won't notice automatically, tell it that the // points changed beginEditCP(testgeocore, Geometry::PositionsFieldMask); endEditCP (testgeocore, Geometry::PositionsFieldMask); std::cerr << std::endl; glutPostRedisplay(); } break; } }