1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-09 18:50:54 +03:00
occt/src/BRepExtrema/BRepExtrema_SelfIntersection.cxx
dbp ae9a414af0 0026180: Modeling Algorithms - Provide shape self-intersection detector
Small correction of test case for issue CR26180

Fix GCC compilation warnings.
2015-05-28 12:19:25 +03:00

313 lines
12 KiB
C++

// Created on: 2015-04-26
// Created by: Denis BOGOLEPOV
// Copyright (c) 2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRepExtrema_SelfIntersection.hxx>
#include <Precision.hxx>
#include <TopExp_Explorer.hxx>
//=======================================================================
//function : BRepExtrema_SelfIntersection
//purpose :
//=======================================================================
BRepExtrema_SelfIntersection::BRepExtrema_SelfIntersection (const Standard_Real theTolerance)
: myTolerance (theTolerance)
{
myIsInit = Standard_False;
}
//=======================================================================
//function : BRepExtrema_SelfIntersection
//purpose :
//=======================================================================
BRepExtrema_SelfIntersection::BRepExtrema_SelfIntersection (const TopoDS_Shape& theShape, const Standard_Real theTolerance)
: myTolerance (theTolerance)
{
LoadShape (theShape);
}
//=======================================================================
//function : LoadShape
//purpose :
//=======================================================================
Standard_Boolean BRepExtrema_SelfIntersection::LoadShape (const TopoDS_Shape& theShape)
{
myFaceList.Clear();
for (TopExp_Explorer anIter (theShape, TopAbs_FACE); anIter.More(); anIter.Next())
{
myFaceList.Append (static_cast<const TopoDS_Face&> (anIter.Current()));
}
if (myElementSet.IsNull())
{
myElementSet = new BRepExtrema_TriangleSet;
}
myIsInit = myElementSet->Init (myFaceList);
if (myIsInit)
{
myOverlapTool.LoadTriangleSets (myElementSet,
myElementSet);
}
return myIsInit;
}
#define ZERO_VEC BVH_Vec3d (0.0, 0.0, 0.0)
namespace
{
// =======================================================================
// function : ccw
// purpose : Check if triple is in counterclockwise order
// =======================================================================
Standard_Boolean ccw (const BVH_Vec3d& theVertex0,
const BVH_Vec3d& theVertex1,
const BVH_Vec3d& theVertex2,
const Standard_Integer theX,
const Standard_Integer theY)
{
const Standard_Real aSum =
(theVertex1[theX] - theVertex0[theX]) * (theVertex1[theY] + theVertex0[theY]) +
(theVertex2[theX] - theVertex1[theX]) * (theVertex2[theY] + theVertex1[theY]) +
(theVertex0[theX] - theVertex2[theX]) * (theVertex0[theY] + theVertex2[theY]);
return aSum < 0.0;
}
// =======================================================================
// function : rayInsideAngle
// purpose : Check the given ray is inside the angle
// =======================================================================
Standard_Boolean rayInsideAngle (const BVH_Vec3d& theDirec,
const BVH_Vec3d& theEdge0,
const BVH_Vec3d& theEdge1,
const Standard_Integer theX,
const Standard_Integer theY)
{
const Standard_Boolean aCCW = ccw (ZERO_VEC, theEdge0, theEdge1, theX, theY);
return ccw (ZERO_VEC, theEdge0, theDirec, theX, theY) == aCCW
&& ccw (ZERO_VEC, theDirec, theEdge1, theX, theY) == aCCW;
}
// =======================================================================
// function : getProjectionAxes
// purpose :
// =======================================================================
void getProjectionAxes (const BVH_Vec3d& theNorm,
Standard_Integer& theAxisX,
Standard_Integer& theAxisY)
{
if (fabs (theNorm[0]) > fabs (theNorm[1]))
{
theAxisX = fabs (theNorm[0]) > fabs (theNorm[2]) ? 1 : 0;
theAxisY = fabs (theNorm[0]) > fabs (theNorm[2]) ? 2 : 1;
}
else
{
theAxisX = fabs (theNorm[1]) > fabs (theNorm[2]) ? 0 : 0;
theAxisY = fabs (theNorm[1]) > fabs (theNorm[2]) ? 2 : 1;
}
}
}
//=======================================================================
//function : isRegularSharedVertex
//purpose :
//=======================================================================
BRepExtrema_ElementFilter::FilterResult BRepExtrema_SelfIntersection::isRegularSharedVertex (const BVH_Vec3d& theSharedVert,
const BVH_Vec3d& theTrng0Vtxs1,
const BVH_Vec3d& theTrng0Vtxs2,
const BVH_Vec3d& theTrng1Vtxs1,
const BVH_Vec3d& theTrng1Vtxs2)
{
const BVH_Vec3d aTrng0Edges[] = { (theTrng0Vtxs1 - theSharedVert).Normalized(),
(theTrng0Vtxs2 - theSharedVert).Normalized() };
const BVH_Vec3d aTrng1Edges[] = { (theTrng1Vtxs1 - theSharedVert).Normalized(),
(theTrng1Vtxs2 - theSharedVert).Normalized() };
const BVH_Vec3d aTrng0Normal = BVH_Vec3d::Cross (aTrng0Edges[0], aTrng0Edges[1]);
const BVH_Vec3d aTrng1Normal = BVH_Vec3d::Cross (aTrng1Edges[0], aTrng1Edges[1]);
BVH_Vec3d aCrossLine = BVH_Vec3d::Cross (aTrng0Normal,
aTrng1Normal);
Standard_Integer anX;
Standard_Integer anY;
if (aCrossLine.SquareModulus() < Precision::SquareConfusion()) // coplanar case
{
getProjectionAxes (aTrng0Normal, anX, anY);
if (rayInsideAngle (aTrng1Edges[0], aTrng0Edges[0], aTrng0Edges[1], anX, anY)
|| rayInsideAngle (aTrng1Edges[1], aTrng0Edges[0], aTrng0Edges[1], anX, anY)
|| rayInsideAngle (aTrng0Edges[0], aTrng1Edges[0], aTrng1Edges[1], anX, anY)
|| rayInsideAngle (aTrng0Edges[1], aTrng1Edges[0], aTrng1Edges[1], anX, anY))
{
return BRepExtrema_ElementFilter::Overlap;
}
return BRepExtrema_ElementFilter::NoCheck;
}
else // shared line should lie outside at least one triangle
{
getProjectionAxes (aTrng0Normal, anX, anY);
const Standard_Boolean aPosOutTrgn0 = !rayInsideAngle ( aCrossLine, aTrng0Edges[0], aTrng0Edges[1], anX, anY);
const Standard_Boolean aNegOutTrgn0 = !rayInsideAngle (-aCrossLine, aTrng0Edges[0], aTrng0Edges[1], anX, anY);
Standard_ASSERT_RAISE (aPosOutTrgn0 || aNegOutTrgn0,
"Failed to detect if shared vertex is regular or not");
if (aPosOutTrgn0 && aNegOutTrgn0)
{
return BRepExtrema_ElementFilter::NoCheck;
}
getProjectionAxes (aTrng1Normal, anX, anY);
const Standard_Boolean aPosOutTrgn1 = !rayInsideAngle ( aCrossLine, aTrng1Edges[0], aTrng1Edges[1], anX, anY);
const Standard_Boolean aNegOutTrgn1 = !rayInsideAngle (-aCrossLine, aTrng1Edges[0], aTrng1Edges[1], anX, anY);
Standard_ASSERT_RAISE (aPosOutTrgn1 || aNegOutTrgn1,
"Failed to detect if shared vertex is regular or not");
if (aPosOutTrgn1 && aNegOutTrgn1)
{
return BRepExtrema_ElementFilter::NoCheck;
}
return (aPosOutTrgn0 || aPosOutTrgn1) && (aNegOutTrgn0 || aNegOutTrgn1) ?
BRepExtrema_ElementFilter::NoCheck : BRepExtrema_ElementFilter::Overlap;
}
}
//=======================================================================
//function : isRegularSharedEdge
//purpose :
//=======================================================================
BRepExtrema_ElementFilter::FilterResult BRepExtrema_SelfIntersection::isRegularSharedEdge (const BVH_Vec3d& theTrng0Vtxs0,
const BVH_Vec3d& theTrng0Vtxs1,
const BVH_Vec3d& theTrng0Vtxs2,
const BVH_Vec3d& theTrng1Vtxs2)
{
const BVH_Vec3d aSharedEdge = (theTrng0Vtxs1 - theTrng0Vtxs0).Normalized();
const BVH_Vec3d aUniqueEdges[] = { (theTrng0Vtxs2 - theTrng0Vtxs0).Normalized(),
(theTrng1Vtxs2 - theTrng0Vtxs0).Normalized() };
const BVH_Vec3d aTrng0Normal = BVH_Vec3d::Cross (aSharedEdge, aUniqueEdges[0]);
const BVH_Vec3d aTrng1Normal = BVH_Vec3d::Cross (aSharedEdge, aUniqueEdges[1]);
BVH_Vec3d aCrossLine = BVH_Vec3d::Cross (aTrng0Normal,
aTrng1Normal);
if (aCrossLine.SquareModulus() > Precision::SquareConfusion()) // non-coplanar case
{
return BRepExtrema_ElementFilter::NoCheck;
}
Standard_Integer anX;
Standard_Integer anY;
getProjectionAxes (aTrng0Normal, anX, anY);
return ccw (ZERO_VEC, aSharedEdge, aUniqueEdges[0], anX, anY) !=
ccw (ZERO_VEC, aSharedEdge, aUniqueEdges[1], anX, anY) ? BRepExtrema_ElementFilter::NoCheck
: BRepExtrema_ElementFilter::Overlap;
}
//=======================================================================
//function : PreCheckElements
//purpose :
//=======================================================================
BRepExtrema_ElementFilter::FilterResult BRepExtrema_SelfIntersection::PreCheckElements (const Standard_Integer theIndex1,
const Standard_Integer theIndex2)
{
if (myElementSet->GetFaceID (theIndex1) == myElementSet->GetFaceID (theIndex2))
{
return BRepExtrema_ElementFilter::NoCheck; // triangles are from the same face
}
BVH_Vec3d aTrng0Vtxs[3];
BVH_Vec3d aTrng1Vtxs[3];
myElementSet->GetVertices (theIndex1,
aTrng0Vtxs[0],
aTrng0Vtxs[1],
aTrng0Vtxs[2]);
myElementSet->GetVertices (theIndex2,
aTrng1Vtxs[0],
aTrng1Vtxs[1],
aTrng1Vtxs[2]);
std::vector<std::pair<Standard_Integer, Standard_Integer> > aSharedVtxs;
for (Standard_Integer aVertIdx1 = 0; aVertIdx1 < 3; ++aVertIdx1)
{
for (Standard_Integer aVertIdx2 = 0; aVertIdx2 < 3; ++aVertIdx2)
{
if ((aTrng0Vtxs[aVertIdx1] - aTrng1Vtxs[aVertIdx2]).SquareModulus() < Precision::SquareConfusion())
{
aSharedVtxs.push_back (std::pair<Standard_Integer, Standard_Integer> (aVertIdx1, aVertIdx2));
break; // go to next vertex of the 1st triangle
}
}
}
if (aSharedVtxs.size() == 2) // check shared edge
{
return isRegularSharedEdge (aTrng0Vtxs[aSharedVtxs[0].first],
aTrng0Vtxs[aSharedVtxs[1].first],
aTrng0Vtxs[3 - aSharedVtxs[0]. first - aSharedVtxs[1]. first],
aTrng1Vtxs[3 - aSharedVtxs[0].second - aSharedVtxs[1].second]);
}
else if (aSharedVtxs.size() == 1) // check shared vertex
{
std::swap (*aTrng0Vtxs, aTrng0Vtxs[aSharedVtxs.front(). first]);
std::swap (*aTrng1Vtxs, aTrng1Vtxs[aSharedVtxs.front().second]);
return isRegularSharedVertex (aTrng0Vtxs[0],
aTrng0Vtxs[1],
aTrng0Vtxs[2],
aTrng1Vtxs[1],
aTrng1Vtxs[2]);
}
return BRepExtrema_ElementFilter::DoCheck;
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void BRepExtrema_SelfIntersection::Perform()
{
if (!myIsInit || myOverlapTool.IsDone())
{
return;
}
myOverlapTool.SetElementFilter (this);
myOverlapTool.Perform (myTolerance);
}