Author: eudoxos Date: 2009-08-07 12:27:49 +0200 (Fri, 07 Aug 2009) New Revision: 1929
Modified: trunk/extra/PeriodicInsertionSortCollider.cpp trunk/extra/PeriodicInsertionSortCollider.hpp trunk/gui/qt3/GLViewer.cpp trunk/gui/qt3/GLViewer.hpp trunk/pkg/common/Engine/MetaEngine/InteractionDispatchers.cpp trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.cpp trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.hpp trunk/scripts/test/periodic-simple.py Log: 1. Beta version of periodic boundary conditions (try scripts/test/periodic-simple.py Modified: trunk/extra/PeriodicInsertionSortCollider.cpp =================================================================== --- trunk/extra/PeriodicInsertionSortCollider.cpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/extra/PeriodicInsertionSortCollider.cpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -18,34 +18,33 @@ YADE_PLUGIN((PeriodicInsertionSortCollider)) CREATE_LOGGER(PeriodicInsertionSortCollider); -Real PeriodicInsertionSortCollider::cellWrap(const Real x, const Real x0, const Real x1, long& period){ +Real PeriodicInsertionSortCollider::cellWrap(const Real x, const Real x0, const Real x1, int& period){ Real xNorm=(x-x0)/(x1-x0); - period=(long)floor(xNorm); // FIXME: some people say this is very slow + period=(int)floor(xNorm); // FIXME: some people say this is very slow return x0+(xNorm-period)*(x1-x0); } +Real PeriodicInsertionSortCollider::cellWrapRel(const Real x, const Real x0, const Real x1){ + Real xNorm=(x-x0)/(x1-x0); + return (xNorm-floor(xNorm))*(x1-x0); +} + // return true if bodies bb overlap in all 3 dimensions bool PeriodicInsertionSortCollider::spatialOverlap(body_id_t id1, body_id_t id2,MetaBody* rb, Vector3<int>& periods) const { - assert(id1!=id2) // programming error, or weird bodies (too large?) + assert(id1!=id2); // programming error, or weird bodies (too large?) for(int axis=0; axis<3; axis++){ Real dim=rb->cellMax[axis]-rb->cellMin[axis]; - // wrap all 4 numbers to the period starting and the most minimal number - #if 0 - Real mn=min(minima[3*id1+axis],minima[3*id2+axis])-0.001*dim; // avoid rounding issues - Real mx=max(maxima[3*id1+axis],maxima[3*id2+axis]); - TRVAR2(mn,mx); - #endif // too big bodies in interaction assert(maxima[3*id1+axis]-minima[3*id1+axis]<.99*dim); assert(maxima[3*id2+axis]-minima[3*id2+axis]<.99*dim); // different way: find body of which when taken as period start will make the gap smaller - long p; - Real mn1w=cellWrap(minima[3*id1+axis],0,dim,p), mn2w=cellWrap(minima[3*id2+axis],0,dim,p); - Real wMn=(abs(mn2w-mn1w)<dim/2 ? mn1w : mn2w) -/*avoid rounding issues*/1e-4*dim; /* selected wrap base */ + Real m1=minima[3*id1+axis],m2=minima[3*id2+axis]; + Real wMn=(cellWrapRel(m1,m2,m2+dim)<cellWrapRel(m2,m1,m1+dim)) ? m2 : m1; //TRVAR3(id1,id2,axis); //TRVAR4(minima[3*id1+axis],maxima[3*id1+axis],minima[3*id2+axis],maxima[3*id2+axis]); - //TRVAR3(mn1w,mn2w,wMn); - long pmn1,pmx1,pmn2,pmx2; + //TRVAR2(cellWrapRel(m1,m2,m2+dim),cellWrapRel(m2,m1,m1+dim)); + //TRVAR3(m1,m2,wMn); + int pmn1,pmx1,pmn2,pmx2; Real mn1=cellWrap(minima[3*id1+axis],wMn,wMn+dim,pmn1), mx1=cellWrap(maxima[3*id1+axis],wMn,wMn+dim,pmx1); Real mn2=cellWrap(minima[3*id2+axis],wMn,wMn+dim,pmn2), mx2=cellWrap(maxima[3*id2+axis],wMn,wMn+dim,pmx2); //TRVAR4(mn1,mx1,mn2,mx2); @@ -93,16 +92,17 @@ long i_1=v.norm(i-1), loIdx_1=v.norm(loIdx-1); // fast test, if the first pair is inverted if(v[i].coord<v[i_1].coord-(i_1==loIdx_1 ? v.cellDim : 0) ){ - // v.dump(cerr); + //v.dump(cerr); + if(i==loIdx && v[i].coord<v.cellMin){ v[i].period-=1; v[i].coord+=v.cellDim; loIdx=v.norm(loIdx+1); } hadInversion=true; Bound vi=v[i]; int j; const bool viBB=vi.flags.hasBB; for(j=i_1; vi.coord<v[j].coord-(j==v.norm(loIdx-1) ? v.cellDim : 0); j=v.norm(j-1)) { //{ Bound vj1=v[v.norm(j+1)]; v[v.norm(j+1)]=vi; //v[v.norm(j+1)]=vj1; } - long j1=v.norm(j+1); // j2=v.norm(j+2); - //LOG_TRACE("Inversion of i="<<i<<"(#"<<vi.id<<" @ "<<vi.coord<<") j="<<j<<"(#"<<v[j].id<<" @ "<<v[j].coord<<"); j1="<<j1<<", j2="<<j2); v.dump(cerr); + long j1=v.norm(j+1); + //LOG_TRACE("Inversion of i="<<i<<"(#"<<vi.id<<" @ "<<vi.coord<<") j="<<j<<"(#"<<v[j].id<<" @ "<<v[j].coord<<"); j1="<<j1); v.dump(cerr); v[j1]=v[j]; //if(v[j1].coord>v.cellMax && j2==loIdx){ v[j1].period+=1; v[j1].coord-=v.cellDim; loIdx=v.norm(loIdx-1); } - if(j1==loIdx) { assert(v[j1].coord>v.cellMax); v[j1].period+=1; v[j1].coord-=v.cellDim; loIdx=v.norm(loIdx-1); } + if(j1==loIdx) { assert(v[j1].coord>=v.cellMax); v[j1].period+=1; v[j1].coord-=v.cellDim; loIdx=v.norm(loIdx-1); } else if (vi.coord<v.cellMin && j==loIdx){ vi.period-=1; vi.coord+=v.cellDim; loIdx=v.norm(loIdx+1); } if(doCollide && viBB && v[j].flags.hasBB) handleBoundInversion(vi.id,v[j].id,interactions,rb); //v.dump(cerr); @@ -163,6 +163,13 @@ XX[i].coord=((XX[i].flags.hasBB=(bool)bvXX) ? (XX[i].flags.isMin ? bvXX->min[0] : bvXX->max[0]) : (Body::byId(idXX,rb)->physicalParameters->se3.position[0])) - XX.cellDim*XX[i].period; YY[i].coord=((YY[i].flags.hasBB=(bool)bvYY) ? (YY[i].flags.isMin ? bvYY->min[1] : bvYY->max[1]) : (Body::byId(idYY,rb)->physicalParameters->se3.position[1])) - YY.cellDim*YY[i].period; ZZ[i].coord=((ZZ[i].flags.hasBB=(bool)bvZZ) ? (ZZ[i].flags.isMin ? bvZZ->min[2] : bvZZ->max[2]) : (Body::byId(idZZ,rb)->physicalParameters->se3.position[2])) - ZZ.cellDim*ZZ[i].period; + // PERI: at the initial step, fix periods of bodies + // doInitSort is also called when bodies are just added; changing the period should not have influence here, though. + if(doInitSort){ + if(XX[i].coord<XX.cellMin || XX[i].coord>=XX.cellMax) XX[i].coord=cellWrap(XX[i].coord,XX.cellMin,XX.cellMax,XX[i].period); + if(YY[i].coord<XX.cellMin || YY[i].coord>=YY.cellMax) YY[i].coord=cellWrap(YY[i].coord,YY.cellMin,YY.cellMax,YY[i].period); + if(ZZ[i].coord<ZZ.cellMin || ZZ[i].coord>=ZZ.cellMax) ZZ[i].coord=cellWrap(ZZ[i].coord,ZZ.cellMin,ZZ.cellMax,ZZ[i].period); + } // and for each body, copy its minima and maxima arrays as well if(XX[i].flags.isMin){ BOOST_STATIC_ASSERT(sizeof(Vector3r)==3*sizeof(Real)); @@ -171,15 +178,15 @@ } else{ const Vector3r& pos=Body::byId(idXX,rb)->physicalParameters->se3.position; memcpy(&minima[3*idXX],pos,3*sizeof(Real)); memcpy(&maxima[3*idXX],pos,3*sizeof(Real)); } // PERI: add periods, but such that both minimum and maximum is within the cell! - Vector3r period(XX[i].period*XX.cellDim,YY[i].period*YY.cellDim,ZZ[i].period*ZZ.cellDim); - *(Vector3r*)(&minima[3*idXX])+=period; *(Vector3r*)(&maxima[3*idXX])+=period; //ugh + //Vector3r period(XX[i].period*XX.cellDim,YY[i].period*YY.cellDim,ZZ[i].period*ZZ.cellDim); + //*(Vector3r*)(&minima[3*idXX])+=period; *(Vector3r*)(&maxima[3*idXX])+=period; //ugh } } // process interactions that the constitutive law asked to be erased interactions->erasePending(*this,rb); - LOG_DEBUG("Step "<<Omega::instance().getCurrentIteration()); - ZZ.dump(cerr); + //LOG_TRACE("Step "<<Omega::instance().getCurrentIteration()); + //ZZ.dump(cerr); // XX.dump(cerr); YY.dump(cerr); ZZ.dump(cerr); // sort @@ -188,13 +195,10 @@ insertionSort(XX,interactions,rb); insertionSort(YY,interactions,rb); insertionSort(ZZ,interactions,rb); } else { - if(doInitSort){ - // the initial sort is in independent in 3 dimensions, may be run in parallel - // it seems that there is no time gain running this in parallel, though - std::sort(XX.vec.begin(),XX.vec.end()); std::sort(YY.vec.begin(),YY.vec.end()); std::sort(ZZ.vec.begin(),ZZ.vec.end()); - } else { // sortThenCollide - insertionSort(XX,interactions,rb,false); insertionSort(YY,interactions,rb,false); insertionSort(ZZ,interactions,rb,false); - } + // the initial sort is in independent in 3 dimensions, may be run in parallel + // it seems that there is no time gain running this in parallel, though + std::sort(XX.vec.begin(),XX.vec.end()); std::sort(YY.vec.begin(),YY.vec.end()); std::sort(ZZ.vec.begin(),ZZ.vec.end()); + // traverse the container along requested axis assert(sortAxis==0 || sortAxis==1 || sortAxis==2); VecBounds& V=(sortAxis==0?XX:(sortAxis==1?YY:ZZ)); @@ -219,7 +223,7 @@ */ // TRVAR3(i,iid,V[i].coord); // go up until we meet the upper bound - for(size_t j=i+1; V[j].id!=iid && /* handle case 2. of swapped min/max */ j<2*(size_t)nBodies; j++){ + for(size_t j=i+1; /* handle case 2. of swapped min/max */ j<2*(size_t)nBodies && V[j].id!=iid; j++){ const body_id_t& jid=V[j].id; /// Not sure why this doesn't work. If this condition is commented out, we have exact same interactions as from SpatialQuickSort. Otherwise some interactions are missing! // skip bodies with smaller (arbitrary, could be greater as well) id, since they will detect us when their turn comes Modified: trunk/extra/PeriodicInsertionSortCollider.hpp =================================================================== --- trunk/extra/PeriodicInsertionSortCollider.hpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/extra/PeriodicInsertionSortCollider.hpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -43,8 +43,10 @@ void insertionSort(VecBounds& v,InteractionContainer*,MetaBody*,bool doCollide=true); void handleBoundInversion(body_id_t,body_id_t,InteractionContainer*,MetaBody*); bool spatialOverlap(body_id_t,body_id_t, MetaBody*, Vector3<int>&) const; - static Real cellWrap(Real,Real,Real,long&); + static Real cellWrap(const Real, const Real, const Real, int&); + static Real cellWrapRel(const Real, const Real, const Real); + public: //! axis for the initial sort int sortAxis; Modified: trunk/gui/qt3/GLViewer.cpp =================================================================== --- trunk/gui/qt3/GLViewer.cpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/gui/qt3/GLViewer.cpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -323,6 +323,18 @@ else if(e->key()!=Qt::Key_Escape && e->key()!=Qt::Key_Space) QGLViewer::keyPressEvent(e); updateGL(); } +/* Center the scene such that periodic cell is contained in the view */ +void GLViewer::centerPeriodic(){ + MetaBody* rb=Omega::instance().getRootBody().get(); + assert(rb->isPeriodic); + Vector3r center=.5*(rb->cellMin+rb->cellMax); + Vector3r halfSize=.5*(rb->cellMax-rb->cellMin); + float radius=std::max(halfSize[0],std::max(halfSize[1],halfSize[2])); + LOG_DEBUG("Periodic scene center="<<center<<", halfSize="<<halfSize<<", radius="<<radius); + setSceneCenter(qglviewer::Vec(center[0],center[1],center[2])); + setSceneRadius(radius*1.5); + showEntireScene(); +} /* Calculate medians for x, y and z coordinates of all bodies; *then set scene center to median position and scene radius to 2*inter-quartile distance. @@ -332,6 +344,7 @@ * "central" (where most bodies is) part very small or even invisible. */ void GLViewer::centerMedianQuartile(){ + if(Omega::instance().getRootBody()->isPeriodic){ centerPeriodic(); return; } long nBodies=Omega::instance().getRootBody()->bodies->size(); if(nBodies<4) { LOG_INFO("Less than 4 bodies, median makes no sense; calling centerScene() instead."); @@ -357,6 +370,7 @@ void GLViewer::centerScene(){ MetaBody* rb=Omega::instance().getRootBody().get(); if (!rb) return; + if(rb->isPeriodic){ centerPeriodic(); return; } if(rb->bodies->size()<renderer->selectBodyLimit){LOG_INFO("Less than "+lexical_cast<string>(renderer->selectBodyLimit)+" bodies, moving possible. Select with shift, press 'm' to move.");} else{LOG_INFO("More than "+lexical_cast<string>(renderer->selectBodyLimit)+" (OpenGLRenderingEngine::selectBodyLimit) bodies. Moving not possible.");} Modified: trunk/gui/qt3/GLViewer.hpp =================================================================== --- trunk/gui/qt3/GLViewer.hpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/gui/qt3/GLViewer.hpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -66,6 +66,7 @@ virtual void draw(); virtual void drawWithNames(); void centerScene(); + void centerPeriodic(); void mouseMovesCamera(); void mouseMovesManipulatedFrame(qglviewer::Constraint* c=NULL); void resetManipulation(); Modified: trunk/pkg/common/Engine/MetaEngine/InteractionDispatchers.cpp =================================================================== --- trunk/pkg/common/Engine/MetaEngine/InteractionDispatchers.cpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/pkg/common/Engine/MetaEngine/InteractionDispatchers.cpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -34,6 +34,7 @@ LOG_WARN("Interactions pending erase found (erased), no collider being used?"); alreadyWarnedNoCollider=true; } + Vector3r cellSize; if(rootBody->isPeriodic) cellSize=rootBody->cellMax-rootBody->cellMin; #ifdef YADE_OPENMP const long size=rootBody->interactions->size(); #pragma omp parallel for schedule(guided) @@ -72,7 +73,12 @@ assert(I->functorCache.geom); bool wasReal=I->isReal(); - bool geomCreated=I->functorCache.geom->go(b1->interactingGeometry,b2->interactingGeometry,b1->physicalParameters->se3, b2->physicalParameters->se3,I); + bool geomCreated; + if(!rootBody->isPeriodic) geomCreated=I->functorCache.geom->go(b1->interactingGeometry,b2->interactingGeometry,b1->physicalParameters->se3, b2->physicalParameters->se3,I); + else{ // handle periodicity + Se3r se32=b2->physicalParameters->se3; se32.position+=Vector3r(I->cellDist[0]*cellSize[0],I->cellDist[1]*cellSize[1],I->cellDist[2]*cellSize[2]); + geomCreated=I->functorCache.geom->go(b1->interactingGeometry,b2->interactingGeometry,b1->physicalParameters->se3,se32,I); + } if(!geomCreated){ if(wasReal) rootBody->interactions->requestErase(I->getId1(),I->getId2()); // fully created interaction without geometry is reset and perhaps erased in the next step continue; // in any case don't care about this one anymore Modified: trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp =================================================================== --- trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -51,6 +51,7 @@ } shared_ptr<BodyContainer>& bodies = ncb->bodies; + Vector3r cellSize; if(ncb->isPeriodic) cellSize=ncb->cellMax-ncb->cellMin; #ifdef YADE_OPENMP const long size=ncb->transientInteractions->size(); #pragma omp parallel for @@ -63,10 +64,16 @@ const shared_ptr<Body>& b2=(*bodies)[I->getId2()]; bool wasReal=I->isReal(); if (!b1->interactingGeometry || !b2->interactingGeometry) { assert(!wasReal); continue; } // some bodies do not have interactingGeometry - bool geomCreated=operator()(b1->interactingGeometry, b2->interactingGeometry, b1->physicalParameters->se3, b2->physicalParameters->se3, I); + bool geomCreated; + if(!ncb->isPeriodic){ + geomCreated=operator()(b1->interactingGeometry, b2->interactingGeometry, b1->physicalParameters->se3, b2->physicalParameters->se3, I); + } else{ + Se3r se32=b2->physicalParameters->se3; se32.position+=Vector3r(I->cellDist[0]*cellSize[0],I->cellDist[1]*cellSize[1],I->cellDist[2]*cellSize[2]); // add periodicity to the position of the 2nd body + geomCreated=operator()(b1->interactingGeometry, b2->interactingGeometry, b1->physicalParameters->se3, se32, I); + } // reset && erase interaction that existed but now has no geometry anymore if(wasReal && !geomCreated){ ncb->interactions->requestErase(I->getId1(),I->getId2()); } } } -YADE_PLUGIN((InteractionGeometryMetaEngine)); \ No newline at end of file +YADE_PLUGIN((InteractionGeometryMetaEngine)); Modified: trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp =================================================================== --- trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -230,7 +230,7 @@ */ // TRVAR3(i,iid,V[i].coord); // go up until we meet the upper bound - for(size_t j=i+1; V[j].id!=iid && /* handle case 2. of swapped min/max */ j<2*nBodies; j++){ + for(size_t j=i+1; /* handle case 2. of swapped min/max */ j<2*nBodies && V[j].id!=iid; j++){ const body_id_t& jid=V[j].id; /// Not sure why this doesn't work. If this condition is commented out, we have exact same interactions as from SpatialQuickSort. Otherwise some interactions are missing! // skip bodies with smaller (arbitrary, could be greater as well) id, since they will detect us when their turn comes Modified: trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.cpp =================================================================== --- trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.cpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.cpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -109,16 +109,28 @@ numBodiesWhenRefSe3LastSet=rootBody->bodies->size(); numIterWhenRefSe3LastSet=Omega::instance().getCurrentIteration(); } +/* mostly copied from PeriodicInsertionSortCollider + FIXME: common implementation somewhere */ +Real OpenGLRenderingEngine::wrapCell(const Real x, const Real x0, const Real x1){ + Real xNorm=(x-x0)/(x1-x0); + return x0+(xNorm-floor(xNorm))*(x1-x0); +} +Vector3r OpenGLRenderingEngine::wrapCellPt(const Vector3r& pt, MetaBody* rb){ + if(!rb->isPeriodic) return pt; + return Vector3r(wrapCell(pt[0],rb->cellMin[0],rb->cellMax[0]),wrapCell(pt[1],rb->cellMin[1],rb->cellMax[1]),wrapCell(pt[2],rb->cellMin[2],rb->cellMax[2])); +} + void OpenGLRenderingEngine::setBodiesDispSe3(const shared_ptr<MetaBody>& rootBody){ FOREACH(const shared_ptr<Body>& b, *rootBody->bodies){ if(!b->physicalParameters) continue; const Se3r& se3=b->physicalParameters->se3; const Se3r& refSe3=b->physicalParameters->refSe3; Se3r& dispSe3=b->physicalParameters->dispSe3; - b->physicalParameters->isDisplayed=!pointClipped(se3.position); + Vector3r posCell=wrapCellPt(se3.position,rootBody.get()); + b->physicalParameters->isDisplayed=!pointClipped(posCell); // if no scaling, return quickly - if(!(scaleDisplacements||scaleRotations)){ b->physicalParameters->dispSe3=b->physicalParameters->se3; continue; } + if(!(scaleDisplacements||scaleRotations||rootBody->isPeriodic)){ b->physicalParameters->dispSe3=b->physicalParameters->se3; continue; } // apply scaling - dispSe3.position=(scaleDisplacements ? diagMult(displacementScale,se3.position-refSe3.position)+refSe3.position : se3.position ); + dispSe3.position=(scaleDisplacements ? diagMult(displacementScale,se3.position-refSe3.position)+wrapCellPt(refSe3.position,rootBody.get()) : posCell ); if(scaleRotations){ Quaternionr relRot=refSe3.orientation.Conjugate()*se3.orientation; Vector3r axis; Real angle; relRot.ToAxisAngle(axis,angle); @@ -127,7 +139,19 @@ } else {dispSe3.orientation=se3.orientation;} } } +// draw periodic cell, if active +void OpenGLRenderingEngine::drawPeriodicCell(MetaBody* rootBody){ + if(!rootBody->isPeriodic) return; + glPushMatrix(); + glColor3v(Vector3r(1,1,0)); + Vector3r cent=.5*(rootBody->cellMin+rootBody->cellMax); Vector3r size=rootBody->cellMax-rootBody->cellMin; + glTranslate(cent[0],cent[1],cent[2]); glScale(size[0],size[1],size[2]); + glutWireCube(1); + glPopMatrix(); +} + + void OpenGLRenderingEngine::render(const shared_ptr<MetaBody>& rootBody, body_id_t selection /*FIXME: not sure. maybe a list of selections, or maybe bodies themselves should remember if they are selected? */) { assert(glutInitDone); @@ -167,6 +191,8 @@ // set displayed Se3 of body (scaling) and isDisplayed (clipping) setBodiesDispSe3(rootBody); + drawPeriodicCell(rootBody.get()); + if (Show_DOF || Show_ID) renderDOF_ID(rootBody); if (Body_geometrical_model){ if (Cast_shadows){ @@ -401,49 +427,78 @@ if(rootBody->geometricalModel) geometricalModelDispatcher(rootBody->geometricalModel,rootBody->physicalParameters,Body_wire); } -void OpenGLRenderingEngine::renderGeometricalModel(const shared_ptr<MetaBody>& rootBody){ +void OpenGLRenderingEngine::renderGeometricalModel(const shared_ptr<MetaBody>& rootBody){ const GLfloat ambientColorSelected[4]={10.0,0.0,0.0,1.0}; const GLfloat ambientColorUnselected[4]={0.5,0.5,0.5,1.0}; - if((rootBody->geometricalModel || Draw_inside) && Draw_inside) { - FOREACH(const shared_ptr<Body> b, *rootBody->bodies){ - if(b->geometricalModel && ((b->getGroupMask() & Draw_mask) || b->getGroupMask()==0)){ - if(b->physicalParameters && !b->physicalParameters->isDisplayed) continue; - const Se3r& se3=b->physicalParameters->dispSe3; - glPushMatrix(); - Real angle; Vector3r axis; se3.orientation.ToAxisAngle(axis,angle); - glTranslatef(se3.position[0],se3.position[1],se3.position[2]); - glRotatef(angle*Mathr::RAD_TO_DEG,axis[0],axis[1],axis[2]); - if(current_selection==b->getId() || b->geometricalModel->highlight){ - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColorSelected); - glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); - const Vector3r& h(current_selection==b->getId() ? highlightEmission0 : highlightEmission1); - glColor4(h[0],h[1],h[2],.2); - glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE); + if(rootBody->geometricalModel) geometricalModelDispatcher(rootBody->geometricalModel,rootBody->physicalParameters,Body_wire); + if(!Draw_inside) return; + FOREACH(const shared_ptr<Body> b, *rootBody->bodies){ + if(!b->geometricalModel || (!((b->getGroupMask() & Draw_mask) || b->getGroupMask()==0))) continue; + if(b->physicalParameters && !b->physicalParameters->isDisplayed) continue; + const Se3r& se3=b->physicalParameters->dispSe3; + glPushMatrix(); + Real angle; Vector3r axis; se3.orientation.ToAxisAngle(axis,angle); + glTranslatef(se3.position[0],se3.position[1],se3.position[2]); + glRotatef(angle*Mathr::RAD_TO_DEG,axis[0],axis[1],axis[2]); + if(current_selection==b->getId() || b->geometricalModel->highlight){ + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColorSelected); + glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); + const Vector3r& h(current_selection==b->getId() ? highlightEmission0 : highlightEmission1); + glColor4(h[0],h[1],h[2],.2); + glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE); - geometricalModelDispatcher(b->geometricalModel,b->physicalParameters,Body_wire); + geometricalModelDispatcher(b->geometricalModel,b->physicalParameters,Body_wire); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColorUnselected); - glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); - glColor3v(Vector3r::ZERO); - glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE); - } else { - geometricalModelDispatcher(b->geometricalModel,b->physicalParameters,Body_wire); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColorUnselected); + glColorMaterial(GL_FRONT_AND_BACK,GL_EMISSION); + glColor3v(Vector3r::ZERO); + glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE); + } else { + geometricalModelDispatcher(b->geometricalModel,b->physicalParameters,Body_wire); + } + glPopMatrix(); + if(current_selection==b->getId() || b->geometricalModel->highlight){ + if(!b->boundingVolume || Body_wire || b->geometricalModel->wire) GLUtils::GLDrawInt(b->getId(),se3.position); + else { + // move the label towards the camera by the bounding box so that it is not hidden inside the body + const Vector3r& mn=b->boundingVolume->min; const Vector3r& mx=b->boundingVolume->max; const Vector3r& p=se3.position; + Vector3r ext(viewDirection[0]>0?p[0]-mn[0]:p[0]-mx[0],viewDirection[1]>0?p[1]-mn[1]:p[1]-mx[1],viewDirection[2]>0?p[2]-mn[2]:p[2]-mx[2]); // signed extents towards the camera + Vector3r dr=-1.01*(viewDirection.Dot(ext)*viewDirection); + GLUtils::GLDrawInt(b->getId(),se3.position+dr,Vector3r::ONE); + } + } + // if the body goes over the cell margin, draw it in all other positions with wire + if(b->boundingVolume && rootBody->isPeriodic){ + const Vector3r& cellMin(rootBody->cellMin); const Vector3r& cellMax(rootBody->cellMax); Vector3r cellSize=cellMax-cellMin; + Vector3<int> bodyPer,minPer,maxPer; + for(int i=0; i<3; i++){ + bodyPer[i]=(int)floor((b->physicalParameters->se3.position[i]-cellMin[i])/cellSize[i]); + minPer[i]=(int)floor((b->boundingVolume->min[i]-cellMin[i])/cellSize[i]); + maxPer[i]=(int)floor((b->boundingVolume->max[i]-cellMin[i])/cellSize[i]); + //assert(bodyPer[i]<=maxPer[i]); assert(bodyPer[i]>=minPer[i]); + } + /* m is bitmask from 3 couples (0…64=2^6) */ + for(int m=0; m<64; m++){ + // any mask containing 00 couple is invalid + if((!(m&1) && (!(m&2))) || (!(m&4) && (!(m&8))) || (!(m&16) && (!(m&32)))) continue; + Vector3r pt(se3.position); + bool isInside=false; + for(int j=0; j<3; j++){ + if(m&(1<<(2*j))) { + if(m&(1<<(2*j+1))) { if(bodyPer[j]>=maxPer[j]) {isInside=true; break; } pt[j]-=cellSize[j]; } + else { if(bodyPer[j]<=minPer[j]){ isInside=true; break; } pt[j]+=cellSize[j]; } + } } + if(isInside) continue; + if(pt==se3.position) continue; // shouldn't happen, but it happens :-( + glPushMatrix(); + glTranslatev(pt); + glRotatef(angle*Mathr::RAD_TO_DEG,axis[0],axis[1],axis[2]); + geometricalModelDispatcher(b->geometricalModel,b->physicalParameters,/*Body_wire*/ true); glPopMatrix(); - if(current_selection==b->getId() || b->geometricalModel->highlight){ - if(!b->boundingVolume || Body_wire || b->geometricalModel->wire) GLUtils::GLDrawInt(b->getId(),se3.position); - else { - // move the label towards the camera by the bounding box so that it is not hidden inside the body - const Vector3r& mn=b->boundingVolume->min; const Vector3r& mx=b->boundingVolume->max; const Vector3r& p=se3.position; - Vector3r ext(viewDirection[0]>0?p[0]-mn[0]:p[0]-mx[0],viewDirection[1]>0?p[1]-mn[1]:p[1]-mx[1],viewDirection[2]>0?p[2]-mn[2]:p[2]-mx[2]); // signed extents towards the camera - Vector3r dr=-1.01*(viewDirection.Dot(ext)*viewDirection); - GLUtils::GLDrawInt(b->getId(),se3.position+dr,Vector3r::ONE); - } - } } } } - if(rootBody->geometricalModel) geometricalModelDispatcher(rootBody->geometricalModel,rootBody->physicalParameters,Body_wire); } @@ -509,10 +564,10 @@ const Se3r& se3=b->physicalParameters->dispSe3; if(b->interactingGeometry && ((b->getGroupMask()&Draw_mask) || b->getGroupMask()==0)){ glPushMatrix(); - Real angle; Vector3r axis; se3.orientation.ToAxisAngle(axis,angle); - glTranslatef(se3.position[0],se3.position[1],se3.position[2]); - glRotatef(angle*Mathr::RAD_TO_DEG,axis[0],axis[1],axis[2]); - interactingGeometryDispatcher(b->interactingGeometry,b->physicalParameters,Body_wire); + Real angle; Vector3r axis; se3.orientation.ToAxisAngle(axis,angle); + glTranslatef(se3.position[0],se3.position[1],se3.position[2]); + glRotatef(angle*Mathr::RAD_TO_DEG,axis[0],axis[1],axis[2]); + interactingGeometryDispatcher(b->interactingGeometry,b->physicalParameters,Body_wire); glPopMatrix(); } } Modified: trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.hpp =================================================================== --- trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.hpp 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/pkg/common/RenderingEngine/OpenGLRenderingEngine/OpenGLRenderingEngine.hpp 2009-08-07 10:27:49 UTC (rev 1929) @@ -39,6 +39,13 @@ Real normSaw(Real t, Real period){ Real xi=(t-period*((int)(t/period)))/period; /* normalized value, (0-1〉 */ return (xi<.5?2*xi:2-2*xi); } Real normSquare(Real t, Real period){ Real xi=(t-period*((int)(t/period)))/period; /* normalized value, (0-1〉 */ return (xi<.5?0:1); } + //! wrap number to interval x0…x1 + Real wrapCell(const Real x, const Real x0, const Real x1); + //! wrap point to inside MetaBody's cell (identity if !MetaBody::isPeriodic) + Vector3r wrapCellPt(const Vector3r& pt, MetaBody* rb); + void drawPeriodicCell(MetaBody*); + + private : DynLibDispatcher< InteractionGeometry , GLDrawInteractionGeometryFunctor, void , TYPELIST_5(const shared_ptr<InteractionGeometry>&, const shared_ptr<Interaction>& , const shared_ptr<Body>&, const shared_ptr<Body>&, bool) > interactionGeometryDispatcher; DynLibDispatcher< InteractionPhysics , GLDrawInteractionPhysicsFunctor, void , TYPELIST_5(const shared_ptr<InteractionPhysics>& , const shared_ptr<Interaction>&, const shared_ptr<Body>&, const shared_ptr<Body>&, bool) > interactionPhysicsDispatcher; Modified: trunk/scripts/test/periodic-simple.py =================================================================== --- trunk/scripts/test/periodic-simple.py 2009-08-06 22:05:28 UTC (rev 1928) +++ trunk/scripts/test/periodic-simple.py 2009-08-07 10:27:49 UTC (rev 1929) @@ -10,15 +10,15 @@ [Law2_Dem3Dof_Elastic_Elastic()], ), GravityEngine(gravity=[0,0,-10]), - NewtonsDampedLaw(damping=.1) + TranslationEngine(translationAxis=(1,0,0),velocity=10,subscribedBodies=[0]), + NewtonsDampedLaw(damping=.4) ] -O.bodies.append(utils.sphere([0,0,2],1,dynamic=False,density=1000)) -O.bodies.append(utils.sphere([0,0,3],1,density=1000)) +O.bodies.append(utils.sphere([-4,0,11],2,dynamic=False,density=1000)) +O.bodies.append(utils.sphere([0,-1,5.5],2,density=1000)) +O.bodies.append(utils.sphere([0,2,5.5],2,density=2000)) O.periodicCell=((-5,-5,0),(5,5,10)) -O.dt=utils.PWaveTimeStep() +O.dt=.1*utils.PWaveTimeStep() O.saveTmp() from yade import qt qt.Controller() qt.View() -O.run(17) - _______________________________________________ Mailing list: https://launchpad.net/~yade-dev Post to : yade-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~yade-dev More help : https://help.launchpad.net/ListHelp