Loading files
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright (c) 1999-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 <Select3D_SensitivePoly.hxx>
#include <ElCLib.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePoly, Select3D_SensitiveSet)
namespace
{
static int GetCircleNbPoints(const gp_Circ& theCircle,
const int theNbPnts,
const double theU1,
const double theU2,
const bool theIsFilled)
{
// Check if number of points is invalid.
// In this case myPolyg raises Standard_ConstructionError
// exception (see constructor below).
if (theNbPnts <= 0)
{
return 0;
}
if (theCircle.Radius() > Precision::Confusion())
{
const bool isSector =
theIsFilled && std::abs(std::abs(theU2 - theU1) - 2.0 * M_PI) > gp::Resolution();
return 2 * theNbPnts + 1 + (isSector ? 2 : 0);
}
// The radius is too small and circle degenerates into point
return 1;
}
//! Definition of circle polyline
static void initCircle(Select3D_PointData& thePolygon,
const gp_Circ& theCircle,
const double theU1,
const double theU2,
const bool theIsFilled,
const int theNbPnts)
{
const double aStep = (theU2 - theU1) / theNbPnts;
const double aRadius = theCircle.Radius();
int aPntIdx = 0;
double aCurU = theU1;
gp_Pnt aP1;
gp_Vec aV1;
const bool isSector = std::abs(theU2 - theU1 - 2.0 * M_PI) > gp::Resolution();
if (isSector && theIsFilled)
{
thePolygon.SetPnt(aPntIdx++, theCircle.Location());
}
for (int anIndex = 1; anIndex <= theNbPnts; ++anIndex, aCurU += aStep)
{
ElCLib::CircleD1(aCurU, theCircle.Position(), theCircle.Radius(), aP1, aV1);
thePolygon.SetPnt(aPntIdx++, aP1);
aV1.Normalize();
const gp_Pnt aP2 = aP1.XYZ() + aV1.XYZ() * std::tan(aStep * 0.5) * aRadius;
thePolygon.SetPnt(aPntIdx++, aP2);
}
aP1 = ElCLib::CircleValue(theU2, theCircle.Position(), theCircle.Radius());
thePolygon.SetPnt(aPntIdx++, aP1);
if (isSector && theIsFilled)
{
thePolygon.SetPnt(aPntIdx++, theCircle.Location());
}
}
} // namespace
//=================================================================================================
Select3D_SensitivePoly::Select3D_SensitivePoly(const occ::handle<SelectMgr_EntityOwner>& theOwnerId,
const NCollection_Array1<gp_Pnt>& thePoints,
const bool theIsBVHEnabled)
: Select3D_SensitiveSet(theOwnerId),
myPolyg(thePoints.Upper() - thePoints.Lower() + 1),
mySensType(Select3D_TOS_BOUNDARY)
{
int aLowerIdx = thePoints.Lower();
int anUpperIdx = thePoints.Upper();
gp_XYZ aPntSum(0.0, 0.0, 0.0);
Select3D_BndBox3d aBndBox;
for (int aIdx = aLowerIdx; aIdx <= anUpperIdx; ++aIdx)
{
aPntSum += thePoints.Value(aIdx).XYZ();
const NCollection_Vec3<double> aPnt(thePoints.Value(aIdx).X(),
thePoints.Value(aIdx).Y(),
thePoints.Value(aIdx).Z());
aBndBox.Add(aPnt);
myPolyg.SetPnt(aIdx - aLowerIdx, thePoints.Value(aIdx));
}
myBndBox = aBndBox;
myCOG = aPntSum / myPolyg.Size();
if (theIsBVHEnabled)
{
const int aPntsNum = myPolyg.Size();
mySegmentIndexes = new NCollection_HArray1<int>(0, aPntsNum - 2);
for (int aSegmIter = 0; aSegmIter < aPntsNum - 1; ++aSegmIter)
{
mySegmentIndexes->SetValue(aSegmIter, aSegmIter);
}
}
myIsComputed = true;
}
//=================================================================================================
Select3D_SensitivePoly::Select3D_SensitivePoly(
const occ::handle<SelectMgr_EntityOwner>& theOwnerId,
const occ::handle<NCollection_HArray1<gp_Pnt>>& thePoints,
const bool theIsBVHEnabled)
: Select3D_SensitiveSet(theOwnerId),
myPolyg(thePoints->Upper() - thePoints->Lower() + 1),
mySensType(Select3D_TOS_BOUNDARY)
{
int aLowerIdx = thePoints->Lower();
int anUpperIdx = thePoints->Upper();
gp_XYZ aPntSum(0.0, 0.0, 0.0);
Select3D_BndBox3d aBndBox;
for (int aIdx = aLowerIdx; aIdx <= anUpperIdx; ++aIdx)
{
aPntSum += thePoints->Value(aIdx).XYZ();
const NCollection_Vec3<double> aPnt(thePoints->Value(aIdx).X(),
thePoints->Value(aIdx).Y(),
thePoints->Value(aIdx).Z());
aBndBox.Add(aPnt);
myPolyg.SetPnt(aIdx - aLowerIdx, thePoints->Value(aIdx));
}
myBndBox = aBndBox;
myCOG = aPntSum / myPolyg.Size();
if (theIsBVHEnabled)
{
const int aPntsNum = myPolyg.Size();
mySegmentIndexes = new NCollection_HArray1<int>(0, aPntsNum - 2);
for (int aSegmIter = 0; aSegmIter < aPntsNum - 1; ++aSegmIter)
{
mySegmentIndexes->SetValue(aSegmIter, aSegmIter);
}
}
myIsComputed = true;
}
//=================================================================================================
Select3D_SensitivePoly::Select3D_SensitivePoly(const occ::handle<SelectMgr_EntityOwner>& theOwnerId,
const bool theIsBVHEnabled,
const int theNbPnts)
: Select3D_SensitiveSet(theOwnerId),
myPolyg(theNbPnts),
mySensType(Select3D_TOS_BOUNDARY)
{
if (theIsBVHEnabled)
{
mySegmentIndexes = new NCollection_HArray1<int>(0, theNbPnts - 2);
for (int aIdx = 0; aIdx < theNbPnts - 1; ++aIdx)
{
mySegmentIndexes->SetValue(aIdx, aIdx);
}
}
myCOG = gp_Pnt(RealLast(), RealLast(), RealLast());
myIsComputed = false;
}
//=================================================================================================
Select3D_SensitivePoly::Select3D_SensitivePoly(const occ::handle<SelectMgr_EntityOwner>& theOwnerId,
const gp_Circ& theCircle,
const double theU1,
const double theU2,
const bool theIsFilled,
const int theNbPnts)
: Select3D_SensitivePoly(theOwnerId,
!theIsFilled,
GetCircleNbPoints(theCircle, theNbPnts, theU1, theU2, theIsFilled))
{
mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
if (myPolyg.Size() != 1)
{
initCircle(myPolyg,
theCircle,
std::min(theU1, theU2),
std::max(theU1, theU2),
theIsFilled,
theNbPnts);
}
else
{
myPolyg.SetPnt(0, theCircle.Position().Location());
}
if (!theIsFilled)
{
SetSensitivityFactor(6);
}
}
//=================================================================================================
bool Select3D_SensitivePoly::Matches(SelectBasics_SelectingVolumeManager& theMgr,
SelectBasics_PickResult& thePickResult)
{
if (mySensType == Select3D_TOS_BOUNDARY)
{
if (!Select3D_SensitiveSet::Matches(theMgr, thePickResult))
{
return false;
}
}
else if (mySensType == Select3D_TOS_INTERIOR)
{
const occ::handle<NCollection_HArray1<gp_Pnt>> anArrayOfPnt = Points3D();
if (!theMgr.IsOverlapAllowed())
{
if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
{
SelectBasics_PickResult aDummy;
return theMgr.OverlapsPolygon(anArrayOfPnt->Array1(), mySensType, aDummy);
}
for (int aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx)
{
if (!theMgr.OverlapsPoint(anArrayOfPnt->Value(aPntIdx)))
{
return false;
}
}
return true;
}
if (!theMgr.OverlapsPolygon(anArrayOfPnt->Array1(), Select3D_TOS_INTERIOR, thePickResult))
{
return false;
}
thePickResult.SetDistToGeomCenter(distanceToCOG(theMgr));
}
return true;
}
//==================================================
// function : BoundingBox
// purpose : Returns bounding box of a polygon. If location
// transformation is set, it will be applied
//==================================================
Select3D_BndBox3d Select3D_SensitivePoly::BoundingBox()
{
if (myBndBox.IsValid())
{
return myBndBox;
}
Select3D_BndBox3d aBndBox;
for (int aPntIter = 0; aPntIter < myPolyg.Size(); ++aPntIter)
{
NCollection_Vec3<double> aPnt(myPolyg.Pnt(aPntIter).x,
myPolyg.Pnt(aPntIter).y,
myPolyg.Pnt(aPntIter).z);
aBndBox.Add(aPnt);
}
myBndBox = aBndBox;
return myBndBox;
}
//==================================================
// Function: Size
// Purpose : Returns the amount of segments of
// the poly
//==================================================
int Select3D_SensitivePoly::Size() const
{
if (!mySegmentIndexes.IsNull())
{
return mySegmentIndexes->Length();
}
return -1;
}
//==================================================
// Function: Box
// Purpose : Returns bounding box of segment with
// index theIdx
//==================================================
Select3D_BndBox3d Select3D_SensitivePoly::Box(const int theIdx) const
{
if (mySegmentIndexes.IsNull())
{
return Select3D_BndBox3d(NCollection_Vec3<double>(RealLast()));
}
const int aSegmentIdx = mySegmentIndexes->Value(theIdx);
gp_Pnt aPnt1 = myPolyg.Pnt3d(aSegmentIdx);
gp_Pnt aPnt2 = myPolyg.Pnt3d(aSegmentIdx + 1);
const NCollection_Vec3<double> aMinPnt(std::min(aPnt1.X(), aPnt2.X()),
std::min(aPnt1.Y(), aPnt2.Y()),
std::min(aPnt1.Z(), aPnt2.Z()));
const NCollection_Vec3<double> aMaxPnt(std::max(aPnt1.X(), aPnt2.X()),
std::max(aPnt1.Y(), aPnt2.Y()),
std::max(aPnt1.Z(), aPnt2.Z()));
return Select3D_BndBox3d(aMinPnt, aMaxPnt);
}
//==================================================
// Function: Center
// Purpose : Returns geometry center of sensitive
// entity index theIdx in the vector along
// the given axis theAxis
//==================================================
double Select3D_SensitivePoly::Center(const int theIdx, const int theAxis) const
{
if (mySegmentIndexes.IsNull())
{
return RealLast();
}
const Select3D_BndBox3d aBndBox = Box(theIdx);
const NCollection_Vec3<double> aCenter = (aBndBox.CornerMin() + aBndBox.CornerMax()) * 0.5;
return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
}
//==================================================
// Function: Swap
// Purpose : Swaps items with indexes theIdx1 and
// theIdx2 in the vector
//==================================================
void Select3D_SensitivePoly::Swap(const int theIdx1, const int theIdx2)
{
if (mySegmentIndexes.IsNull())
{
return;
}
const int aSegmentIdx1 = mySegmentIndexes->Value(theIdx1);
const int aSegmentIdx2 = mySegmentIndexes->Value(theIdx2);
mySegmentIndexes->ChangeValue(theIdx1) = aSegmentIdx2;
mySegmentIndexes->ChangeValue(theIdx2) = aSegmentIdx1;
}
//==================================================
// Function: overlapsElement
// Purpose : Checks whether the segment with index
// theIdx overlaps the current selecting
// volume
//==================================================
bool Select3D_SensitivePoly::overlapsElement(SelectBasics_PickResult& thePickResult,
SelectBasics_SelectingVolumeManager& theMgr,
int theElemIdx,
bool theIsFullInside)
{
if (mySegmentIndexes.IsNull())
{
return false;
}
else if (theIsFullInside)
{
return true;
}
const int aSegmentIdx = mySegmentIndexes->Value(theElemIdx);
gp_Pnt aPnt1 = myPolyg.Pnt3d(aSegmentIdx);
gp_Pnt aPnt2 = myPolyg.Pnt3d(aSegmentIdx + 1);
return theMgr.OverlapsSegment(aPnt1, aPnt2, thePickResult);
}
//=================================================================================================
bool Select3D_SensitivePoly::elementIsInside(SelectBasics_SelectingVolumeManager& theMgr,
int theElemIdx,
bool theIsFullInside)
{
if (theIsFullInside)
{
return true;
}
const int aSegmentIdx = mySegmentIndexes->Value(theElemIdx);
if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
{
SelectBasics_PickResult aDummy;
return theMgr.OverlapsSegment(myPolyg.Pnt3d(aSegmentIdx + 0),
myPolyg.Pnt3d(aSegmentIdx + 1),
aDummy);
}
return theMgr.OverlapsPoint(myPolyg.Pnt3d(aSegmentIdx + 0))
&& theMgr.OverlapsPoint(myPolyg.Pnt3d(aSegmentIdx + 1));
}
//==================================================
// Function: distanceToCOG
// Purpose : Calculates distance from the 3d
// projection of used-picked screen point
// to center of the geometry
//==================================================
double Select3D_SensitivePoly::distanceToCOG(SelectBasics_SelectingVolumeManager& theMgr)
{
if (!myIsComputed)
{
gp_XYZ aCenter(0.0, 0.0, 0.0);
for (int aIdx = 0; aIdx < myPolyg.Size(); ++aIdx)
{
aCenter += myPolyg.Pnt(aIdx);
}
myCOG = aCenter / myPolyg.Size();
myIsComputed = true;
}
return theMgr.DistToGeometryCenter(myCOG);
}
//==================================================
// Function: NbSubElements
// Purpose : Returns the amount of segments in poly
//==================================================
int Select3D_SensitivePoly::NbSubElements() const
{
return myPolyg.Size();
}
//==================================================
// Function: CenterOfGeometry
// Purpose : Returns center of the point set. If
// location transformation is set, it will
// be applied
//==================================================
gp_Pnt Select3D_SensitivePoly::CenterOfGeometry() const
{
if (!myIsComputed)
{
gp_XYZ aCenter(0.0, 0.0, 0.0);
for (int aIdx = 0; aIdx < myPolyg.Size(); ++aIdx)
{
aCenter += myPolyg.Pnt(aIdx);
}
myCOG = aCenter / myPolyg.Size();
myIsComputed = true;
}
return myCOG;
}
//=================================================================================================
void Select3D_SensitivePoly::DumpJson(Standard_OStream& theOStream, int theDepth) const
{
OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream)
OCCT_DUMP_BASE_CLASS(theOStream, theDepth, Select3D_SensitiveSet)
OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &myBndBox)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myIsComputed)
}