diff --git a/src/Gui/Utilities.cpp b/src/Gui/Utilities.cpp index df08844f9d..478f843510 100644 --- a/src/Gui/Utilities.cpp +++ b/src/Gui/Utilities.cpp @@ -51,6 +51,7 @@ Base::Vector3f ViewVolumeProjection::operator()(const Base::Vector3f &pt) const pt3d.setValue(ptt.x, ptt.y, ptt.z); } + // Calling this function is expensive as the complete projection matrix is recomputed on each step viewVolume.projectToScreen(pt3d,pt3d); return Base::Vector3f(pt3d[0],pt3d[1],pt3d[2]); } @@ -101,12 +102,26 @@ Base::Matrix4D ViewVolumeProjection::getProjectionMatrix () const // Inventor stores the transposed matrix Base::Matrix4D mat; SbMatrix affine, proj; + + // The Inventor projection matrix is obtained by multiplying both matrices together (cf source) viewVolume.getMatrices(affine, proj); + SbMatrix pmatrix = affine.multRight(proj); + for (int i=0; i<4; i++) { for (int j=0; j<4; j++) - mat[i][j] = proj[j][i]; + mat[i][j] = pmatrix[j][i]; } + // Compose the object transform, if defined + if (hasTransform) { + mat = mat * transform; + } + + // Scale from [-1,1] to [0,1] + // As done in OpenInventor sources (see SbDPViewVolume::projectToScreen) + mat.scale(0.5, 0.5, 0.5); + mat.move(0.5, 0.5, 0.5); + return mat; } diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index aea7f8b669..c444d33adc 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -1083,23 +1083,24 @@ void MeshAlgorithm::CheckFacets(const MeshFacetGrid& rclGrid, const Base::ViewPr Base::Vector3f clPt2d; Base::Vector3f clGravityOfFacet; bool bNoPointInside; + // Cache current view projection matrix since calls to COIN's projection are expensive + Base::ViewProjMatrix fixedProj(pclProj->getProjectionMatrix()); + // Precompute the polygon's bounding box + Base::BoundBox2d clPolyBBox = rclPoly.CalcBoundBox(); // Falls true, verwende Grid auf Mesh, um Suche zu beschleunigen if (bInner) { BoundBox3f clBBox3d; - BoundBox2d clViewBBox, clPolyBBox; + BoundBox2d clViewBBox; std::vector aulAllElements; - - //B-Box des Polygons - clPolyBBox = rclPoly.CalcBoundBox(); // Iterator fuer die zu durchsuchenden B-Boxen des Grids MeshGridIterator clGridIter(rclGrid); // alle B-Boxen durchlaufen und die Facets speichern for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) { clBBox3d = clGridIter.GetBoundBox(); - clViewBBox = clBBox3d.ProjectBox(pclProj); + clViewBBox = clBBox3d.ProjectBox(&fixedProj); if (clViewBBox.Intersect(clPolyBBox)) { // alle Elemente in AllElements sammeln @@ -1119,9 +1120,10 @@ void MeshAlgorithm::CheckFacets(const MeshFacetGrid& rclGrid, const Base::ViewPr MeshGeomFacet rclFacet = _rclMesh.GetFacet(*it); for (int j=0; j<3; j++) { - clPt2d = pclProj->operator()(rclFacet._aclPoints[j]); + clPt2d = fixedProj(rclFacet._aclPoints[j]); clGravityOfFacet += clPt2d; - if (rclPoly.Contains(Base::Vector2d(clPt2d.x, clPt2d.y)) == bInner) + if ((clPolyBBox.Contains(Base::Vector2d(clPt2d.x, clPt2d.y)) && + rclPoly.Contains(Base::Vector2d(clPt2d.x, clPt2d.y))) ^ !bInner) { raulFacets.push_back(*it); bNoPointInside = false; @@ -1134,8 +1136,9 @@ void MeshAlgorithm::CheckFacets(const MeshFacetGrid& rclGrid, const Base::ViewPr { clGravityOfFacet *= 1.0f/3.0f; - if (rclPoly.Contains(Base::Vector2d(clGravityOfFacet.x, clGravityOfFacet.y)) == bInner) - raulFacets.push_back(*it); + if ((clPolyBBox.Contains(Base::Vector2d(clGravityOfFacet.x, clGravityOfFacet.y)) && + rclPoly.Contains(Base::Vector2d(clGravityOfFacet.x, clGravityOfFacet.y))) ^ !bInner) + raulFacets.push_back(*it); } seq.next(); @@ -1144,20 +1147,21 @@ void MeshAlgorithm::CheckFacets(const MeshFacetGrid& rclGrid, const Base::ViewPr // Dreiecke ausserhalb schneiden, dann alles durchsuchen else { - Base::SequencerLauncher seq("Check facets", _rclMesh.CountFacets()); - for (clIter.Init(); clIter.More(); clIter.Next()) - { - for (int j=0; j<3; j++) - { - clPt2d = pclProj->operator()(clIter->_aclPoints[j]); - if (rclPoly.Contains(Base::Vector2d(clPt2d.x, clPt2d.y)) == bInner) - { - raulFacets.push_back(clIter.Position()); - break; - } - } - seq.next(); - } + Base::SequencerLauncher seq("Check facets", _rclMesh.CountFacets()); + for (clIter.Init(); clIter.More(); clIter.Next()) + { + for (int j=0; j<3; j++) + { + clPt2d = fixedProj(clIter->_aclPoints[j]); + if ((clPolyBBox.Contains(Base::Vector2d(clPt2d.x, clPt2d.y)) && + rclPoly.Contains(Base::Vector2d(clPt2d.x, clPt2d.y))) ^ !bInner) + { + raulFacets.push_back(clIter.Position()); + break; + } + } + seq.next(); + } } } @@ -1167,11 +1171,19 @@ void MeshAlgorithm::CheckFacets(const Base::ViewProjMethod* pclProj, const Base: const MeshPointArray& p = _rclMesh.GetPoints(); const MeshFacetArray& f = _rclMesh.GetFacets(); Base::Vector3f pt2d; + // Use a bounding box to reduce number of call to Polygon::Contains + Base::BoundBox2d bb = rclPoly.CalcBoundBox(); + // Precompute the screen projection matrix as COIN's projection function is expensive + Base::Matrix4D pmat = pclProj->getProjectionMatrix(); + unsigned long index=0; for (MeshFacetArray::_TConstIterator it = f.begin(); it != f.end(); ++it,++index) { for (int i = 0; i < 3; i++) { - pt2d = (*pclProj)(p[it->_aulPoints[i]]); - if (rclPoly.Contains(Base::Vector2d(pt2d.x, pt2d.y)) == bInner) { + pt2d = pmat * p[it->_aulPoints[i]]; + + // First check whether the point is in the bounding box of the polygon + if ((bb.Contains(Base::Vector2d(pt2d.x, pt2d.y)) && + rclPoly.Contains(Base::Vector2d(pt2d.x, pt2d.y))) ^ !bInner) { raulFacets.push_back(index); break; } @@ -1181,13 +1193,13 @@ void MeshAlgorithm::CheckFacets(const Base::ViewProjMethod* pclProj, const Base: float MeshAlgorithm::Surface (void) const { - float fTotal = 0.0f; - MeshFacetIterator clFIter(_rclMesh); + float fTotal = 0.0f; + MeshFacetIterator clFIter(_rclMesh); - for (clFIter.Init(); clFIter.More(); clFIter.Next()) - fTotal += clFIter->Area(); - - return fTotal; + for (clFIter.Init(); clFIter.More(); clFIter.Next()) + fTotal += clFIter->Area(); + + return fTotal; } void MeshAlgorithm::SubSampleByDist (float fDist, std::vector &rclPoints) const