1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-09-03 14:10:33 +03:00

Compare commits

...

14 Commits

Author SHA1 Message Date
nbv
fdbfdb571a 0029935: Foundation Classes - introduce OSD_ThreadPool class defining a thread pool 2019-02-20 17:03:08 +03:00
nbv
8c8ccd1d84 Additional fixes 2019-02-20 15:41:30 +03:00
nbv
cadb9817be tests 2018-06-20 12:24:23 +03:00
nbv
b17bbb8566 Parallel mode 2018-06-07 17:08:05 +03:00
nbv
48a3db93cf Debug 2018-05-29 12:14:17 +03:00
nbv
570c74d4f7 0029523: Problem with BRepOffsetAPI_MakeEvolved
1. New class BRepFill_Voluved has been created in order to provide new OCCT-algorithm combining BRepFill_PipeShell and BOPAlgo_MakerVolume.

2. The interface of DRAW-command "evolved" has been corrected.

3. DRAW-command "evolvedsolid" has been deleted. Currently it can be replaced with DRAW-command "evolved" with specific options.

4. Some test cases have been corrected.

5. Testgrid "evolved" has been created.
2018-05-29 12:14:15 +03:00
nbv
4dff80e12a # Warning: Building 2D curve of edge on face has failed.
(cherry picked from commit d0d712265120631f5cc58c3d480492e79a6c5123)
2018-05-29 12:14:13 +03:00
nbv
8289ec43e5 # Walking hangs 2018-05-29 12:14:11 +03:00
jgv
eea519f643 0029813: BRepFill_PipeShell algorithm produces invalid result
Modified method: BRepFill_Sweep::BuildShell
case of global closedness of path containing several C0-connected parts is corrected.

(cherry picked from commit 02e4bacfb08113dcac54707b40a6499725ea00ee)
2018-05-29 12:14:09 +03:00
nbv
efb8681bfc 0029663: Exception in BRepFill_PipeShell algorithm
BRepFill_Sweep algorithm is improved to handle cases when generated revolution surface has degenerated point in the middle.

Added test bugs modalg_7 bug29663

TODO added in test bugs modalg_1 bug1477_11: here two additional self-intersecting faces are now created, previously missing from the result.

(cherry picked from commit c37f570215)
2018-04-28 09:31:18 +03:00
nbv
34b2e62bd6 0029660: Misprint in BuildEdge(...) static function of BRepFill_Sweep.cxx file
Misprint has been eliminated.

(cherry picked from commit 10a55e0d05)
2018-04-28 09:31:16 +03:00
jgv
8c2adc035d 0029204: BRepOffsetAPI_MakePipeShell produces invalid result and raises exception in Draw
1.The algorithm searching the section in the corner (ChooseSection) is modified to be able to find simple cases with rather big tolerance.

2. The constructor of BRepFill_Section is modified: now it removes locations in the shape of section like it was done in BRepFill_Pipe.

3. Correction of U-edges by Same Parameter has been added to the method BRepFill_Sweep::Build.

(cherry picked from commit 833e75611f)
2018-04-28 09:31:15 +03:00
emv
a829053aed 0029351: Boolean Operations create invalid pcurves
When making pcurve for edge on face make sure that the produced 2D curve will have the same range as 3D curve of the edge.

(cherry picked from commit 0a807dd9a3)
2018-04-28 09:31:13 +03:00
emv
f109d88899 0029073: Regression: General Cut produces invalid shape
Boolean Operations:
1. Face/Face intersection post treatment - Unify vertices put on the section curves, which were rejected as existing ones, with the vertices of edges by which these section curves have been rejected.

2. Extend Warnings Reporting system of Boolean operations with the new warnings:
- BOPAlgo_AlertIntersectionOfPairOfShapesFailed - to be added when the intersection of pair of sub-shapes of the arguments has failed;
- BOPAlgo_AlertBuildingPCurveFailed - to be added when the building of the 2D curve of the edge on face has failed;
- BOPAlgo_AlertAcquiredSelfIntersection - to be added when the positioning and tolerances of the arguments leads to creation of self-interfered shapes.

These new warnings allow completing the operation even if intersection of some of the sub-shapes or building of some of the PCurves has failed. Moreover, they allow getting the pairs of sub-shapes on which the intersection/projection has failed, providing the user ability to analyze the intersection results.

Note that if some of these warnings appear, the result of the operation should be carefully analyzed for validity.

3. Print messages for the Warnings/Errors met during checking of the shape on self-intersection ("bopcheck" command).

(cherry picked from commit ad8b073e19)
2018-04-19 15:33:38 +03:00
126 changed files with 10963 additions and 1225 deletions

View File

@@ -68,6 +68,7 @@ FILE_TO_LIST ("adm/RESOURCES" RESOURCES)
foreach (CurrentResource ${RESOURCES})
get_filename_component (CurrentResource_FileName "${CurrentResource}" NAME)
if ("${CurrentResource_FileName}" STREQUAL TObj.msg OR
"${CurrentResource_FileName}" STREQUAL BOPAlgo.msg OR
"${CurrentResource_FileName}" STREQUAL Units.dat OR
"${CurrentResource}" STREQUAL XSMessage OR
"${CurrentResource}" STREQUAL SHMessage OR

View File

@@ -67,3 +67,12 @@ Warning: Removal of internal boundaries among Faces has failed
.BOPAlgo_AlertRemovalOfIBForEdgesFailed
Warning: Removal of internal boundaries among Edges has failed
.BOPAlgo_AlertIntersectionOfPairOfShapesFailed
Warning: Intersection of pair of shapes has failed
.BOPAlgo_AlertBuildingPCurveFailed
Warning: Building 2D curve of edge on face has failed
.BOPAlgo_AlertAcquiredSelfIntersection
Warning: Some sub-shapes of some of the argument become connected through other shapes and the argument became self-interfered

View File

@@ -78,4 +78,14 @@ DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertShellSplitterFailed)
//! Some edges are too small and have no valid range
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertTooSmallEdge)
//! Intersection of pair of shapes has failed
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertIntersectionOfPairOfShapesFailed)
//! Building 2D curve of edge on face has failed
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertBuildingPCurveFailed)
//! Some sub-shapes of some of the argument become connected through
//! other shapes and the argument became self-interfered
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertAcquiredSelfIntersection)
#endif // _BOPAlgo_Alerts_HeaderFile

View File

@@ -69,4 +69,13 @@ static const char BOPAlgo_BOPAlgo_msg[] =
"Warning: Removal of internal boundaries among Faces has failed\n"
"\n"
".BOPAlgo_AlertRemovalOfIBForEdgesFailed\n"
"Warning: Removal of internal boundaries among Edges has failed\n";
"Warning: Removal of internal boundaries among Edges has failed\n"
"\n"
".BOPAlgo_AlertIntersectionOfPairOfShapesFailed\n"
"Warning: Intersection of pair of shapes has failed\n"
"\n"
".BOPAlgo_AlertBuildingPCurveFailed\n"
"Warning: Building 2D curve of edge on face has failed\n"
"\n"
".BOPAlgo_AlertAcquiredSelfIntersection\n"
"Warning: Some sub-shapes of some of the argument become connected through other shapes and the argument became self-interfered\n";

View File

@@ -294,6 +294,8 @@ void BOPAlgo_PaveFiller::PerformInternal()
//
UpdateBlocksWithSharedVertices();
//
myDS->RefineFaceInfoIn();
//
MakeSplitEdges();
if (HasErrors()) {
return;

View File

@@ -87,13 +87,19 @@ class TopoDS_Face;
//! - *Gluing options* - allows to speed up the calculation on the special
//! cases, in which some sub-shapes are coincide.<br>
//!
//! The algorithm returns the following Warning statuses:<br>
//! - *BOPAlgo_AlertSelfInterferingShape* - in case some of the argument shapes are self-interfering shapes;<br>
//! - *BOPAlgo_AlertTooSmallEdge* - in case some edges of the input shapes have no valid range;<br>
//! The algorithm returns the following Warning statuses:
//! - *BOPAlgo_AlertSelfInterferingShape* - in case some of the argument shapes are self-interfering shapes;
//! - *BOPAlgo_AlertTooSmallEdge* - in case some edges of the input shapes have no valid range;
//! - *BOPAlgo_AlertNotSplittableEdge* - in case some edges of the input shapes has such a small
//! valid range so it cannot be split;<br>
//! valid range so it cannot be split;
//! - *BOPAlgo_AlertBadPositioning* - in case the positioning of the input shapes leads to creation
//! of small edges.<br>
//! of small edges;
//! - *BOPAlgo_AlertIntersectionOfPairOfShapesFailed* - in case intersection of some of the
//! sub-shapes has failed;
//! - *BOPAlgo_AlertAcquiredSelfIntersection* - in case some sub-shapes of the argument become connected
//! through other shapes;
//! - *BOPAlgo_AlertBuildingPCurveFailed* - in case building 2D curve for some of the edges
//! on the faces has failed.
//!
//! The algorithm returns the following Error alerts:
//! - *BOPAlgo_AlertTooFewArguments* - in case there are no enough arguments to
@@ -290,6 +296,7 @@ protected:
BOPDS_DataMapOfPaveBlockListOfPaveBlock& theDMExEdges,
BOPCol_DataMapOfIntegerInteger& theDMNewSD,
const BOPCol_IndexedMapOfShape& theMicroEdges,
const BOPCol_IndexedMapOfShape& theVertsOnRejectedPB,
const BOPCol_BaseAllocator& theAllocator);
Standard_EXPORT void FindPaveBlocks (const Standard_Integer theV, const Standard_Integer theF, BOPDS_ListOfPaveBlock& theLPB);
@@ -474,6 +481,8 @@ protected:
//! In case self-interference is found the warning is added.
Standard_EXPORT void CheckSelfInterference();
//! Adds the warning about failed intersection of pair of sub-shapes
Standard_EXPORT void AddIntersectionFailedWarning(const TopoDS_Shape& theS1, const TopoDS_Shape& theS2);
BOPCol_ListOfShape myArguments;
BOPDS_PDS myDS;

View File

@@ -112,7 +112,8 @@ void BOPAlgo_PaveFiller::CheckSelfInterference()
}
//
if (aLE.Extent() > 1) {
// Add warning
// Add the acquired self-interference warning:
// The same common block contains several edges from one argument
TopoDS_Compound aWC;
aBB.MakeCompound(aWC);
//
@@ -122,7 +123,7 @@ void BOPAlgo_PaveFiller::CheckSelfInterference()
aBB.Add(aWC, aE1);
}
//
AddWarning (new BOPAlgo_AlertSelfInterferingShape (aWC));
AddWarning (new BOPAlgo_AlertAcquiredSelfIntersection (aWC));
}
}
}
@@ -168,7 +169,8 @@ void BOPAlgo_PaveFiller::CheckSelfInterference()
for (j = 1; j <= aNbC; ++j) {
const BOPCol_IndexedMapOfShape& aMCS = aMCSI(j);
if (aMCS.Extent() > 1) {
// Add self-interference warning
// Add acquired self-interference warning:
// Several faces from one argument contain the same vertex or edge
TopoDS_Compound aWC;
aBB.MakeCompound(aWC);
//
@@ -177,7 +179,7 @@ void BOPAlgo_PaveFiller::CheckSelfInterference()
const TopoDS_Shape& aSx = aMCS(iS);
aBB.Add(aWC, aSx);
}
AddWarning (new BOPAlgo_AlertSelfInterferingShape (aWC));
AddWarning (new BOPAlgo_AlertAcquiredSelfIntersection (aWC));
}
}
}

View File

@@ -17,6 +17,7 @@
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Alerts.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BOPCol_NCVector.hxx>
#include <BOPCol_Parallel.hxx>
@@ -27,6 +28,7 @@
#include <BOPDS_PaveBlock.hxx>
#include <BOPDS_VectorOfInterfVE.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <gp_Pnt.hxx>
#include <IntTools_Context.hxx>
@@ -110,7 +112,16 @@ class BOPAlgo_VertexEdge : public BOPAlgo_Algo {
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
myFlag=myContext->ComputeVE (myV, myE, myT, myTolVNew, myFuzzyValue);
try
{
OCC_CATCH_SIGNALS
myFlag=myContext->ComputeVE (myV, myE, myT, myTolVNew, myFuzzyValue);
}
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
};
//
protected:
@@ -267,6 +278,11 @@ void BOPAlgo_PaveFiller::IntersectVE
for (i = 0; i < aNbVE; ++i) {
const BOPAlgo_VertexEdge& aVESolver = aVVE(i);
if (aVESolver.Flag() != 0) {
if (aVESolver.HasErrors())
{
// Warn about failed intersection of sub-shapes
AddIntersectionFailedWarning(aVESolver.Vertex(), aVESolver.Edge());
}
continue;
}
//
@@ -491,3 +507,19 @@ void BOPAlgo_PaveFiller::SplitPaveBlocks(const BOPCol_MapOfInteger& theMEdges,
}
}
}
//=======================================================================
// function: AddIntersectionFailedWarning
// purpose:
//=======================================================================
void BOPAlgo_PaveFiller::AddIntersectionFailedWarning(const TopoDS_Shape& theS1,
const TopoDS_Shape& theS2)
{
// Create the warn shape
TopoDS_Compound aWC;
BRep_Builder().MakeCompound(aWC);
BRep_Builder().Add(aWC, theS1);
BRep_Builder().Add(aWC, theS2);
// Add the warning
AddWarning(new BOPAlgo_AlertIntersectionOfPairOfShapesFailed(aWC));
}

View File

@@ -93,7 +93,16 @@ class BOPAlgo_EdgeEdge :
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
IntTools_EdgeEdge::Perform();
try
{
OCC_CATCH_SIGNALS
IntTools_EdgeEdge::Perform();
}
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
}
//
protected:
@@ -229,7 +238,11 @@ void BOPAlgo_PaveFiller::PerformEE()
Bnd_Box aBB1, aBB2;
//
BOPAlgo_EdgeEdge& anEdgeEdge=aVEdgeEdge(k);
if (!anEdgeEdge.IsDone()) {
if (!anEdgeEdge.IsDone() || anEdgeEdge.HasErrors()) {
// Warn about failed intersection of sub-shapes
const TopoDS_Shape& aE1 = myDS->Shape(anEdgeEdge.PaveBlock1()->OriginalEdge());
const TopoDS_Shape& aE2 = myDS->Shape(anEdgeEdge.PaveBlock2()->OriginalEdge());
AddIntersectionFailedWarning(aE1, aE2);
continue;
}
//

View File

@@ -17,6 +17,7 @@
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Alerts.hxx>
#include <BOPAlgo_SectionAttribute.hxx>
#include <BOPCol_MapOfInteger.hxx>
#include <BOPCol_NCVector.hxx>
@@ -107,7 +108,16 @@ class BOPAlgo_VertexFace : public BOPAlgo_Algo {
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
myFlag=myContext->ComputeVF(myV, myF, myT1, myT2, myTolVNew, myFuzzyValue);
try
{
OCC_CATCH_SIGNALS
myFlag=myContext->ComputeVF(myV, myF, myT1, myT2, myTolVNew, myFuzzyValue);
}
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
}
//
protected:
@@ -212,7 +222,12 @@ void BOPAlgo_PaveFiller::PerformVF()
const BOPAlgo_VertexFace& aVertexFace=aVVF(k);
//
iFlag=aVertexFace.Flag();
if (iFlag) {
if (iFlag != 0) {
if (aVertexFace.HasErrors())
{
// Warn about failed intersection of sub-shapes
AddIntersectionFailedWarning(aVertexFace.Vertex(), aVertexFace.Face());
}
continue;
}
//

View File

@@ -103,7 +103,16 @@ class BOPAlgo_EdgeFace :
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
IntTools_EdgeFace::Perform();
try
{
OCC_CATCH_SIGNALS
IntTools_EdgeFace::Perform();
}
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
}
//
protected:
@@ -258,7 +267,9 @@ void BOPAlgo_PaveFiller::PerformEF()
//
for (k=0; k < aNbEdgeFace; ++k) {
BOPAlgo_EdgeFace& aEdgeFace=aVEdgeFace(k);
if (!aEdgeFace.IsDone()) {
if (!aEdgeFace.IsDone() || aEdgeFace.HasErrors()) {
// Warn about failed intersection of sub-shapes
AddIntersectionFailedWarning(aEdgeFace.Edge(), aEdgeFace.Face());
continue;
}
//

View File

@@ -144,7 +144,16 @@ class BOPAlgo_FaceFace :
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
IntTools_FaceFace::Perform(myF1, myF2);
try
{
OCC_CATCH_SIGNALS
IntTools_FaceFace::Perform(myF1, myF2);
}
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
}
//
protected:
@@ -263,10 +272,12 @@ void BOPAlgo_PaveFiller::PerformFF()
for (k = 0; k < aNbFaceFace; ++k) {
BOPAlgo_FaceFace& aFaceFace = aVFaceFace(k);
aFaceFace.Indices(nF1, nF2);
if (!aFaceFace.IsDone()) {
if (!aFaceFace.IsDone() || aFaceFace.HasErrors()) {
BOPDS_InterfFF& aFF = aFFs.Append1();
aFF.SetIndices(nF1, nF2);
aFF.Init(0, 0);
// Warn about failed intersection of faces
AddIntersectionFailedWarning(aFaceFace.Face1(), aFaceFace.Face2());
continue;
}
//
@@ -373,6 +384,7 @@ void BOPAlgo_PaveFiller::MakeBlocks()
BOPCol_DataMapOfIntegerListOfInteger aDMBV(100, aAllocator);
BOPCol_DataMapIteratorOfDataMapOfIntegerReal aItMV;
BOPCol_IndexedMapOfShape aMicroEdges(100, aAllocator);
BOPCol_IndexedMapOfShape aVertsOnRejectedPB;
//
for (i=0; i<aNbFF; ++i) {
//
@@ -557,6 +569,19 @@ void BOPAlgo_PaveFiller::MakeBlocks()
if (!bInBothFaces) {
aMPBAdd.Add(aPBOut);
PreparePostTreatFF(i, j, aPBOut, aMSCPB, aMVI, aLPBC);
// Try fusing the vertices of the existing pave block
// with the vertices put on the real section curve (except
// for technological vertices, which will be removed)
Standard_Integer nVOut1, nVOut2;
aPBOut->Indices(nVOut1, nVOut2);
if (nV1 != nVOut1 && nV1 != nVOut2 && !aMVBounds.Contains(nV1))
{
aVertsOnRejectedPB.Add(aV1);
}
if (nV2 != nVOut1 && nV2 != nVOut2 && !aMVBounds.Contains(nV2))
{
aVertsOnRejectedPB.Add(aV2);
}
}
}
continue;
@@ -639,7 +664,7 @@ void BOPAlgo_PaveFiller::MakeBlocks()
//
// post treatment
MakeSDVerticesFF(aDMVLV, aDMNewSD);
PostTreatFF(aMSCPB, aDMExEdges, aDMNewSD, aMicroEdges, aAllocator);
PostTreatFF(aMSCPB, aDMExEdges, aDMNewSD, aMicroEdges, aVertsOnRejectedPB, aAllocator);
if (HasErrors()) {
return;
}
@@ -697,6 +722,7 @@ void BOPAlgo_PaveFiller::PostTreatFF
BOPDS_DataMapOfPaveBlockListOfPaveBlock& aDMExEdges,
BOPCol_DataMapOfIntegerInteger& aDMNewSD,
const BOPCol_IndexedMapOfShape& theMicroEdges,
const BOPCol_IndexedMapOfShape& theVertsOnRejectedPB,
const Handle(NCollection_BaseAllocator)& theAllocator)
{
Standard_Integer aNbS = theMSCPB.Extent();
@@ -724,8 +750,9 @@ void BOPAlgo_PaveFiller::PostTreatFF
BOPDS_VectorOfInterfFF& aFFs=myDS->InterfFF();
//
Standard_Integer aNbME = theMicroEdges.Extent();
Standard_Integer aNbVOnRPB = theVertsOnRejectedPB.Extent();
// 0
if (aNbS==1 && (aNbME == 0)) {
if (aNbS==1 && (aNbME == 0) && (aNbVOnRPB == 0)) {
const TopoDS_Shape& aS=theMSCPB.FindKey(1);
const BOPDS_CoupleOfPaveBlocks &aCPB=theMSCPB.FindFromIndex(1);
//
@@ -824,6 +851,20 @@ void BOPAlgo_PaveFiller::PostTreatFF
aBB.UpdateVertex(aVerts[1], aTolV2 + aDist);
}
}
// Add vertices put on the real section curves to unify them with the
// vertices of the edges, by which these sections curves have been rejected
for (Standard_Integer i = 1; i <= aNbVOnRPB; ++i)
{
TopoDS_Shape aVer = theVertsOnRejectedPB(i);
Standard_Integer iVer = myDS->Index(aVer);
const Standard_Integer* pSD = aDMNewSD.Seek(iVer);
if (pSD)
aVer = myDS->Shape(*pSD);
if (anAddedSD.Add(aVer))
aLS.Append(aVer);
}
//
// 2 Fuse shapes
aPF.SetProgressIndicator(myProgressIndicator);

View File

@@ -16,6 +16,7 @@
// commercial license or contractual agreement.
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Alerts.hxx>
#include <BOPAlgo_SectionAttribute.hxx>
#include <BOPAlgo_Tools.hxx>
#include <BOPCol_IndexedMapOfShape.hxx>
@@ -241,28 +242,37 @@ class BOPAlgo_MPC : public BOPAlgo_Algo {
}
//
virtual void Perform() {
Standard_Integer iErr;
//
iErr=1;
if (!myEz.IsNull()) {
TopoDS_Edge aSpz;
try
{
OCC_CATCH_SIGNALS
Standard_Integer iErr;
//
BOPTools_AlgoTools::MakeSplitEdge(myEz,myV1, myT1,
myV2, myT2, aSpz);
iErr=1;
if (!myEz.IsNull()) {
TopoDS_Edge aSpz;
//
BOPTools_AlgoTools::MakeSplitEdge(myEz,myV1, myT1,
myV2, myT2, aSpz);
//
iErr=
BOPTools_AlgoTools2D::AttachExistingPCurve(aSpz,
myE,
myF,
myContext);
}
//
iErr=
BOPTools_AlgoTools2D::AttachExistingPCurve(aSpz,
myE,
myF,
myContext);
if (iErr) {
BOPTools_AlgoTools2D::BuildPCurveForEdgeOnFace(myE, myF, myContext);
}
//
if (myFlag) {
UpdateVertices(myE, myF);
}
}
//
if (iErr) {
BOPTools_AlgoTools2D::BuildPCurveForEdgeOnFace(myE, myF, myContext);
}
//
if (myFlag) {
UpdateVertices(myE, myF);
catch (Standard_Failure)
{
AddError(new BOPAlgo_AlertBuildingPCurveFailed(TopoDS_Shape()));
}
}
//
@@ -676,6 +686,20 @@ void BOPAlgo_PaveFiller::MakePCurves()
//======================================================
BOPAlgo_MPCCnt::Perform(myRunParallel, aVMPC, myContext);
//======================================================
// Add warnings of the failed projections
Standard_Integer aNb = aVMPC.Extent();
for (i = 0; i < aNb; ++i)
{
if (aVMPC(i).HasErrors())
{
TopoDS_Compound aWC;
BRep_Builder().MakeCompound(aWC);
BRep_Builder().Add(aWC, aVMPC(i).Edge());
BRep_Builder().Add(aWC, aVMPC(i).Face());
AddWarning(new BOPAlgo_AlertBuildingPCurveFailed(aWC));
}
}
}
//=======================================================================
//function : UpdateVertices

View File

@@ -1418,6 +1418,44 @@ void BOPDS_DS::RefineFaceInfoOn()
}
}
}
//=======================================================================
//function : RefineFaceInfoIn
//purpose :
//=======================================================================
void BOPDS_DS::RefineFaceInfoIn()
{
for (Standard_Integer i = 0; i < myNbSourceShapes; ++i)
{
const BOPDS_ShapeInfo& aSI = ShapeInfo(i);
if (aSI.ShapeType() != TopAbs_FACE)
continue;
if (!aSI.HasReference())
continue;
BOPDS_FaceInfo& aFI = ChangeFaceInfo(i);
const BOPDS_IndexedMapOfPaveBlock& aMPBOn = aFI.PaveBlocksOn();
BOPDS_IndexedMapOfPaveBlock& aMPBIn = aFI.ChangePaveBlocksIn();
if (aMPBIn.IsEmpty() || aMPBOn.IsEmpty())
continue;
BOPDS_IndexedMapOfPaveBlock aMPBInNew;
const Standard_Integer aNbPBIn = aMPBIn.Extent();
for (Standard_Integer j = 1; j <= aNbPBIn; ++j)
{
if (!aMPBOn.Contains(aMPBIn(j)))
aMPBInNew.Add(aMPBIn(j));
}
if (aMPBInNew.Extent() < aNbPBIn)
aMPBIn = aMPBInNew;
}
}
//=======================================================================
//function : AloneVertices
//purpose :

View File

@@ -302,6 +302,9 @@ Standard_EXPORT virtual ~BOPDS_DS();
//! ++
Standard_EXPORT void RefineFaceInfoOn();
//! Removes faces with state ON from the
//! list of IN-faces
Standard_EXPORT void RefineFaceInfoIn();
//! Returns information about ON/IN subshapes of the given faces.
//! @param theMVOnIn the indices of ON/IN vertices from both faces

View File

@@ -235,6 +235,8 @@ Standard_Integer bopcheck (Draw_Interpretor& di,
//
aTimer.Stop();
//
BOPTest::ReportAlerts(aChecker);
//
iErr=aChecker.HasErrors();
//
const BOPDS_DS& aDS=*(aChecker.PDS());

View File

@@ -46,6 +46,7 @@
#include <GeomAdaptor_HSurface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomInt.hxx>
#include <GeomLib.hxx>
#include <GeomProjLib.hxx>
#include <gp.hxx>
#include <gp_Cylinder.hxx>
@@ -667,12 +668,25 @@ void BOPTools_AlgoTools2D::MakePCurveOnFace
}
//
TolReached2d=aTolR;
//
// Adjust curve for periodic surface
Handle(Geom2d_Curve) aC2DA;
BOPTools_AlgoTools2D::AdjustPCurveOnSurf (*pBAS, aT1, aT2, aC2D, aC2DA);
//
aC2D=aC2DA;
//
aC2D = aC2DA;
// Make sure that the range of the 2D curve is sufficient for representation of the 3D curve.
Standard_Real aTCFirst = aC2D->FirstParameter();
Standard_Real aTCLast = aC2D->LastParameter();
if ((aTCFirst - aT1) > Precision::PConfusion() ||
(aT2 - aTCLast ) > Precision::PConfusion())
{
if (aTCFirst < aT1) aTCFirst = aT1;
if (aTCLast > aT2) aTCLast = aT2;
GeomLib::SameRange(Precision::PConfusion(), aC2D,
aTCFirst, aTCLast, aT1, aT2, aC2D);
}
// compute the appropriate tolerance for the edge
Handle(Geom_Surface) aS = pBAS->Surface().Surface();
aS = Handle(Geom_Surface)::DownCast(aS->Transformed(pBAS->Trsf()));

View File

@@ -102,40 +102,6 @@ static Standard_Boolean UpdateMap(const TopoDS_Shape& theKey,
return !found;
}
static void ReverseModifiedEdges(TopoDS_Shape& aShape,
TopTools_MapOfShape& Emap)
{
TopExp_Explorer Explo(aShape, TopAbs_FACE);
BRep_Builder BB;
for (; Explo.More(); Explo.Next())
{
TopoDS_Shape aFace = Explo.Current();
TopoDS_Iterator itf(aFace);
for (; itf.More(); itf.Next())
{
TopoDS_Shape aWire = itf.Value();
TopTools_ListOfShape Ledges;
TopoDS_Iterator itw(aWire);
for (; itw.More(); itw.Next())
Ledges.Append(itw.Value());
aWire.Free(Standard_True);
TopTools_ListIteratorOfListOfShape itl(Ledges);
for (; itl.More(); itl.Next())
BB.Remove(aWire, itl.Value());
for (itl.Initialize(Ledges); itl.More(); itl.Next())
{
TopoDS_Shape anEdge = itl.Value();
if (Emap.Contains(anEdge))
anEdge.Reverse();
BB.Add(aWire, anEdge);
}
}
}
}
static void UpdateTolFromTopOrBottomPCurve(const TopoDS_Face& aFace,
TopoDS_Edge& anEdge)
{
@@ -739,9 +705,6 @@ TopoDS_Shape BRepFill_Pipe::MakeShape(const TopoDS_Shape& S,
result = MkSw.Shape();
UpdateMap(TheS.Located(myProfile.Location()), result, myGenMap);
myErrorOnSurf = MkSw.ErrorOnSurface();
//Correct <myFirst> and <myLast>
ReverseModifiedEdges(myFirst, myReversedEdges);
ReverseModifiedEdges(myLast, myReversedEdges);
// Labeling of elements
if (mySections.IsNull()) {

View File

@@ -583,28 +583,15 @@ void BRepFill_PipeShell::SetForceApproxC1(const Standard_Boolean ForceApproxC1)
//=======================================================================
void BRepFill_PipeShell::DeleteProfile(const TopoDS_Shape& Profile)
{
Standard_Boolean isVertex = (Profile.ShapeType() == TopAbs_VERTEX);
Standard_Boolean Trouve=Standard_False;
Standard_Integer ii;
for (ii=1; ii<=mySeq.Length() && !Trouve; ii++) {
Standard_Boolean found = Standard_False;
const TopoDS_Wire& aWire = mySeq.Value(ii).Wire();
if (isVertex)
{
TopExp_Explorer Explo(aWire, TopAbs_VERTEX);
for (; Explo.More(); Explo.Next())
if (Profile.IsSame(Explo.Current()))
found = Standard_True;
}
else if (Profile.IsSame(aWire))
found = Standard_True;
if (found)
{
Trouve = Standard_True;
mySeq.Remove(ii);
}
const TopoDS_Shape& aSection = mySeq.Value(ii).OriginalShape();
if (Profile.IsSame(aSection))
{
Trouve = Standard_True;
mySeq.Remove(ii);
}
}
if (Trouve) mySection.Nullify();
@@ -705,7 +692,7 @@ void BRepFill_PipeShell::SetForceApproxC1(const Standard_Boolean ForceApproxC1)
//function : Build
//purpose : Construct the Shell and the history
//=======================================================================
Standard_Boolean BRepFill_PipeShell::Build()
Standard_Boolean BRepFill_PipeShell::Build()
{
Standard_Boolean Ok;
Standard_Real FirstS, LastS;
@@ -759,8 +746,9 @@ void BRepFill_PipeShell::SetForceApproxC1(const Standard_Boolean ForceApproxC1)
MkSw.SetTolerance(myTol3d, myBoundTol, 1.e-5, myTolAngular);
MkSw.SetAngularControl(angmin, angmax);
MkSw.SetForceApproxC1(myForceApproxC1);
MkSw.SetBounds(TopoDS::Wire(myFirst),
TopoDS::Wire(myLast));
MkSw.SetBounds(TopoDS::Wire(myFirst),
TopoDS::Wire(myLast));
GeomAbs_Shape theContinuity = GeomAbs_C2;
if (myTrihedron == GeomFill_IsDiscreteTrihedron)
theContinuity = GeomAbs_C0;
@@ -914,13 +902,9 @@ const TopoDS_Shape& BRepFill_PipeShell::LastShape() const
//function : Generated
//purpose :
//=======================================================================
// void BRepFill_PipeShell::Generated(const TopoDS_Shape& ,
// TopTools_ListOfShape& )
void BRepFill_PipeShell::Generated(const TopoDS_Shape& theShape,
TopTools_ListOfShape& theList)
{
// throw Standard_NotImplemented("Generated:Pas Fait");
theList.Clear();
if(myGenMap.IsBound(theShape)) {
@@ -1197,9 +1181,6 @@ void BRepFill_PipeShell::Place(const BRepFill_Section& Sec,
Sec.WithCorrection());
TopoDS_Wire TmpWire = Sec.Wire();
aTrsf = Place.Transformation();
//TopLoc_Location Loc2(Place.Transformation()), Loc1;
//Loc1 = TmpWire.Location();
//W.Location(Loc2.Multiplied(Loc1));
//Transform the copy
W = TopoDS::Wire(BRepBuilderAPI_Transform(TmpWire, aTrsf, Standard_True));
////////////////////////////////////
@@ -1240,37 +1221,40 @@ void BRepFill_PipeShell::BuildHistory(const BRepFill_Sweep& theSweep)
TopoDS_Iterator itw;
for (indw = 1; indw <= mySeq.Length(); indw++)
{
const TopoDS_Wire& aSection = mySeq(indw).Wire();
const TopoDS_Shape& Section = mySeq(indw).OriginalShape();
TopoDS_Wire aSection;
Standard_Boolean IsPunctual = mySeq(indw).IsPunctual();
if (IsPunctual)
{
//for punctual sections (first or last)
//we take all the wires generated along the path
TopExp_Explorer Explo(aSection, TopAbs_VERTEX);
const TopoDS_Shape& VerSection = Explo.Current();
TopTools_ListOfShape Elist;
for (Standard_Integer i = 1; i <= anUEdges->UpperRow(); i++)
for (Standard_Integer j = 1; j <= anUEdges->UpperCol(); j++)
Elist.Append(anUEdges->Value(i,j));
myGenMap.Bind(VerSection, Elist);
myGenMap.Bind(Section, Elist);
continue;
}
else
aSection = TopoDS::Wire(Section);
//Take the real index of section on the path
Standard_Integer IndOfW = myIndOfSec(indw);
const TopoDS_Wire& theWire = TopoDS::Wire(WSeq(IndOfW));
BRepTools_WireExplorer wexp_sec(aSection);
for (inde = 1; wexp_sec.More(); wexp_sec.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(wexp_sec.Current());
const TopoDS_Edge& anOriginalEdge = TopoDS::Edge(wexp_sec.Current());
TopoDS_Edge anEdge = TopoDS::Edge(mySeq(indw).ModifiedShape(anOriginalEdge));
if (BRep_Tool::Degenerated(anEdge))
continue;
TopoDS_Shell aShell;
BB.MakeShell(aShell);
TopoDS_Vertex aVertex [2];
TopExp::Vertices(anEdge, aVertex[0], aVertex[1]);
TopExp::Vertices(anOriginalEdge, aVertex[0], aVertex[1]);
Standard_Integer SignOfAnEdge =
(anEdge.Orientation() == TopAbs_FORWARD)? 1 : -1;
(anOriginalEdge.Orientation() == TopAbs_FORWARD)? 1 : -1;
//For each non-degenerated inde-th edge of <aSection>
//we find inde-th edge in <theWire>
@@ -1422,7 +1406,7 @@ void BRepFill_PipeShell::BuildHistory(const BRepFill_Sweep& theSweep)
TopTools_ListOfShape ListShell;
ListShell.Append(aShell);
myGenMap.Bind(anEdge, ListShell);
myGenMap.Bind(anOriginalEdge, ListShell);
////////////////////////
inde++;

View File

@@ -168,6 +168,10 @@ public:
Standard_EXPORT void Simulate (const Standard_Integer NumberOfSection, TopTools_ListOfShape& Sections);
//! Builds the resulting shape (redefined from MakeShape).
//! If theIsToCheckValidity == FALSE then BRepFill_Sweep algorithm
//! is allowed to create invalid faces (having self-interferences).
//! It is considered for them that such faces will be processed and
//! fixed by the high-level algorithms
Standard_EXPORT Standard_Boolean Build();
//! Transform the sweeping Shell in Solid.

View File

@@ -22,6 +22,9 @@
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp_Explorer.hxx>
#include <ShapeUpgrade_RemoveLocations.hxx>
BRepFill_Section::BRepFill_Section() :islaw(0),
ispunctual(0),
@@ -41,12 +44,19 @@ BRepFill_Section::BRepFill_Section(const TopoDS_Shape& Profile,
contact(WithContact),
correction(WithCorrection)
{
if (Profile.ShapeType() == TopAbs_WIRE)
wire = TopoDS::Wire(Profile);
else if (Profile.ShapeType() == TopAbs_VERTEX)
myOriginalShape = Profile;
ShapeUpgrade_RemoveLocations RemLoc;
RemLoc.SetRemoveLevel(TopAbs_COMPOUND);
RemLoc.Remove(Profile);
TopoDS_Shape aProfile = RemLoc.GetResult();
if (aProfile.ShapeType() == TopAbs_WIRE)
wire = TopoDS::Wire(aProfile);
else if (aProfile.ShapeType() == TopAbs_VERTEX)
{
ispunctual = Standard_True;
TopoDS_Vertex aVertex = TopoDS::Vertex(Profile);
TopoDS_Vertex aVertex = TopoDS::Vertex(aProfile);
BRep_Builder BB;
TopoDS_Edge DegEdge;
@@ -67,3 +77,58 @@ void BRepFill_Section::Set(const Standard_Boolean IsLaw)
{
islaw = IsLaw;
}
TopoDS_Shape BRepFill_Section::ModifiedShape(const TopoDS_Shape& theShape) const
{
TopoDS_Shape aModifiedShape;
switch (theShape.ShapeType())
{
case TopAbs_WIRE:
if (theShape.IsSame(myOriginalShape))
aModifiedShape = wire;
break;
case TopAbs_EDGE:
{
TopoDS_Iterator itor(myOriginalShape);
TopoDS_Iterator itw(wire);
for (; itor.More(); itor.Next(),itw.Next())
{
const TopoDS_Shape& anOriginalEdge = itor.Value();
const TopoDS_Shape& anEdge = itw.Value();
if (anOriginalEdge.IsSame(theShape))
{
aModifiedShape = anEdge;
break;
}
}
}
break;
case TopAbs_VERTEX:
if (theShape.IsSame(myOriginalShape))
{
TopExp_Explorer Explo(wire, TopAbs_VERTEX);
aModifiedShape = Explo.Current();
}
else
{
TopExp_Explorer ExpOrig(myOriginalShape, TopAbs_VERTEX);
TopExp_Explorer ExpWire(wire, TopAbs_VERTEX);
for (; ExpOrig.More(); ExpOrig.Next(),ExpWire.Next())
{
const TopoDS_Shape& anOriginalVertex = ExpOrig.Current();
const TopoDS_Shape& aVertex = ExpWire.Current();
if (anOriginalVertex.IsSame(theShape))
{
aModifiedShape = aVertex;
break;
}
}
}
break;
default:
break;
}
return aModifiedShape;
}

View File

@@ -43,10 +43,14 @@ public:
Standard_EXPORT void Set (const Standard_Boolean IsLaw);
const TopoDS_Shape& OriginalShape() const;
const TopoDS_Wire& Wire() const;
const TopoDS_Vertex& Vertex() const;
Standard_EXPORT TopoDS_Shape ModifiedShape(const TopoDS_Shape& theShape) const;
Standard_Boolean IsLaw() const;
Standard_Boolean IsPunctual() const;
@@ -68,6 +72,7 @@ private:
TopoDS_Shape myOriginalShape;
TopoDS_Wire wire;
TopoDS_Vertex vertex;
Standard_Boolean islaw;

View File

@@ -14,6 +14,11 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
inline const TopoDS_Shape& BRepFill_Section::OriginalShape() const
{
return myOriginalShape;
}
inline const TopoDS_Wire& BRepFill_Section::Wire() const
{
return wire;

View File

@@ -366,6 +366,56 @@ static Standard_Boolean SameParameter(TopoDS_Edge& E,
return Standard_True;
}
static void CorrectSameParameter(TopoDS_Edge& theEdge,
const TopoDS_Face& theFace1,
const TopoDS_Face& theFace2)
{
if (BRep_Tool::Degenerated(theEdge))
return;
Standard_Real fpar, lpar;
Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, fpar, lpar);
Standard_Boolean PCurveExists [2] = {Standard_False, Standard_False};
BRepAdaptor_Curve BAcurve [2];
if (!theFace1.IsNull())
{
PCurveExists[0] = Standard_True;
BAcurve[0].Initialize(theEdge, theFace1);
}
if (!theFace1.IsNull() &&
theFace1.IsSame(theFace2))
theEdge.Reverse();
if (!theFace2.IsNull())
{
PCurveExists[1] = Standard_True;
BAcurve[1].Initialize(theEdge, theFace2);
}
Standard_Real MaxSqDist = 0.;
const Standard_Integer NCONTROL = 23;
Standard_Real delta = (lpar - fpar)/NCONTROL;
for (Standard_Integer i = 0; i <= NCONTROL; i++)
{
Standard_Real aParam = fpar + i*delta;
gp_Pnt aPnt = aCurve->Value(aParam);
for (Standard_Integer j = 0; j < 2; j++)
if (PCurveExists[j])
{
gp_Pnt aPntFromFace = BAcurve[j].Value(aParam);
Standard_Real aSqDist = aPnt.SquareDistance(aPntFromFace);
if (aSqDist > MaxSqDist)
MaxSqDist = aSqDist;
}
}
Standard_Real aTol = sqrt(MaxSqDist);
BRep_Builder BB;
BB.UpdateEdge(theEdge, aTol);
}
//=======================================================================
//Objet : Orientate an edge of natural restriction
// : General
@@ -666,7 +716,7 @@ static TopoDS_Edge BuildEdge(Handle(Geom_Curve)& C3d,
// P2 = BT.Pnt(VL);
P2 = BRep_Tool::Pnt(VL);
// Tol2 = BT.Tolerance(VF);
Tol2 = BRep_Tool::Tolerance(VF);
Tol2 = BRep_Tool::Tolerance(VL);
Tol = Max(Tol1, Tol2);
if (VF.IsSame(VL) ||
@@ -809,24 +859,44 @@ static Standard_Boolean Filling(const TopoDS_Shape& EF,
Prof1 = BRep_Tool::Curve(E1, f1, l1);
// Prof2 = BT.Curve(E2, f2, l2);
Prof2 = BRep_Tool::Curve(E2, f2, l2);
gp_Pnt P1, P2, P;
gp_Pnt2d p1, p2;
gp_Trsf Tf;
Tf.SetTransformation(Axe);
// Choose the angle of opening
P1 = Prof1->Value((f1+l1)/2);
P2 = Prof2->Value((f2+l2)/2);
P1.Transform(Tf);
P2.Transform(Tf);
p1.SetCoord(P1.Z(), P1.X());
p2.SetCoord(P2.Z(), P2.X());
gp_Vec2d v1(gp::Origin2d(), p1);
gp_Vec2d v2(gp::Origin2d(), p2);
if (v1.Magnitude() <= gp::Resolution() ||
v2.Magnitude() <= gp::Resolution())
// Indeed, both Prof1 and Prof2 are the same curves but in different positions
gp_Pnt P1, P2, P;
// Choose the angle of opening
gp_Trsf aTf;
aTf.SetTransformation(Axe);
// Choose the furthest point from the "center of revolution"
// to provide correct angle measurement.
const Standard_Real aPrm[] = {f1, 0.5*(f1 + l1), l1};
const gp_Pnt aP1[] = {Prof1->Value(aPrm[0]).Transformed(aTf),
Prof1->Value(aPrm[1]).Transformed(aTf),
Prof1->Value(aPrm[2]).Transformed(aTf)};
Standard_Integer aMaxIdx = -1;
Standard_Real aMaxDist = RealFirst();
for (Standard_Integer i = 0; i < 3; i++)
{
const Standard_Real aDist = aP1[i].X()*aP1[i].X() + aP1[i].Z()*aP1[i].Z();
if (aDist > aMaxDist)
{
aMaxDist = aDist;
aMaxIdx = i;
}
}
const gp_Pnt aP2 = Prof2->Value(aPrm[aMaxIdx]).Transformed(aTf);
const gp_Vec2d aV1(aP1[aMaxIdx].Z(), aP1[aMaxIdx].X());
const gp_Vec2d aV2(aP2.Z(), aP2.X());
if (aV1.SquareMagnitude() <= gp::Resolution() ||
aV2.SquareMagnitude() <= gp::Resolution())
{
return Standard_False;
Angle = v1.Angle(v2);
}
Angle = aV1.Angle(aV2);
gp_Ax1 axe(Axe.Location(), Axe.YDirection());
@@ -837,14 +907,14 @@ static Standard_Boolean Filling(const TopoDS_Shape& EF,
Handle(Geom_SurfaceOfRevolution) Rev =
new (Geom_SurfaceOfRevolution) (Prof1, axe);
Handle(Geom_Surface) Surf =
new (Geom_RectangularTrimmedSurface) (Rev, 0, Angle, f1, l1);
// Control the direction of the rotation
Standard_Boolean ToReverseResult = Standard_False;
gp_Vec d1u;
d1u = Surf->DN(0, (f1+l1)/2, 1, 0);
d1u = Surf->DN(0, aPrm[aMaxIdx], 1, 0);
if (d1u.Angle(TangentOnPart1) > M_PI/2) { //Invert everything
ToReverseResult = Standard_True;
/*
@@ -1135,19 +1205,40 @@ static Standard_Boolean Filling(const TopoDS_Shape& EF,
B.MakeEdge(Aux2);
// Set the orientation
gp_Vec D1U, D1V, N1, N2;
C1->D0( (f1+l1)/2, P2d);
Surf->D1(P2d.X(), P2d.Y(), P, D1U, D1V);
N1 = D1U^D1V;
// Provide correct normals computation
// (the normal will be computed not in
// singularity point definitely).
Angle = RealFirst();
for (Standard_Integer i = 0; i < 3; i++)
{
gp_Vec D1U, D1V, N1, N2;
C1->D0(aPrm[i], P2d);
Surf->D1(P2d.X(), P2d.Y(), P, D1U, D1V);
N1 = D1U^D1V;
if (N1.SquareMagnitude() < Precision::SquareConfusion())
continue;
// C1 = BT.CurveOnSurface(E1, TopoDS::Face(F1), f2, l2);
C1 = BRep_Tool::CurveOnSurface(E1, TopoDS::Face(F1), f2, l2);
C1->D0(aPrm[i], P2d);
Handle(BRepAdaptor_HSurface) AS = new BRepAdaptor_HSurface(TopoDS::Face(F1));
AS->D1(P2d.X(), P2d.Y(), P, D1U, D1V);
N2 = D1U^D1V;
if (N2.SquareMagnitude() < Precision::SquareConfusion())
continue;
Angle = N1.Angle(N2);
break;
}
// C1 = BT.CurveOnSurface(E1, TopoDS::Face(F1), f2, l2);
C1 = BRep_Tool::CurveOnSurface(E1, TopoDS::Face(F1), f2, l2);
C1->D0( (f1+l1)/2, P2d);
Handle(BRepAdaptor_HSurface) AS = new BRepAdaptor_HSurface(TopoDS::Face(F1));
AS->D1(P2d.X(), P2d.Y(), P, D1U, D1V);
N2 = D1U^D1V;
if ( (F1.Orientation() == TopAbs_REVERSED) ^ (N1.Angle(N2)>M_PI/2) )
if (Angle == RealFirst())
return Standard_False;
if ( (F1.Orientation() == TopAbs_REVERSED) ^ (Angle>M_PI/2))
Result.Orientation(TopAbs_REVERSED);
else Result.Orientation(TopAbs_FORWARD);
@@ -1661,6 +1752,60 @@ static Standard_Boolean IsDegen(const Handle(Geom_Surface)& S,
return B;
}
static void ReverseEdgeInFirstOrLastWire(TopoDS_Shape& theWire,
const TopoDS_Shape& theEdge)
{
TopoDS_Shape EdgeToReverse;
TopoDS_Iterator itw(theWire);
for (; itw.More(); itw.Next())
{
const TopoDS_Shape& anEdge = itw.Value();
if (anEdge.IsSame(theEdge))
{
EdgeToReverse = anEdge;
break;
}
}
if (!EdgeToReverse.IsNull())
{
BRep_Builder BB;
theWire.Free(Standard_True);
BB.Remove(theWire, EdgeToReverse);
EdgeToReverse.Reverse();
BB.Add(theWire, EdgeToReverse);
}
}
static void ReverseModifiedEdges(TopoDS_Wire& theWire,
const TopTools_MapOfShape& theEmap)
{
if (theEmap.IsEmpty())
return;
TopoDS_Iterator itw(theWire);
BRep_Builder BB;
TopTools_ListOfShape Ledges;
for (; itw.More(); itw.Next())
Ledges.Append(itw.Value());
theWire.Free(Standard_True);
TopTools_ListIteratorOfListOfShape itl(Ledges);
for (; itl.More(); itl.Next())
BB.Remove(theWire, itl.Value());
for (itl.Initialize(Ledges); itl.More(); itl.Next())
{
TopoDS_Shape anEdge = itl.Value();
if (theEmap.Contains(anEdge))
anEdge.Reverse();
BB.Add(theWire, anEdge);
}
}
//=======================================================================
//function : Constructeur
//purpose :
@@ -1670,8 +1815,6 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
const Standard_Boolean WithKPart) :
isDone(Standard_False),
KPart(WithKPart)
{
mySec = Section;
myLoc = Location;
@@ -1947,11 +2090,12 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
BRep_Builder B;
Standard_Integer NbPath = ILast - IFirst;
Standard_Integer NbLaw = mySec->NbLaw();
Standard_Boolean uclose, vclose, constSection, hasdegen = Standard_False;
Standard_Boolean uclose, vclose, global_vclose, constSection, hasdegen = Standard_False;
constSection = mySec->IsConstant();
uclose = mySec->IsUClosed();
vclose = (mySec->IsVClosed() && myLoc->IsClosed()) &&
(NbPath == myLoc->NbLaw()) && (myLoc->IsG1(0, myTol3d)>= 0);
global_vclose = (myLoc->IsClosed()) && (myLoc->IsG1(0, myTol3d)>= 0);
Error = 0.;
// (1) Construction of all surfaces
@@ -2064,6 +2208,10 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
Standard_Boolean exuv, singu, singv;
Handle(Geom_Surface) S;
//Correct <FirstShape> and <LastShape>: reverse modified edges
ReverseModifiedEdges(FirstShape, ReversedEdges);
ReverseModifiedEdges(LastShape, ReversedEdges);
// (2.0) return preexisting Edges and vertices
TopoDS_Edge E;
TColStd_Array1OfBoolean IsBuilt(1, NbLaw);
@@ -2293,7 +2441,6 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
// ---------- Creation of Vertex and edge ------------
ReversedEdges.Clear();
for (ipath=1, IPath=IFirst; ipath<=NbPath;
ipath++, IPath++) {
for (isec=1; isec <=NbLaw; isec++) {
@@ -2496,7 +2643,10 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
TopoDS::Edge(VEdge(isec, ipath)),
ReversedEdges);
if (ReversedEdges.Contains(VEdge(isec, ipath)))
{
ReverseEdgeInFirstOrLastWire(FirstShape, VEdge(isec, ipath));
StartEdges(isec).Reverse();
}
}
}
@@ -2524,7 +2674,10 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
myTol3d);
else
{
if (ipath != NbPath || vclose)
if (ipath != NbPath ||
vclose ||
(global_vclose && ILast == myLoc->NbLaw()+1))
UpdateEdge(TopoDS::Edge(VEdge(isec, ipath+1)),
S, exuv, VLast);
else //ipath == NbPath && !vclose => rebuild last edge
@@ -2536,6 +2689,8 @@ BRepFill_Sweep::BRepFill_Sweep(const Handle(BRepFill_SectionLaw)& Section,
RebuildTopOrBottomEdge(aNewLastEdge,
TopoDS::Edge(VEdge(isec, ipath+1)),
ReversedEdges);
if (ReversedEdges.Contains(VEdge(isec, ipath+1)))
ReverseEdgeInFirstOrLastWire(LastShape, VEdge(isec, ipath+1));
}
}
}
@@ -2877,6 +3032,30 @@ void BRepFill_Sweep::Build(TopTools_MapOfShape& ReversedEdges,
}
}
//Ensure Same Parameter on U-edges
for (ii = myUEdges->LowerRow(); ii <= myUEdges->UpperRow(); ii++)
{
if (mySec->IsUClosed() && ii == myUEdges->UpperRow())
continue;
for (jj = myUEdges->LowerCol(); jj <= myUEdges->UpperCol(); jj++)
{
TopoDS_Edge anEdge = TopoDS::Edge(myUEdges->Value(ii, jj));
if (anEdge.IsNull())
continue;
TopoDS_Face Face1, Face2;
Standard_Integer i1 = ii-1, i2 = ii;
if (i1 == 0 && mySec->IsUClosed())
i1 = myFaces->UpperRow();
if (i2 > myFaces->UpperRow())
i2 = 0;
if (i1 != 0)
Face1 = TopoDS::Face(myFaces->Value(i1, jj));
if (i2 != 0)
Face2 = TopoDS::Face(myFaces->Value(i2, jj));
CorrectSameParameter(anEdge, Face1, Face2);
}
}
for (ii = 1; ii <= NbLaw; ii++)
for (jj = 1; jj <= NbPath; jj++)
{
@@ -3083,7 +3262,7 @@ TopoDS_Shape BRepFill_Sweep::Tape(const Standard_Integer Index) const
}
}
BRepFill_TrimShellCorner aTrim(aFaces, AxeOfBisPlane, aPlaneF);
BRepFill_TrimShellCorner aTrim(aFaces, Transition, AxeOfBisPlane);
aTrim.AddBounds(Bounds);
aTrim.AddUEdges(aUEdges);
aTrim.Perform();
@@ -3172,7 +3351,8 @@ TopoDS_Shape BRepFill_Sweep::Tape(const Standard_Integer Index) const
// Filling
B = Filling(It1.Value(), myFaces->Value(ii, I1),
It2.Value(), myFaces->Value(ii, I2),
myVEdgesModified, myTol3d, Axe, T1, Bord1, Bord2, FF);
myVEdgesModified, myTol3d, Axe, T1,
Bord1, Bord2, FF);
if (B) {
myAuxShape.Append(FF);

View File

@@ -80,7 +80,7 @@ public:
//! to be C0.
Standard_EXPORT void SetForceApproxC1 (const Standard_Boolean ForceApproxC1);
//! Build the Sweeep Surface
//! Build the Sweep Surface
//! Transition define Transition strategy
//! Approx define Approximation Strategy
//! - GeomFill_Section : The composed Function Location X Section
@@ -118,13 +118,6 @@ public:
protected:
private:
Standard_EXPORT Standard_Boolean CorrectApproxParameters();
Standard_EXPORT Standard_Boolean BuildWire (const BRepFill_TransitionStyle Transition);
@@ -142,6 +135,13 @@ private:
Standard_EXPORT void RebuildTopOrBottomEdge (const TopoDS_Edge& aNewEdge, TopoDS_Edge& anEdge, TopTools_MapOfShape& ReversedEdges) const;
private:
Standard_Boolean isDone;
Standard_Boolean KPart;
Standard_Real myTol3d;
@@ -168,7 +168,6 @@ private:
TopoDS_Wire FirstShape;
TopoDS_Wire LastShape;
};

View File

@@ -25,6 +25,7 @@
#include <BRepFill_TrimShellCorner.hxx>
#include <BRepLib_MakeEdge.hxx>
#include <BRepLib_MakeWire.hxx>
#include <BRepLib_MakeVertex.hxx>
#include <BRepTools_ReShape.hxx>
#include <gce_MakeLin.hxx>
#include <GCPnts_UniformAbscissa.hxx>
@@ -63,6 +64,23 @@
#include <TopTools_ListOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <BRepExtrema_ExtCC.hxx>
static TopoDS_Edge FindEdgeCloseToBisectorPlane(const TopoDS_Vertex& theVertex,
TopoDS_Compound& theComp,
const gp_Ax1& theAxis);
static Standard_Boolean FindMiddleEdges(const TopoDS_Vertex& theVertex1,
const TopoDS_Vertex& theVertex2,
const gp_Ax1& theAxis,
TopoDS_Compound& theComp,
TopTools_ListOfShape& theElist);
static Standard_Boolean FindCommonVertex(const TopoDS_Edge& theFirstEdge,
const TopoDS_Edge& theLastEdge,
const TopoDS_Vertex& theFirstVertex,
const TopoDS_Vertex& theLastVertex,
TopoDS_Vertex& theCommonVertex);
static Standard_Boolean FindCommonVertex(const BOPDS_PDS& theDS,
const Standard_Integer theEIndex1,
@@ -71,24 +89,6 @@ static Standard_Boolean FindCommonVertex(const BOPDS_PDS& theDS,
Standard_Real& theParamOnE1,
Standard_Real& theParamOnE2);
static Standard_Boolean MakeFacesNonSec(const Standard_Integer theIndex,
const Handle(TopTools_HArray2OfShape)& theUEdges,
const Handle(TopTools_HArray2OfShape)& theBounds,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
TopTools_DataMapOfShapeListOfShape& theHistMap);
static Standard_Boolean MakeFacesSec(const Standard_Integer theIndex,
const Handle(TopTools_HArray2OfShape)& theUEdges,
const Handle(TopTools_HArray2OfShape)& theBounds,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
const Standard_Integer theSSInterfIndex,
const gp_Ax2& AxeOfBisPlane,
TopTools_DataMapOfShapeListOfShape& theHistMap);
static Standard_Boolean SplitUEdges(const Handle(TopTools_HArray2OfShape)& theUEdges,
const BOPDS_PDS& theDS,
TopTools_DataMapOfShapeListOfShape& theHistMap);
@@ -186,55 +186,27 @@ static Standard_Real ComputeAveragePlaneAndMaxDeviation(const TopoDS_Shape& aWir
gp_Pln& thePlane,
Standard_Boolean& IsSingular);
static Standard_Boolean ChooseSection(const TopoDS_Shape& Comp,
const gp_Ax2& bis,
TopoDS_Shape& resWire,
gp_Pln& resPlane,
Standard_Boolean& IsSingular);
static void UpdateSectionEdge(TopoDS_Edge& theEdge,
const TopoDS_Vertex& theConstVertex,
TopoDS_Vertex& theVertex,
const Standard_Real theParam);
// ===========================================================================================
// function: Constructor
// purpose:
// ===========================================================================================
BRepFill_TrimShellCorner::BRepFill_TrimShellCorner(const Handle(TopTools_HArray2OfShape)& theFaces,
const gp_Ax2& theAxeOfBisPlane,
const TopoDS_Face& theSecPlane) :
myAxeOfBisPlane(theAxeOfBisPlane),
myDone(Standard_False),
myHasSection(Standard_False)
const BRepFill_TransitionStyle theTransition,
const gp_Ax2& theAxeOfBisPlane) :
myTransition(theTransition),
myAxeOfBisPlane(theAxeOfBisPlane),
myDone(Standard_False),
myHasSection(Standard_False)
{
myFaces = new TopTools_HArray2OfShape(theFaces->LowerRow(), theFaces->UpperRow(),
theFaces->LowerCol(), theFaces->UpperCol());
myFaces->ChangeArray2() = theFaces->Array2();
mySecPln = theSecPlane;
}
// ===========================================================================================
// function: Constructor
// purpose:
// ===========================================================================================
BRepFill_TrimShellCorner::BRepFill_TrimShellCorner(const Handle(TopTools_HArray2OfShape)& theFaces,
const gp_Ax2& theAxeOfBisPlane,
const TopoDS_Wire& theSpine,
const TopoDS_Face& theSecPlane):
myAxeOfBisPlane(theAxeOfBisPlane),
myDone(Standard_False),
myHasSection(Standard_False)
{
myFaces = new TopTools_HArray2OfShape(theFaces->LowerRow(), theFaces->UpperRow(),
theFaces->LowerCol(), theFaces->UpperCol());
myFaces->ChangeArray2() = theFaces->Array2();
mySpine = theSpine;
mySecPln = theSecPlane;
}
// ===========================================================================================
// function: SetSpine
// purpose:
// ===========================================================================================
void BRepFill_TrimShellCorner::SetSpine(const TopoDS_Wire& theSpine)
{
mySpine = theSpine;
}
// ===========================================================================================
@@ -351,14 +323,13 @@ void BRepFill_TrimShellCorner::Perform()
}
if(!bhassec) {
if(!MakeFacesNonSec(ii, myUEdges, myBounds, theDS, anIndex1, anIndex2, myHistMap)) {
if(!MakeFacesNonSec(ii, theDS, anIndex1, anIndex2)) {
myHistMap.Clear();
return;
}
}
else {
if(!MakeFacesSec(ii, myUEdges, myBounds, theDS, anIndex1, anIndex2,
i, myAxeOfBisPlane, myHistMap)) {
if(!MakeFacesSec(ii, theDS, anIndex1, anIndex2, i)) {
myHistMap.Clear();
return;
}
@@ -403,23 +374,21 @@ void BRepFill_TrimShellCorner::Modified(const TopoDS_Shape& theShape,
}
// ----------------------------------------------------------------------------------------------------
// static function: MakeFacesNonSec
// purpose:
// function: MakeFacesNonSec
// purpose: Updates <myHistMap> by new faces in the case when old faces do not intersect
// ----------------------------------------------------------------------------------------------------
Standard_Boolean MakeFacesNonSec(const Standard_Integer theIndex,
const Handle(TopTools_HArray2OfShape)& theUEdges,
const Handle(TopTools_HArray2OfShape)& theBounds,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
TopTools_DataMapOfShapeListOfShape& theHistMap)
Standard_Boolean
BRepFill_TrimShellCorner::MakeFacesNonSec(const Standard_Integer theIndex,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2)
{
Standard_Boolean bHasNewEdge = Standard_False;
TopoDS_Edge aNewEdge;
BRep_Builder aBB;
const TopoDS_Shape& aE1 = theBounds->Value(theIndex, 1);
const TopoDS_Shape& aE2 = theBounds->Value(theIndex, 2);
const TopoDS_Shape& aE1 = myBounds->Value(theIndex, 1);
const TopoDS_Shape& aE2 = myBounds->Value(theIndex, 2);
// search common vertex between bounds. begin
TopoDS_Vertex aCommonVertex;
@@ -439,20 +408,20 @@ Standard_Boolean MakeFacesNonSec(const Standard_Integer theI
Standard_Integer ueit = 0, eindex = 0;
for(ueit = 1, eindex = theIndex; ueit <= 2; ueit++, eindex++) {
const TopoDS_Shape& aShape1 = theUEdges->Value(eindex, theUEdges->LowerCol());
const TopoDS_Shape& aShape2 = theUEdges->Value(eindex, theUEdges->UpperCol());
const TopoDS_Shape& aShape1 = myUEdges->Value(eindex, myUEdges->LowerCol());
const TopoDS_Shape& aShape2 = myUEdges->Value(eindex, myUEdges->UpperCol());
TopoDS_Edge aUE1 = TopoDS::Edge(aShape1);
TopoDS_Edge aUE2 = TopoDS::Edge(aShape2);
if(theHistMap.IsBound(aShape1)) {
const TopTools_ListOfShape& lst = theHistMap.Find(aShape1);
if (myHistMap.IsBound(aShape1)) {
const TopTools_ListOfShape& lst = myHistMap.Find(aShape1);
if(!lst.IsEmpty())
aUE1 = TopoDS::Edge(lst.First());
}
if(theHistMap.IsBound(aShape2)) {
const TopTools_ListOfShape& lst = theHistMap.Find(aShape2);
if (myHistMap.IsBound(aShape2)) {
const TopTools_ListOfShape& lst = myHistMap.Find(aShape2);
if(!lst.IsEmpty())
aUE2 = TopoDS::Edge(lst.First());
@@ -499,11 +468,11 @@ Standard_Boolean MakeFacesNonSec(const Standard_Integer theI
aBB.MakeCompound(aComp);
for(ueit = 1, eindex = theIndex; ueit <= 2; ueit++, eindex++) {
const TopoDS_Shape& aShape = theUEdges->Value(eindex, theUEdges->LowerCol() + fit - 1);
const TopoDS_Shape& aShape = myUEdges->Value(eindex, myUEdges->LowerCol() + fit - 1);
TopoDS_Shape aUE = aShape;
if(theHistMap.IsBound(aShape)) {
const TopTools_ListOfShape& lst = theHistMap.Find(aShape);
if(myHistMap.IsBound(aShape)) {
const TopTools_ListOfShape& lst = myHistMap.Find(aShape);
if(!lst.IsEmpty())
aUE = TopoDS::Edge(lst.First());
@@ -638,7 +607,7 @@ Standard_Boolean MakeFacesNonSec(const Standard_Integer theI
aNewFace.Orientation(aFaceOri);
TopTools_ListOfShape atmpList;
atmpList.Append(aNewFace);
theHistMap.Bind(aFace, atmpList);
myHistMap.Bind(aFace, atmpList);
anExpE.Init(aFace, TopAbs_EDGE);
@@ -648,7 +617,7 @@ Standard_Boolean MakeFacesNonSec(const Standard_Integer theI
if(aNewValue.IsNull() || aNewValue.IsSame(anExpE.Current()))
continue;
if(theHistMap.IsBound(anExpE.Current()))
if (myHistMap.IsBound(anExpE.Current()))
continue;
TopTools_ListOfShape aListOfNewEdge;
TopExp_Explorer anExpE2(aNewValue, TopAbs_EDGE);
@@ -656,7 +625,7 @@ Standard_Boolean MakeFacesNonSec(const Standard_Integer theI
for(; anExpE2.More(); anExpE2.Next()) {
aListOfNewEdge.Append(anExpE2.Current());
}
theHistMap.Bind(anExpE.Current(), aListOfNewEdge);
myHistMap.Bind(anExpE.Current(), aListOfNewEdge);
}
}
@@ -664,18 +633,15 @@ Standard_Boolean MakeFacesNonSec(const Standard_Integer theI
}
// ----------------------------------------------------------------------------------------------------
// static function: MakeFacesSec
// purpose:
// function: MakeFacesSec
// purpose: Updates <myHistMap> by new faces in the case when old faces intersect each other
// ----------------------------------------------------------------------------------------------------
Standard_Boolean MakeFacesSec(const Standard_Integer theIndex,
const Handle(TopTools_HArray2OfShape)& theUEdges,
const Handle(TopTools_HArray2OfShape)& theBounds,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
const Standard_Integer theSSInterfIndex,
const gp_Ax2& AxeOfBisPlane,
TopTools_DataMapOfShapeListOfShape& theHistMap)
Standard_Boolean
BRepFill_TrimShellCorner::MakeFacesSec(const Standard_Integer theIndex,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
const Standard_Integer theSSInterfIndex)
{
const BOPDS_VectorOfInterfFF& aFFs = theDS->InterfFF();
const BOPDS_InterfFF& aFFi = aFFs(theSSInterfIndex);
@@ -687,10 +653,30 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
if(!FilterSectionEdges(aBCurves, aSecPlane, theDS, aSecEdges))
return Standard_False;
//Extract vertices on the intersection of correspondent U-edges
const TopoDS_Shape& LeftE1 = myUEdges->Value(theIndex, 1);
const TopoDS_Shape& LeftE2 = myUEdges->Value(theIndex, 2);
const TopoDS_Shape& RightE1 = myUEdges->Value(theIndex+1, 1);
const TopoDS_Shape& RightE2 = myUEdges->Value(theIndex+1, 2);
Standard_Integer IndexOfLeftE1 = theDS->Index(LeftE1);
Standard_Integer IndexOfLeftE2 = theDS->Index(LeftE2);
Standard_Integer IndexOfRightE1 = theDS->Index(RightE1);
Standard_Integer IndexOfRightE2 = theDS->Index(RightE2);
TopoDS_Vertex FirstVertex, LastVertex;
Standard_Real ParamOnLeftE1, ParamOnLeftE2, ParamOnRightE1, ParamOnRightE2;
FindCommonVertex(theDS, IndexOfLeftE1, IndexOfLeftE2,
FirstVertex, ParamOnLeftE1, ParamOnLeftE2);
FindCommonVertex(theDS, IndexOfRightE1, IndexOfRightE2,
LastVertex, ParamOnRightE1, ParamOnRightE2);
TopoDS_Shape SecWire;
gp_Pln SecPlane;
Standard_Boolean IsSingular;
Standard_Boolean WireFound = ChooseSection( aSecEdges, AxeOfBisPlane, SecWire, SecPlane, IsSingular );
Standard_Boolean WireFound = ChooseSection(aSecEdges,
FirstVertex, LastVertex,
SecWire, SecPlane, IsSingular );
if(WireFound) {
//aSecEdges = SecWire;
@@ -715,19 +701,19 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
TopAbs_Orientation aFaceOri = aFace.Orientation();
TopoDS_Face aFaceF = aFace;
aFaceF.Orientation(TopAbs_FORWARD);
TopoDS_Edge aBoundEdge = TopoDS::Edge(theBounds->Value(theIndex, theBounds->LowerCol() +fit));
TopoDS_Edge aBoundEdge = TopoDS::Edge(myBounds->Value(theIndex, myBounds->LowerCol() +fit));
Standard_Integer aBoundEdgeIndex = theDS->Index(aBoundEdge);
TopoDS_Edge aUE1;
TopoDS_Edge aUE2;
if(!GetUEdges(theIndex, fit, theUEdges, aBoundEdge, aFaceF, aUE1, aUE2))
if(!GetUEdges(theIndex, fit, myUEdges, aBoundEdge, aFaceF, aUE1, aUE2))
return Standard_False;
TopoDS_Edge aUE1old = aUE1;
TopoDS_Edge aUE2old = aUE2;
if(theHistMap.IsBound(aUE1)) {
const TopTools_ListOfShape& lst = theHistMap.Find(aUE1);
if (myHistMap.IsBound(aUE1)) {
const TopTools_ListOfShape& lst = myHistMap.Find(aUE1);
if(!lst.IsEmpty()) {
const TopoDS_Shape& anEdge = lst.First().Oriented(aUE1.Orientation());
@@ -738,8 +724,8 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
}
}
if(theHistMap.IsBound(aUE2)) {
const TopTools_ListOfShape& lst = theHistMap.Find(aUE2);
if (myHistMap.IsBound(aUE2)) {
const TopTools_ListOfShape& lst = myHistMap.Find(aUE2);
if(!lst.IsEmpty()) {
const TopoDS_Shape& anEdge = lst.First().Oriented(aUE2.Orientation());
@@ -757,12 +743,12 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
Standard_Boolean isPave1OnUEdge = Standard_True;
if(FindFromUEdge(aUE1old, aUE2old, aUE1, aUE2, aFace, aSecEdges, fit, aBoundEdge, aBoundEdgeIndex,
theDS, theHistMap, aCompOfSecEdges, aListOfWireEdges, aPave1, isPave1OnUEdge)) {
theDS, myHistMap, aCompOfSecEdges, aListOfWireEdges, aPave1, isPave1OnUEdge)) {
TopTools_ListOfShape aSecondListOfEdges;
Standard_Boolean bisSectionFound = Standard_False;
if(!FindFromVEdge(aPave1, isPave1OnUEdge, aUE1old, aUE2old, aFace, aCompOfSecEdges, fit, aBoundEdge,
aBoundEdgeIndex, theDS, theHistMap, aSecondListOfEdges, bisSectionFound)) {
aBoundEdgeIndex, theDS, myHistMap, aSecondListOfEdges, bisSectionFound)) {
return Standard_False;
}
@@ -792,7 +778,7 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
aNewFace.Orientation(aFaceOri);
TopTools_ListOfShape atmpList;
atmpList.Append(aNewFace);
theHistMap.Bind(aFace, atmpList);
myHistMap.Bind(aFace, atmpList);
TopExp_Explorer anExpE(aFace, TopAbs_EDGE);
@@ -802,7 +788,7 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
if(aNewValue.IsNull() || aNewValue.IsSame(anExpE.Current()))
continue;
if(theHistMap.IsBound(anExpE.Current()))
if (myHistMap.IsBound(anExpE.Current()))
continue;
TopTools_ListOfShape aListOfNewEdge;
TopExp_Explorer anExpE2(aNewValue, TopAbs_EDGE);
@@ -810,12 +796,240 @@ Standard_Boolean MakeFacesSec(const Standard_Integer theInde
for(; anExpE2.More(); anExpE2.Next()) {
aListOfNewEdge.Append(anExpE2.Current());
}
theHistMap.Bind(anExpE.Current(), aListOfNewEdge);
myHistMap.Bind(anExpE.Current(), aListOfNewEdge);
}
}
return Standard_True;
}
//=======================================================================
//function : ChooseSection
//purpose :
//=======================================================================
Standard_Boolean BRepFill_TrimShellCorner::ChooseSection(const TopoDS_Shape& Comp,
const TopoDS_Vertex& theFirstVertex,
const TopoDS_Vertex& theLastVertex,
TopoDS_Shape& resWire,
gp_Pln& resPlane,
Standard_Boolean& IsSingular)
{
IsSingular = Standard_False;
Standard_Integer ind, i, j;
BRep_Builder BB;
if (myTransition == BRepFill_Right &&
!theFirstVertex.IsNull() &&
!theLastVertex.IsNull()) //the case where section wire goes from
//its known first vertex to its known last vertex
{
TopoDS_Wire NewWire;
BB.MakeWire(NewWire);
TopoDS_Compound OldComp;
BB.MakeCompound( OldComp );
TopoDS_Iterator iter( Comp );
for (; iter.More(); iter.Next())
BB.Add( OldComp, iter.Value() );
TopoDS_Edge FirstEdge = FindEdgeCloseToBisectorPlane(theFirstVertex,
OldComp,
myAxeOfBisPlane.Axis());
iter.Initialize(OldComp);
if (!iter.More())
{
iter.Initialize(Comp);
BB.Add( OldComp, iter.Value() );
}
TopoDS_Edge LastEdge = FindEdgeCloseToBisectorPlane(theLastVertex,
OldComp,
myAxeOfBisPlane.Axis());
BB.Add(NewWire, FirstEdge);
if (!FirstEdge.IsSame(LastEdge))
{
TopoDS_Vertex aCommonVertex;
Standard_Boolean CommonVertexExists = FindCommonVertex(FirstEdge, LastEdge,
theFirstVertex, theLastVertex,
aCommonVertex);
if (CommonVertexExists)
BB.Add(NewWire, LastEdge);
else
{
TopoDS_Vertex Vertex1, Vertex2, V1, V2;
TopExp::Vertices(FirstEdge, V1, V2);
Vertex1 = (theFirstVertex.IsSame(V1))? V2 : V1;
TopExp::Vertices(LastEdge, V1, V2);
Vertex2 = (theLastVertex.IsSame(V1))? V2 : V1;
TopTools_ListOfShape MiddleEdges;
if (FindMiddleEdges(Vertex1, Vertex2, myAxeOfBisPlane.Axis(), OldComp, MiddleEdges))
{
TopTools_ListIteratorOfListOfShape itl(MiddleEdges);
for (; itl.More(); itl.Next())
BB.Add(NewWire, itl.Value());
BB.Add(NewWire, LastEdge);
}
else
{
//trim <FirstEdge> and <LastEdge> in the points of extrema
//these points become new vertex with centre between them
BRepExtrema_ExtCC Extrema(FirstEdge, LastEdge);
if (Extrema.IsDone() && Extrema.NbExt() > 0)
{
Standard_Integer imin = 1;
for (i = 2; i <= Extrema.NbExt(); i++)
if (Extrema.SquareDistance(i) < Extrema.SquareDistance(imin))
imin = i;
Standard_Real aMinDist = sqrt(Extrema.SquareDistance(imin));
Standard_Real ParamOnFirstEdge = Extrema.ParameterOnE1(imin);
Standard_Real ParamOnLastEdge = Extrema.ParameterOnE2(imin);
gp_Pnt PointOnFirstEdge = Extrema.PointOnE1(imin);
gp_Pnt PointOnLastEdge = Extrema.PointOnE2(imin);
gp_Pnt MidPnt((PointOnFirstEdge.XYZ() + PointOnLastEdge.XYZ())/2);
aCommonVertex = BRepLib_MakeVertex(MidPnt);
BB.UpdateVertex(aCommonVertex, 1.001*aMinDist/2);
UpdateSectionEdge(FirstEdge, theFirstVertex, aCommonVertex, ParamOnFirstEdge);
UpdateSectionEdge(LastEdge, theLastVertex, aCommonVertex, ParamOnLastEdge);
BB.Add(NewWire, LastEdge);
}
}
}
}
resWire = NewWire;
resPlane = gp_Pln(myAxeOfBisPlane);
return Standard_True;
}
//General case: try to find continuous section closest to bisector plane
TopoDS_Compound OldComp;
BRep_Builder B;
B.MakeCompound( OldComp );
TopoDS_Iterator iter( Comp );
for (; iter.More(); iter.Next())
B.Add( OldComp, iter.Value() );
Standard_Boolean anError = Standard_False;
//TopoDS_Wire NewWire [2];
TopTools_SequenceOfShape Wseq;
for (;;)
{
TopExp_Explorer explo( OldComp, TopAbs_EDGE );
if (!explo.More())
break;
TopoDS_Edge FirstEdge = TopoDS::Edge( explo.Current() );
TopoDS_Wire NewWire = BRepLib_MakeWire( FirstEdge );
B.Remove( OldComp, FirstEdge );
if (NewWire.Closed())
{
Wseq.Append(NewWire);
continue;
}
for (;;)
{
TopoDS_Vertex Extremity [2];
TopExp::Vertices( NewWire, Extremity[0], Extremity[1] );
if (Extremity[0].IsNull() || Extremity[1].IsNull())
{
anError = Standard_True;
break;
}
TopTools_IndexedDataMapOfShapeListOfShape VEmap;
TopExp::MapShapesAndAncestors( OldComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap );
TopTools_ListOfShape Vedges [2];
for (j = 0; j < 2; j++)
if (VEmap.Contains( Extremity[j] ))
Vedges[j] = VEmap.FindFromKey( Extremity[j] );
if (Vedges[0].IsEmpty() && Vedges[1].IsEmpty())
//no more edges in OldComp to continue NewWire
break;
Standard_Boolean Modified = Standard_False;
for (j = 0; j < 2; j++)
{
if (Vedges[j].Extent() == 1)
{
const TopoDS_Edge& anEdge = TopoDS::Edge( Vedges[j].First() );
NewWire = BRepLib_MakeWire( NewWire, anEdge );
B.Remove( OldComp, anEdge );
Modified = Standard_True;
}
}
if (!Modified) //only multiple connections
{
ind = (Vedges[0].IsEmpty())? 1 : 0;
TopTools_SequenceOfShape Edges;
TopTools_ListIteratorOfListOfShape itl( Vedges[ind] );
for (; itl.More(); itl.Next())
Edges.Append( itl.Value() );
Standard_Integer theind=0;
Standard_Real MinDeviation = RealLast();
for (j = 1; j <= Edges.Length(); j++)
{
TopoDS_Wire aWire = BRepLib_MakeWire( NewWire, TopoDS::Edge(Edges(j)) );
gp_Pln aPlane;
Standard_Boolean issing;
Standard_Real Deviation = ComputeAveragePlaneAndMaxDeviation( aWire, aPlane, issing );
if (Deviation < MinDeviation)
{
MinDeviation = Deviation;
theind = j;
}
}
NewWire = BRepLib_MakeWire( NewWire, TopoDS::Edge(Edges(theind)) );
B.Remove( OldComp, Edges(theind) );
}
if (NewWire.Closed())
break;
}
Wseq.Append(NewWire);
if (anError)
break;
}
Standard_Real MinAngle = RealLast();
TopExp_Explorer Explo( OldComp, TopAbs_EDGE );
if (!anError && !Explo.More()) //wires are built successfully and compound <OldComp> is empty
{
if (Wseq.Length() == 1) //only one wire => it becomes result
{
resWire = Wseq.First();
ComputeAveragePlaneAndMaxDeviation( resWire, resPlane, IsSingular );
return Standard_True;
}
else //we must choose the wire which average plane is closest to bisector plane
{ //(check angle between axes)
for (i = 1; i <= Wseq.Length(); i++)
{
TopoDS_Wire aWire = TopoDS::Wire( Wseq(i) );
gp_Pln aPln;
Standard_Boolean issing;
ComputeAveragePlaneAndMaxDeviation( aWire, aPln, issing );
if (issing)
continue;
Standard_Real Angle = aPln.Axis().Angle( myAxeOfBisPlane.Axis() );
if (Angle > M_PI/2)
Angle = M_PI - Angle;
if (Angle < MinAngle)
{
MinAngle = Angle;
resWire = aWire;
resPlane = aPln;
}
}
return Standard_True;
}
}
return Standard_False;
}
// ------------------------------------------------------------------------------------------
// static function: SplitUEdges
@@ -966,13 +1180,15 @@ Standard_Boolean FindCommonVertex(const BOPDS_PDS& theDS,
continue;
IntTools_CommonPrt aCP = aEE.CommonPart();
if(aCP.Type() == TopAbs_VERTEX) {
if(aCP.Type() == TopAbs_VERTEX)
{
theCommonVertex = *(TopoDS_Vertex*)&theDS->Shape(aEE.IndexNew());
if (theEIndex1 == aEE.Index1()) {
if (theEIndex1 == aEE.Index1())
IntTools_Tools::VertexParameters(aCP, theParamOnE1, theParamOnE2);
} else {
else
IntTools_Tools::VertexParameters(aCP, theParamOnE2, theParamOnE1);
}
//
bvertexfound = Standard_True;
break;
@@ -2004,147 +2220,182 @@ static Standard_Real ComputeAveragePlaneAndMaxDeviation(const TopoDS_Shape& aWir
return MaxDeviation;
}
//=======================================================================
//function : ChooseSection
//purpose :
//=======================================================================
static Standard_Boolean ChooseSection(const TopoDS_Shape& Comp,
const gp_Ax2& bis,
TopoDS_Shape& resWire,
gp_Pln& resPlane,
Standard_Boolean& IsSingular)
static void UpdateSectionEdge(TopoDS_Edge& theEdge,
const TopoDS_Vertex& theConstVertex,
TopoDS_Vertex& theVertex,
const Standard_Real theParam)
{
IsSingular = Standard_False;
Standard_Real TolDeviation = 0.01; //, TolConf = 1.e-4, TolAng = 1.e-5;
TopoDS_Edge F_Edge = theEdge;
F_Edge.Orientation(TopAbs_FORWARD);
TopAbs_Orientation OrOfVertex;
TopoDS_Vertex V1, V2, AnotherVertex;
TopExp::Vertices(F_Edge, V1, V2);
if (theConstVertex.IsSame(V1))
{
//OrOfConst = TopAbs_FORWARD;
OrOfVertex = TopAbs_REVERSED;
AnotherVertex = V2;
}
else
{
//OrOfConst = TopAbs_REVERSED;
OrOfVertex = TopAbs_FORWARD;
AnotherVertex = V1;
}
// Standard_Integer N = 100;
Standard_Integer ind, i, j;
BRep_Builder BB;
Standard_Real fpar, lpar;
BRep_Tool::Range(F_Edge, fpar, lpar);
if (OrOfVertex == TopAbs_FORWARD)
fpar = theParam;
else
lpar = theParam;
BB.Range(F_Edge, fpar, lpar);
//Simplest case
TopoDS_Compound OldComp;
BRep_Builder B;
B.MakeCompound( OldComp );
TopoDS_Iterator iter( Comp );
for (; iter.More(); iter.Next())
B.Add( OldComp, iter.Value() );
Standard_Boolean anError = Standard_False;
//TopoDS_Wire NewWire [2];
TopTools_SequenceOfShape Wseq;
for (;;)
{
TopExp_Explorer explo( OldComp, TopAbs_EDGE );
if (!explo.More())
break;
TopoDS_Edge FirstEdge = TopoDS::Edge( explo.Current() );
TopoDS_Wire NewWire = BRepLib_MakeWire( FirstEdge );
B.Remove( OldComp, FirstEdge );
if (NewWire.Closed())
{
Wseq.Append(NewWire);
continue;
}
for (;;)
{
TopoDS_Vertex Extremity [2];
TopExp::Vertices( NewWire, Extremity[0], Extremity[1] );
if (Extremity[0].IsNull() || Extremity[1].IsNull())
{
anError = Standard_True;
break;
}
TopTools_IndexedDataMapOfShapeListOfShape VEmap;
TopExp::MapShapesAndAncestors( OldComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap );
TopTools_ListOfShape Vedges [2];
for (j = 0; j < 2; j++)
if (VEmap.Contains( Extremity[j] ))
Vedges[j] = VEmap.FindFromKey( Extremity[j] );
if (Vedges[0].IsEmpty() && Vedges[1].IsEmpty())
//no more edges in OldComp to continue NewWire
break;
Standard_Boolean Modified = Standard_False;
for (j = 0; j < 2; j++)
{
if (Vedges[j].Extent() == 1)
{
const TopoDS_Edge& anEdge = TopoDS::Edge( Vedges[j].First() );
NewWire = BRepLib_MakeWire( NewWire, anEdge );
B.Remove( OldComp, anEdge );
Modified = Standard_True;
}
}
if (!Modified) //only multiple connections
{
ind = (Vedges[0].IsEmpty())? 1 : 0;
TopTools_SequenceOfShape Edges;
TopTools_ListIteratorOfListOfShape itl( Vedges[ind] );
for (; itl.More(); itl.Next())
Edges.Append( itl.Value() );
Standard_Integer theind=0;
Standard_Real MinDeviation = RealLast();
for (j = 1; j <= Edges.Length(); j++)
{
TopoDS_Wire aWire = BRepLib_MakeWire( NewWire, TopoDS::Edge(Edges(j)) );
gp_Pln aPlane;
Standard_Boolean issing;
Standard_Real Deviation = ComputeAveragePlaneAndMaxDeviation( aWire, aPlane, issing );
if (Deviation < MinDeviation)
{
MinDeviation = Deviation;
theind = j;
}
}
NewWire = BRepLib_MakeWire( NewWire, TopoDS::Edge(Edges(theind)) );
B.Remove( OldComp, Edges(theind) );
}
if (NewWire.Closed())
break;
}
Wseq.Append(NewWire);
if (anError)
break;
}
Standard_Real Deviation=0.;
Standard_Real MinAngle = RealLast();
TopExp_Explorer Explo( OldComp, TopAbs_EDGE );
if (!anError && !Explo.More())
{
if (Wseq.Length() == 1)
{
resWire = Wseq.First();
Deviation = ComputeAveragePlaneAndMaxDeviation( resWire, resPlane, IsSingular );
return Standard_True;
}
else
{
for (i = 1; i <= Wseq.Length(); i++)
{
TopoDS_Wire aWire = TopoDS::Wire( Wseq(i) );
gp_Pln aPln;
Standard_Boolean issing;
Standard_Real aDeviation =
ComputeAveragePlaneAndMaxDeviation( aWire, aPln, issing );
if (issing)
continue;
Standard_Real Angle = aPln.Axis().Angle( bis.Axis() );
if (Angle > M_PI/2)
Angle = M_PI - Angle;
if (Angle < MinAngle)
{
MinAngle = Angle;
resWire = aWire;
resPlane = aPln;
Deviation = aDeviation;
}
}
if (Deviation <= TolDeviation)
return Standard_True;
}
}
return Standard_False;
//end of simplest case
F_Edge.Free(Standard_True);
BB.Remove(F_Edge, AnotherVertex);
theVertex.Orientation(OrOfVertex);
BB.Add(F_Edge, theVertex);
}
//Finds the edge connected to <theVertex> in the compound <theComp>
//that is closest to bisector plane angularly.
//Removes found edge from <theComp>
//<theAxis> is the axis of bisector plane
static TopoDS_Edge FindEdgeCloseToBisectorPlane(const TopoDS_Vertex& theVertex,
TopoDS_Compound& theComp,
const gp_Ax1& theAxis)
{
TopTools_IndexedDataMapOfShapeListOfShape VEmap;
TopExp::MapShapesAndAncestors( theComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap );
TopoDS_Edge MinEdge;
if (!VEmap.Contains(theVertex))
return MinEdge;
BRep_Builder BB;
const TopTools_ListOfShape& Edges = VEmap.FindFromKey(theVertex);
if (Edges.Extent() == 1)
MinEdge = TopoDS::Edge(Edges.First());
else
{
TopTools_ListIteratorOfListOfShape itl(Edges);
Standard_Real MinAngle = RealLast();
for (; itl.More(); itl.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
TopoDS_Wire aWire;
BB.MakeWire(aWire);
BB.Add(aWire, anEdge);
gp_Pln aPln;
Standard_Boolean issing;
ComputeAveragePlaneAndMaxDeviation( aWire, aPln, issing );
Standard_Real anAngle;
if (issing) //edge is a segment of line
{
//<anAngle> is angle between <anEdge> and its projection on bisector plane
BRepAdaptor_Curve BAcurve(anEdge);
gp_Pnt FirstPnt = BAcurve.Value(BAcurve.FirstParameter());
gp_Pnt LastPnt = BAcurve.Value(BAcurve.LastParameter());
gp_Vec EdgeVec(FirstPnt, LastPnt);
gp_Ax1 EdgeAxis(FirstPnt, EdgeVec);
anAngle = EdgeAxis.Direction().Angle(theAxis.Direction());
if (anAngle > M_PI/2)
anAngle = M_PI - anAngle;
anAngle = M_PI/2 - anAngle;
}
else
{
anAngle = aPln.Axis().Angle( theAxis );
if (anAngle > M_PI/2)
anAngle = M_PI - anAngle;
}
if (anAngle < MinAngle)
{
MinAngle = anAngle;
MinEdge = anEdge;
}
}
} //else (more than one edge)
BB.Remove(theComp, MinEdge);
return MinEdge;
}
static Standard_Boolean FindMiddleEdges(const TopoDS_Vertex& theVertex1,
const TopoDS_Vertex& theVertex2,
const gp_Ax1& theAxis,
TopoDS_Compound& theComp,
TopTools_ListOfShape& theElist)
{
TopTools_IndexedDataMapOfShapeListOfShape VEmap;
TopExp::MapShapesAndAncestors( theComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap );
if (VEmap.IsEmpty())
return Standard_False;
if (!VEmap.Contains(theVertex1) ||
!VEmap.Contains(theVertex2))
return Standard_False;
TopoDS_Vertex CurVertex = theVertex1;
for (;;)
{
TopoDS_Edge CurEdge;
CurEdge = FindEdgeCloseToBisectorPlane(CurVertex, theComp, theAxis);
if (CurEdge.IsNull())
return Standard_False;
TopoDS_Vertex V1, V2;
TopExp::Vertices(CurEdge, V1, V2);
CurVertex = (V1.IsSame(CurVertex))? V2 : V1;
theElist.Append(CurEdge);
if (CurVertex.IsSame(theVertex2))
return Standard_True;
}
}
static Standard_Boolean FindCommonVertex(const TopoDS_Edge& theFirstEdge,
const TopoDS_Edge& theLastEdge,
const TopoDS_Vertex& theFirstVertex,
const TopoDS_Vertex& theLastVertex,
TopoDS_Vertex& theCommonVertex)
{
if (!theFirstVertex.IsSame(theLastVertex))
{
Standard_Boolean CommonVertexExists = TopExp::CommonVertex(theFirstEdge,
theLastEdge,
theCommonVertex);
return CommonVertexExists;
}
TopoDS_Vertex V1, V2, V3, V4;
TopExp::Vertices(theFirstEdge, V1, V2);
TopExp::Vertices(theLastEdge, V3, V4);
if (V1.IsSame(theFirstVertex))
{
if (V2.IsSame(V3) ||
V2.IsSame(V4))
{
theCommonVertex = V2;
return Standard_True;
}
}
else
{
if (V1.IsSame(V3) ||
V1.IsSame(V4))
{
theCommonVertex = V1;
return Standard_True;
}
}
return Standard_False;
}

View File

@@ -20,6 +20,7 @@
#include <Standard_DefineAlloc.hxx>
#include <Standard_Handle.hxx>
#include <BRepFill_TransitionStyle.hxx>
#include <gp_Ax2.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Wire.hxx>
@@ -28,13 +29,14 @@
#include <Standard_Boolean.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BOPDS_PDS.hxx>
class gp_Ax2;
class TopoDS_Face;
class TopoDS_Wire;
class TopoDS_Shape;
//! Trims sets of faces in the corner to make proper parts of pipe
class BRepFill_TrimShellCorner
{
public:
@@ -42,12 +44,13 @@ public:
DEFINE_STANDARD_ALLOC
Standard_EXPORT BRepFill_TrimShellCorner(const Handle(TopTools_HArray2OfShape)& theFaces, const gp_Ax2& theAxeOfBisPlane, const TopoDS_Face& theSecPlane);
Standard_EXPORT BRepFill_TrimShellCorner(const Handle(TopTools_HArray2OfShape)& theFaces, const gp_Ax2& theAxeOfBisPlane, const TopoDS_Wire& theSpine, const TopoDS_Face& theSecPlane);
Standard_EXPORT void SetSpine (const TopoDS_Wire& theSpine);
//! Constructor: takes faces to intersect,
//! type of transition (it can be RightCorner or RoundCorner)
//! and axis of bisector plane
Standard_EXPORT BRepFill_TrimShellCorner(const Handle(TopTools_HArray2OfShape)& theFaces,
const BRepFill_TransitionStyle theTransition,
const gp_Ax2& theAxeOfBisPlane);
Standard_EXPORT void AddBounds (const Handle(TopTools_HArray2OfShape)& Bounds);
Standard_EXPORT void AddUEdges (const Handle(TopTools_HArray2OfShape)& theUEdges);
@@ -71,13 +74,29 @@ protected:
private:
Standard_Boolean MakeFacesSec(const Standard_Integer theIndex,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
const Standard_Integer theSSInterfIndex);
Standard_Boolean MakeFacesNonSec(const Standard_Integer theIndex,
const BOPDS_PDS& theDS,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2);
Standard_Boolean ChooseSection(const TopoDS_Shape& Comp,
const TopoDS_Vertex& theFirstVertex,
const TopoDS_Vertex& theLastVertex,
TopoDS_Shape& resWire,
gp_Pln& resPlane,
Standard_Boolean& IsSingular);
BRepFill_TransitionStyle myTransition;
gp_Ax2 myAxeOfBisPlane;
TopoDS_Shape myShape1;
TopoDS_Shape myShape2;
TopoDS_Wire mySpine;
TopoDS_Face mySecPln;
Handle(TopTools_HArray2OfShape) myBounds;
Handle(TopTools_HArray2OfShape) myUEdges;
Handle(TopTools_HArray2OfShape) myFaces;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
// Created on: 2018-03-14
// Created by: Nikolai BUKHALOV
// Copyright (c) 1999-2018 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.
#ifndef _BRepFill_Voluved_HeaderFile
#define _BRepFill_Voluved_HeaderFile
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <Standard_Handle.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Wire.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
class BOPAlgo_MakerVolume;
class TopoDS_Face;
//! Constructs an evolved volume from a spine (wire or face)
//! and a profile ( wire).
class BRepFill_Voluved
{
public:
DEFINE_STANDARD_ALLOC
Standard_EXPORT BRepFill_Voluved() :myErrorStatus(BRepFill_Voluved_Empty),
myFuzzyValue(0.0),
myIsParallel(Standard_True)
{
}
Standard_EXPORT void Perform(const TopoDS_Wire& theSpine, const TopoDS_Wire& theProfile, const Standard_Real theTolerance, const Standard_Boolean theSolidReq = Standard_True);
Standard_Boolean IsDone(unsigned int* theErrorCode = 0) const
{
if (theErrorCode)
*theErrorCode = myErrorStatus;
return (myErrorStatus == BRepFill_Voluved_OK);
}
//! returns the resulting shape.
const TopoDS_Shape& Shape() const
{
return myResult;
}
//! Triggers computation mode between Parallel/Single-thread
void SetRunParallel(Standard_Boolean theValue)
{
myIsParallel = theValue;
}
protected:
Standard_EXPORT void PerformSweep();
Standard_EXPORT void GetLids();
Standard_EXPORT void BuildSolid();
Standard_EXPORT void RemoveExcessSolids(const TopTools_ListOfShape& theLSplits,
TopoDS_Shape& theShape,
TopTools_ListOfShape& theArgsList,
BOPAlgo_MakerVolume& theMV);
Standard_EXPORT void ExtractOuterSolid(TopoDS_Shape& theShape,
TopTools_ListOfShape& theArgsList);
Standard_EXPORT void GetSpineAndProfile(const TopoDS_Wire& theSpine,
const TopoDS_Wire& theProfile);
Standard_EXPORT Standard_Boolean CheckSingularityAndAdd(const TopoDS_Face& theF,
const Standard_Real theFuzzyToler,
TopTools_ListOfShape& theListOfFaces,
TopTools_ListOfShape& theListOfSplits) const;
private:
enum
{
BRepFill_Voluved_Empty = 0,
BRepFill_Voluved_NotPlanarSpine,
BRepFill_Voluved_SweepError,
BRepFill_Voluved_NoLids,
BRepFill_Voluved_NotSolid,
BRepFill_Voluved_NotVolume,
BRepFill_Voluved_OK = UINT_MAX
} myErrorStatus;
TopoDS_Wire mySpine;
TopoDS_Wire myProfile;
TopoDS_Shape myPipeShell;
TopoDS_Compound myTopBottom; // Lids can be split on several faces
TopoDS_Shape myResult;
Standard_Real myFuzzyValue;
Standard_Boolean myIsParallel;
};
#endif // _BRepFill_Voluved_HeaderFile

View File

@@ -83,3 +83,5 @@ BRepFill_TrimShellCorner.hxx
BRepFill_TrimSurfaceTool.cxx
BRepFill_TrimSurfaceTool.hxx
BRepFill_TypeOfContact.hxx
BRepFill_Voluved.cxx
BRepFill_Voluved.hxx

View File

@@ -120,7 +120,7 @@ void BRepMesh_FastDiscret::Perform(const TopoDS_Shape& theShape)
aFaces.push_back(aFace);
}
OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel);
OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel, (Standard_Integer )aFaces.size());
}

View File

@@ -234,7 +234,7 @@ void BRepMesh_IncrementalMesh::update()
update(aFaceIt.Value());
// Mesh faces
OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel);
OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel, myFaces.Size());
commit();
clear();

View File

@@ -22,6 +22,8 @@
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS.hxx>
//=======================================================================
//function : BRepOffsetAPI_MakeEvolved
@@ -43,19 +45,31 @@ BRepOffsetAPI_MakeEvolved::BRepOffsetAPI_MakeEvolved(const TopoDS_Wire& Spin
const Standard_Boolean AxeProf,
const Standard_Boolean Solid,
const Standard_Boolean ProfOnSpine,
const Standard_Real Tol)
const Standard_Boolean theIsVolume,
const Standard_Real Tol,
const Standard_Boolean theRunInParallel)
{
gp_Ax3 Axis(gp_Pnt(0.,0.,0.),
gp_Dir(0.,0.,1.),
gp_Dir(1.,0.,0.));
if (theIsVolume)
{
myVolume.SetRunParallel(theRunInParallel);
myVolume.Perform(Spine, Profil, Tol);
}
else
{
gp_Ax3 Axis(gp_Pnt(0., 0., 0.),
gp_Dir(0., 0., 1.),
gp_Dir(1., 0., 0.));
if ( !AxeProf) {
Standard_Boolean POS;
BRepFill::Axe(Spine,Profil,Axis,POS,Tol);
if (ProfOnSpine && !POS) return;
if (!AxeProf)
{
Standard_Boolean POS;
BRepFill::Axe(Spine, Profil, Axis, POS, Max(Tol, Precision::Confusion()));
if (ProfOnSpine && !POS) return;
}
myEvolved.Perform(Spine, Profil, Axis, Join, Solid);
}
myEvolved.Perform(Spine,Profil,Axis,Join,Solid);
Build();
Done();
}
@@ -72,20 +86,33 @@ BRepOffsetAPI_MakeEvolved::BRepOffsetAPI_MakeEvolved(const TopoDS_Face& Spin
const Standard_Boolean AxeProf,
const Standard_Boolean Solid,
const Standard_Boolean ProfOnSpine,
const Standard_Real Tol)
const Standard_Boolean theIsVolume,
const Standard_Real Tol,
const Standard_Boolean theRunInParallel)
{
gp_Ax3 Axis(gp_Pnt(0.,0.,0.),
gp_Dir(0.,0.,1.),
gp_Dir(1.,0.,0.));
if (theIsVolume)
{
myVolume.SetRunParallel(theRunInParallel);
myVolume.Perform(TopoDS::Wire(TopoDS_Iterator(Spine).Value()), Profil, Tol);
}
else
{
gp_Ax3 Axis(gp_Pnt(0., 0., 0.),
gp_Dir(0., 0., 1.),
gp_Dir(1., 0., 0.));
if ( !AxeProf) {
Standard_Boolean POS;
BRepFill::Axe(Spine,Profil,Axis,POS,Tol);
if (ProfOnSpine && !POS) return;
if (!AxeProf)
{
Standard_Boolean POS;
BRepFill::Axe(Spine, Profil, Axis, POS, Max(Tol, Precision::Confusion()));
if (ProfOnSpine && !POS) return;
}
myEvolved.Perform(Spine, Profil, Axis, Join, Solid);
}
myEvolved.Perform(Spine,Profil,Axis,Join,Solid);
Build();
Done();
}
@@ -107,8 +134,16 @@ const BRepFill_Evolved& BRepOffsetAPI_MakeEvolved::Evolved() const
void BRepOffsetAPI_MakeEvolved::Build()
{
myShape = myEvolved.Shape();
if (myEvolved.IsDone()) Done();
if (myEvolved.IsDone())
{
myShape = myEvolved.Shape();
}
else if (myVolume.IsDone())
{
myShape = myVolume.Shape();
}
Done();
}

View File

@@ -22,6 +22,7 @@
#include <Standard_Handle.hxx>
#include <BRepFill_Evolved.hxx>
#include <BRepFill_Voluved.hxx>
#include <BRepBuilderAPI_MakeShape.hxx>
#include <GeomAbs_JoinType.hxx>
#include <Standard_Boolean.hxx>
@@ -66,7 +67,7 @@ public:
Standard_EXPORT BRepOffsetAPI_MakeEvolved();
Standard_EXPORT BRepOffsetAPI_MakeEvolved(const TopoDS_Wire& Spine, const TopoDS_Wire& Profil, const GeomAbs_JoinType Join = GeomAbs_Arc, const Standard_Boolean AxeProf = Standard_True, const Standard_Boolean Solid = Standard_False, const Standard_Boolean ProfOnSpine = Standard_False, const Standard_Real Tol = 0.0000001);
Standard_EXPORT BRepOffsetAPI_MakeEvolved(const TopoDS_Wire& Spine, const TopoDS_Wire& Profil, const GeomAbs_JoinType Join/* = GeomAbs_Arc*/, const Standard_Boolean AxeProf/* = Standard_True*/, const Standard_Boolean Solid/* = Standard_False*/, const Standard_Boolean ProfOnSpine/* = Standard_False*/, const Standard_Boolean theIsVolume, const Standard_Real Tol/* = Precision::Confusion()*/, const Standard_Boolean theRunInParallel);
//! These constructors construct an evolved shape by sweeping the profile
//! Profile along the spine Spine.
@@ -88,7 +89,7 @@ public:
//! axis passing along the vertex and the normal to the
//! plane of the spine. At present, this is the only
//! construction type implemented.
Standard_EXPORT BRepOffsetAPI_MakeEvolved(const TopoDS_Face& Spine, const TopoDS_Wire& Profil, const GeomAbs_JoinType Join = GeomAbs_Arc, const Standard_Boolean AxeProf = Standard_True, const Standard_Boolean Solid = Standard_False, const Standard_Boolean ProfOnSpine = Standard_False, const Standard_Real Tol = 0.0000001);
Standard_EXPORT BRepOffsetAPI_MakeEvolved(const TopoDS_Face& Spine, const TopoDS_Wire& Profil, const GeomAbs_JoinType Join/* = GeomAbs_Arc*/, const Standard_Boolean AxeProf/* = Standard_True*/, const Standard_Boolean Solid/* = Standard_False*/, const Standard_Boolean ProfOnSpine/* = Standard_False*/, const Standard_Boolean theIsVolume, const Standard_Real Tol/* = Precision::Confusion()*/, const Standard_Boolean theRunInParallel);
Standard_EXPORT const BRepFill_Evolved& Evolved() const;
@@ -118,9 +119,8 @@ protected:
private:
BRepFill_Evolved myEvolved;
BRepFill_Voluved myVolume;
};

View File

@@ -33,8 +33,6 @@
//purpose :
//=======================================================================
BRepOffsetAPI_MakePipeShell::BRepOffsetAPI_MakePipeShell(const TopoDS_Wire& Spine)
{
myPipe = new (BRepFill_PipeShell) (Spine);
SetTolerance();

View File

@@ -211,7 +211,7 @@ public:
//! discontinuities are treated like round
//! corner. The corner is treated as rotation
//! of the profile around an axis which
//! passes through the point of the spine?s
//! passes through the point of the spine's
//! fracture. This axis is based on cross
//! product of directions tangent to the
//! adjacent segments of the spine at their common point.
@@ -276,7 +276,6 @@ private:
Handle(BRepFill_PipeShell) myPipe;
};

View File

@@ -237,33 +237,93 @@ Standard_Integer evolved(Draw_Interpretor& di, Standard_Integer n, const char**
if ( n < 4 ) return 1;
Standard_Boolean IsAFace = Standard_False;
Standard_Boolean Solid = (!strcmp(a[0],"evolvedsolid"));
Standard_Boolean Solid = Standard_False;
Standard_Boolean isVolume = Standard_False;
Standard_Boolean hasToComputeAxes = Standard_False;
Standard_Real aTolerance = 0.0;
TopoDS_Shape Base;
TopoDS_Wire Prof;
Standard_Boolean isParallel = Standard_True;
for (Standard_Integer i = 2; i < n; i++)
{
if (a[i][0] != '-')
{
di << "Error: wrong option!\n";
return 1;
}
if (!strcmp(a[i], "-solid"))
{
Solid = Standard_True;
continue;
}
if (!strcmp(a[i], "-stm"))
{
isParallel = Standard_False;
continue;
}
switch (a[i][1])
{
case 's':
{
Base = DBRep::Get(a[++i], TopAbs_WIRE, Standard_False);
if (Base.IsNull())
{
Base = DBRep::Get(a[i], TopAbs_FACE, Standard_False);
IsAFace = Standard_True;
}
}
break;
case 'p':
{
Prof = TopoDS::Wire(DBRep::Get(a[++i], TopAbs_WIRE, Standard_False));
}
break;
case 'v':
{
isVolume = Standard_True;
}
break;
case 'a':
{
hasToComputeAxes = Standard_True;
}
break;
case 't':
{
aTolerance = Draw::Atof(a[++i]);
}
break;
default:
di << "Error: Unknown option!\n";
break;
}
}
TopoDS_Shape Base = DBRep::Get(a[2],TopAbs_WIRE,Standard_False);
if ( Base.IsNull()) {
Base = DBRep::Get(a[2],TopAbs_FACE,Standard_False);
IsAFace = Standard_True;
if (Base.IsNull() || Prof.IsNull())
{
di << "Error: Null-shapes are not allowed\n";
return 1;
}
if ( Base.IsNull()) return 1;
TopoDS_Shape InpuTShape(DBRep::Get(a[3],TopAbs_WIRE,Standard_False));
TopoDS_Wire Prof = TopoDS::Wire(InpuTShape);
// TopoDS_Wire Prof =
// TopoDS::Wire(DBRep::Get(a[3],TopAbs_WIRE,Standard_False));
if ( Prof.IsNull()) return 1;
TopoDS_Shape Volevo = IsAFace ? BRepOffsetAPI_MakeEvolved(TopoDS::Face(Base),
Prof, GeomAbs_Arc, !hasToComputeAxes,
Solid, Standard_False, isVolume,
aTolerance, isParallel) :
BRepOffsetAPI_MakeEvolved(TopoDS::Wire(Base),
Prof, GeomAbs_Arc, !hasToComputeAxes,
Solid, Standard_False, isVolume,
aTolerance, isParallel);
if (IsAFace) {
TopoDS_Shape Volevo
= BRepOffsetAPI_MakeEvolved(TopoDS::Face(Base),Prof,GeomAbs_Arc,n == 4,Solid);
DBRep::Set(a[1],Volevo);
}
else {
TopoDS_Shape Volevo
= BRepOffsetAPI_MakeEvolved(TopoDS::Wire(Base),Prof,GeomAbs_Arc,n == 4,Solid);
DBRep::Set(a[1],Volevo);
}
DBRep::Set(a[1],Volevo);
return 0;
}
@@ -785,7 +845,11 @@ static Standard_Integer buildsweep(Draw_Interpretor& di,
Sweep->SetTransitionMode(Transition);
}
// Reading solid ?
if ((n>cur) && (!strcmp(a[cur],"-S")) ) mksolid = Standard_True;
if ((n > cur) && (!strcmp(a[cur], "-S")))
{
mksolid = Standard_True;
++cur;
}
// Calcul le resultat
Sweep->Build();
@@ -979,10 +1043,6 @@ void BRepTest::SweepCommands(Draw_Interpretor& theCommands)
"evolved , no args to get help",
__FILE__,evolved,g);
theCommands.Add("evolvedsolid",
"evolved , no args to get help",
__FILE__,evolved,g);
theCommands.Add("pruled",
"pruled result Edge1/Wire1 Edge2/Wire2",
__FILE__,pruled,g);

2705
src/BRepTest/QABugs_20.cxx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -595,6 +595,14 @@ proc checkprops {shape args} {
if { $m == 0 } {
puts "Error : The command is not valid. The $prop is 0."
}
# Provide comparation with negative value
if { [expr $mass*$m ] < 0.0 } {
# Value and expected value have different sign
puts "Error : The $prop of result shape is $m"
} else {
set mass [expr abs($mass)]
set m [expr abs($m)]
}
if { $mass > 0 } {
puts "The expected $prop is $mass"
}

View File

@@ -66,9 +66,10 @@ namespace
//! Auxiliary method to convert FT_Vector to gp_XY
static gp_XY readFTVec (const FT_Vector& theVec,
const Standard_Real theScaleUnits)
const Standard_Real theScaleUnits,
const Standard_Real theWidthScaling = 1.0)
{
return gp_XY (theScaleUnits * Standard_Real(theVec.x) / 64.0, theScaleUnits * Standard_Real(theVec.y) / 64.0);
return gp_XY (theScaleUnits * Standard_Real(theVec.x) * theWidthScaling / 64.0, theScaleUnits * Standard_Real(theVec.y) / 64.0);
}
}
@@ -265,7 +266,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
TopLoc_Location aLoc;
TopoDS_Face aFaceDraft;
myBuilder.MakeFace (aFaceDraft, mySurface, myPrecision);
TopoDS_Compound aFaceCompDraft;
// Get orientation is useless since it doesn't retrieve any in-font information and just computes orientation.
// Because it fails in some cases - leave this to ShapeFix.
@@ -277,7 +278,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
const short anEndIndex = anOutline.contours[aContour];
const short aPntsNb = (anEndIndex - aStartIndex) + 1;
aStartIndex = anEndIndex + 1;
if (aPntsNb < 3)
if (aPntsNb < 3 && !myIsSingleLine)
{
// closed contour can not be constructed from < 3 points
continue;
@@ -286,10 +287,11 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
BRepBuilderAPI_MakeWire aWireMaker;
gp_XY aPntPrev;
gp_XY aPntCurr = readFTVec (aPntList[aPntsNb - 1], myScaleUnits);
gp_XY aPntNext = readFTVec (aPntList[0], myScaleUnits);
gp_XY aPntCurr = readFTVec (aPntList[aPntsNb - 1], myScaleUnits, myWidthScaling);
gp_XY aPntNext = readFTVec (aPntList[0], myScaleUnits, myWidthScaling);
Standard_Integer aLinePnts = (FT_CURVE_TAG(aTags[aPntsNb - 1]) == FT_Curve_Tag_On) ? 1 : 0;
bool isLineSeg = !myIsSingleLine
&& FT_CURVE_TAG(aTags[aPntsNb - 1]) == FT_Curve_Tag_On;
gp_XY aPntLine1 = aPntCurr;
// see http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html
@@ -298,15 +300,15 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
{
aPntPrev = aPntCurr;
aPntCurr = aPntNext;
aPntNext = readFTVec (aPntList[(aPntId + 1) % aPntsNb], myScaleUnits);
aPntNext = readFTVec (aPntList[(aPntId + 1) % aPntsNb], myScaleUnits, myWidthScaling);
// process tags
if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_On)
{
if (aLinePnts < 1)
if (!isLineSeg)
{
aPntLine1 = aPntCurr;
aLinePnts = 1;
isLineSeg = true;
continue;
}
@@ -315,7 +317,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
if (aLen <= myPrecision)
{
aPntLine1 = aPntCurr;
aLinePnts = 1;
isLineSeg = true;
continue;
}
@@ -339,7 +341,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
}
else if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_Conic)
{
aLinePnts = 0;
isLineSeg = false;
gp_XY aPntPrev2 = aPntPrev;
gp_XY aPntNext2 = aPntNext;
@@ -378,11 +380,11 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
else if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_Cubic
&& FT_CURVE_TAG(aTags[(aPntId + 1) % aPntsNb]) == FT_Curve_Tag_Cubic)
{
aLinePnts = 0;
isLineSeg = false;
my4Poles.SetValue (1, aPntPrev);
my4Poles.SetValue (2, aPntCurr);
my4Poles.SetValue (3, aPntNext);
my4Poles.SetValue (4, gp_Pnt2d(readFTVec (aPntList[(aPntId + 2) % aPntsNb], myScaleUnits)));
my4Poles.SetValue (4, gp_Pnt2d(readFTVec (aPntList[(aPntId + 2) % aPntsNb], myScaleUnits, myWidthScaling)));
Handle(Geom2d_BezierCurve) aBezier = new Geom2d_BezierCurve (my4Poles);
if (myIsCompositeCurve)
{
@@ -411,7 +413,8 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
const gp_Pnt2d aFirstPnt = aDraft2d->StartPoint();
const gp_Pnt2d aLastPnt = aDraft2d->EndPoint();
if (!aFirstPnt.IsEqual (aLastPnt, myPrecision))
if (!myIsSingleLine
&& !aFirstPnt.IsEqual (aLastPnt, myPrecision))
{
Handle(Geom2d_TrimmedCurve) aLine = GCE2d_MakeSegment (aLastPnt, aFirstPnt);
myConcatMaker.Add (aLine, myPrecision);
@@ -438,7 +441,8 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
TopExp::Vertices (aWireMaker.Wire(), aFirstV, aLastV);
gp_Pnt aFirstPoint = BRep_Tool::Pnt (aFirstV);
gp_Pnt aLastPoint = BRep_Tool::Pnt (aLastV);
if (!aFirstPoint.IsEqual (aLastPoint, myPrecision))
if (!myIsSingleLine
&& !aFirstPoint.IsEqual (aLastPoint, myPrecision))
{
aWireMaker.Add (BRepLib_MakeEdge (aFirstV, aLastV));
}
@@ -450,31 +454,64 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
}
TopoDS_Wire aWireDraft = aWireMaker.Wire();
//if (anOrient == FT_ORIENTATION_FILL_LEFT)
//{
// According to the TrueType specification, clockwise contours must be filled
aWireDraft.Reverse();
//}
myBuilder.Add (aFaceDraft, aWireDraft);
if (!myIsSingleLine)
{
//if (anOrient == FT_ORIENTATION_FILL_LEFT)
//{
// According to the TrueType specification, clockwise contours must be filled
aWireDraft.Reverse();
//}
if (aFaceDraft.IsNull())
{
myBuilder.MakeFace (aFaceDraft, mySurface, myPrecision);
}
myBuilder.Add (aFaceDraft, aWireDraft);
}
else
{
if (aFaceCompDraft.IsNull())
{
myBuilder.MakeCompound (aFaceCompDraft);
}
myBuilder.Add (aFaceCompDraft, aWireDraft);
}
}
myFixer.Init (aFaceDraft);
myFixer.Perform();
theShape = myFixer.Result();
if (!theShape.IsNull()
&& theShape.ShapeType() != TopAbs_FACE)
if (!aFaceDraft.IsNull())
{
// shape fix can not fix orientation within the single call
TopoDS_Compound aComp;
myBuilder.MakeCompound (aComp);
for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
myFixer.Init (aFaceDraft);
myFixer.Perform();
TopoDS_Shape aFixResult = myFixer.Result();
if (!aFixResult.IsNull()
&& aFixResult.ShapeType() != TopAbs_FACE)
{
TopoDS_Face aFace = TopoDS::Face (aFaceIter.Current());
myFixer.Init (aFace);
myFixer.Perform();
myBuilder.Add (aComp, myFixer.Result());
// shape fix can not fix orientation within the single call
if (aFaceCompDraft.IsNull())
{
myBuilder.MakeCompound (aFaceCompDraft);
}
for (TopExp_Explorer aFaceIter (aFixResult, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
{
TopoDS_Face aFace = TopoDS::Face (aFaceIter.Current());
myFixer.Init (aFace);
myFixer.Perform();
myBuilder.Add (aFaceCompDraft, myFixer.Result());
}
theShape = aFaceCompDraft;
}
theShape = aComp;
else if (!aFaceCompDraft.IsNull())
{
myBuilder.Add (aFaceCompDraft, aFixResult);
theShape = aFaceCompDraft;
}
else
{
theShape = aFixResult;
}
}
else if (!aFaceCompDraft.IsNull())
{
theShape = aFaceCompDraft;
}
myCache.Bind (theChar, theShape);

View File

@@ -29,12 +29,14 @@ IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient)
// purpose :
// =======================================================================
Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
: myFTLib (theFTLib),
myFTFace (NULL),
myPointSize (0U),
myLoadFlags (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
myKernAdvance(new FT_Vector()),
myUChar (0U)
: myFTLib (theFTLib),
myFTFace (NULL),
myPointSize (0U),
myWidthScaling(1.0),
myLoadFlags (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
myIsSingleLine(false),
myKernAdvance (new FT_Vector()),
myUChar (0U)
{
if (myFTLib.IsNull())
{
@@ -118,9 +120,12 @@ bool Font_FTFont::Init (const NCollection_String& theFontName,
{
Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
const Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (theFontName.ToCString());
Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, theFontAspect, thePointSize);
return !aRequestedFont.IsNull()
&& Font_FTFont::Init (aRequestedFont->FontPath()->ToCString(), thePointSize, theResolution);
if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, theFontAspect, thePointSize))
{
myIsSingleLine = aRequestedFont->IsSingleStrokeFont();
return Font_FTFont::Init (aRequestedFont->FontPath()->ToCString(), thePointSize, theResolution);
}
return false;
}
// =======================================================================
@@ -263,12 +268,19 @@ float Font_FTFont::AdvanceX (const Standard_Utf32Char theUCharNext)
return 0.0f;
}
if (FT_HAS_KERNING (myFTFace) == 0 || theUCharNext == 0
|| FT_Get_Kerning (myFTFace, myUChar, theUCharNext, FT_KERNING_UNFITTED, myKernAdvance) != 0)
FT_Pos aKerningX = 0;
if (theUCharNext != 0
&& FT_HAS_KERNING (myFTFace) != 0)
{
return fromFTPoints<float> (myFTFace->glyph->advance.x);
const FT_UInt aCharCurr = FT_Get_Char_Index (myFTFace, myUChar);
const FT_UInt aCharNext = FT_Get_Char_Index (myFTFace, theUCharNext);
if (aCharCurr != 0 && aCharNext != 0
&& FT_Get_Kerning (myFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, myKernAdvance) == 0)
{
aKerningX = myKernAdvance->x;
}
}
return fromFTPoints<float> (myKernAdvance->x + myFTFace->glyph->advance.x);
return myWidthScaling * fromFTPoints<float> (myFTFace->glyph->advance.x + aKerningX);
}
// =======================================================================
@@ -282,12 +294,19 @@ float Font_FTFont::AdvanceY (const Standard_Utf32Char theUCharNext)
return 0.0f;
}
if (FT_HAS_KERNING (myFTFace) == 0 || theUCharNext == 0
|| FT_Get_Kerning (myFTFace, myUChar, theUCharNext, FT_KERNING_UNFITTED, myKernAdvance) != 0)
FT_Pos aKerningY = 0;
if (theUCharNext != 0
&& FT_HAS_KERNING (myFTFace) != 0)
{
return fromFTPoints<float> (myFTFace->glyph->advance.y);
const FT_UInt aCharCurr = FT_Get_Char_Index (myFTFace, myUChar);
const FT_UInt aCharNext = FT_Get_Char_Index (myFTFace, theUCharNext);
if (aCharCurr != 0 && aCharNext != 0
&& FT_Get_Kerning (myFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, myKernAdvance) == 0)
{
aKerningY = myKernAdvance->y;
}
}
return fromFTPoints<float> (myKernAdvance->y + myFTFace->glyph->advance.y);
return fromFTPoints<float> (myFTFace->glyph->advance.y + aKerningY);
}
// =======================================================================

View File

@@ -73,6 +73,13 @@ public:
const unsigned int thePointSize,
const unsigned int theResolution);
//! Return TRUE if this is single-stroke (one-line) font, FALSE by default.
//! Such fonts define single-line glyphs instead of closed contours, so that they are rendered incorrectly by normal software.
bool IsSingleStrokeFont() const { return myIsSingleLine; }
//! Set if this font should be rendered as single-stroke (one-line).
void SetSingleStrokeFont (bool theIsSingleLine) { myIsSingleLine = theIsSingleLine; }
//! Release currently loaded font.
Standard_EXPORT virtual void Release();
@@ -100,6 +107,13 @@ public:
return myPointSize;
}
//! Setup glyph scaling along X-axis.
//! By default glyphs are not scaled (scaling factor = 1.0)
void SetWidthScaling (const float theScaleFactor)
{
myWidthScaling = theScaleFactor;
}
//! Compute advance to the next character with kerning applied when applicable.
//! Assuming text rendered horizontally.
Standard_EXPORT float AdvanceX (const Standard_Utf32Char theUCharNext);
@@ -154,15 +168,17 @@ protected:
protected:
Handle(Font_FTLibrary) myFTLib; //!< handle to the FT library object
FT_Face myFTFace; //!< FT face object
NCollection_String myFontPath; //!< font path
unsigned int myPointSize; //!< point size set by FT_Set_Char_Size
int32_t myLoadFlags; //!< default load flags
Handle(Font_FTLibrary) myFTLib; //!< handle to the FT library object
FT_Face myFTFace; //!< FT face object
NCollection_String myFontPath; //!< font path
unsigned int myPointSize; //!< point size set by FT_Set_Char_Size
float myWidthScaling; //!< scale glyphs along X-axis
int32_t myLoadFlags; //!< default load flags
bool myIsSingleLine; //!< single stroke font flag, FALSE by default
Image_PixMap myGlyphImg; //!< cached glyph plane
FT_Vector* myKernAdvance; //!< buffer variable
Standard_Utf32Char myUChar; //!< currently loaded unicode character
Image_PixMap myGlyphImg; //!< cached glyph plane
FT_Vector* myKernAdvance; //!< buffer variable
Standard_Utf32Char myUChar; //!< currently loaded unicode character
public:

View File

@@ -49,7 +49,8 @@ static const Font_FontMgr_FontAliasMapNode Font_FontMgr_MapOfFontsAliases[] =
{ "Symbol" , "Symbol" , Font_FA_Regular },
{ "ZapfDingbats" , "WingDings" , Font_FA_Regular },
{ "Rock" , "Arial" , Font_FA_Regular },
{ "Iris" , "Lucida Console" , Font_FA_Regular }
{ "Iris" , "Lucida Console" , Font_FA_Regular },
{ "NSimSun" , "SimSun" , Font_FA_Regular }
#elif defined(__ANDROID__)
@@ -218,6 +219,8 @@ static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib
Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aFontFace->family_name);
Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (theFontPath);
aResult = new Font_SystemFont (aFontName, anAspect, aFontPath);
// automatically identify some known single-line fonts
aResult->SetSingleStrokeFont (aFontName->String().StartsWith ("OLF "));
}
FT_Done_Face (aFontFace);

View File

@@ -13,126 +13,113 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// Updated:
#include <Font_SystemFont.hxx>
#include <OSD_Path.hxx>
#include <Standard_Type.hxx>
#include <TCollection_HAsciiString.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Font_SystemFont,Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT(Font_SystemFont, Standard_Transient)
Font_SystemFont::Font_SystemFont():
MyFontName(),
MyFontAspect(Font_FA_Undefined),
MyFaceSize(-1),
MyVerification(Standard_False)
// =======================================================================
// function : Font_SystemFont
// purpose :
// =======================================================================
Font_SystemFont::Font_SystemFont()
: myFontAspect (Font_FA_Undefined),
myFaceSize (-1),
myIsSingleLine (Standard_False),
myIsDefined (Standard_False)
{
//
}
Font_SystemFont::Font_SystemFont( const Handle(TCollection_HAsciiString)& FontName,
const Font_FontAspect FontAspect,
const Handle(TCollection_HAsciiString)& FilePath ):
MyFontName(FontName),
MyFontAspect(FontAspect),
MyFaceSize(-1),
MyFilePath(FilePath),
MyVerification(Standard_True)
// =======================================================================
// function : Font_SystemFont
// purpose :
// =======================================================================
Font_SystemFont::Font_SystemFont (const Handle(TCollection_HAsciiString)& theFontName,
const Font_FontAspect theFontAspect,
const Handle(TCollection_HAsciiString)& theFilePath)
: myFontName (theFontName),
myFontAspect (theFontAspect),
myFaceSize (-1),
myFilePath (theFilePath),
myIsSingleLine (Standard_False),
myIsDefined (Standard_True)
{
//
}
// =======================================================================
// function : Font_SystemFont
// purpose :
// =======================================================================
Font_SystemFont::Font_SystemFont (const Handle(TCollection_HAsciiString)& theXLFD,
const Handle(TCollection_HAsciiString)& theFilePath) :
MyFontAspect(Font_FA_Regular),
MyFaceSize(-1),
MyFilePath(theFilePath)
const Handle(TCollection_HAsciiString)& theFilePath)
: myFontAspect (Font_FA_Regular),
myFaceSize (-1),
myFilePath (theFilePath),
myIsSingleLine (Standard_False),
myIsDefined (Standard_True)
{
MyVerification = Standard_True;
if (theXLFD.IsNull())
if (theXLFD.IsNull()
|| theXLFD->IsEmpty())
{
MyVerification = Standard_False; // empty font description handler
}
if (theXLFD->IsEmpty())
{
MyVerification = Standard_False; // empty font description
myIsDefined = Standard_False;
return;
}
if (MyVerification)
myFontName = theXLFD->Token ("-", 2);
const TCollection_AsciiString& aXLFD = theXLFD->String();
// Getting font size for fixed size fonts
if (aXLFD.Search ("-0-0-0-0-") >= 0)
{
MyFontName = theXLFD->Token ("-", 2);
TCollection_AsciiString aXLFD (theXLFD->ToCString());
myFaceSize = -1; // Scalable font
}
else
{
myFaceSize = aXLFD.Token ("-", 7).IntegerValue();
}
// Getting font size for fixed size fonts
if (aXLFD.Search ("-0-0-0-0-") >= 0)
MyFaceSize = -1; // Scalable font
else
//TODO catch exeption
MyFaceSize = aXLFD.Token ("-", 7).IntegerValue();
// Detect font aspect
if (aXLFD.Token ("-", 3).IsEqual ("bold") &&
(aXLFD.Token ("-", 4).IsEqual ("i") || aXLFD.Token ("-", 4).IsEqual ("o")))
{
MyFontAspect = Font_FA_BoldItalic;
}
else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
{
MyFontAspect = Font_FA_Bold;
}
else if (aXLFD.Token ("-", 4).IsEqual ("i") || aXLFD.Token ("-", 4).IsEqual ("o"))
{
MyFontAspect = Font_FA_Italic;
}
// Detect font aspect
if (aXLFD.Token ("-", 3).IsEqual ("bold")
&& (aXLFD.Token ("-", 4).IsEqual ("i")
|| aXLFD.Token ("-", 4).IsEqual ("o")))
{
myFontAspect = Font_FA_BoldItalic;
}
else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
{
myFontAspect = Font_FA_Bold;
}
else if (aXLFD.Token ("-", 4).IsEqual ("i")
|| aXLFD.Token ("-", 4).IsEqual ("o"))
{
myFontAspect = Font_FA_Italic;
}
}
Standard_Boolean Font_SystemFont::IsValid() const{
if ( !MyVerification)
return Standard_False;
if ( MyFontAspect == Font_FA_Undefined )
return Standard_False;
if ( MyFontName->IsEmpty() || !MyFontName->IsAscii() )
return Standard_False;
OSD_Path path;
return path.IsValid( MyFilePath->String() );
}
Handle(TCollection_HAsciiString) Font_SystemFont::FontPath() const{
return MyFilePath;
}
Handle(TCollection_HAsciiString) Font_SystemFont::FontName() const{
return MyFontName;
}
Font_FontAspect Font_SystemFont::FontAspect() const{
return MyFontAspect;
}
Standard_Integer Font_SystemFont::FontHeight() const {
return MyFaceSize;
}
Standard_Boolean Font_SystemFont::IsEqual(const Handle(Font_SystemFont)& theOtherFont) const
// =======================================================================
// function : IsValid
// purpose :
// =======================================================================
Standard_Boolean Font_SystemFont::IsValid() const
{
if (!MyFontName->IsSameString (theOtherFont->FontName(), Standard_False))
{
return Standard_False;
}
if (MyFontAspect != theOtherFont->FontAspect())
{
return Standard_False;
}
if (MyFaceSize != theOtherFont->FontHeight())
{
return Standard_False;
}
return Standard_True;
return myIsDefined
&& myFontAspect != Font_FA_Undefined
&& !myFontName->IsEmpty()
&& OSD_Path::IsValid (myFilePath->String());
}
// =======================================================================
// function : IsEqual
// purpose :
// =======================================================================
Standard_Boolean Font_SystemFont::IsEqual (const Handle(Font_SystemFont)& theOtherFont) const
{
return myFontName->IsSameString (myFontName, Standard_False)
&& myFontAspect == theOtherFont->myFontAspect
&& myFaceSize == theOtherFont->myFaceSize;
}

View File

@@ -25,76 +25,60 @@
#include <Standard_Transient.hxx>
class TCollection_HAsciiString;
class Font_SystemFont;
DEFINE_STANDARD_HANDLE(Font_SystemFont, Standard_Transient)
//! Structure for store of Font System Information
//! This class stores information about the font, which is merely a file path and cached metadata about the font.
class Font_SystemFont : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Font_SystemFont, Standard_Transient)
public:
//! Creates empty font object
//! Creates an empty font object.
Standard_EXPORT Font_SystemFont();
//! Creates a new font object.
Standard_EXPORT Font_SystemFont (const Handle(TCollection_HAsciiString)& theFontName,
const Font_FontAspect theFontAspect,
const Handle(TCollection_HAsciiString)& theFilePath);
//! Creates a font object and initialize class fields with values taken from XLFD (X Logical Font Description)
Standard_EXPORT Font_SystemFont (const Handle(TCollection_HAsciiString)& theXLFD,
const Handle(TCollection_HAsciiString)& theFilePath);
//! Returns font family name.
const Handle(TCollection_HAsciiString)& FontName() const { return myFontName; }
//! Creates Font object initialized with <FontName> as name
//! <FontAspect>.... TODO
Standard_EXPORT Font_SystemFont(const Handle(TCollection_HAsciiString)& theFontName, const Font_FontAspect theFontAspect, const Handle(TCollection_HAsciiString)& theFilePath);
//! Returns font file path.
const Handle(TCollection_HAsciiString)& FontPath() const { return myFilePath; }
//! Creates Font object and initialize class fields with
//! values taken from XLFD (X Logical Font Description)
Standard_EXPORT Font_SystemFont(const Handle(TCollection_HAsciiString)& theXLFD, const Handle(TCollection_HAsciiString)& theFilePath);
//! Returns font family name
Standard_EXPORT Handle(TCollection_HAsciiString) FontName() const;
//! Returns font file path
//! Level: Public
Standard_EXPORT Handle(TCollection_HAsciiString) FontPath() const;
//! Returns font aspect
//! Level: Public
Standard_EXPORT Font_FontAspect FontAspect() const;
//! Returns font height
//! If returned value is equal -1 it means that font is resizable
//! Level: Public
Standard_EXPORT Standard_Integer FontHeight() const;
//! Returns font aspect.
Font_FontAspect FontAspect() const { return myFontAspect; }
//! Returns font height.
//! If returned value is equal -1 it means that font is resizable.
Standard_Integer FontHeight() const { return myFaceSize; }
Standard_EXPORT Standard_Boolean IsValid() const;
//! Return true if the FontName, FontAspect and FontSize are the same.
//! Level: Public
Standard_EXPORT Standard_Boolean IsEqual (const Handle(Font_SystemFont)& theOtherFont) const;
//! Return TRUE if this is single-stroke (one-line) font, FALSE by default.
//! Such fonts define single-line glyphs instead of closed contours, so that they are rendered incorrectly by normal software.
Standard_Boolean IsSingleStrokeFont() const { return myIsSingleLine; }
DEFINE_STANDARD_RTTIEXT(Font_SystemFont,Standard_Transient)
protected:
//! Set if this font should be rendered as single-stroke (one-line).
void SetSingleStrokeFont (Standard_Boolean theIsSingleLine) { myIsSingleLine = theIsSingleLine; }
private:
Handle(TCollection_HAsciiString) MyFontName;
Font_FontAspect MyFontAspect;
Standard_Integer MyFaceSize;
Handle(TCollection_HAsciiString) MyFilePath;
Standard_Boolean MyVerification;
Handle(TCollection_HAsciiString) myFontName;
Font_FontAspect myFontAspect;
Standard_Integer myFaceSize;
Handle(TCollection_HAsciiString) myFilePath;
Standard_Boolean myIsSingleLine; //!< single stroke font flag, FALSE by default
Standard_Boolean myIsDefined;
};
DEFINE_STANDARD_HANDLE(Font_SystemFont, Standard_Transient)
#endif // _Font_SystemFont_HeaderFile

View File

@@ -229,13 +229,16 @@ void Geom_ConicalSurface::SetSemiAngle (const Standard_Real Ang) {
//function : Apex
//purpose :
//=======================================================================
Pnt Geom_ConicalSurface::Apex () const
Pnt Geom_ConicalSurface::Apex(Standard_Real* const theVParametr) const
{
XYZ Coord = Position().Direction().XYZ();
Coord.Multiply (-radius / Tan (semiAngle));
Coord.Add (Position().Location().XYZ());
if (theVParametr)
*theVParametr = -radius / Sin(semiAngle);
return Pnt (Coord);
}

View File

@@ -179,7 +179,9 @@ public:
//! side of the axis of revolution of this cone if the
//! half-angle at the apex is positive, and on the positive
//! side of the "main Axis" if the half-angle is negative.
Standard_EXPORT gp_Pnt Apex() const;
//! If theVParametr != 0 (points on the real variable) then it will store
//! the V-parameter of the apex.
Standard_EXPORT gp_Pnt Apex(Standard_Real* const theVParametr = 0L) const;
//! The conical surface is infinite in the V direction so

View File

@@ -53,6 +53,7 @@
#include <CSLib.hxx>
#include <CSLib_NormalStatus.hxx>
#include <ElCLib.hxx>
#include <Extrema_ECC.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Circle.hxx>
@@ -74,16 +75,19 @@
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_Circle.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_Hyperbola.hxx>
#include <Geom_Line.hxx>
#include <Geom_OffsetCurve.hxx>
#include <Geom_OffsetSurface.hxx>
#include <Geom_Parabola.hxx>
#include <Geom_Plane.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_Surface.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_HSurface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomConvert.hxx>
@@ -962,14 +966,7 @@ void GeomLib::SameRange(const Standard_Real Tolerance,
else
{ // On segmente le resultat
Handle(Geom2d_TrimmedCurve) TC;
Handle(Geom2d_Curve) aCCheck = CurvePtr;
if(aCCheck->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
{
aCCheck = Handle(Geom2d_TrimmedCurve)::DownCast(aCCheck)->BasisCurve();
}
if(aCCheck->IsPeriodic())
if (CurvePtr->IsPeriodic())
{
TC = new Geom2d_TrimmedCurve( CurvePtr, FirstOnCurve, LastOnCurve );
}
@@ -2737,12 +2734,148 @@ Standard_Boolean GeomLib::IsBzVClosed (const Handle(Geom_BezierSurface)& S,
return CompareWeightPoles(aPF, 0, aPL, 0, Tol2);
}
//=======================================================================
//function : AllowExtendUParameter
//purpose :
//=======================================================================
Standard_Boolean GeomLib::IsUTrimAllowed(const GeomAdaptor_Surface& theS,
const Standard_Real theNewUFirst,
const Standard_Real theNewULast)
{
const Handle(Geom_Surface) &aSurf = theS.Surface();
Standard_Real anIsoParameter = theS.FirstVParameter();
if (Precision::IsInfinite(anIsoParameter))
anIsoParameter = theS.LastVParameter();
if (Precision::IsInfinite(anIsoParameter))
anIsoParameter = 0.0;
Handle(Geom_Curve) aC = aSurf->VIso(anIsoParameter);
if (aC->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
{
// In order to obtain the default curve's work range
aC = Handle(Geom_TrimmedCurve)::DownCast(aC)->BasisCurve();
}
return (IsTrimAllowed(aC, theNewUFirst, theNewULast));
}
//=======================================================================
//function : AllowExtendVParameter
//purpose :
//=======================================================================
Standard_Boolean GeomLib::IsVTrimAllowed(const GeomAdaptor_Surface& theS,
const Standard_Real theNewVFirst,
const Standard_Real theNewVLast)
{
const GeomAbs_SurfaceType aSType = theS.GetType();
const Handle(Geom_Surface) &aSurf = theS.Surface();
if (aSType == GeomAbs_OffsetSurface)
{
const Handle(Geom_OffsetSurface) aOS = Handle(Geom_OffsetSurface)::DownCast(aSurf);
return IsVTrimAllowed(GeomAdaptor_Surface(aOS->BasisSurface()),
theNewVFirst, theNewVLast);
}
Standard_Real anIsoParameter = theS.FirstUParameter();
if (Precision::IsInfinite(anIsoParameter))
anIsoParameter = theS.LastUParameter();
if (Precision::IsInfinite(anIsoParameter))
anIsoParameter = 0.0;
Handle(Geom_Curve) aC = aSurf->UIso(anIsoParameter);
if (aC.IsNull())
return Standard_False;
if (aC->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
{
// In order to obtain the default curve's work range
aC = Handle(Geom_TrimmedCurve)::DownCast(aC)->BasisCurve();
}
if (!IsTrimAllowed(aC, theNewVFirst, theNewVLast))
return Standard_False;
switch (aSType)
{
case GeomAbs_OtherSurface:
return Standard_True;
case GeomAbs_Sphere:
{
if ((theNewVFirst < -M_PI_2) || (theNewVLast > M_PI_2))
{
// After extending, the surface isoline will go
// through the sphere pole
return Standard_False;
}
}
break;
case GeomAbs_Cone:
{
const Handle(Geom_ConicalSurface) aCone = Handle(Geom_ConicalSurface)::DownCast(aSurf);
Standard_Real anApexPrm = 0.0;
aCone->Apex(&anApexPrm);
if ((anApexPrm - theNewVFirst)*(theNewVLast - anApexPrm) > 0.0)
{
// The new boundaries intersect the cone apex
return Standard_False;
}
}
break;
case GeomAbs_SurfaceOfRevolution:
{
const Handle(Adaptor3d_HCurve) aCurv = theS.BasisCurve();
const Standard_Real aParTol = aCurv->Resolution(Precision::Confusion());
const Standard_Real aParF = theNewVFirst + aParTol,
aParL = theNewVLast - aParTol;
const Handle(Geom_Line) aL = new Geom_Line(theS.AxeOfRevolution());
const GeomAdaptor_Curve aLin(aL);
Extrema_ECC anExtr(aCurv->Curve(), aLin);
anExtr.Perform();
if (anExtr.IsDone() && anExtr.NbExt() > 0)
{
Extrema_POnCurv aP1, aP2;
for (Standard_Integer i = 1; i <= anExtr.NbExt(); i++)
{
if (anExtr.SquareDistance(i) > Precision::SquareConfusion())
continue;
anExtr.Points(i, aP1, aP2);
if ((aParF < aP1.Parameter()) && (aP1.Parameter() < aParL))
{
// After extending, the surface isoline will go
// through the pole (singular point like pole of sphere)
return Standard_False;
}
}
}
}
break;
default:
break;
}
return Standard_True;
}
//=======================================================================
//function : CompareWeightPoles
//purpose : Checks if thePoles1(i)*theW1(i) is equal to thePoles2(i)*theW2(i)
// with tolerance theTol.
// It is necessary for not rational B-splines and Bezier curves
// to set theW1 and theW2 adresses to zero.
// to set theW1 and theW2 addresses to zero.
//=======================================================================
static Standard_Boolean CompareWeightPoles(const TColgp_Array1OfPnt& thePoles1,
const TColStd_Array1OfReal* const theW1,

View File

@@ -23,6 +23,7 @@
#include <Standard_Real.hxx>
#include <GeomAbs_Shape.hxx>
#include <Precision.hxx>
#include <Standard_Integer.hxx>
#include <Standard_Boolean.hxx>
#include <TColgp_Array1OfPnt.hxx>
@@ -34,6 +35,7 @@ class gp_Ax2;
class Geom2d_Curve;
class gp_GTrsf2d;
class Adaptor3d_CurveOnSurface;
class GeomAdaptor_Surface;
class Geom_BoundedCurve;
class gp_Pnt;
class gp_Vec;
@@ -54,7 +56,6 @@ class GeomLib_Tool;
class GeomLib_PolyFunc;
class GeomLib_LogSample;
//! Geom Library. This package provides an
//! implementation of functions for basic computation
//! on geometric entity from packages Geom and Geom2d.
@@ -193,6 +194,71 @@ public:
Standard_EXPORT static void IsClosed(const Handle(Geom_Surface)& S, const Standard_Real Tol,
Standard_Boolean& isUClosed, Standard_Boolean& isVClosed);
//! This method determines if the ends of the given curve are
//! coincided with given tolerance.
//! This is a template-method. Therefore, it can be applied to
//! 2D- and 3D-curve and to Adaptor-HCurve.
template <typename TypeCurve>
Standard_EXPORT static Standard_Boolean IsClosed(const Handle(TypeCurve)& theCurve,
const Standard_Real theTol)
{
const Standard_Real aFPar = theCurve->FirstParameter(),
aLPar = theCurve->LastParameter();
if (Precision::IsInfinite(aFPar) || Precision::IsInfinite(aLPar))
return Standard_False;
return (theCurve->Value(aFPar).SquareDistance(theCurve->Value(aLPar)) < theTol*theTol);
}
//! Returns TRUE if theCurve will keep its validity for OCCT-algorithms
//! after its trimming in range [theNewFPar, theNewLPar].
//! This is a template-method. Therefore, it can be applied to
//! 2D- and 3D-curve.
//! Using trimmed curves or Adaptor_HCurves is possible but undesirable
//! because theCurve must be parametrized in its default work-range
//! in order for this method to work correctly.
template <typename TypeCurve>
Standard_EXPORT static Standard_Boolean IsTrimAllowed(const Handle(TypeCurve)& theCurve,
const Standard_Real theNewFPar,
const Standard_Real theNewLPar)
{
Standard_Real aFPar = theCurve->FirstParameter(),
aLPar = theCurve->LastParameter();
if ((aFPar <= theNewFPar) && (theNewLPar <= aLPar) && (theNewFPar < theNewLPar))
{
//New boundaries are in the current ones
return Standard_True;
}
if (!theCurve->IsPeriodic())
{
return Standard_False;
}
const Standard_Real aPeriod = theCurve->Period();
if ((theNewLPar - theNewFPar - aPeriod) > Epsilon(aPeriod))
return Standard_False;
return Standard_True;
}
//! Returns TRUE if theS will keep its validity for OCCT-algorithms
//! after its trimming in range [theNewUFirst, theNewULast] along U-direction
Standard_EXPORT static Standard_Boolean
IsUTrimAllowed(const GeomAdaptor_Surface& theS,
const Standard_Real theNewUFirst,
const Standard_Real theNewULast);
//! Returns TRUE if theS will keep its validity for OCCT-algorithms
//! after its trimming in range [theNewVFirst, theNewVLast] along V-direction
Standard_EXPORT static Standard_Boolean
IsVTrimAllowed(const GeomAdaptor_Surface& theS,
const Standard_Real theNewVFirst,
const Standard_Real theNewVLast);
//! Returns true if the poles of U1 isoline and the poles of
//! U2 isoline of surface are identical according to tolerance criterion.
//! For rational surfaces Weights(i)*Poles(i) are checked.

View File

@@ -41,10 +41,12 @@ extern "C"
#pragma warning(disable : 4244)
#endif
#ifdef HAVE_FFMPEG
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#endif
#ifdef _MSC_VER
#pragma warning(default : 4244)

View File

@@ -687,7 +687,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
}
//
Standard_Boolean Arrive, DejaReparti;
const Standard_Integer RejectIndexMAX = 250000;
const Standard_Integer RejectIndexMAX = 25000;
Standard_Integer IncKey, RejectIndex;
gp_Pnt pf,pl;
//
@@ -736,6 +736,12 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
Arrive = Standard_False;
while(!Arrive) //010
{
if (line->NbPoints() >= RejectIndexMAX)
{
Arrive = Standard_True;
break;
}
aPrevStatus = aStatus;
LevelOfIterWithoutAppend++;
@@ -745,7 +751,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
if(DejaReparti) {
break;
}
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
LevelOfIterWithoutAppend = 0;
}
//
@@ -872,7 +878,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
Param(2)=SvParam[1];
Param(3)=SvParam[2];
Param(4)=SvParam[3];
RepartirOuDiviser(DejaReparti, ChoixIso, Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
}
else //009
{
@@ -903,7 +909,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
Arrive=Standard_True;
}
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
LevelOfEmptyInmyIntersectionOn2S++;
//
if(LevelOfEmptyInmyIntersectionOn2S>10)
@@ -1036,7 +1042,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
case IntWalk_ArretSurPointPrecedent:
{
Arrive = Standard_False;
RepartirOuDiviser(DejaReparti, ChoixIso, Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
break;
}
case IntWalk_PasTropGrand:
@@ -1046,7 +1052,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
Param(3)=SvParam[2];
Param(4)=SvParam[3];
if(LevelOfIterWithoutAppend > 5)
if ((LevelOfIterWithoutAppend > 5) && (aPrevStatus != IntWalk_StepTooSmall))
{
for (Standard_Integer i = 0; i < 4; i++)
{
@@ -1240,7 +1246,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
if (aStatus == IntWalk_ArretSurPoint)
{
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
}
else
{
@@ -1321,13 +1327,13 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
//
LevelOfIterWithoutAppend=0;
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
}
else
{
//fail framing divides the step
Arrive = Standard_False;
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
NoTestDeflection = Standard_True;
ChoixIso = SauvChoixIso;
}
@@ -1582,7 +1588,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
}
}
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
if(Arrive &&
myIntersectionOn2S.IsDone() && !myIntersectionOn2S.IsEmpty() &&
@@ -1603,7 +1609,7 @@ void IntWalk_PWalking::Perform(const TColStd_Array1OfReal& ParDep,
//echec framing on border; division of step
Arrive = Standard_False;
NoTestDeflection = Standard_True;
RepartirOuDiviser(DejaReparti,ChoixIso,Arrive);
RepartirOuDiviser(aStatus, DejaReparti, ChoixIso, Arrive);
}
}//$$$ end framing on border (!close)
}//004 fin TestArret return Arrive = True
@@ -2769,16 +2775,17 @@ SeekAdditionalPoints( const Handle(Adaptor3d_HSurface)& theASurf1,
return isPrecise;
}
void IntWalk_PWalking::
RepartirOuDiviser(Standard_Boolean& DejaReparti,
IntImp_ConstIsoparametric& ChoixIso,
Standard_Boolean& Arrive)
// at the neighborhood of a point, there is a fail of marching
// it is required to divide the steps to try to continue
// if the step is too small if we are on border
// restart in another direction if it was not done, otherwise stop
//=======================================================================
//function : RepartirOuDiviser
//purpose : at the neighborhood of a point, there is a fail of marching
// it is required to divide the steps to try to continue
// if the step is too small if we are on border
// restart in another direction if it was not done, otherwise stop
//=======================================================================
void IntWalk_PWalking::RepartirOuDiviser(const IntWalk_StatusDeflection& theCurrentStatus,
Standard_Boolean& DejaReparti,
IntImp_ConstIsoparametric& ChoixIso,
Standard_Boolean& Arrive)
{
// Standard_Integer i;
if (Arrive) { //restart in the other direction
@@ -2821,11 +2828,12 @@ RepartirOuDiviser(Standard_Boolean& DejaReparti,
}
}
else {
if ( pasuv[0]*0.5 < ResoU1
&& pasuv[1]*0.5 < ResoV1
&& pasuv[2]*0.5 < ResoU2
&& pasuv[3]*0.5 < ResoV2
) {
if ((theCurrentStatus == IntWalk_StepTooSmall) ||
(pasuv[0] * 0.5 < ResoU1
&& pasuv[1] * 0.5 < ResoV1
&& pasuv[2] * 0.5 < ResoU2
&& pasuv[3] * 0.5 < ResoV2))
{
if (!previoustg) {
tglast = Standard_True; // IS IT ENOUGH ????
}

View File

@@ -130,7 +130,10 @@ public:
Standard_EXPORT Standard_Boolean TestArret (const Standard_Boolean DejaReparti, TColStd_Array1OfReal& Param, IntImp_ConstIsoparametric& ChoixIso);
Standard_EXPORT void RepartirOuDiviser (Standard_Boolean& DejaReparti, IntImp_ConstIsoparametric& ChoixIso, Standard_Boolean& Arrive);
Standard_EXPORT void RepartirOuDiviser(const IntWalk_StatusDeflection& theCurrentStatus,
Standard_Boolean& DejaReparti,
IntImp_ConstIsoparametric& ChoixIso,
Standard_Boolean& Arrive);
void AddAPoint (Handle(IntSurf_LineOn2S)& line, const IntSurf_PntOn2S& POn2S);

View File

@@ -117,7 +117,7 @@ LocOpe_DPrism::LocOpe_DPrism(const TopoDS_Face& Spine,
myProfile = BRepLib_MakeWire(myProfile1,myProfile2,myProfile3);
myDPrism.Perform(mySpine,myProfile,gp::XOY());
myDPrism.Perform(mySpine,myProfile,gp::XOY(), GeomAbs_Arc, Standard_False);
if (myDPrism.IsDone()) {
@@ -370,7 +370,7 @@ LocOpe_DPrism::LocOpe_DPrism(const TopoDS_Face& Spine,
myProfile1 = BRepLib_MakeEdge(Vert4, Vert1);
myProfile = BRepLib_MakeWire(myProfile1,myProfile2,myProfile3);
myDPrism.Perform(mySpine,myProfile,gp::XOY());
myDPrism.Perform(mySpine,myProfile,gp::XOY(), GeomAbs_Arc, Standard_False);
if (myDPrism.IsDone()) {

View File

@@ -57,6 +57,8 @@ OSD_OpenMode.hxx
OSD_OSDError.hxx
OSD_Parallel.cxx
OSD_Parallel.hxx
OSD_Parallel_TBB.cxx
OSD_Parallel_Threads.cxx
OSD_Path.cxx
OSD_Path.hxx
OSD_PerfMeter.cxx
@@ -83,6 +85,8 @@ OSD_SingleProtection.hxx
OSD_SysType.hxx
OSD_Thread.cxx
OSD_Thread.hxx
OSD_ThreadPool.cxx
OSD_ThreadPool.hxx
OSD_ThreadFunction.hxx
OSD_Timer.cxx
OSD_Timer.hxx

View File

@@ -104,7 +104,10 @@ public:
//! user's code. Refer to Foundation Classes User's Guide for further details.
//!
Standard_EXPORT static void SetSignal (const Standard_Boolean theFloatingSignal = Standard_True);
//! Return floating signal catching value previously set by SetSignal().
Standard_EXPORT static Standard_Boolean ToCatchFloatingSignals();
//! Commands the process to sleep for a number of seconds.
Standard_EXPORT static void SecSleep (const Standard_Integer aDelay);

View File

@@ -14,25 +14,25 @@
#ifndef OSD_Parallel_HeaderFile
#define OSD_Parallel_HeaderFile
#include <OSD_Thread.hxx>
#include <Standard_Mutex.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_Atomic.hxx>
#include <NCollection_Array1.hxx>
#include <Standard_Type.hxx>
#include <memory>
#include <type_traits>
#ifdef HAVE_TBB
#include <tbb/parallel_for.h>
#include <tbb/parallel_for_each.h>
#include <tbb/blocked_range.h>
#endif
//! @class OSD_Parallel
//! @brief Simplifies code parallelization.
//! @brief Simple tool for code parallelization.
//!
//! The Class provides an interface of parallel processing "for" and "foreach" loops.
//! These primitives encapsulates complete logic for creating and managing parallel context of loops.
//! Moreover the primitives may be a wrapper for some primitives from 3rd-party library - TBB.
//! To use it is necessary to implement TBB like interface which is based on functors.
//! OSD_Parallel class provides simple interface for parallel processing of
//! tasks that can be formulated in terms of "for" or "foreach" loops.
//!
//! To use this tool it is necessary to:
//! - organize the data to be processed in a collection accessible by
//! iteration (usually array or vector);
//! - implement a functor class providing operator () accepting iterator
//! (or index in array) that does the job;
//! - call either For() or ForEach() providing begin and end iterators and
//! a functor object.
//!
//! Iterators should satisfy requirements of STL forward iterator.
//! Functor
//!
//! @code
//! class Functor
@@ -45,268 +45,290 @@
//! };
//! @endcode
//!
//! In the body of the operator () should be implemented thread-safe logic of computations that can be performed in parallel context.
//! If parallelized loop iterates on the collections with direct access by index (such as Vector, Array),
//! it is more efficient to use the primitive ParallelFor (because it has no critical section).
//! The operator () should be implemented in a thread-safe way so that
//! the same functor object can process different data items in parallel threads.
//!
//! Iteration by index (For) is expected to be more efficient than using iterators
//! (ForEach).
//!
//! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
//! uses ad-hoc parallelization tool. In general, if TBB is available, it is
//! more efficient to use it directly instead of using OSD_Parallel.
class OSD_Parallel
{
//! Auxiliary class which ensures exclusive
//! access to iterators of processed data pool.
template <typename Value>
class Range
private:
//! Interface class defining API for polymorphic wrappers over iterators.
//! Intended to add polymorphic behaviour to For and ForEach functionality
//! for arbitrary objects and eliminate dependency on template parameters.
class IteratorInterface
{
public: //! @name public methods
public:
virtual ~IteratorInterface() {}
typedef Value Iterator;
//! Returns true if iterators wrapped by this and theOther are equal
virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
//! Constructor
Range(const Value& theBegin, const Value& theEnd)
: myBegin(theBegin),
myEnd (theEnd),
myIt (theBegin)
{
}
//! Increments wrapped iterator
virtual void Increment () = 0;
//! Returns const link on the first element.
inline const Value& Begin() const
{
return myBegin;
}
//! Returns const link on the last element.
inline const Value& End() const
{
return myEnd;
}
//! Returns first non processed element or end.
//! Thread-safe method.
inline Iterator It() const
{
Standard_Mutex::Sentry aMutex( myMutex );
return ( myIt != myEnd ) ? myIt++ : myEnd;
}
private: //! @name private methods
//! Empty copy constructor
Range(const Range& theCopy);
//! Empty copy operator.
Range& operator=(const Range& theCopy);
private: //! @name private fields
const Value& myBegin; //!< Fisrt element of range.
const Value& myEnd; //!< Last element of range.
mutable Value myIt; //!< First non processed element of range.
mutable Standard_Mutex myMutex; //!< Access controller for the first non processed element.
//! Returns new instance of the wrapper containing copy
//! of the wrapped iterator.
virtual IteratorInterface* Clone() const = 0;
};
//! Auxiliary wrapper class for thread function.
template <typename Functor, typename InputIterator>
class Task
//! Implementation of polymorphic iterator wrapper suitable for basic
//! types as well as for std iterators.
//! Wraps instance of actual iterator type Type.
template<class Type>
class IteratorWrapper : public IteratorInterface
{
public: //! @name public methods
public:
IteratorWrapper() {}
IteratorWrapper(const Type& theValue) : myValue(theValue) {}
//! Constructor.
Task(const Functor& thePerformer, Range<InputIterator>& theRange)
: myPerformer(thePerformer),
myRange (theRange)
virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
{
return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
}
//! Method is executed in the context of thread,
//! so this method defines the main calculations.
static Standard_Address RunWithIterator(Standard_Address theTask)
virtual void Increment () Standard_OVERRIDE
{
Task<Functor, InputIterator>& aTask =
*( static_cast< Task<Functor, InputIterator>* >(theTask) );
const Range<InputIterator>& aData( aTask.myRange );
typename Range<InputIterator>::Iterator i = aData.It();
for ( ; i != aData.End(); i = aData.It() )
{
aTask.myPerformer(*i);
}
return NULL;
++myValue;
}
//! Method is executed in the context of thread,
//! so this method defines the main calculations.
static Standard_Address RunWithIndex(Standard_Address theTask)
virtual IteratorInterface* Clone() const Standard_OVERRIDE
{
Task<Functor, InputIterator>& aTask =
*( static_cast< Task<Functor, Standard_Integer>* >(theTask) );
const Range<Standard_Integer>& aData( aTask.myRange );
Standard_Integer i = aData.It();
for ( ; i < aData.End(); i = aData.It())
{
aTask.myPerformer(i);
}
return NULL;
return new IteratorWrapper<Type>(myValue);
}
private: //! @name private methods
const Type& Value() const { return myValue; }
//! Empty copy constructor.
Task(const Task& theCopy);
//! Empty copy operator.
Task& operator=(const Task& theCopy);
private: //! @name private fields
const Functor& myPerformer; //!< Link on functor.
const Range<InputIterator>& myRange; //!< Link on processed data block.
private:
Type myValue;
};
public: //! @name public methods
protected:
// Note: UniversalIterator and FunctorInterface are made protected to be
// accessible from specialization using threads (non-TBB).
//! Returns number of logical proccesrs.
Standard_EXPORT static Standard_Integer NbLogicalProcessors();
//! Fixed-type iterator, implementing STL forward iterator interface, used for
//! iteration over objects subject to parallel processing.
//! It stores pointer to instance of polymorphic iterator inheriting from
//! IteratorInterface, which contains actual type-specific iterator.
class UniversalIterator :
// Note that TBB requires that value_type of iterator be copyable,
// thus we use its own type for that
public std::iterator<std::forward_iterator_tag, UniversalIterator, ptrdiff_t, UniversalIterator*, UniversalIterator&>
{
public:
UniversalIterator() {}
UniversalIterator(IteratorInterface* theOther)
: myPtr(theOther)
{
}
UniversalIterator(const UniversalIterator& theOther)
: myPtr (theOther.myPtr->Clone())
{
}
UniversalIterator& operator= (const UniversalIterator& theOther)
{
myPtr.reset (theOther.myPtr->Clone());
return *this;
}
bool operator!= (const UniversalIterator& theOther) const
{
return ! myPtr->IsEqual (*theOther.myPtr);
}
bool operator== (const UniversalIterator& theOther) const
{
return myPtr->IsEqual (*theOther.myPtr);
}
UniversalIterator& operator++()
{
myPtr->Increment();
return *this;
}
UniversalIterator operator++(int)
{
UniversalIterator aValue(*this);
myPtr->Increment();
return aValue;
}
const UniversalIterator& operator* () const { return *this; }
UniversalIterator& operator* () { return *this; }
const UniversalIterator* operator->() const { return this; }
UniversalIterator* operator->() { return this; }
// type cast to actual iterator
template <typename Iterator>
const Iterator& DownCast () const
{
return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(myPtr.get())->Value();
}
private:
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
std::auto_ptr<IteratorInterface> myPtr;
#else
std::unique_ptr<IteratorInterface> myPtr;
#endif
};
//! Interface class representing functor object.
//! Intended to add polymorphic behavour to For and ForEach functionality
//! enabling execution of arbitrary function in parallel mode.
class FunctorInterface
{
public:
virtual ~FunctorInterface() {}
virtual void operator () (UniversalIterator& theIterator) const = 0;
};
private:
//! Wrapper for functors manipulating on std iterators.
template<class Iterator, class Functor>
class FunctorWrapperIter : public FunctorInterface
{
public:
FunctorWrapperIter (const Functor& theFunctor)
: myFunctor(theFunctor)
{
}
virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
{
const Iterator& anIt = theIterator.DownCast<Iterator>();
myFunctor(*anIt);
}
private:
FunctorWrapperIter (const FunctorWrapperIter&);
void operator = (const FunctorWrapperIter&);
const Functor& myFunctor;
};
//! Wrapper for functors manipulating on integer index.
template<class Functor>
class FunctorWrapperInt : public FunctorInterface
{
public:
FunctorWrapperInt (const Functor& theFunctor)
: myFunctor(theFunctor)
{
}
virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
{
Standard_Integer anIndex = theIterator.DownCast<Standard_Integer>();
myFunctor(anIndex);
}
private:
FunctorWrapperInt (const FunctorWrapperInt&);
void operator = (const FunctorWrapperInt&);
const Functor& myFunctor;
};
private:
//! Simple primitive for parallelization of "foreach" loops, e.g.:
//! @code
//! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
//! @endcode
//! Implementation of framework-dependent functionality should be provided by
//! forEach_impl function defined in opencascade::parallel namespace.
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}" performing task for specified iterator position
//! @param isForceSingleThreadExecution if true, then no threads will be created
template <typename InputIterator, typename Functor>
static void ForEach( InputIterator theBegin,
InputIterator theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution
= Standard_False );
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
//! performing task for the specified iterator position
//! @param theNbItems number of items passed by iterator, -1 if unknown
Standard_EXPORT static void forEach (UniversalIterator& theBegin,
UniversalIterator& theEnd,
const FunctorInterface& theFunctor,
Standard_Integer theNbItems);
//! Simple primitive for parallelization of "for" loops, e.g.:
public: //! @name public methods
//! Returns number of logical proccesrs.
Standard_EXPORT static Standard_Integer NbLogicalProcessors();
//! Simple primitive for parallelization of "foreach" loops, equivalent to:
//! @code
//! for (int anIter = theBegin; anIter < theEnd; ++anIter) {}
//! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
//! theFunctor(*anIter);
//! }
//! @endcode
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
//! @param theFunctor functor providing an interface "void operator(int theIndex){}" performing task for specified index
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
//! performing task for specified iterator position
//! @param isForceSingleThreadExecution if true, then no threads will be created
//! @param theNbItems number of items passed by iterator, -1 if unknown
template <typename InputIterator, typename Functor>
static void ForEach(InputIterator theBegin,
InputIterator theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution = Standard_False,
Standard_Integer theNbItems = -1)
{
if (isForceSingleThreadExecution || theNbItems == 1)
{
for (InputIterator it(theBegin); it != theEnd; ++it)
theFunctor(*it);
}
else
{
UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
forEach(aBegin, aEnd, aFunctor, theNbItems);
}
}
//! Simple primitive for parallelization of "for" loops, equivalent to:
//! @code
//! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
//! theFunctor(anIter);
//! }
//! @endcode
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
//! @param theFunctor functor providing an interface "void operator(int theIndex){}"
//! performing task for specified index
//! @param isForceSingleThreadExecution if true, then no threads will be created
template <typename Functor>
static void For( const Standard_Integer theBegin,
const Standard_Integer theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution
= Standard_False );
static void For(const Standard_Integer theBegin,
const Standard_Integer theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution = Standard_False)
{
if (isForceSingleThreadExecution || (theEnd - theBegin) == 1)
{
for (Standard_Integer it (theBegin); it != theEnd; ++it)
theFunctor(it);
}
else
{
UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
FunctorWrapperInt<Functor> aFunctor (theFunctor);
forEach(aBegin, aEnd, aFunctor, theEnd - theBegin);
}
}
};
//=======================================================================
//function : OSD_Parallel::Range::It
//purpose : Template concretization.
//=======================================================================
template<> inline Standard_Integer OSD_Parallel::Range<Standard_Integer>::It() const
{
return Standard_Atomic_Increment( reinterpret_cast<volatile int*>(&myIt) ) - 1;
}
//=======================================================================
//function : ParallelForEach
//purpose :
//=======================================================================
template <typename InputIterator, typename Functor>
void OSD_Parallel::ForEach( InputIterator theBegin,
InputIterator theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution )
{
if ( isForceSingleThreadExecution )
{
for ( InputIterator it(theBegin); it != theEnd; ++it )
theFunctor(*it);
return;
}
#ifdef HAVE_TBB
{
try
{
tbb::parallel_for_each(theBegin, theEnd, theFunctor);
}
catch ( tbb::captured_exception& anException )
{
throw Standard_NotImplemented(anException.what());
}
}
#else
{
Range<InputIterator> aData(theBegin, theEnd);
Task<Functor, InputIterator> aTask(theFunctor, aData);
const Standard_Integer aNbThreads = OSD_Parallel::NbLogicalProcessors();
NCollection_Array1<OSD_Thread> aThreads(0, aNbThreads - 1);
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
{
OSD_Thread& aThread = aThreads(i);
aThread.SetFunction(&Task<Functor, InputIterator>::RunWithIterator);
aThread.Run(&aTask);
}
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
aThreads(i).Wait();
}
#endif
}
//=======================================================================
//function : ParallelFor
//purpose :
//=======================================================================
template <typename Functor>
void OSD_Parallel::For( const Standard_Integer theBegin,
const Standard_Integer theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution )
{
if ( isForceSingleThreadExecution )
{
for ( Standard_Integer i = theBegin; i < theEnd; ++i )
theFunctor(i);
return;
}
#ifdef HAVE_TBB
{
try
{
tbb::parallel_for( theBegin, theEnd, theFunctor );
}
catch ( tbb::captured_exception& anException )
{
throw Standard_NotImplemented(anException.what());
}
}
#else
{
Range<Standard_Integer> aData(theBegin, theEnd);
Task<Functor, Standard_Integer> aTask(theFunctor, aData);
const Standard_Integer aNbThreads = OSD_Parallel::NbLogicalProcessors();
NCollection_Array1<OSD_Thread> aThreads(0, aNbThreads - 1);
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
{
OSD_Thread& aThread = aThreads(i);
aThread.SetFunction(&Task<Functor, Standard_Integer>::RunWithIndex);
aThread.Run(&aTask);
}
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
aThreads(i).Wait();
}
#endif
}
#endif

View File

@@ -0,0 +1,48 @@
// Created on: 2014-08-19
// Created by: Alexander Zaikin
// Copyright (c) 1996-1999 Matra Datavision
// Copyright (c) 2013-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.
// Version of parallel executor used when TBB is available
#ifdef HAVE_TBB
#include <OSD_Parallel.hxx>
#include <Standard_ProgramError.hxx>
#include <tbb/parallel_for.h>
#include <tbb/parallel_for_each.h>
#include <tbb/blocked_range.h>
//=======================================================================
//function : forEach
//purpose :
//=======================================================================
void OSD_Parallel::forEach (UniversalIterator& theBegin,
UniversalIterator& theEnd,
const FunctorInterface& theFunctor,
Standard_Integer theNbItems)
{
(void )theNbItems;
try
{
tbb::parallel_for_each(theBegin, theEnd, theFunctor);
}
catch (tbb::captured_exception& anException)
{
throw Standard_ProgramError(anException.what());
}
}
#endif /* HAVE_TBB */

View File

@@ -0,0 +1,159 @@
// Created on: 2014-08-19
// Created by: Alexander Zaikin
// Copyright (c) 1996-1999 Matra Datavision
// Copyright (c) 2013-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.
// Version of parallel executor used when TBB is not available
#ifndef HAVE_TBB
#include <OSD_Parallel.hxx>
#include <OSD_ThreadPool.hxx>
#include <NCollection_Array1.hxx>
#include <Standard_Mutex.hxx>
#include <OSD_Thread.hxx>
namespace
{
//! Class implementing tools for parallel processing
//! using threads (when TBB is not available);
//! it is derived from OSD_Parallel to get access to
//! Iterator and FunctorInterface nested types.
class OSD_Parallel_Threads : public OSD_ThreadPool, public OSD_Parallel
{
public:
//! Auxiliary class which ensures exclusive
//! access to iterators of processed data pool.
class Range
{
public: //! @name public methods
//! Constructor
Range(const OSD_Parallel::UniversalIterator& theBegin,
const OSD_Parallel::UniversalIterator& theEnd)
: myBegin(theBegin),
myEnd(theEnd),
myIt(theBegin)
{
}
//! Returns const link on the first element.
inline const OSD_Parallel::UniversalIterator& Begin() const
{
return myBegin;
}
//! Returns const link on the last element.
inline const OSD_Parallel::UniversalIterator& End() const
{
return myEnd;
}
//! Returns first non processed element or end.
//! Thread-safe method.
inline OSD_Parallel::UniversalIterator It() const
{
Standard_Mutex::Sentry aMutex(myMutex);
return (myIt != myEnd) ? myIt++ : myEnd;
}
private: //! @name private methods
//! Empty copy constructor
Range(const Range& theCopy);
//! Empty copy operator.
Range& operator=(const Range& theCopy);
private: //! @name private fields
const OSD_Parallel::UniversalIterator& myBegin; //!< Fisrt element of range.
const OSD_Parallel::UniversalIterator& myEnd; //!< Last element of range.
mutable OSD_Parallel::UniversalIterator myIt; //!< First non processed element of range.
mutable Standard_Mutex myMutex; //!< Access controller for the first non processed element.
};
//! Auxiliary wrapper class for thread function.
class Task : public JobInterface
{
public: //! @name public methods
//! Constructor.
Task(const OSD_Parallel::FunctorInterface& thePerformer, Range& theRange)
: myPerformer(thePerformer),
myRange(theRange)
{
}
//! Method is executed in the context of thread,
//! so this method defines the main calculations.
virtual void Perform (int ) Standard_OVERRIDE
{
for (OSD_Parallel::UniversalIterator anIter = myRange.It(); anIter != myRange.End(); anIter = myRange.It())
{
myPerformer (anIter);
}
}
private: //! @name private methods
//! Empty copy constructor.
Task(const Task& theCopy);
//! Empty copy operator.
Task& operator=(const Task& theCopy);
private: //! @name private fields
const FunctorInterface& myPerformer; //!< Link on functor
const Range& myRange; //!< Link on processed data block
};
//! Launcher specialization.
class UniversalLauncher : public Launcher
{
public:
//! Constructor.
UniversalLauncher (OSD_ThreadPool& thePool, int theMaxThreads = -1)
: Launcher (thePool, theMaxThreads) {}
//! Primitive for parallelization of "for" loops.
void Perform (OSD_Parallel::UniversalIterator& theBegin,
OSD_Parallel::UniversalIterator& theEnd,
const OSD_Parallel::FunctorInterface& theFunctor)
{
Range aData (theBegin, theEnd);
Task aJob (theFunctor, aData);
perform (aJob);
}
};
};
}
//=======================================================================
//function : forEach
//purpose :
//=======================================================================
void OSD_Parallel::forEach (UniversalIterator& theBegin,
UniversalIterator& theEnd,
const FunctorInterface& theFunctor,
Standard_Integer theNbItems)
{
const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
const Standard_Integer aNbThreads = theNbItems != -1 ? Min (theNbItems, aThreadPool->NbDefaultThreadsToLaunch()) : -1;
OSD_Parallel_Threads::UniversalLauncher aLauncher (*aThreadPool, aNbThreads);
aLauncher.Perform (theBegin, theEnd, theFunctor);
}
#endif /* ! HAVE_TBB */

401
src/OSD/OSD_ThreadPool.cxx Normal file
View File

@@ -0,0 +1,401 @@
// Created by: Kirill Gavrilov
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of commercial software by OPEN CASCADE SAS.
//
// This software is furnished in accordance with the terms and conditions
// of the contract and with the inclusion of this copyright notice.
// This software or any other copy thereof may not be provided or otherwise
// be made available to any third party.
// No ownership title to the software is transferred hereby.
//
// OPEN CASCADE SAS makes no representation or warranties with respect to the
// performance of this software, and specifically disclaims any responsibility
// for any damages, special or consequential, connected with its use.
#include <OSD_ThreadPool.hxx>
#include <OSD.hxx>
#include <Standard_Atomic.hxx>
#include <TCollection_AsciiString.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OSD_ThreadPool, Standard_Transient)
// =======================================================================
// function : Lock
// purpose :
// =======================================================================
bool OSD_ThreadPool::EnumeratedThread::Lock()
{
return Standard_Atomic_CompareAndSwap (&myUsageCounter, 0, 1);
}
// =======================================================================
// function : Free
// purpose :
// =======================================================================
void OSD_ThreadPool::EnumeratedThread::Free()
{
Standard_Atomic_CompareAndSwap (&myUsageCounter, 1, 0);
}
// =======================================================================
// function : WakeUp
// purpose :
// =======================================================================
void OSD_ThreadPool::EnumeratedThread::WakeUp (JobInterface* theJob, bool theToCatchFpe)
{
myJob = theJob;
myToCatchFpe = theToCatchFpe;
if (myIsSelfThread)
{
if (theJob != NULL)
{
OSD_ThreadPool::performJob (myFailure, myJob, myThreadIndex);
}
return;
}
myWakeEvent.Set();
if (theJob != NULL && !myIsStarted)
{
myIsStarted = true;
Run (this);
}
}
// =======================================================================
// function : WaitIdle
// purpose :
// =======================================================================
void OSD_ThreadPool::EnumeratedThread::WaitIdle()
{
if (!myIsSelfThread)
{
myIdleEvent.Wait();
myIdleEvent.Reset();
}
}
// =======================================================================
// function : DefaultPool
// purpose :
// =======================================================================
const Handle(OSD_ThreadPool)& OSD_ThreadPool::DefaultPool (int theNbThreads)
{
static const Handle(OSD_ThreadPool) THE_GLOBAL_POOL = new OSD_ThreadPool (theNbThreads);
return THE_GLOBAL_POOL;
}
// =======================================================================
// function : OSD_ThreadPool
// purpose :
// =======================================================================
OSD_ThreadPool::OSD_ThreadPool (int theNbThreads)
: myNbDefThreads (0),
myShutDown (false)
{
Init (theNbThreads);
myNbDefThreads = NbThreads();
}
// =======================================================================
// function : IsInUse
// purpose :
// =======================================================================
bool OSD_ThreadPool::IsInUse()
{
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
aThreadIter.More(); aThreadIter.Next())
{
EnumeratedThread& aThread = aThreadIter.ChangeValue();
if (!aThread.Lock())
{
return true;
}
aThread.Free();
}
return false;
}
// =======================================================================
// function : Init
// purpose :
// =======================================================================
void OSD_ThreadPool::Init (int theNbThreads)
{
const int aNbThreads = Max (0, (theNbThreads > 0 ? theNbThreads : OSD_Parallel::NbLogicalProcessors()) - 1);
if (myThreads.Size() == aNbThreads)
{
return;
}
// release old threads
if (!myThreads.IsEmpty())
{
NCollection_Array1<EnumeratedThread*> aLockThreads (myThreads.Lower(), myThreads.Upper());
aLockThreads.Init (NULL);
int aThreadIndex = myThreads.Lower();
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
aThreadIter.More(); aThreadIter.Next())
{
EnumeratedThread& aThread = aThreadIter.ChangeValue();
if (!aThread.Lock())
{
for (NCollection_Array1<EnumeratedThread*>::Iterator aLockThreadIter (aLockThreads);
aLockThreadIter.More() && aLockThreadIter.Value() != NULL; aLockThreadIter.Next())
{
aLockThreadIter.ChangeValue()->Free();
}
throw Standard_ProgramError ("Error: active ThreadPool is reinitialized");
}
aLockThreads.SetValue (aThreadIndex++, &aThread);
}
}
release();
myShutDown = false;
if (aNbThreads > 0)
{
myThreads.Resize (0, aNbThreads - 1, false);
int aLastThreadIndex = 0;
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
aThreadIter.More(); aThreadIter.Next())
{
EnumeratedThread& aThread = aThreadIter.ChangeValue();
aThread.myPool = this;
aThread.myThreadIndex = aLastThreadIndex++;
aThread.SetFunction (&OSD_ThreadPool::EnumeratedThread::runThread);
}
}
else
{
NCollection_Array1<EnumeratedThread> anEmpty;
myThreads.Move (anEmpty);
}
}
// =======================================================================
// function : ~OSD_ThreadPool
// purpose :
// =======================================================================
OSD_ThreadPool::~OSD_ThreadPool()
{
release();
}
// =======================================================================
// function : release
// purpose :
// =======================================================================
void OSD_ThreadPool::release()
{
if (myThreads.IsEmpty())
{
return;
}
myShutDown = true;
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
aThreadIter.More(); aThreadIter.Next())
{
aThreadIter.ChangeValue().WakeUp (NULL, false);
aThreadIter.ChangeValue().Wait();
}
}
// =======================================================================
// function : perform
// purpose :
// =======================================================================
void OSD_ThreadPool::Launcher::perform (JobInterface& theJob)
{
run (theJob);
wait();
}
// =======================================================================
// function : run
// purpose :
// =======================================================================
void OSD_ThreadPool::Launcher::run (JobInterface& theJob)
{
bool toCatchFpe = OSD::ToCatchFloatingSignals();
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
{
aThreadIter.ChangeValue()->WakeUp (&theJob, toCatchFpe);
}
}
// =======================================================================
// function : wait
// purpose :
// =======================================================================
void OSD_ThreadPool::Launcher::wait()
{
int aNbFailures = 0;
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
{
aThreadIter.ChangeValue()->WaitIdle();
if (!aThreadIter.Value()->myFailure.IsNull())
{
++aNbFailures;
}
}
if (aNbFailures == 0)
{
return;
}
TCollection_AsciiString aFailures;
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
{
if (!aThreadIter.Value()->myFailure.IsNull())
{
if (aNbFailures == 1)
{
aThreadIter.Value()->myFailure->Reraise();
}
if (!aFailures.IsEmpty())
{
aFailures += "\n";
}
aFailures += aThreadIter.Value()->myFailure->GetMessageString();
}
}
aFailures = TCollection_AsciiString("Multiple exceptions:\n") + aFailures;
throw Standard_ProgramError (aFailures.ToCString());
}
// =======================================================================
// function : performJob
// purpose :
// =======================================================================
void OSD_ThreadPool::performJob (Handle(Standard_Failure)& theFailure,
OSD_ThreadPool::JobInterface* theJob,
int theThreadIndex)
{
try
{
OCC_CATCH_SIGNALS
theJob->Perform (theThreadIndex);
}
catch (Standard_Failure const& aFailure)
{
TCollection_AsciiString aMsg = TCollection_AsciiString (aFailure.DynamicType()->Name())
+ ": " + aFailure.GetMessageString();
theFailure = new Standard_ProgramError (aMsg.ToCString());
}
catch (std::exception& anStdException)
{
TCollection_AsciiString aMsg = TCollection_AsciiString (typeid(anStdException).name())
+ ": " + anStdException.what();
theFailure = new Standard_ProgramError (aMsg.ToCString());
}
catch (...)
{
theFailure = new Standard_ProgramError ("Error: Unknown exception");
}
}
// =======================================================================
// function : performThread
// purpose :
// =======================================================================
void OSD_ThreadPool::EnumeratedThread::performThread()
{
OSD::SetSignal (false);
for (;;)
{
myWakeEvent.Wait();
myWakeEvent.Reset();
if (myPool->myShutDown)
{
return;
}
myFailure.Nullify();
if (myJob != NULL)
{
OSD::SetSignal (myToCatchFpe);
OSD_ThreadPool::performJob (myFailure, myJob, myThreadIndex);
myJob = NULL;
}
myIdleEvent.Set();
}
}
// =======================================================================
// function : runThread
// purpose :
// =======================================================================
Standard_Address OSD_ThreadPool::EnumeratedThread::runThread (Standard_Address theTask)
{
EnumeratedThread* aThread = static_cast<EnumeratedThread*>(theTask);
aThread->performThread();
return NULL;
}
// =======================================================================
// function : Launcher
// purpose :
// =======================================================================
OSD_ThreadPool::Launcher::Launcher (OSD_ThreadPool& thePool, Standard_Integer theMaxThreads)
: mySelfThread (true),
myNbThreads (0)
{
const int aNbThreads = theMaxThreads > 0
? Min (theMaxThreads, thePool.NbThreads())
: (theMaxThreads < 0
? Max (thePool.NbDefaultThreadsToLaunch(), 1)
: 1);
myThreads.Resize (0, aNbThreads - 1, false);
myThreads.Init (NULL);
if (aNbThreads > 1)
{
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (thePool.myThreads);
aThreadIter.More(); aThreadIter.Next())
{
if (aThreadIter.ChangeValue().Lock())
{
myThreads.SetValue (myNbThreads, &aThreadIter.ChangeValue());
// make thread index to fit into myThreads range
aThreadIter.ChangeValue().myThreadIndex = myNbThreads;
if (++myNbThreads == aNbThreads - 1)
{
break;
}
}
}
}
// self thread should be executed last
myThreads.SetValue (myNbThreads, &mySelfThread);
mySelfThread.myThreadIndex = myNbThreads;
++myNbThreads;
}
// =======================================================================
// function : Release
// purpose :
// =======================================================================
void OSD_ThreadPool::Launcher::Release()
{
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
{
if (aThreadIter.Value() != &mySelfThread)
{
aThreadIter.Value()->Free();
}
}
NCollection_Array1<EnumeratedThread*> anEmpty;
myThreads.Move (anEmpty);
myNbThreads = 0;
}

301
src/OSD/OSD_ThreadPool.hxx Normal file
View File

@@ -0,0 +1,301 @@
// Created by: Kirill Gavrilov
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of commercial software by OPEN CASCADE SAS.
//
// This software is furnished in accordance with the terms and conditions
// of the contract and with the inclusion of this copyright notice.
// This software or any other copy thereof may not be provided or otherwise
// be made available to any third party.
// No ownership title to the software is transferred hereby.
//
// OPEN CASCADE SAS makes no representation or warranties with respect to the
// performance of this software, and specifically disclaims any responsibility
// for any damages, special or consequential, connected with its use.
#ifndef _OSD_ThreadPool_HeaderFile
#define _OSD_ThreadPool_HeaderFile
#include <NCollection_Array1.hxx>
#include <OSD_Thread.hxx>
#include <OSD_Parallel.hxx>
#include <Standard_Atomic.hxx>
#include <Standard_Condition.hxx>
#include <Standard_Mutex.hxx>
//! Class defining a thread pool for executing algorithms in multi-threaded mode.
//! Thread pool allocates requested amount of threads and keep them alive
//! (in sleep mode when unused) during thread pool lifetime.
//! The same pool can be used by multiple consumers,
//! including nested multi-threading algorithms and concurrent threads:
//! - Thread pool can be used either by multi-threaded algorithm by creating OSD_ThreadPool::Launcher.
//! The functor performing a job takes two parameters - Thread Index and Data Index:
//! void operator(int theThreadIndex, int theDataIndex){}
//! Multi-threaded algorithm may rely on Thread Index for allocating thread-local variables in array form,
//! since the Thread Index is guaranteed to be within range OSD_ThreadPool::Lower() and OSD_ThreadPool::Upper().
//! - Default thread pool (OSD_ThreadPool::DefaultPool()) can be used in general case,
//! but application may prefer creating a dedicated pool for better control.
//! - Default thread pool allocates the amount of threads considering concurrency
//! level of the system (amount of logical processors).
//! This can be overridden during OSD_ThreadPool construction or by calling OSD_ThreadPool::Init()
//! (the pool should not be used!).
//! - OSD_ThreadPool::Launcher reserves specific amount of threads from the pool for executing multi-threaded Job.
//! Normally, single Launcher instance will occupy all threads available in thread pool,
//! so that nested multi-threaded algorithms (within the same thread)
//! and concurrent threads trying to use the same thread pool will run sequentially.
//! This behavior is affected by OSD_ThreadPool::NbDefaultThreadsToLaunch() parameter
//! and Launcher constructor, so that single Launcher instance will occupy not all threads
//! in the pool allowing other threads to be used concurrently.
//! - OSD_ThreadPool::Launcher locks thread one-by-one from thread pool in a thread-safe way.
//! - Each working thread catches exceptions occurred during job execution, and Launcher will
//! throw Standard_Failure in a caller thread on completed execution.
class OSD_ThreadPool : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(OSD_ThreadPool, Standard_Transient)
public:
//! Return (or create) a default thread pool.
//! Number of threads argument will be considered only when called first time.
Standard_EXPORT static const Handle(OSD_ThreadPool)& DefaultPool (int theNbThreads = -1);
public:
//! Main constructor.
//! Application may consider specifying more threads than actually
//! available (OSD_Parallel::NbLogicalProcessors()) and set up NbDefaultThreadsToLaunch() to a smaller value
//! so that concurrent threads will be able using single Thread Pool instance more efficiently.
//! @param theNbThreads threads number to be created by pool
//! (if -1 is specified then OSD_Parallel::NbLogicalProcessors() will be used)
Standard_EXPORT OSD_ThreadPool (int theNbThreads = -1);
//! Destructor.
Standard_EXPORT virtual ~OSD_ThreadPool();
//! Return TRUE if at least 2 threads are available (including self-thread).
bool HasThreads() const { return NbThreads() >= 2; }
//! Return the lower thread index.
int LowerThreadIndex() const { return 0; }
//! Return the upper thread index (last index is reserved for self-thread).
int UpperThreadIndex() const { return LowerThreadIndex() + myThreads.Size(); }
//! Return the number of threads; >= 1.
int NbThreads() const { return myThreads.Size() + 1; }
//! Return maximum number of threads to be locked by a single Launcher object by default;
//! the entire thread pool size is returned by default.
int NbDefaultThreadsToLaunch() const { return myNbDefThreads; }
//! Set maximum number of threads to be locked by a single Launcher object by default.
//! Should be set BEFORE first usage.
void SetNbDefaultThreadsToLaunch (int theNbThreads) { myNbDefThreads = theNbThreads; }
//! Checks if thread pools has active consumers.
Standard_EXPORT bool IsInUse();
//! Reinitialize the thread pool with a different number of threads.
//! Should be called only with no active jobs, or exception Standard_ProgramError will be thrown!
Standard_EXPORT void Init (int theNbThreads);
protected:
//! Thread function interface.
class JobInterface
{
public:
virtual void Perform (int theThreadIndex) = 0;
};
//! Thread with back reference to thread pool and thread index in it.
class EnumeratedThread : public OSD_Thread
{
friend class OSD_ThreadPool;
public:
EnumeratedThread (bool theIsSelfThread = false)
: myPool (NULL), myJob (NULL), myWakeEvent (false),
myIdleEvent (false), myThreadIndex (0), myUsageCounter(0),
myIsStarted (false), myToCatchFpe (false),
myIsSelfThread (theIsSelfThread) {}
//! Occupy this thread for thread pool launcher.
//! @return TRUE on success, or FALSE if thread has been already occupied
Standard_EXPORT bool Lock();
//! Release this thread for thread pool launcher; should be called only after successful OccupyThread().
Standard_EXPORT void Free();
//! Wake up the thread.
Standard_EXPORT void WakeUp (JobInterface* theJob, bool theToCatchFpe);
//! Wait the thread going into Idle state (finished jobs).
Standard_EXPORT void WaitIdle();
private:
//! Method is executed in the context of thread.
void performThread();
//! Method is executed in the context of thread.
static Standard_Address runThread (Standard_Address theTask);
private:
OSD_ThreadPool* myPool;
JobInterface* myJob;
Handle(Standard_Failure) myFailure;
Standard_Condition myWakeEvent;
Standard_Condition myIdleEvent;
int myThreadIndex;
volatile int myUsageCounter;
bool myIsStarted;
bool myToCatchFpe;
bool myIsSelfThread;
};
public:
//! Launcher object locking a subset of threads (or all threads)
//! in a thread pool to perform parallel execution of the job.
class Launcher
{
public:
//! Lock specified number of threads from the thread pool.
//! If thread pool is already locked by another user,
//! Launcher will lock as many threads as possible
//! (if none will be locked, then single threaded execution will be done).
//! @param thePool thread pool to lock the threads
//! @param theMaxThreads number of threads to lock;
//! -1 specifies that default number of threads
//! to be used OSD_ThreadPool::NbDefaultThreadsToLaunch()
Standard_EXPORT Launcher (OSD_ThreadPool& thePool, int theMaxThreads = -1);
//! Release threads.
~Launcher() { Release(); }
//! Return TRUE if at least 2 threads have been locked for parallel execution (including self-thread);
//! otherwise, the functor will be executed within the caller thread.
bool HasThreads() const { return myNbThreads >= 2; }
//! Return amount of locked threads; >= 1.
int NbThreads() const { return myNbThreads; }
//! Return the lower thread index.
int LowerThreadIndex() const { return 0; }
//! Return the upper thread index (last index is reserved for the self-thread).
int UpperThreadIndex() const { return LowerThreadIndex() + myNbThreads - 1; }
//! Simple primitive for parallelization of "for" loops, e.g.:
//! @code
//! for (int anIter = theBegin; anIter < theEnd; ++anIter) {}
//! @endcode
//! @param theBegin the first data index (inclusive)
//! @param theEnd the last data index (exclusive)
//! @param theFunctor functor providing an interface
//! "void operator(int theThreadIndex, int theDataIndex){}" performing task for specified index
template<typename Functor>
void Perform (int theBegin, int theEnd, const Functor& theFunctor)
{
JobRange aData (theBegin, theEnd);
Job<Functor> aJob (theFunctor, aData);
perform (aJob);
}
//! Release threads before Launcher destruction.
Standard_EXPORT void Release();
protected:
//! Execute job.
Standard_EXPORT void perform (JobInterface& theJob);
//! Initialize job and start threads.
Standard_EXPORT void run (JobInterface& theJob);
//! Wait threads execution.
Standard_EXPORT void wait();
private:
Launcher (const Launcher& theCopy);
Launcher& operator=(const Launcher& theCopy);
private:
NCollection_Array1<EnumeratedThread*> myThreads; //!< array of locked threads (including self-thread)
EnumeratedThread mySelfThread;
int myNbThreads; //!< amount of locked threads
};
protected:
//! Auxiliary class which ensures exclusive access to iterators of processed data pool.
class JobRange
{
public:
//! Constructor
JobRange (const int& theBegin, const int& theEnd) : myBegin(theBegin), myEnd (theEnd), myIt (theBegin) {}
//! Returns const link on the first element.
const int& Begin() const { return myBegin; }
//! Returns const link on the last element.
const int& End() const { return myEnd; }
//! Returns first non processed element or end.
//! Thread-safe method.
int It() const { return Standard_Atomic_Increment (reinterpret_cast<volatile int*>(&myIt)) - 1; }
private:
JobRange (const JobRange& theCopy);
JobRange& operator=(const JobRange& theCopy);
private:
const int& myBegin; //!< First element of range
const int& myEnd; //!< Last element of range
mutable int myIt; //!< First non processed element of range
};
//! Auxiliary wrapper class for thread function.
template<typename FunctorT> class Job : public JobInterface
{
public:
//! Constructor.
Job (const FunctorT& thePerformer, JobRange& theRange)
: myPerformer (thePerformer), myRange (theRange) {}
//! Method is executed in the context of thread.
virtual void Perform (int theThreadIndex) Standard_OVERRIDE
{
for (Standard_Integer anIter = myRange.It(); anIter < myRange.End(); anIter = myRange.It())
{
myPerformer (theThreadIndex, anIter);
}
}
private:
Job (const Job& theCopy);
Job& operator=(const Job& theCopy);
private: //! @name private fields
const FunctorT& myPerformer; //!< Link on functor
const JobRange& myRange; //!< Link on processed data block
};
//! Release threads.
void release();
//! Perform the job and catch exceptions.
static void performJob (Handle(Standard_Failure)& theFailure,
OSD_ThreadPool::JobInterface* theJob,
int theThreadIndex);
private:
NCollection_Array1<EnumeratedThread> myThreads; //!< array of defined threads (excluding self-thread)
int myNbDefThreads; //!< maximum number of threads to be locked by a single Launcher by default
bool myShutDown; //!< flag to shut down (destroy) the thread pool
};
#endif // _OSD_ThreadPool_HeaderFile

View File

@@ -17,6 +17,17 @@
#include <Standard_DivideByZero.hxx>
#include <Standard_Overflow.hxx>
static Standard_THREADLOCAL Standard_Boolean fFltExceptions = Standard_False;
//=======================================================================
//function : ToCatchFloatingSignals
//purpose :
//=======================================================================
Standard_Boolean OSD::ToCatchFloatingSignals()
{
return fFltExceptions;
}
#ifdef _WIN32
//---------------------------- Windows NT System --------------------------------
@@ -53,7 +64,7 @@
#include <Standard_ProgramError.hxx>
#include <Standard_Mutex.hxx>
#include <OSD_WNT_1.hxx>
#include <OSD_WNT.hxx>
#ifdef _MSC_VER
#include <eh.h>
@@ -65,10 +76,8 @@
#include <float.h>
static Standard_Boolean fCtrlBrk;
#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
static Standard_Boolean fMsgBox;
static Standard_Boolean fFltExceptions;
static Standard_Boolean fDbgLoaded;
// used to forbid simultaneous execution of setting / executing handlers
static Standard_Mutex THE_SIGNAL_MUTEX;
@@ -76,13 +85,20 @@ static Standard_Mutex THE_SIGNAL_MUTEX;
static LONG __fastcall _osd_raise ( DWORD, LPSTR );
static BOOL WINAPI _osd_ctrl_break_handler ( DWORD );
#ifndef OCCT_UWP
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
static Standard_Boolean fDbgLoaded;
static LONG _osd_debug ( void );
#endif
//# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
#ifdef OCC_CONVERT_SIGNALS
#define THROW_OR_JUMP(Type,Message) Type::NewInstance(Message)->Jump()
#else
#define THROW_OR_JUMP(Type,Message) throw Type(Message)
#endif
//=======================================================================
//function : CallHandler
//purpose :
@@ -148,7 +164,8 @@ static LONG CallHandler (DWORD dwExceptionCode,
break ;
case STATUS_NO_MEMORY:
// cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
throw OSD_Exception_STATUS_NO_MEMORY ( "MEMORY ALLOCATION ERROR ( no room in the process heap )" );
THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )");
break;
case EXCEPTION_ACCESS_VIOLATION:
// cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
StringCchPrintfW (buffer, _countof(buffer), L"%s%s%s0x%.8p%s%s%s", L"ACCESS VIOLATION",
@@ -227,7 +244,7 @@ static LONG CallHandler (DWORD dwExceptionCode,
_fpreset();
_clearfp();
#ifndef OCCT_UWP
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
MessageBeep ( MB_ICONHAND );
int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
if (aChoice == IDRETRY)
@@ -287,7 +304,7 @@ static void SIGWntHandler (int signum, int sub_code)
break ;
default:
cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << endl;
throw Standard_NumericError("Floating Point Error");
THROW_OR_JUMP (Standard_NumericError, "Floating Point Error");
break ;
}
break ;
@@ -309,7 +326,6 @@ static void SIGWntHandler (int signum, int sub_code)
DebugBreak ();
#endif
}
#endif
//=======================================================================
//function : TranslateSE
@@ -342,7 +358,6 @@ static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
// option and unless user sets his own exception handler with
// ::SetUnhandledExceptionFilter().
//=======================================================================
#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
{
DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
@@ -351,7 +366,6 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
lpXP->ExceptionRecord->ExceptionInformation[1],
lpXP->ExceptionRecord->ExceptionInformation[0]);
}
#endif
//=======================================================================
//function : SetSignal
@@ -359,11 +373,8 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
//=======================================================================
void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
{
#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
#if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
OSD_Environment env ("CSF_DEBUG_MODE");
TCollection_AsciiString val = env.Value();
if (!env.Failed())
@@ -380,7 +391,7 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
// when user's code is compiled with /EHs
// Replaces the existing top-level exception filter for all existing and all future threads
// in the calling process
aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
#endif // NTDDI_WIN10_TH2
// Signal handlers will only be used when the method ::raise() will be used
@@ -410,7 +421,6 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
else {
_controlfp (_OSD_FPX, _OSD_FPX); // JR add :
}
#endif
} // end OSD :: SetSignal
//============================================================================
@@ -422,7 +432,7 @@ void OSD::ControlBreak () {
throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
}
} // end OSD :: ControlBreak
#if !defined(__MINGW32__) && !defined(__CYGWIN32__)
#ifndef OCCT_UWP
//============================================================================
//==== _osd_ctrl_break_handler
@@ -437,6 +447,7 @@ static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
return TRUE;
} // end _osd_ctrl_break_handler
#endif
//============================================================================
//==== _osd_raise
//============================================================================
@@ -447,54 +458,54 @@ static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
switch (dwCode)
{
case EXCEPTION_ACCESS_VIOLATION:
throw OSD_Exception_ACCESS_VIOLATION(msg);
THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, msg);
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
throw OSD_Exception_ARRAY_BOUNDS_EXCEEDED(msg);
THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, msg);
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
throw Standard_ProgramError(msg);
THROW_OR_JUMP (Standard_ProgramError, msg);
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
throw OSD_Exception_ILLEGAL_INSTRUCTION(msg);
THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, msg);
break;
case EXCEPTION_IN_PAGE_ERROR:
throw OSD_Exception_IN_PAGE_ERROR(msg);
THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, msg);
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
throw Standard_DivideByZero(msg);
THROW_OR_JUMP (Standard_DivideByZero, msg);
break;
case EXCEPTION_INT_OVERFLOW:
throw OSD_Exception_INT_OVERFLOW(msg);
THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, msg);
break;
case EXCEPTION_INVALID_DISPOSITION:
throw OSD_Exception_INVALID_DISPOSITION(msg);
THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, msg);
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
throw OSD_Exception_NONCONTINUABLE_EXCEPTION(msg);
THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, msg);
break;
case EXCEPTION_PRIV_INSTRUCTION:
throw OSD_Exception_PRIV_INSTRUCTION(msg);
THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, msg);
break;
case EXCEPTION_STACK_OVERFLOW:
throw OSD_Exception_STACK_OVERFLOW(msg);
THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, msg);
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
throw Standard_DivideByZero(msg);
THROW_OR_JUMP (Standard_DivideByZero, msg);
break;
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_OVERFLOW:
throw Standard_Overflow(msg);
THROW_OR_JUMP (Standard_Overflow, msg);
break;
case EXCEPTION_FLT_UNDERFLOW:
throw Standard_Underflow(msg);
THROW_OR_JUMP (Standard_Underflow, msg);
break;
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_INEXACT_RESULT:
case STATUS_FLOAT_MULTIPLE_TRAPS:
case STATUS_FLOAT_MULTIPLE_FAULTS:
throw Standard_NumericError(msg);
THROW_OR_JUMP (Standard_NumericError, msg);
break;
default:
break;
@@ -502,10 +513,10 @@ static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
return EXCEPTION_EXECUTE_HANDLER;
} // end _osd_raise
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
//============================================================================
//==== _osd_debug
//============================================================================
#ifndef OCCT_UWP
LONG _osd_debug ( void ) {
LONG action ;
@@ -588,10 +599,9 @@ LONG _osd_debug ( void ) {
return action ;
} // end _osd_debug
#endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
#endif
#endif
#else
#else /* ! _WIN32 */
//---------- All Systems except Windows NT : ----------------------------------
@@ -616,7 +626,6 @@ LONG _osd_debug ( void ) {
#ifdef __linux__
#include <cfenv>
//#include <fenv.h>
static Standard_Boolean fFltExceptions = Standard_False;
#endif
// variable signalling that Control-C has been pressed (SIGINT signal)
@@ -635,7 +644,7 @@ typedef void (* SIG_PFV) (int);
# include <stdlib.h>
# include <stdio.h>
#else
# ifdef SA_SIGINFO
# ifdef SA_SIGINFO
# ifndef _AIX
# include <sys/siginfo.h>
# endif
@@ -866,11 +875,11 @@ static void SegvHandler(const int theSignal,
#endif
//============================================================================
//==== SetSignal
//==== SetSignal
//==== Set the differents signals:
//============================================================================
void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
{
struct sigaction act, oact;
int stat = 0;
@@ -932,7 +941,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
#endif
//==== Always detected the signal "SIGFPE" =================================
stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
if (stat) {
#ifdef OCCT_DEBUG
cerr << "sigaction does not work !!! KO " << endl;
@@ -941,38 +950,38 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
}
//==== Detected the only the "free" signals ================================
sigaction(SIGHUP,&act,&oact); // ...... hangup
sigaction(SIGHUP,&act,&oact); // ...... hangup
#ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGHUP,&oact,&oact);
#endif
sigaction(SIGINT,&act,&oact); // ...... interrupt
sigaction(SIGINT,&act,&oact); // ...... interrupt
#ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGINT,&oact,&oact);
#endif
sigaction(SIGQUIT,&act,&oact); // ...... quit
#ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGQUIT,&oact,&oact);
#endif
sigaction(SIGILL,&act,&oact); // ...... illegal instruction
sigaction(SIGILL,&act,&oact); // ...... illegal instruction
#ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGILL,&oact,&oact);
#endif
sigaction(SIGBUS,&act,&oact); // ...... bus error
sigaction(SIGBUS,&act,&oact); // ...... bus error
#ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGBUS,&oact,&oact);
#endif
@@ -980,7 +989,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
sigaction(SIGSYS,&act,&oact); // ...... bad argument to system call
# ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGSYS,&oact,&oact);
# endif
#endif
@@ -989,7 +998,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
sigaction(SIGTRAP,&act,&oact); // Integer Divide By Zero (IRIX)
# ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGTRAP,&oact,&oact);
# endif
#endif
@@ -1004,7 +1013,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
#ifdef OBJS
if(oact.sa_handler)
if(oact.sa_handler)
sigaction(SIGSEGV,&oact,&oact);
#endif
#if defined(__osf__) || defined(DECOSF1)
@@ -1012,7 +1021,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
action.sa_handler = SIG_IGN;
action.sa_mask = 0;
action.sa_flags = 0;
if (sigaction (SIGFPE, &action, &prev_action) == -1) {
perror ("sigaction");
exit (1);
@@ -1022,14 +1031,14 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
}
//============================================================================
//==== ControlBreak
//==== ControlBreak
//============================================================================
void OSD :: ControlBreak ()
void OSD :: ControlBreak ()
{
if ( fCtrlBrk ) {
fCtrlBrk = Standard_False;
throw OSD_Exception_CTRL_BREAK("*** INTERRUPT ***");
throw OSD_Exception_CTRL_BREAK ("*** INTERRUPT ***");
}
}

View File

@@ -0,0 +1,471 @@
// Created on: 2007-04-15
// Created by: Alexey MORENOV & Alexander GRIGORIEV
// Copyright (c) 2007-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 <OpenGl_AVIWriter.hxx>
#if (defined(_WIN32) || defined(__WIN32__)) && defined(HAVE_VIDEOCAPTURE)
#ifdef _MSC_VER
#pragma comment (lib, "vfw32.lib")
#endif
OpenGl_AVIWriter* OpenGl_AVIWriter::MyAVIWriterInstance = 0L;
OpenGl_AVIWriter * OpenGl_AVIWriter::GetInstance()
{
return MyAVIWriterInstance;
}
//=======================================================================
//function : OpenGl_AVIWriter
//purpose :
//=======================================================================
Standard_EXPORT OpenGl_AVIWriter::OpenGl_AVIWriter
(const wchar_t * theFileName,
DWORD dwCodec /* = mmioFOURCC('M','P','G','4') */,
Standard_Integer theFrameRate /* = 25 */)
: myhHeap (0L),
myhWindow (0L),
myhAviDC (0L),
mylpBits (0L),
mylSample (0L),
mypAviFile (0L),
mypAviStream (0L),
mypAviCompressedStream(0L),
myFileName (0L),
myIsAllowRecord (Standard_False),
myAppendFuncSelector(1) //0=Dummy 1=FirstTime 2=Usual
{
::AVIFileInit();
if (theFileName != 0L && theFileName[0] != L'\0') {
const size_t aLen = wcslen(theFileName) + 1;
myFileName = new wchar_t [aLen];
memcpy(myFileName, theFileName, aLen * sizeof(wchar_t));
myErrMsg = "Method Succeeded";
pAppendFrame[0]= &OpenGl_AVIWriter::AppendDummy;
pAppendFrame[1]= &OpenGl_AVIWriter::AppendFrameFirstTime;
pAppendFrame[2]= &OpenGl_AVIWriter::AppendFrameUsual;
pAppendFrameBits[0]=&OpenGl_AVIWriter::AppendDummyBits;
pAppendFrameBits[1]=&OpenGl_AVIWriter::AppendFrameBitsFirstTime;
pAppendFrameBits[2]=&OpenGl_AVIWriter::AppendFrameBitsUsual;
MyAVIWriterInstance = this;
ZeroMemory(&myAviStreamInfo,sizeof(AVISTREAMINFOW));
myAviStreamInfo.fccType = streamtypeVIDEO;
myAviStreamInfo.fccHandler = dwCodec;
myAviStreamInfo.dwScale = 1;
myAviStreamInfo.dwRate = theFrameRate; // Frames Per Second;
myAviStreamInfo.dwQuality = 100;/*//-1; // Default Quality*/
ZeroMemory(&myAviCompressOptions,sizeof(AVICOMPRESSOPTIONS));
myAviCompressOptions.fccType = streamtypeVIDEO;
myAviCompressOptions.fccHandler = myAviStreamInfo.fccHandler;
myAviCompressOptions.dwFlags =
AVICOMPRESSF_KEYFRAMES|AVICOMPRESSF_VALID|AVICOMPRESSF_DATARATE;
myAviCompressOptions.dwKeyFrameEvery = 1;
myAviCompressOptions.dwBytesPerSecond = 125000;
myAviCompressOptions.dwQuality = 100;
}
}
//=======================================================================
//function : ~OpenGl_AVIWriter
//purpose :
//=======================================================================
Standard_EXPORT OpenGl_AVIWriter::~OpenGl_AVIWriter(void)
{
ReleaseMemory();
AVIFileExit();
if (myFileName)
delete [] myFileName;
MyAVIWriterInstance = 0L;
}
//=======================================================================
//function : StartRecording
//purpose :
//=======================================================================
void OpenGl_AVIWriter::StartRecording(const HANDLE hWin)
{
if (hWin != NULL)
myhWindow = hWin;
myIsAllowRecord = Standard_True;
}
//=======================================================================
//function : StopRecording
//purpose :
//=======================================================================
void OpenGl_AVIWriter::StopRecording()
{
myIsAllowRecord = Standard_False;
}
//=======================================================================
//function : ReleaseMemory
//purpose :
//=======================================================================
void OpenGl_AVIWriter::ReleaseMemory()
{
myAppendFuncSelector=0; //Point to DummyFunction
if (myhAviDC)
{
DeleteDC(myhAviDC);
myhAviDC=NULL;
}
if (mypAviCompressedStream)
{
AVIStreamRelease(mypAviCompressedStream);
mypAviCompressedStream=NULL;
}
if (mypAviStream)
{
AVIStreamRelease(mypAviStream);
mypAviStream=NULL;
}
if (mypAviFile)
{
AVIFileRelease(mypAviFile);
mypAviFile=NULL;
}
if (mylpBits)
{
HeapFree(myhHeap,HEAP_NO_SERIALIZE,mylpBits);
mylpBits=NULL;
}
if (myhHeap)
{
HeapDestroy(myhHeap);
myhHeap=NULL;
}
}
//=======================================================================
//function : SetErrorMessage
//purpose :
//=======================================================================
void OpenGl_AVIWriter::SetErrorMessage(const char * theErrorMessage)
{
myErrMsg = theErrorMessage;
}
//=======================================================================
//function : InitMovieCreation
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::InitMovieCreation (int nFrameWidth,
int nFrameHeight,
int nBitsPerPixel)
{
int nMaxWidth=GetSystemMetrics(SM_CXSCREEN),
nMaxHeight=GetSystemMetrics(SM_CYSCREEN);
myhAviDC = CreateCompatibleDC(NULL);
if (myhAviDC == NULL)
{
SetErrorMessage("Unable to Create Compatible DC");
return E_FAIL;
}
if (nFrameWidth > nMaxWidth)
nMaxWidth= nFrameWidth;
if (nFrameHeight > nMaxHeight)
nMaxHeight = nFrameHeight;
myhHeap = HeapCreate(HEAP_NO_SERIALIZE, nMaxWidth*nMaxHeight*4, 0);
if (myhHeap == NULL)
{
SetErrorMessage("Unable to Create Heap");
return E_FAIL;
}
mylpBits = HeapAlloc(myhHeap, HEAP_ZERO_MEMORY|HEAP_NO_SERIALIZE,
nMaxWidth*nMaxHeight*4);
if (mylpBits == NULL)
{
SetErrorMessage("Unable to Allocate Memory on Heap");
return E_FAIL;
}
HRESULT hr;
hr = ::AVIFileOpenW(&mypAviFile, myFileName, OF_CREATE|OF_WRITE, NULL);
if (!hr == AVIERR_OK)
{
SetErrorMessage("Unable to Create the Movie File");
return E_FAIL;
}
myAviStreamInfo.dwSuggestedBufferSize = nMaxWidth * nMaxHeight * 4;
SetRect(&myAviStreamInfo.rcFrame, 0, 0, nFrameWidth, nFrameHeight);
wcsncpy(myAviStreamInfo.szName, L"Video Stream", 64);
if (FAILED(AVIFileCreateStreamW(mypAviFile, &mypAviStream, &myAviStreamInfo)))
{
SetErrorMessage("Unable to Create Video Stream in the Movie File");
return E_FAIL;
}
if (FAILED(AVIMakeCompressedStream(&mypAviCompressedStream,
mypAviStream,
&myAviCompressOptions,
NULL)))
{
// One reason this error might occur is if you are using a Codec that is not
// available on your system. Check the mmioFOURCC() code you are using and
// make sure you have that codec installed properly on your machine.
SetErrorMessage("Unable to Create Compressed Stream: "
"Check your CODEC options");
return E_FAIL;
}
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biWidth = nFrameWidth;
bmpInfo.bmiHeader.biHeight = nFrameHeight;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biBitCount = static_cast<WORD>(nBitsPerPixel);
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biSizeImage = (bmpInfo.bmiHeader.biWidth *
bmpInfo.bmiHeader.biHeight*
bmpInfo.bmiHeader.biBitCount)/8;
if (FAILED(AVIStreamSetFormat(mypAviCompressedStream,
0,
(LPVOID)&bmpInfo,
bmpInfo.bmiHeader.biSize)))
{
// One reason this error might occur is if your bitmap does not meet
// the Codec requirements.
// For example,
// your bitmap is 32bpp while the Codec supports only 16 or 24 bpp; Or
// your bitmap is 274 * 258 size, while the Codec supports only sizes
// that are powers of 2; etc...
// Possible solution to avoid this is: make your bitmap suit the codec
// requirements, or Choose a codec that is suitable for your bitmap.
SetErrorMessage("Unable to Set Video Stream Format");
return E_FAIL;
}
return S_OK; // Everything went Fine
}
//=======================================================================
//function : AppendFrameFirstTime
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendFrameFirstTime(HBITMAP hBitmap)
{
BITMAP Bitmap;
GetObject(hBitmap, sizeof(BITMAP), &Bitmap);
if (SUCCEEDED(InitMovieCreation(Bitmap.bmWidth,
Bitmap.bmHeight,
Bitmap.bmBitsPixel)))
{
myAppendFuncSelector = 2; //Point to the UsualAppend Function
return AppendFrameUsual(hBitmap);
}
ReleaseMemory();
return E_FAIL;
}
//=======================================================================
//function : AppendFrameUsual
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendFrameUsual(HBITMAP hBitmap)
{
BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biBitCount=0;
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
GetDIBits(myhAviDC,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
bmpInfo.bmiHeader.biCompression=BI_RGB;
GetDIBits(myhAviDC,
hBitmap,
0,
bmpInfo.bmiHeader.biHeight,
mylpBits,
&bmpInfo,
DIB_RGB_COLORS);
if (FAILED(AVIStreamWrite(mypAviCompressedStream,
mylSample++,
1,
mylpBits,
bmpInfo.bmiHeader.biSizeImage,
0,
NULL,
NULL)))
{
SetErrorMessage("Unable to Write Video Stream to the output Movie File");
ReleaseMemory();
return E_FAIL;
}
return S_OK;
}
//=======================================================================
//function : AppendDummy
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendDummy(HBITMAP)
{
return E_FAIL;
}
//=======================================================================
//function : AppendNewFrame
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendNewFrame(HBITMAP hBitmap)
{
return (this->*pAppendFrame[myAppendFuncSelector])((HBITMAP)hBitmap);
}
//=======================================================================
//function : AppendNewFrame
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendNewFrame(int nWidth,
int nHeight,
LPVOID pBits,
int nBitsPerPixel)
{
return (this->*pAppendFrameBits[myAppendFuncSelector])(nWidth,
nHeight,
pBits,
nBitsPerPixel);
}
//=======================================================================
//function : AppendFrameFirstTime
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendFrameBitsFirstTime(int nWidth,
int nHeight,
LPVOID pBits,
int nBitsPerPixel)
{
if (SUCCEEDED(InitMovieCreation(nWidth, nHeight, nBitsPerPixel)))
{
myAppendFuncSelector=2; //Point to the UsualAppend Function
return AppendFrameBitsUsual(nWidth, nHeight, pBits, nBitsPerPixel);
}
ReleaseMemory();
return E_FAIL;
}
//=======================================================================
//function : AppendFrameUsual
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendFrameBitsUsual(int nWidth,
int nHeight,
LPVOID pBits,
int nBitsPerPixel)
{
DWORD dwSize=nWidth*nHeight*nBitsPerPixel/8;
if (FAILED(AVIStreamWrite(mypAviCompressedStream,
mylSample++,
1,
pBits,
dwSize,
0,
NULL,
NULL)))
{
SetErrorMessage("Unable to Write Video Stream to the output Movie File");
ReleaseMemory();
return E_FAIL;
}
return S_OK;
}
//=======================================================================
//function : AppendDummy
//purpose :
//=======================================================================
HRESULT OpenGl_AVIWriter::AppendDummyBits(int /*nWidth*/,
int /*nHeight*/,
LPVOID /*pBits*/,
int /*nBitsPerPixel*/)
{
return E_FAIL;
}
//=======================================================================
//function : AviWriter
//purpose :
//=======================================================================
void OpenGl_AVIWriter_AVIWriter(void * pp,
int nWidth,
int nHeight,
int nBitsPerPixel)
{
OpenGl_AVIWriter * anInst = OpenGl_AVIWriter::GetInstance();
if (anInst != 0L)
if (anInst->IsRecording())
{
anInst->AppendNewFrame(nWidth, nHeight, pp, nBitsPerPixel);
}
}
//=======================================================================
//function : AllowWriting
//purpose :
//=======================================================================
Standard_Boolean OpenGl_AVIWriter_AllowWriting(void * hWin)
{
Standard_Boolean aResult(Standard_False);
const OpenGl_AVIWriter * anInst = OpenGl_AVIWriter::GetInstance();
if (anInst != 0L) {
if (hWin == NULL || anInst->HWindow() == hWin)
aResult = static_cast<Standard_Boolean> (anInst->IsRecording());
}
return aResult;
}
#endif

View File

@@ -0,0 +1,191 @@
// Created on: 2007-04-15
// Created by: Alexey MORENOV & Alexander GRIGORIEV
// Copyright (c) 2007-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.
#ifndef __OPENGL_AVIWRITER_H
#define __OPENGL_AVIWRITER_H
#if defined(_WIN32)
#include <windows.h>
#endif
#include <Standard_Macro.hxx>
#if defined(_MSC_VER) && !defined(OCCT_UWP)
#include <stdlib.h>
#include <vfw.h>
#include <TCollection_AsciiString.hxx>
/**
* Class providing the API to record AVI files using a codec installed in the
* system -- Only on Windows NT/2k/XP/Vista platform under MS Visual Studio.
* The following tasks are supported:
* <ol>
*
* <li>Creation of AVI data stream: launched by the constructor.
* The constructor accepts the filename, FOURCC video code and the frame rate
* setting as parameters.
* The default codec name used here is MPG4. To use a different codec, pass
* its FOURCC value as the input parameter for dwCodec.
* For example,
* <ul>
* <li>pass mmioFOURCC('D','I','V','X') to use DIVX codec, or</li>
* <li>pass mmioFOURCC('I','V','5','0') to use IV50 codec etc...</li>
* </ul>
* Also, you can pass just 0 to avoid the codecs altogether. In that case,
* the frames would be saved as they are without any compression; However,
* the output movie file size would be very huge in that case.
*
* Finally, make sure you have the codec installed on the machine before
* passing its Fourcc here.
* </li>
* <li>
* Start the recording: call the method StartRecording(). This method should be
* called at least once; execution of the constructor does not begin the
* process.
* </li>
* <li>
* Stop the recording: call the method StopRecording(). Can be omitted if the
* next to execute would be the destructor.
* </li>
* <li>
* Close the AVI file and exit the process of recording. This is done
* automatically by the destructor.
* </li>
* </ol>
*/
class OpenGl_AVIWriter
{
public:
/**
* Constructor. Initializes the internal data structures, prepares for the
* creation of an AVI stream when the first frame is ready to be captured.
* @param theFileName
* Name of the output movie file to create.
* @param theCodec
* FourCC of the Video Codec to be used for compression
* @param theFrameRate
* The Frames Per Second (FPS) setting to be used for the movie
*/
Standard_EXPORT OpenGl_AVIWriter(const wchar_t * theFileName,
DWORD theCodec = mmioFOURCC('M','P','G','4'),
Standard_Integer theFrameRate = 25);
/**
* Destructor: closes the movie file and flushes all the frames
*/
Standard_EXPORT ~OpenGl_AVIWriter ();
/**
* Begin the recording.
*/
Standard_EXPORT void StartRecording(const HANDLE hWin = NULL);
/**
* Stop the recording (can be restarted using StartRecording()).
*/
Standard_EXPORT void StopRecording ();
/**
* Query the state of recording.
*/
Standard_Boolean IsRecording () const { return myIsAllowRecord; }
/**
* Returns the last error message, if any.
*/
const TCollection_AsciiString& GetLastErrorMessage() const
{ return myErrMsg; }
/**
* Get the instance of AVI Writer class.
*/
static Standard_EXPORT OpenGl_AVIWriter * GetInstance ();
/**
* Get the Window handle that contains the actual OpenGl context.
*/
HANDLE HWindow () const
{ return myhWindow; }
/// Inserts the given HBitmap into the movie as a new Frame at the end.
HRESULT AppendNewFrame(HBITMAP hBitmap);
/// Inserts the given bitmap bits into the movie as a new Frame at the end.
/// The width, height and nBitsPerPixel are the width, height and bits per pixel
/// of the bitmap pointed to by the input pBits.
HRESULT AppendNewFrame(int nWidth,
int nHeight,
LPVOID pBits,
int nBitsPerPixel);
private:
void call_avi();
private:
static OpenGl_AVIWriter * MyAVIWriterInstance;
Standard_Boolean myIsAllowRecord;
BYTE * mypBits;
UINT myWidth;
UINT myHeight;
HDC myhAviDC;
HANDLE myhHeap;
HANDLE myhWindow; // window containing the OGL context
LPVOID mylpBits; // Useful to hold the bitmap content if any
LONG mylSample; // Keeps track of the current Frame Index
PAVIFILE mypAviFile;
PAVISTREAM mypAviStream;
PAVISTREAM mypAviCompressedStream;
AVISTREAMINFOW myAviStreamInfo;
AVICOMPRESSOPTIONS myAviCompressOptions;
wchar_t * myFileName; // Holds the Output Movie File Name
TCollection_AsciiString myErrMsg; // Holds the Last Error Message, if any
int myAppendFuncSelector; //0=Dummy 1=FirstTime 2=Usual
HRESULT AppendFrameFirstTime(HBITMAP );
HRESULT AppendFrameUsual(HBITMAP);
HRESULT AppendDummy(HBITMAP);
HRESULT (OpenGl_AVIWriter::*pAppendFrame[3])(HBITMAP hBitmap);
HRESULT AppendFrameBitsFirstTime(int, int, LPVOID,int );
HRESULT AppendFrameBitsUsual(int, int, LPVOID,int );
HRESULT AppendDummyBits(int, int, LPVOID,int );
HRESULT (OpenGl_AVIWriter::*pAppendFrameBits[3])(int, int, LPVOID, int);
/// Takes care of creating the memory, streams, compression options etc.
/// required for the movie
HRESULT InitMovieCreation(int nFrameWidth,int nFrameHeight,int nBitsPerPixel);
/// Takes care of releasing the memory and movie related handles
void ReleaseMemory();
/// Sets the Error Message
void SetErrorMessage(const char * theErrMsg);
};
Standard_EXPORT void OpenGl_AVIWriter_AVIWriter(void * pp,
int nWidth,
int nHeight,
int nBitsPerPixel);
Standard_EXPORT Standard_Boolean OpenGl_AVIWriter_AllowWriting(void * hWin);
#endif // _MSC_VER
#endif

View File

@@ -39,6 +39,10 @@
#include <OpenGl_Structure.hxx>
#include <OpenGl_ArbFBO.hxx>
#if defined(_WIN32) && defined(HAVE_VIDEOCAPTURE)
#include <OpenGl_AVIWriter.hxx>
#endif
namespace
{
//! Format Frame Buffer format for logging messages.
@@ -523,6 +527,24 @@ void OpenGl_View::Redraw()
}
}
#if defined(_WIN32) && defined(HAVE_VIDEOCAPTURE)
if (OpenGl_AVIWriter_AllowWriting(myWindow->PlatformWindow()->NativeHandle()))
{
GLint params[4];
glGetIntegerv(GL_VIEWPORT, params);
int nWidth = params[2] & ~0x7;
int nHeight = params[3] & ~0x7;
const int nBitsPerPixel = 24;
GLubyte* aDumpData = new GLubyte[nWidth * nHeight * nBitsPerPixel / 8];
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, nWidth, nHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, aDumpData);
OpenGl_AVIWriter_AVIWriter(aDumpData, nWidth, nHeight, nBitsPerPixel);
delete[] aDumpData;
}
#endif
if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
&& myRenderParams.IsGlobalIlluminationEnabled)
{

546
src/Poly/Poly_IBuffer.cxx Normal file
View File

@@ -0,0 +1,546 @@
// File: Poly_IBuffer.cxx
// Created: 15.06.07 08:32
// Author: Alexander GRIGORIEV
// Copyright: Open CASCADE 2007
#include <Poly_IBuffer.hxx>
#include <Precision.hxx>
#include <NCollection_IncAllocator.hxx>
#include <Standard_ProgramError.hxx>
#pragma warning(disable:4291)
IMPLEMENT_STANDARD_RTTIEXT(Poly_IBuffer, Standard_Transient)
static const Standard_Size INDEXLEN = 10;
#ifdef _DEBUG
int Poly_IBuffer::GlobalCount = 0;
#endif
//=======================================================================
//function : GetZ
//purpose : local function
//=======================================================================
inline Standard_Real GetZ (const Poly_IBuffer::Interval& theInt,
const Standard_Real theX)
{
return (theInt.XZ(0).Y() + (theInt.XZ(1).Y() - theInt.XZ(0).Y()) *
(theX - theInt.XZ(0).X()) / (theInt.XZ(1).X() - theInt.XZ(0).X()));
}
//=======================================================================
//function : Poly_IBuffer
//purpose : Constructor
//=======================================================================
Poly_IBuffer::Poly_IBuffer (const Poly_IBuffer::Interval& theInterval,
const Standard_Real theTol,
const Handle(NCollection_BaseAllocator)& theAlloc)
{
Init (theInterval, theTol, theAlloc);
#ifdef _DEBUG
myCount = GlobalCount++;
#endif
}
//=======================================================================
//function : Init
//purpose : Initialization, to be used after the default constructor.
//=======================================================================
void Poly_IBuffer::Init (const Interval& theInterval,
const Standard_Real theTol,
const Handle(NCollection_BaseAllocator)& theAlloc)
{
clearIntervals();
myTol = theTol;
if (theAlloc.IsNull())
myAllocator = new NCollection_IncAllocator(1000);
else
myAllocator = theAlloc;
myMinOrd = Precision::Infinite();
myMaxOrd = -Precision::Infinite();
myNIntervals = 1;
// Create the first interval covering all possible X coordinates
Interval * pInt = &theInterval.Clone(myAllocator);
// Create the index array
myIndex = static_cast <PInterval *>
(myAllocator->Allocate((INDEXLEN+1) * sizeof(PInterval)));
const Standard_Real anXmin = theInterval.XZ(0).X();
const Standard_Real aXstep = (theInterval.XZ(1).X() - anXmin) / INDEXLEN;
for (Standard_Size i = 0; i <= INDEXLEN; i++) {
myIndex[i].X = Standard_Real (anXmin + i*aXstep);
myIndex[i].Int = pInt;
}
}
//=======================================================================
//function : ~Poly_IBuffer
//purpose : Destructor
//=======================================================================
Poly_IBuffer::~Poly_IBuffer ()
{
clearIntervals();
}
//=======================================================================
//function : Clone
//purpose : Create a copy of the given Interval in the given allocator.
//=======================================================================
Poly_IBuffer::Interval& Poly_IBuffer::Interval::Clone
(const Handle(NCollection_BaseAllocator)& theAlloc,
Poly_IBuffer::Interval * theDest) const
{
if (theDest == 0L)
theDest = new (theAlloc) Interval(myXZ[0], myXZ[1], 0UL);
else {
theDest->myXZ[0] = myXZ[0];
theDest->myXZ[1] = myXZ[1];
theDest->myNext = 0L;
theDest->myModID = 0UL;
theDest->U.myModX = RealLast();
}
return * theDest;
}
//=======================================================================
//function : NewRejectID
//purpose : Generator of unique Reject ID values.
//=======================================================================
unsigned long Poly_IBuffer::Interval::NewRejectID ()
{
static unsigned long aValue(0UL);
aValue += 4;
return aValue;
}
//=======================================================================
//function : IsIntersect
//purpose : Check for intersection, returns the intersection point abscissa.
// @return
// True if a modification or removal is required. The decision is based
// on 2 lower bits of myRejectID value:
// - 0 : remove this interval;
// - 1 : keep the lower abscisse part, remove the upper part;
// - 2 : keep the upper abscisse part, remove the lower part;
// - 3 : remove the middle.
//=======================================================================
Standard_Boolean Poly_IBuffer::Interval::IsIntersect
(const Poly_IBuffer::Interval& theInt,
const Standard_Real theTol,
const unsigned long theRejectID)
{
Standard_Boolean aRes(Standard_False);
Standard_Integer aResult (-1);
Standard_Real anAbscisse (Precision::Infinite());
const Standard_Real anXtol[2] = {
myXZ[0].X() + theTol,
myXZ[1].X() - theTol
};
if (theInt.myXZ[0].X() < anXtol[1] && theInt.myXZ[1].X() > anXtol[0]) {
const gp_XY aVec[3] = {
gp_XY(theInt.myXZ[0] - myXZ[0]),
gp_XY(myXZ[1] - myXZ[0]),
gp_XY(theInt.myXZ[1] - theInt.myXZ[0])
};
const Standard_Real aDirProd = aVec[1] ^ aVec[2];
if (aDirProd > Precision::Intersection()) {
// Intersection coefficients
const Standard_Real fInter[2] = {
(aVec[0] ^ aVec[2]) / aDirProd,
(aVec[0] ^ aVec[1]) / aDirProd
};
anAbscisse = (myXZ[1].X() * fInter[0] + myXZ[0].X() * (1.-fInter[0]));
if (anAbscisse > anXtol[0] && fInter[1] > 0.)
if (anAbscisse < anXtol[1] && fInter[1] < 1.) {
if (theInt.myXZ[0].X() < anXtol[0])
aResult = 2; // keep upper abscissa
else {
anAbscisse = theInt.myXZ[0].X();
aResult = 3;
}
} else {
if (theInt.myXZ[0].X() > anXtol[0]) {
anAbscisse = theInt.myXZ[0].X();
if (theInt.myXZ[1].X() > anXtol[1])
aResult = 1; // keep lower abscissa
else
aResult = 3;
} else
if (theInt.myXZ[1].X() > anXtol[1])
aResult = 0; // remove
else {
anAbscisse = theInt.myXZ[1].X();
aResult = 2; // keep upper abscissa
}
}
} else {
Standard_Real fInter[2] = { 2., -1. };
if (aDirProd < -Precision::Intersection()) {
// Intersection coefficients
fInter[0] = (aVec[0] ^ aVec[2]) / aDirProd;
fInter[1] = (aVec[0] ^ aVec[1]) / aDirProd;
anAbscisse = (myXZ[1].X() * fInter[0] + myXZ[0].X() * (1.-fInter[0]));
} else if (GetZ (theInt, myXZ[0].X()) < myXZ[0].Y())
anAbscisse = theInt.myXZ[0].X();
if (anAbscisse < anXtol[1] &&
fInter[1] < 1.-Precision::Intersection())
if (anAbscisse > anXtol[0] &&
fInter[1] > Precision::Intersection())
{
if (theInt.myXZ[1].X() > anXtol[1])
aResult = 1; // keep lower abscissa
else
aResult = 3;
} else {
if (theInt.myXZ[0].X() > anXtol[0]) {
anAbscisse = theInt.myXZ[0].X();
if (theInt.myXZ[1].X() > anXtol[1])
aResult = 1; // keep lower abscissa
else
aResult = 3;
} else
if (theInt.myXZ[1].X() > anXtol[1]) {
aResult = 0; // remove
aRes = Standard_True;
} else {
anAbscisse = theInt.myXZ[1].X();
aResult = 2; //keep upper abscissa
}
}
}
}
if (aResult >= 0) {
myModID = theRejectID + aResult;
U.myModX = anAbscisse;
aRes = Standard_True;
}
return aRes;
}
//=======================================================================
//function : Trim
//purpose : Shorten the interval to the new value of Xmax.
//=======================================================================
void Poly_IBuffer::Interval::Trim (const Standard_Real theX,
const Standard_Integer theMode)
{
const Standard_Real aZ = GetZ(* this, theX);
switch (theMode) {
case 3:
myModID = 0UL;
case 1:
Standard_ProgramError_Raise_if
(theX - myXZ[0].X() < Precision::Confusion() || theX > myXZ[1].X(),
"Trim error");
myXZ[1].SetCoord(theX, aZ);
break;
case 2:
Standard_ProgramError_Raise_if
(theX < myXZ[0].X() || myXZ[1].X() - theX < Precision::Confusion(),
"Trim error");
myXZ[0].SetCoord(theX, aZ);
break;
}
}
//=======================================================================
//function : AddInterval
//purpose : Add one interval to buffer.
//=======================================================================
Poly_IBuffer::Interval * Poly_IBuffer::AddInterval
(const Poly_IBuffer::Interval& theInterval,
Poly_IBuffer::Interval * theStart)
{
// Variables:
// aLastModified: Newly created interval in the buffer. It is returned by
// this method so that it can be passed as theStart
// for the next call (next interval).
// aInt: Currently checked/processed interval
// aBracket[0,1]: The first and the last in the chain of intervals where
// the modification can be done, used for local optimisation.
// pLastInt: The last non-modified interval. This pointer is used to set
// pLastInt->Next() to the newly created interval.
// isWaiting: True if there have been removed intervals, to be replaced by
// a new interval.
// aFirst.Int: Same as pLastInt. probably we can get rid of pLastInt
// aFirst.X: Beginning of the new interval
Interval * aLastModified = 0L, * aStart;
if (theStart == 0L)
aStart = const_cast <Interval *>(myIndex[0].Int);
else
aStart = theStart;
Interval * anInt = aStart;
Interval * aBracket[2] = { 0L, 0L };
unsigned long aRejectID = Interval::NewRejectID();
Interval * pLastInt = theStart;
// Identify the intervals that should be modified
for (; anInt; anInt = anInt->Next()) {
if (anInt->XZ(0).X() > theInterval.XZ(1).X() - myTol)
break;
if (anInt->IsIntersect (theInterval, myTol, aRejectID)) {
if (aBracket[0] == 0L)
aBracket[0] = anInt;
aBracket[1] = anInt->Next();
const long aModMode = anInt->GetModificationID() - aRejectID;
if (aModMode == 3L) {
Interval& aNewInt = anInt->Clone(myAllocator);
anInt->Trim (anInt->GetModificationAbscisse(), aModMode);
aNewInt.myXZ[0] = anInt->XZ(1);
aNewInt.myNext = anInt->Next();
anInt->myNext = &aNewInt;
myNIntervals++;
}
} else if (aBracket[0] == 0L)
pLastInt = anInt;
}
// Modify the intervals
Standard_Boolean isWaiting (Standard_False);
PInterval aFirst;
aFirst.Int = theStart;
aFirst.X = aStart->XZ(0).X();
for (anInt = aBracket[0]; anInt; anInt = anInt->Next()) {
const unsigned long aCurrentID = anInt->GetModificationID();
if ((aCurrentID & ~0x3) != aRejectID) {
if (isWaiting) {
const Standard_Real anX[2] = {
aFirst.X,
anInt->XZ(0).X()
};
aLastModified = addInt (theInterval, anX, aFirst.Int);
if (aStart == 0L)
aStart = aLastModified;
aLastModified->myNext = anInt;
aFirst.Int = anInt;
isWaiting = Standard_False;
}
if (anInt == aBracket[1])
break;
pLastInt = anInt;
} else {
const long aModMode = aCurrentID - aRejectID;
switch (aModMode) {
case 0:
if (aStart == anInt)
aStart = 0L;
if (isWaiting == Standard_False) {
aFirst.Int = pLastInt;
aFirst.X = anInt->XZ(0).X();
isWaiting = Standard_True;
}
myNHoles++;
break;
case 1:
aFirst.X = anInt->GetModificationAbscisse();
aFirst.Int = anInt;
anInt->Trim (aFirst.X, 1);
pLastInt = anInt;
isWaiting = Standard_True;
break;
case 2:
{
if (isWaiting)
isWaiting = Standard_False;
else {
aFirst.Int = pLastInt;
aFirst.X = anInt->XZ(0).X();
}
anInt->Trim (anInt->GetModificationAbscisse(), 2);
const Standard_Real anX[2] = {
aFirst.X,
anInt->GetModificationAbscisse()
};
aLastModified = addInt (theInterval, anX, aFirst.Int);
if (aStart == 0L)
aStart = aLastModified;
aLastModified->myNext = anInt;
aFirst.Int = anInt;
pLastInt = anInt;
}
break;
default:
Standard_ProgramError::Raise ("Poly_IBuffer::AddInterval");
}
}
}
if (isWaiting) {
const Standard_Real anX[2] = {
aFirst.X,
myIndex[INDEXLEN].X
};
aLastModified = addInt (theInterval, anX, aFirst.Int);
}
return aLastModified;
}
//=======================================================================
//function : CloseBuffer
//purpose : Called after all additions of intervals
//=======================================================================
void Poly_IBuffer::CloseBuffer (const Standard_Boolean isFiltering)
{
const Standard_Real aConf2 =
0.01 * Precision::Confusion() * Precision::Confusion();
const Standard_Real aTol2 = myTol * myTol;
Interval * pPrev = 0L, * pInt = const_cast<Interval *>(myIndex[0].Int);
if (pInt) {
pInt->U.myPrev = 0L;
pInt->myModID = 0UL;
pPrev = pInt;
pInt = pInt->Next();
}
while (pInt) {
if (isFiltering &&
(pPrev->myXZ[1] - pInt->myXZ[0]).SquareModulus() < aConf2)
{
const gp_XY aV0 = pInt->myXZ[1] - pPrev->myXZ[0];
const Standard_Real aL0 = aV0.SquareModulus();
if (aL0 > aConf2) {
const Standard_Real aVProd = aV0 ^ (pPrev->myXZ[1] - pPrev->myXZ[0]);
if (aVProd * aVProd / aL0 < aTol2) {
// extend pPrev to take place of pInt
pPrev->myXZ[1] = pInt->myXZ[1];
pPrev->myNext = pInt->Next();
pInt = pInt->Next();
continue;
}
}
}
pInt->U.myPrev = pPrev;
pInt->myModID = 0UL;
pPrev = pInt;
pInt = pInt->Next();
}
}
//=======================================================================
//function : addInt
//purpose : Internal method, called from AddInterval()
//=======================================================================
Poly_IBuffer::Interval * Poly_IBuffer::addInt
(const Poly_IBuffer::Interval& theInterval,
const Standard_Real theX[2],
const Poly_IBuffer::Interval * thePrevious)
{
const gp_XY aXZ[2] = {
gp_XY(theX[0], GetZ (theInterval, theX[0])),
gp_XY(theX[1], GetZ (theInterval, theX[1]))
};
Interval& aNewInt = theInterval.Clone(myAllocator);
aNewInt.myXZ[0] = aXZ[0];
aNewInt.myXZ[1] = aXZ[1];
myNIntervals++;
if (thePrevious)
const_cast<Interval *>(thePrevious)->myNext = &aNewInt;
else {
myIndex[0].Int = &aNewInt;
if (myMinOrd > aXZ[0].Y())
myMinOrd = aXZ[0].Y();
if (myMaxOrd < aXZ[0].Y())
myMaxOrd = aXZ[0].Y();
}
if (myMinOrd > aXZ[1].Y())
myMinOrd = aXZ[1].Y();
if (myMaxOrd < aXZ[1].Y())
myMaxOrd = aXZ[1].Y();
return &aNewInt;
}
//=======================================================================
//function : clearIntervals
//purpose :
//=======================================================================
void Poly_IBuffer::clearIntervals ()
{
if (myAllocator.IsNull() == Standard_False)
{
Interval * anInt = const_cast <Interval *>(myIndex[0].Int);
while (anInt) {
Interval * anInt0 = anInt;
anInt = anInt->Next();
anInt0->Interval::~Interval();
myAllocator->Free(anInt0);
}
myAllocator->Free (myIndex);
}
myIndex = 0L;
myNIntervals = 0;
myNHoles = 0;
}
//=======================================================================
//function : Dump
//purpose : Debug facility.
//=======================================================================
void Poly_IBuffer::Dump (Standard_OStream& theStream)
{
const Interval * anInt = First();
int aCount(0);
for (; anInt; anInt = anInt->Next()) {
char buf[256];
// if (anInt->XZ(0).Y() > Precision::Infinite() * 0.1 &&
// anInt->XZ(1).Y() > Precision::Infinite() * 0.1)
// continue;
sprintf (buf, "%03d (%9.5f %9.5f) - (%9.5f %9.5f)", ++aCount,
anInt->XZ(0).X(), anInt->XZ(0).Y(),
anInt->XZ(1).X(), anInt->XZ(1).Y());
theStream << buf << endl;
}
}
//=======================================================================
//function : DebugPolyline
//purpose : Debug facility.
//=======================================================================
void Poly_IBuffer::DebugPolyline (Standard_OStream& theStream,
const Standard_Real theY)
{
static int aTestCount (0);
const Interval * anInt = First();
Standard_Real aLastVal[2] = { Precision::Infinite(), Precision::Infinite() };
Standard_Boolean isStarted (Standard_True);
std::streamsize oldPrec = theStream.precision(8);
for (; anInt; anInt = anInt->Next()) {
if (anInt->XZ(0).Y() > Precision::Infinite() * 0.1 &&
anInt->XZ(1).Y() > Precision::Infinite() * 0.1)
{
if (isStarted == Standard_False) {
theStream << endl;
isStarted = Standard_True;
}
continue;
}
if (isStarted) {
theStream << "polyline ibuf" << aTestCount++;
isStarted = Standard_False;
}
if (fabs(anInt->XZ(0).X() - aLastVal[0]) > Precision::Confusion() ||
fabs(anInt->XZ(0).Y() - aLastVal[1]) > Precision::Confusion())
theStream << " " << anInt->XZ(0).X() << ' '
<< theY << ' ' << anInt->XZ(0).Y() << ' ';
theStream << " " << anInt->XZ(1).X() << ' '
<< theY << ' ' << anInt->XZ(1).Y() << ' ';
aLastVal[0] = anInt->XZ(1).X();
aLastVal[1] = anInt->XZ(1).Y();
}
theStream.precision(oldPrec);
theStream << endl;
}

253
src/Poly/Poly_IBuffer.hxx Normal file
View File

@@ -0,0 +1,253 @@
// File: Poly_IBuffer.hxx
// Created: 15.06.07 08:08
// Author: Alexander GRIGORIEV
// Copyright: Open CASCADE 2007
#ifndef Poly_IBuffer_HeaderFile
#define Poly_IBuffer_HeaderFile
#include <NCollection_List.hxx>
#include <gp_XY.hxx>
#include <Standard_DefineHandle.hxx>
DEFINE_STANDARD_HANDLE (Poly_IBuffer, Standard_Transient)
typedef NCollection_List<Handle(Poly_IBuffer)> Poly_ListOfIBuffer;
//! Interval buffer to build outline curve on a set of polygons.
class Poly_IBuffer: public Standard_Transient
{
public:
class Interval
{
public:
// ---------- PUBLIC METHODS ----------
Interval (const gp_XY& theXZfirst,
const gp_XY& theXZlast,
const unsigned long theModID = 0UL);
/**
* Allocator-based operator new for dynamic allocations
*/
DEFINE_NCOLLECTION_ALLOC
/**
* Create a copy of the given Interval in the given allocator.
* If theDest==NULL then a new instance is created.
*/
Standard_EXPORT virtual Interval&
Clone (const Handle(NCollection_BaseAllocator)&,
Interval * theDest = NULL) const;
/**
* Query the abscisse of the interval.
*/
const gp_XY& XZ (const Standard_Integer ind) const;
/**
* Query the interval for modification.
*/
gp_XY& XZ (const Standard_Integer ind);
/**
* Shorten the interval to the new value of Xmax.
*/
Standard_EXPORT void Trim (const Standard_Real theX,
const Standard_Integer theMode);
/**
* Query the previous interval in the buffer.
*/
Interval * Previous () const;
/**
* Query the next interval in the buffer.
*/
Interval * Next () const;
/**
* Query the RejectID indicating the modification status of the interval
*/
unsigned long GetModificationID () const;
/**
* Query the abscisse value required for modification.
*/
Standard_Real GetModificationAbscisse() const;
/**
* Set the modification ID.
*/
void SetModificationID (const unsigned long theValue);
/**
* Check for intersection, returns the intersection point abscissa.
* @return
* True if a modification or removal is required. The decision is based
* on 2 lower bits of myRejectID value:
* - 0 : remove this interval;
* - 1 : keep the lower abscisse part, remove the upper part;
* - 2 : keep the upper abscisse part, remove the lower part;
* - 3 : remove the middle.
* @param theInt
* The other interval that may intersect this one.
* @param theTol
* Tolerance of intersection: smaller intersections are neglected.
* @param theRejectID
* Base ID that is stored in the interval with the corresponding
* modification status.
*/
Standard_EXPORT Standard_Boolean
IsIntersect (const Interval& theInt,
const Standard_Real theTol,
const unsigned long theRejectID);
/**
* Generator of unique Reject ID values.
*/
static Standard_EXPORT unsigned long
NewRejectID ();
private:
// ---------- PRIVATE FIELDS ----------
Interval * myNext;
gp_XY myXZ[2];
union {
Standard_Real myModX;
Interval * myPrev;
} U;
unsigned long myModID;
friend class Poly_IBuffer;
};
public:
// ---------- PUBLIC METHODS ----------
/**
* Default constructor.
*/
Poly_IBuffer ();
/**
* Constructor.
*/
Standard_EXPORT Poly_IBuffer
(const Interval& theInterval,
const Standard_Real theTol,
const Handle(NCollection_BaseAllocator)& theAlloc = 0L);
/**
* Get the next IBuffer in the list.
*/
//inline const Poly_IBuffer& YNext() const
//{ return * myNext; }
inline const Poly_IBuffer *& YNext()
{ return myNext; }
/**
* Get the previous IBuffer in the list.
*/
//inline const Poly_IBuffer& YPrevious() const
//{ return * myPrevious; }
inline const Poly_IBuffer *& YPrevious()
{ return myPrevious; }
inline const Standard_Real MyY() const
{ return myY; }
/**
* Set myY value.
*/
inline void SetY (const Standard_Real theY)
{ myY = theY; }
#ifdef _DEBUG
inline int MyCount()
{ return myCount; }
#endif
/**
* Initialization, to be used after the default constructor.
*/
Standard_EXPORT void Init
(const Interval& theInterval,
const Standard_Real theTol,
const Handle(NCollection_BaseAllocator)& theAlloc = 0L);
Standard_EXPORT ~Poly_IBuffer ();
Standard_EXPORT Interval *
AddInterval (const Interval& theInterval,
Interval * theStart = 0L);
/**
* Called when all intervals are added, just before extraction of data.
* This method sets the values 'myPrev' in all Intervals. Can be omittred
* if the method Previous() is not to be called afterwards.
* @param isFiltering
* If True then the method would merge the intervals that form a straight
* line. It can lead to loss of data attached to intervals, use this only
* when you are only interested in geometry of intervals.
*/
Standard_EXPORT void CloseBuffer (const Standard_Boolean isFiltering
= Standard_False);
const Interval * First () const;
void GetOrdinateExtents (Standard_Real& theMin,
Standard_Real& theMax) const;
/**
* Debug facility.
*/
Standard_EXPORT void Dump (Standard_OStream& theStream);
/**
* Debug facility.
*/
Standard_EXPORT void DebugPolyline (Standard_OStream& theStream,
const Standard_Real theY = 1.);
protected:
// ---------- PROTECTED METHODS ----------
typedef struct {
Standard_Real X;
const Interval * Int;
} PInterval;
Interval * addInt (const Interval& theInterval,
const Standard_Real theX[2],
const Interval * thePrevious);
void clearIntervals();
private:
Poly_IBuffer (const Poly_IBuffer& theOther);
Poly_IBuffer& operator = (const Poly_IBuffer& theOther);
private:
// ---------- PRIVATE FIELDS ----------
Handle(NCollection_BaseAllocator) myAllocator;
Standard_Real myTol;
Standard_Real myMinOrd;
Standard_Real myMaxOrd;
Standard_Size myNIntervals;
Standard_Size myNHoles;
PInterval * myIndex;
//Next IBuffer in the list
const Poly_IBuffer* myNext;
//Previous IBuffer in the list
const Poly_IBuffer* myPrevious;
Standard_Real myY;
#ifdef _DEBUG
int myCount;
static int GlobalCount;
#endif
public:
// Declaration of CASCADE RTTI
DEFINE_STANDARD_RTTIEXT (Poly_IBuffer, Standard_Transient)
};
#include <Poly_IBuffer.lxx>
#endif

87
src/Poly/Poly_IBuffer.lxx Normal file
View File

@@ -0,0 +1,87 @@
// File: Poly_IBuffer.lxx
// Created: 15.06.07 07:56
// Author: Alexander GRIGORIEV
// Copyright: Open CASCADE 2007
//! Constructor.
inline Poly_IBuffer::Interval::Interval (const gp_XY& theXZfirst,
const gp_XY& theXZlast,
const unsigned long theModID)
: myNext (0L),
myModID (theModID)
{
U.myModX = RealLast();
myXZ[0] = theXZfirst;
myXZ[1] = theXZlast;
}
//! Query the beginning (ind==0) or end (ind == 1) of the interval.
inline const gp_XY& Poly_IBuffer::Interval::XZ (const Standard_Integer i) const
{
return myXZ[i&0x1];
}
//! Query the beginning (ind==0) or end (ind == 1) of the interval for modif
inline gp_XY& Poly_IBuffer::Interval::XZ (const Standard_Integer i)
{
return myXZ[i&0x1];
}
//! Query the next interval in the buffer.
inline Poly_IBuffer::Interval * Poly_IBuffer::Interval::Next () const
{
return myNext;
}
//! Query the previous interval in the buffer.
inline Poly_IBuffer::Interval * Poly_IBuffer::Interval::Previous () const
{
return U.myPrev;
}
//! Set the modification ID.
inline void Poly_IBuffer::Interval::SetModificationID
(const unsigned long theValue)
{
myModID = theValue;
}
//! Query the RejectID field indicating the modification status of the interval
inline unsigned long Poly_IBuffer::Interval::GetModificationID () const
{
return myModID;
}
//! Query the abscisse value required for modification.
inline Standard_Real Poly_IBuffer::Interval::GetModificationAbscisse() const
{
return U.myModX;
}
//! Returns the head of the list of intervals.
/** Other intervals can be obtained by iterative calling Next() of each
* returned interval.
*/
inline const Poly_IBuffer::Interval * Poly_IBuffer::First () const
{
return myIndex ? myIndex[0].Int : 0L;
}
//! Default constructor
inline Poly_IBuffer::Poly_IBuffer()
: myTol (0.),
myMinOrd (0.),
myMaxOrd (0.),
myNIntervals(0),
myNHoles (0),
myIndex (0L)
{}
//! Get extents of the buffer along the ordinate, excepting the
//! artificial intervals at infinite ordinate
inline void Poly_IBuffer::GetOrdinateExtents (Standard_Real& theMin,
Standard_Real& theMax) const
{
theMin = myMinOrd;
theMax = myMaxOrd;
}

View File

@@ -370,11 +370,6 @@ void SelectMgr_SelectionManager::Activate (const Handle(SelectMgr_SelectableObje
if (myGlobal.Contains (theObject))
{
const Standard_Integer aGlobalSelMode = theObject->GlobalSelectionMode();
if (theMode != aGlobalSelMode && theSelector->IsActive (theObject, aGlobalSelMode))
{
theSelector->Deactivate (theObject->Selection (aGlobalSelMode));
}
theSelector->Activate (theObject->Selection (theMode));
}
else

View File

@@ -11,6 +11,8 @@ Standard_Byte.hxx
Standard_Character.hxx
Standard_CLocaleSentry.cxx
Standard_CLocaleSentry.hxx
Standard_Condition.cxx
Standard_Condition.hxx
Standard_ConstructionError.hxx
Standard_Copy.tcl
Standard_CString.cxx
@@ -79,9 +81,9 @@ Standard_Real.hxx
Standard_ShortReal.cxx
Standard_ShortReal.hxx
Standard_Size.hxx
Standard_SStream.cxx
Standard_SStream.hxx
Standard_Stream.hxx
Standard_Strtod.cxx
Standard_ThreadId.hxx
Standard_Time.hxx
Standard_TooManyUsers.hxx
@@ -92,7 +94,8 @@ Standard_Type.hxx
Standard_TypeDef.hxx
Standard_TypeMismatch.hxx
Standard_Underflow.hxx
Standard_UUID.cxx
Standard_UUID.hxx
Standard_values.h
Standard_Version.hxx
Standard_WarningsDisable.hxx
Standard_WarningsRestore.hxx

View File

@@ -35,6 +35,14 @@ inline int Standard_Atomic_Increment (volatile int* theValue);
//! and returns resulting decremented value.
inline int Standard_Atomic_Decrement (volatile int* theValue);
//! Perform an atomic compare and swap.
//! That is, if the current value of *theValue is theOldValue, then write theNewValue into *theValue.
//! @param theValue pointer to variable to modify
//! @param theOldValue expected value to perform modification
//! @param theNewValue new value to set in case if *theValue was equal to theOldValue
//! @return TRUE if theNewValue has been set to *theValue
inline bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue);
// Platform-dependent implementation
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
// gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
@@ -55,16 +63,23 @@ int Standard_Atomic_Decrement (volatile int* theValue)
return __sync_sub_and_fetch (theValue, 1);
}
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
{
return __sync_val_compare_and_swap (theValue, theOldValue, theNewValue) == theOldValue;
}
#elif defined(_WIN32)
extern "C" {
long _InterlockedIncrement (volatile long* lpAddend);
long _InterlockedDecrement (volatile long* lpAddend);
long _InterlockedCompareExchange (long volatile* Destination, long Exchange, long Comparand);
}
#if defined(_MSC_VER)
#if defined(_MSC_VER) && ! defined(__INTEL_COMPILER)
// force intrinsic instead of WinAPI calls
#pragma intrinsic (_InterlockedIncrement)
#pragma intrinsic (_InterlockedDecrement)
#pragma intrinsic (_InterlockedCompareExchange)
#endif
// WinAPI function or MSVC intrinsic
@@ -80,6 +95,11 @@ int Standard_Atomic_Decrement (volatile int* theValue)
return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
}
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
{
return _InterlockedCompareExchange (reinterpret_cast<volatile long*>(theValue), theNewValue, theOldValue) == theOldValue;
}
#elif defined(__APPLE__)
// use atomic operations provided by MacOS
@@ -95,6 +115,11 @@ int Standard_Atomic_Decrement (volatile int* theValue)
return OSAtomicDecrement32Barrier (theValue);
}
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
{
return OSAtomicCompareAndSwapInt (theOldValue, theNewValue, theValue);
}
#elif defined(__ANDROID__)
// Atomic operations that were exported by the C library didn't
@@ -114,34 +139,9 @@ int Standard_Atomic_Decrement (volatile int* theValue)
return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub
}
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
// use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
inline int Standard_Atomic_Add (volatile int* theValue, int theVal)
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
{
// C equivalent:
// *theValue += theVal;
// return *theValue;
int previous;
__asm__ __volatile__
(
"lock xadd %0,%1"
: "=q"(previous), "=m"(*theValue) //output
: "0"(theVal), "m"(*theValue) //input
: "memory" //clobbers
);
return previous + theVal;
}
int Standard_Atomic_Increment (volatile int* theValue)
{
return Standard_Atomic_Add (theValue, 1);
}
int Standard_Atomic_Decrement (volatile int* theValue)
{
return Standard_Atomic_Add (theValue, -1);
return __atomic_cmpxchg (theOldValue, theNewValue, theValue) == 0;
}
#else
@@ -159,6 +159,16 @@ int Standard_Atomic_Decrement (volatile int* theValue)
return --(*theValue);
}
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
{
if (*theValue == theOldValue)
{
*theValue = theNewValue;
return true;
}
return false;
}
#endif
#endif //_Standard_Atomic_HeaderFile

View File

@@ -0,0 +1,207 @@
// Created by: Kirill Gavrilov
// Copyright (c) 2018 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.
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#endif
#include "Standard_Condition.hxx"
namespace
{
#ifndef _WIN32
//! clock_gettime() wrapper.
static void conditionGetRealTime (struct timespec& theTime)
{
#if defined(__APPLE__)
struct timeval aTime;
gettimeofday (&aTime, NULL);
theTime.tv_sec = aTime.tv_sec;
theTime.tv_nsec = aTime.tv_usec * 1000;
#else
clock_gettime (CLOCK_REALTIME, &theTime);
#endif
}
#endif
}
// =======================================================================
// function : Standard_Condition
// purpose :
// =======================================================================
Standard_Condition::Standard_Condition (bool theIsSet)
#ifdef _WIN32
: myEvent((void* )::CreateEvent (0, true, theIsSet, NULL))
#else
: myFlag (theIsSet)
#endif
{
#ifndef _WIN32
pthread_mutex_init(&myMutex, 0);
pthread_cond_init (&myCond, 0);
#endif
}
// =======================================================================
// function : ~Standard_Condition
// purpose :
// =======================================================================
Standard_Condition::~Standard_Condition()
{
#ifdef _WIN32
::CloseHandle ((HANDLE )myEvent);
#else
pthread_mutex_destroy(&myMutex);
pthread_cond_destroy (&myCond);
#endif
}
// =======================================================================
// function : Set
// purpose :
// =======================================================================
void Standard_Condition::Set()
{
#ifdef _WIN32
::SetEvent ((HANDLE )myEvent);
#else
pthread_mutex_lock(&myMutex);
myFlag = true;
pthread_cond_broadcast(&myCond);
pthread_mutex_unlock (&myMutex);
#endif
}
// =======================================================================
// function : Reset
// purpose :
// =======================================================================
void Standard_Condition::Reset()
{
#ifdef _WIN32
::ResetEvent ((HANDLE )myEvent);
#else
pthread_mutex_lock (&myMutex);
myFlag = false;
pthread_mutex_unlock (&myMutex);
#endif
}
// =======================================================================
// function : Wait
// purpose :
// =======================================================================
void Standard_Condition::Wait()
{
#ifdef _WIN32
::WaitForSingleObject ((HANDLE )myEvent, INFINITE);
#else
pthread_mutex_lock (&myMutex);
if (!myFlag)
{
pthread_cond_wait (&myCond, &myMutex);
}
pthread_mutex_unlock (&myMutex);
#endif
}
// =======================================================================
// function : Wait
// purpose :
// =======================================================================
bool Standard_Condition::Wait (int theTimeMilliseconds)
{
#ifdef _WIN32
return (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )theTimeMilliseconds) != WAIT_TIMEOUT);
#else
bool isSignalled = true;
pthread_mutex_lock (&myMutex);
if (!myFlag)
{
struct timespec aNow;
struct timespec aTimeout;
conditionGetRealTime (aNow);
aTimeout.tv_sec = (theTimeMilliseconds / 1000);
aTimeout.tv_nsec = (theTimeMilliseconds - aTimeout.tv_sec * 1000) * 1000000;
if (aTimeout.tv_nsec > 1000000000)
{
aTimeout.tv_sec += 1;
aTimeout.tv_nsec -= 1000000000;
}
aTimeout.tv_sec += aNow.tv_sec;
aTimeout.tv_nsec += aNow.tv_nsec;
isSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
}
pthread_mutex_unlock (&myMutex);
return isSignalled;
#endif
}
// =======================================================================
// function : Check
// purpose :
// =======================================================================
bool Standard_Condition::Check()
{
#ifdef _WIN32
return (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )0) != WAIT_TIMEOUT);
#else
bool isSignalled = true;
pthread_mutex_lock (&myMutex);
if (!myFlag)
{
struct timespec aNow;
struct timespec aTimeout;
conditionGetRealTime (aNow);
aTimeout.tv_sec = aNow.tv_sec;
aTimeout.tv_nsec = aNow.tv_nsec + 100;
isSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
}
pthread_mutex_unlock (&myMutex);
return isSignalled;
#endif
}
// =======================================================================
// function : CheckReset
// purpose :
// =======================================================================
bool Standard_Condition::CheckReset()
{
#ifdef _WIN32
const bool wasSignalled = (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )0) != WAIT_TIMEOUT);
::ResetEvent ((HANDLE )myEvent);
return wasSignalled;
#else
pthread_mutex_lock (&myMutex);
bool wasSignalled = myFlag;
if (!myFlag)
{
struct timespec aNow;
struct timespec aTimeout;
conditionGetRealTime (aNow);
aTimeout.tv_sec = aNow.tv_sec;
aTimeout.tv_nsec = aNow.tv_nsec + 100;
wasSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
}
myFlag = false;
pthread_mutex_unlock (&myMutex);
return wasSignalled;
#endif
}

View File

@@ -0,0 +1,80 @@
// Created by: Kirill Gavrilov
// Copyright (c) 2018 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.
#ifndef _Standard_Condition_HeaderFile
#define _Standard_Condition_HeaderFile
#include <Standard.hxx>
#ifndef _WIN32
#include <pthread.h>
#endif
//! This is boolean flag intended for communication between threads.
//! One thread sets this flag to TRUE to indicate some event happened
//! and another thread either waits this event or checks periodically its state to perform job.
//!
//! This class provides interface similar to WinAPI Event objects.
class Standard_Condition
{
public:
//! Default constructor.
//! @param theIsSet Initial flag state
Standard_EXPORT Standard_Condition (bool theIsSet);
//! Destructor.
Standard_EXPORT ~Standard_Condition();
//! Set event into signaling state.
Standard_EXPORT void Set();
//! Reset event (unset signaling state)
Standard_EXPORT void Reset();
//! Wait for Event (infinity).
Standard_EXPORT void Wait();
//! Wait for signal requested time.
//! @param theTimeMilliseconds wait limit in milliseconds
//! @return true if get event
Standard_EXPORT bool Wait (int theTimeMilliseconds);
//! Do not wait for signal - just test it state.
//! @return true if get event
Standard_EXPORT bool Check();
//! Method perform two steps at-once - reset the event object
//! and returns true if it was in signaling state.
//! @return true if event object was in signaling state.
Standard_EXPORT bool CheckReset();
#ifdef _WIN32
//! Access native HANDLE to Event object.
void* getHandle() const { return myEvent; }
#endif
private:
#ifdef _WIN32
void* myEvent;
#else
pthread_mutex_t myMutex;
pthread_cond_t myCond;
bool myFlag;
#endif
};
#endif // _Standard_Condition_HeaderFile

View File

@@ -58,23 +58,6 @@ static void deallocate_message(Standard_CString aMessage)
}
}
// Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
#if defined(__clang__)
// CLang version: standard CLang > 3.3 or XCode >= 8 (but excluding 32-bit ARM)
// Note: this has to be in separate #if to avoid failure of preprocessor on other platforms
#if __has_feature(cxx_thread_local)
#define Standard_THREADLOCAL thread_local
#else
#define Standard_THREADLOCAL
#endif
#elif (defined(__INTEL_COMPILER) && __INTEL_COMPILER > 1400) || \
(defined(_MSC_VER) && _MSC_VER >= 1900) /* MSVC++ >= 14 */ || \
(defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) /* GCC >= 4.8 */
#define Standard_THREADLOCAL thread_local
#else
#define Standard_THREADLOCAL
#endif
// ******************************************************************
// Standard_Failure *
// ******************************************************************

View File

@@ -393,10 +393,22 @@ Standard_Integer Standard_GUID::Hash(const Standard_Integer Upper) const
throw Standard_RangeError("Standard_GUID::Hash: Try to apply HashCode method with negative or null argument.");
}
char sguid[Standard_GUID_SIZE_ALLOC];
ToCString(sguid);
return ::HashCode(sguid,Upper);
// ==== AGV 16/12/2012: More optimal hash function ===
//char sguid[Standard_GUID_SIZE_ALLOC];
//ToCString(sguid);
//return ::HashCode(sguid,Upper);
// ===================================================
unsigned int aHash = ((static_cast<unsigned int>(my8b6) << 24) |
(static_cast<unsigned int>(my8b5) << 16) |
(static_cast<unsigned int>(my8b4) << 8) |
(static_cast<unsigned int>(my8b3)));
aHash = (aHash ^ (aHash >> 11)) & 0x07ffffff;
aHash = (aHash * 31 + ((static_cast<unsigned int>(my8b2) << 24) |
(static_cast<unsigned int>(my8b1) << 16) |
(static_cast<unsigned int>(my16b3)))) & 0x07ffffff;
aHash = (aHash * 31 + ((static_cast<unsigned int>(my16b2) << 16) |
(static_cast<unsigned int>(my16b1)))) & 0x07ffffff;
return (aHash * 31 + my32b) % Upper;
}
Standard_Boolean Standard_GUID::IsEqual(const Standard_GUID& aGuid1,const Standard_GUID& aGuid2)

View File

@@ -12,13 +12,21 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// Purpose: This file is intended to be the first file #included to any
// Open CASCADE source. It defines platform-specific pre-processor
// macros necessary for correct compilation of Open CASCADE code
//! @file
//! This file is intended to be the first file included to any
//! Open CASCADE source. It defines platform-specific pre-processor
//! macros necessary for correct compilation of Open CASCADE code.
#ifndef _Standard_Macro_HeaderFile
# define _Standard_Macro_HeaderFile
//! @def Standard_OVERRIDE
//! Should be used in declarations of virtual methods overriden in the
//! derived classes, to cause compilation error in the case if that virtual
//! function disappears or changes its signature in the base class.
//!
//! Expands to C++11 keyword "override" on compilers that are known to
//! suppot it; empty in other cases.
#if defined(__cplusplus) && (__cplusplus >= 201100L)
// part of C++11 standard
#define Standard_OVERRIDE override
@@ -29,16 +37,69 @@
#define Standard_OVERRIDE
#endif
// Macro for marking variables / functions as possibly unused
// so that compiler will not emit redundant "unused" warnings.
//! @def Standard_FALLTHROUGH
//! Should be used in a switch statement immediately before a case label,
//! if code associated with the previous case label may fall through to that
//! next label (i.e. does not end with "break" or "return" etc.).
//! This macro indicates that the fall through is intentional and should not be
//! diagnosed by a compiler that warns on fallthrough.
//!
//! Expands to C++17 attribute statement "[[fallthrough]];" on compilers that
//! declare support of C++17, or to "__attribute__((fallthrough));" on
//! GCC 7+.
#if defined(__cplusplus) && (__cplusplus >= 201703L)
// part of C++17 standard
#define Standard_FALLTHROUGH [[fallthrough]];
#elif defined(__GNUC__) && (__GNUC__ >= 7)
// gcc 7+
#define Standard_FALLTHROUGH __attribute__((fallthrough));
#else
#define Standard_FALLTHROUGH
#endif
//! @def Standard_UNUSED
//! Macro for marking variables / functions as possibly unused
//! so that compiler will not emit redundant "unused" warnings.
//!
//! Expands to "__attribute__((unused))" on GCC and CLang.
#if defined(__GNUC__) || defined(__clang__)
#define Standard_UNUSED __attribute__((unused))
#else
#define Standard_UNUSED
#endif
// Macro Standard_DEPRECATED("message") can be used to declare a method deprecated.
// If OCCT_NO_DEPRECATED is defined, Standard_DEPRECATED is defined empty.
//! @def Standard_THREADLOCAL
//! Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
#if defined(__clang__)
// CLang version: standard CLang > 3.3 or XCode >= 8 (but excluding 32-bit ARM)
// Note: this has to be in separate #if to avoid failure of preprocessor on other platforms
#if __has_feature(cxx_thread_local)
#define Standard_THREADLOCAL thread_local
#endif
#elif defined(__INTEL_COMPILER)
#if (defined(_MSC_VER) && _MSC_VER >= 1900 && __INTEL_COMPILER > 1400)
// requires msvcrt vc14+ (Visual Studio 2015+)
#define Standard_THREADLOCAL thread_local
#elif (!defined(_MSC_VER) && __INTEL_COMPILER > 1500)
#define Standard_THREADLOCAL thread_local
#endif
#elif (defined(_MSC_VER) && _MSC_VER >= 1900)
// msvcrt coming with vc14+ (VS2015+)
#define Standard_THREADLOCAL thread_local
#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
// GCC >= 4.8
#define Standard_THREADLOCAL thread_local
#endif
#ifndef Standard_THREADLOCAL
#define Standard_THREADLOCAL
#endif
//! @def Standard_DEPRECATED("message")
//! Can be used in declaration of a method or a class to mark it as deprecated.
//! Use of such method or class will cause compiler warning (if supported by
//! compiler and unless disabled).
//! If macro OCCT_NO_DEPRECATED is defined, Standard_DEPRECATED is defined empty.
#ifdef OCCT_NO_DEPRECATED
#define Standard_DEPRECATED(theMsg)
#else
@@ -53,9 +114,14 @@
#endif
#endif
// Disable warnings about deprecated features.
// This is useful for sections of code kept for backward compatibility and scheduled for removal.
//! @def Standard_DISABLE_DEPRECATION_WARNINGS
//! Disables warnings on use of deprecated features (see Standard_DEPRECATED),
//! from the current point till appearance of Standard_ENABLE_DEPRECATION_WARNINGS macro.
//! This is useful for sections of code kept for backward compatibility and scheduled for removal.
//!
//! @def Standard_ENABLE_DEPRECATION_WARNINGS
//! Enables warnings on use of deprecated features previously disabled by
//! Standard_DISABLE_DEPRECATION_WARNINGS.
#if defined(__ICL) || defined (__INTEL_COMPILER)
#define Standard_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478))
#define Standard_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop))
@@ -72,6 +138,13 @@
#define Standard_ENABLE_DEPRECATION_WARNINGS
#endif
//! @def OCCT_NO_RVALUE_REFERENCE
//! Disables methods and constructors that use rvalue references
//! (C++11 move semantics) not supported by obsolete compilers.
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
#define OCCT_NO_RVALUE_REFERENCE
#endif
# ifdef _WIN32
// We must be careful including windows.h: it is really poisonous stuff!
@@ -118,7 +191,15 @@
#endif
# if defined(_WIN32) && !defined(HAVE_NO_DLL)
//! @def Standard_EXPORT
//! This macro should be used in declarations of public methods
//! to ensure that they are exported from DLL on Windows and thus
//! can be called from other (dependent) libraries or applications.
//!
//! If macro OCCT_STATIC_BUILD is defined, then Standard_EXPORT
//! is set to empty.
# if defined(_WIN32) && !defined(OCCT_STATIC_BUILD) && !defined(HAVE_NO_DLL)
//======================================================
// Windows-specific definitions
@@ -167,21 +248,9 @@
# endif /* _WIN32 */
//======================================================
// Other
//======================================================
# ifndef __Standard_API
# if !defined(_WIN32) || defined(__Standard_DLL) || defined(__FSD_DLL) || defined(__MMgt_DLL) || defined(__OSD_DLL) || defined(__Plugin_DLL) || defined(__Quantity_DLL) || defined(__Resource_DLL) || defined(__SortTools_DLL) || defined(__StdFail_DLL) || defined(__Storage_DLL) || defined(__TColStd_DLL) || defined(__TCollection_DLL) || defined(__TShort_DLL) || defined(__Units_DLL) || defined(__UnitsAPI_DLL) || defined(__Dico_DLL)
# define __Standard_API Standard_EXPORT
# define __Standard_APIEXTERN Standard_EXPORTEXTERN
# else
# define __Standard_API Standard_IMPORT
# define __Standard_APIEXTERN Standard_IMPORT
# endif // __Standard_DLL
# endif // __Standard_API
// Support of Universal Windows Platform
//! @def OCCT_UWP
//! This macro is defined on Windows platform in the case if the code
//! is being compiled for UWP (Universal Windows Platform).
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP
#define OCCT_UWP
#else

View File

@@ -54,7 +54,7 @@ void StdSelect_Shape::Compute(const Handle(PrsMgr_PresentationManager3d)& /*PM*/
else
StdPrs_WFShape::Add (P, mysh, myDrawer);
}
else if (aMode==0)
else
StdPrs_WFShape::Add (P, mysh, myDrawer);
}

View File

@@ -117,7 +117,7 @@ public:
//! Adds an Attribute to the current label. Raises if
//! there is already one.
Standard_EXPORT void AddAttribute (const Handle(TDF_Attribute)& anAttribute, const Standard_Boolean append = Standard_False) const;
Standard_EXPORT void AddAttribute (const Handle(TDF_Attribute)& anAttribute, const Standard_Boolean append = Standard_True) const;
//! Forgets an Attribute from the current label,
//! setting its forgotten status true and its valid

View File

@@ -285,17 +285,17 @@ void TDataXtd_Presentation::SetMode(const Standard_Integer theMode)
//function : SetSelectionMode
//purpose :
//=======================================================================
void TDataXtd_Presentation::SetSelectionMode(const Standard_Integer theSelectionMode)
void TDataXtd_Presentation::SetSelectionMode(const Standard_Integer theSelectionMode, const Standard_Boolean theTransaction)
{
if (! myHasOwnSelectionMode || mySelectionMode != theSelectionMode)
{
Backup();
if (theTransaction)
Backup();
mySelectionMode = theSelectionMode;
myHasOwnSelectionMode = Standard_True;
}
}
//=======================================================================
//function : MaterialIndex
//purpose :

View File

@@ -114,7 +114,12 @@ public:
Standard_EXPORT void SetMode(const Standard_Integer theMode);
Standard_EXPORT void SetSelectionMode(const Standard_Integer theSelectionMode);
//! Sets selection mode.
//! If "theTransaction" flag is OFF, modification of the attribute doesn't influence the transaction mechanism
//! (the attribute doesn't participate in undo/redo because of this modification).
//! Certainly, if any other data of the attribute is modified (display mode, color, ...),
//! the attribute will be included into undo/redo.
Standard_EXPORT void SetSelectionMode(const Standard_Integer theSelectionMode, const Standard_Boolean theTransaction = Standard_True);
Standard_EXPORT Standard_Integer MaterialIndex() const;

View File

@@ -591,11 +591,16 @@ Standard_Boolean TPrsStd_AISPresentation::HasOwnSelectionMode() const
//function : SetSelectionMode
//purpose :
//=======================================================================
void TPrsStd_AISPresentation::SetSelectionMode(const Standard_Integer theSelectionMode)
void TPrsStd_AISPresentation::SetSelectionMode(const Standard_Integer theSelectionMode, const Standard_Boolean theTransaction)
{
Backup();
getData()->SetSelectionMode (theSelectionMode);
AISUpdate();
if (theTransaction)
Backup();
getData()->SetSelectionMode (theSelectionMode, theTransaction);
if ( myAIS.IsNull() )
AISUpdate();
else
ActivateSelectionMode();
}
//=======================================================================
@@ -800,7 +805,7 @@ void TPrsStd_AISPresentation::AISUpdate()
if ( !(anObj == myAIS) )
{
if ( !aContext.IsNull() )
aContext->Remove (myAIS, Standard_True);
aContext->Remove (myAIS, Standard_False);
// Driver has built new AIS.
myAIS = anObj;
@@ -871,36 +876,7 @@ void TPrsStd_AISPresentation::AISUpdate()
myAIS->SetDisplayMode(aMode);
}
if ( !aContext.IsNull() && IsDisplayed() )
aContext->Redisplay(myAIS, Standard_False);
if (HasOwnSelectionMode()) {
if (!aContext.IsNull())
{
TColStd_ListOfInteger anActivatedModes;
aContext->ActivatedModes (myAIS, anActivatedModes);
Standard_Boolean isActivated = Standard_False;
Standard_Integer aSelectionMode = SelectionMode();
if (aSelectionMode == -1)
{
aContext->Deactivate(myAIS);
}
else
{
for (TColStd_ListIteratorOfListOfInteger aModeIter (anActivatedModes); aModeIter.More(); aModeIter.Next())
{
if (aModeIter.Value() == aSelectionMode)
{
isActivated = Standard_True;
break;
}
}
if (!isActivated)
aContext->Activate (myAIS, aSelectionMode, Standard_False);
}
}
}
ActivateSelectionMode();
}
if (IsDisplayed() && !aContext.IsNull())
@@ -1013,3 +989,40 @@ Handle(AIS_InteractiveContext) TPrsStd_AISPresentation::getAISContext() const
return Handle_AIS_InteractiveContext();
}
//=======================================================================
//function : ActivateSelectionMode
//purpose : Activates selection mode of the interactive object.
// It is called internally on change of selection mode and AISUpdate().
//=======================================================================
void TPrsStd_AISPresentation::ActivateSelectionMode()
{
if (!myAIS.IsNull() && HasOwnSelectionMode())
{
Handle(AIS_InteractiveContext) aContext = getAISContext();
if (!aContext.IsNull())
{
TColStd_ListOfInteger anActivatedModes;
aContext->ActivatedModes (myAIS, anActivatedModes);
Standard_Boolean isActivated = Standard_False;
Standard_Integer aSelectionMode = SelectionMode();
if (aSelectionMode == -1)
{
aContext->Deactivate(myAIS);
}
else
{
for (TColStd_ListIteratorOfListOfInteger aModeIter (anActivatedModes); aModeIter.More(); aModeIter.Next())
{
if (aModeIter.Value() == aSelectionMode)
{
isActivated = Standard_True;
break;
}
}
if (!isActivated)
aContext->Activate (myAIS, aSelectionMode, Standard_False);
}
}
}
}

View File

@@ -157,8 +157,13 @@ public:
Standard_EXPORT void UnsetMode();
Standard_EXPORT Standard_Integer SelectionMode() const;
Standard_EXPORT void SetSelectionMode (const Standard_Integer theSelectionMode);
//! Sets selection mode.
//! If "theTransaction" flag is OFF, modification of the attribute doesn't influence the transaction mechanism
//! (the attribute doesn't participate in undo/redo because of this modification).
//! Certainly, if any other data of the attribute is modified (display mode, color, ...),
//! the attribute will be included into undo/redo.
Standard_EXPORT void SetSelectionMode (const Standard_Integer theSelectionMode, const Standard_Boolean theTransaction = Standard_True);
Standard_EXPORT Standard_Boolean HasOwnSelectionMode() const;
@@ -197,6 +202,10 @@ protected:
private:
Handle(AIS_InteractiveContext) getAISContext() const;
//! Activates selection mode of the interactive object.
//! It is called internally on change of selection mode and AISUpdate().
void ActivateSelectionMode();
//! Updates AIS_InteractiveObject stored in the attribute
//! and applies the visualization settings
@@ -209,7 +218,6 @@ private:
//! the viewer; If <remove> = True then AISObject is removed
//! from AIS_InteractiveContext instead of simple erasing in the viewer
Standard_EXPORT void AISErase (const Standard_Boolean remove = Standard_False);
private:
Handle(AIS_InteractiveObject) myAIS;
};

View File

@@ -134,6 +134,7 @@ void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
TopoDS_Shape aTestedShape;
aTestedShape.TShape (aShape.TShape());
aTestedShape.Orientation (isReverse ? TopAbs_REVERSED : TopAbs_FORWARD);
Standard_Boolean isTessellate (Standard_False);
switch (ShapeType[i]) {
case TopAbs_FACE:
{
@@ -147,6 +148,16 @@ void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
break;
}
if (aTri.IsNull())
isTessellate = Standard_True;
// Check the existing deflection
else if (aTri->Deflection() > aDeflection+ Precision::Confusion())
isTessellate = Standard_True;
if (isTessellate) {
// Triangulate the face by the standard OCC mesher
BRepMesh_IncrementalMesh IM (aFace, aDeflection, Standard_False, theDeflAngle);
aTri = BRep_Tool::Triangulation (aFace, aLoc);
}
if (aTri.IsNull() == Standard_False) {
TopoDS_Shape aTestedShapeRev = aTestedShape;
aTestedShapeRev.Orientation (isReverse ?
@@ -179,6 +190,8 @@ void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
{
const TopoDS_Edge& aEdge = TopoDS::Edge (aShape);
if (aEdge.IsNull() == Standard_False) {
Handle(Poly_Polygon3D) aPol = BRep_Tool::Polygon3D (aEdge, aLoc);
if (aRelMap.IsBound (aTestedShape)) {
aTShapeNode = aRelMap(aTestedShape);
break;
@@ -191,34 +204,53 @@ void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
aTShapeNode = aRelMap(aTestedShape);
break;
}
if (aPol.IsNull())
isTessellate = Standard_True;
// Check the existing deflection
else if (aPol->Deflection() > aDeflection+ Precision::Confusion()
&& BRep_Tool::IsGeometric(aEdge))
isTessellate = Standard_True;
if (isTessellate && BRep_Tool::IsGeometric(aEdge)) {
//try to find PolygonOnTriangulation
Handle(Poly_PolygonOnTriangulation) aPT;
Handle(Poly_Triangulation) aT;
TopLoc_Location aL;
//try to find PolygonOnTriangulation
Handle(Poly_PolygonOnTriangulation) aPT;
Handle(Poly_Triangulation) aT;
TopLoc_Location aL;
BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL);
Standard_Boolean found = Standard_False;
Standard_Integer j = 1;
for (;;) {
BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL, j);
// If PolygonOnTriangulation was found -> get the Polygon3D
Handle(Poly_Polygon3D) aPol;
if(!aPT.IsNull() && !aT.IsNull() && aPT->HasParameters()) {
BRepAdaptor_Curve aCurve(aEdge);
Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters();
Standard_Integer nbNodes = aPT->NbNodes();
TColgp_Array1OfPnt arrNodes(1, nbNodes);
TColStd_Array1OfReal arrUVNodes(1, nbNodes);
if (aPT.IsNull() || aT.IsNull()) break;
for(Standard_Integer j = 1; j <= nbNodes; j++) {
arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1);
arrNodes(j) = aCurve.Value(arrUVNodes(j));
if (aPT->Deflection() <= aDeflection + Precision::Confusion()
&& aPT->HasParameters())
{
found = Standard_True;
break;
}
j++;
}
aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
aPol->Deflection (aPT->Deflection());
}
else {
aPol = BRep_Tool::Polygon3D(aEdge, aL);
if(found) {
// If polygon was not found -> generate it
if (aPol.IsNull()) {
BRepAdaptor_Curve aCurve(aEdge);
Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters();
Standard_Integer nbNodes = aPT->NbNodes();
TColgp_Array1OfPnt arrNodes(1, nbNodes);
TColStd_Array1OfReal arrUVNodes(1, nbNodes);
for(Standard_Integer j = 1; j <= nbNodes; j++) {
arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1);
arrNodes(j) = aCurve.Value(arrUVNodes(j));
}
aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
aPol->Deflection (aPT->Deflection());
}
else{
BRepAdaptor_Curve aCurve(aEdge);
const Standard_Real aFirst = aCurve.FirstParameter();
const Standard_Real aLast = aCurve.LastParameter();
@@ -236,11 +268,10 @@ void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
aPol->Deflection (aDeflection);
}
BRep_Builder aBld;
aBld.UpdateEdge (aEdge, aPol);
}
if (aPol.IsNull())
continue;
aTShapeNode = polToIndexedLineSet (aPol);
myScene.AddNode (aTShapeNode, Standard_False);
// Bind the converted face

View File

@@ -256,7 +256,10 @@ Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element& theElement,
if (isBound)
tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
else
{
tAtt = driver -> NewEmpty();
tAtt->SetID();
}
if (tAtt->Label().IsNull())
theLabel.AddAttribute (tAtt);
else

View File

@@ -24,6 +24,7 @@
#include <XmlObjMgt.hxx>
#include <XmlObjMgt_Document.hxx>
#include <XmlObjMgt_Persistent.hxx>
#include <XmlLDrivers.hxx>
IMPLEMENT_STANDARD_RTTIEXT(XmlMDataStd_ExtStringArrayDriver,XmlMDF_ADriver)
IMPLEMENT_DOMSTRING (FirstIndexString, "first")
@@ -238,39 +239,46 @@ void XmlMDataStd_ExtStringArrayDriver::Paste (const Handle(TDF_Attribute)& theSo
// Find a separator.
Standard_Boolean found(Standard_True);
// Preferrable symbols for the separator: - _ . : ^ ~
// Don't use a space as a separator: XML low-level parser sometimes "eats" it.
// This improvement was defined in the version 8.
// So, if the user wants to save the document under the 7th or earlier versions,
// don't apply this improvement.
Standard_Character c = '-';
static Standard_Character aPreferable[] = "-_.:^~";
for (i = 0; found && aPreferable[i]; i++)
if (XmlLDrivers::StorageVersion() > 7)
{
c = aPreferable[i];
found = Contains(aExtStringArray, TCollection_ExtendedString(c));
}
// If all prefferable symbols exist in the array,
// try to use any other simple symbols.
if (found)
{
c = '!';
while (found && c < '~')
// Preferrable symbols for the separator: - _ . : ^ ~
// Don't use a space as a separator: XML low-level parser sometimes "eats" it.
Standard_Character c = '-';
static Standard_Character aPreferable[] = "-_.:^~";
for (i = 0; found && aPreferable[i]; i++)
{
found = Standard_False;
#ifdef _DEBUG
TCollection_AsciiString cseparator(c); // deb
#endif
TCollection_ExtendedString separator(c);
found = Contains(aExtStringArray, separator);
if (found)
c = aPreferable[i];
found = Contains(aExtStringArray, TCollection_ExtendedString(c));
}
// If all prefferable symbols exist in the array,
// try to use any other simple symbols.
if (found)
{
c = '!';
while (found && c < '~')
{
c++;
// Skip forbidden symbols for XML.
while (c < '~' && (c == '&' || c == '<'))
found = Standard_False;
#ifdef _DEBUG
TCollection_AsciiString cseparator(c); // deb
#endif
TCollection_ExtendedString separator(c);
found = Contains(aExtStringArray, separator);
if (found)
{
c++;
// Skip forbidden symbols for XML.
while (c < '~' && (c == '&' || c == '<'))
{
c++;
}
}
}
}
}
}// check doc version
if (found)
{

View File

@@ -165,15 +165,19 @@ void math_NewtonMinimum::Perform(math_MultipleVarFunctionWithHessian& F,
Standard_Real aMult = RealLast();
for(Standard_Integer anIdx = 1; anIdx <= myLeft.Upper(); anIdx++)
{
const Standard_Real anAbsStep = Abs(TheStep(anIdx));
if (anAbsStep < gp::Resolution())
continue;
if (suivant->Value(anIdx) < myLeft(anIdx))
{
Standard_Real aValue = Abs(precedent->Value(anIdx) - myLeft(anIdx)) / Abs(TheStep(anIdx));
Standard_Real aValue = Abs(precedent->Value(anIdx) - myLeft(anIdx)) / anAbsStep;
aMult = Min (aValue, aMult);
}
if (suivant->Value(anIdx) > myRight(anIdx))
{
Standard_Real aValue = Abs(precedent->Value(anIdx) - myRight(anIdx)) / Abs(TheStep(anIdx));
Standard_Real aValue = Abs(precedent->Value(anIdx) - myRight(anIdx)) / anAbsStep;
aMult = Min (aValue, aMult);
}
}

View File

@@ -8,6 +8,8 @@ puts ""
# (case 11)
######################################################
puts "TODO 29663 ALL: Faulty shapes in variables faulty_1 to faulty_4"
restore [locate_data_file OCC1477-1.brep] s1
restore [locate_data_file OCC1477-2.brep] s2

View File

@@ -8,7 +8,7 @@ checkshape b
restore [locate_data_file pro19424b.brep] p
checkshape p
if [catch {evolved result b p o } catch_result] {
if [catch {evolved result -s b -p p -a } catch_result] {
puts "Faulty PRO19424 : function EVOLVED works wrongly"
} else {
puts "PRO19424 OK: function EVOLVED works properly"

View File

@@ -8,4 +8,4 @@ puts ""
restore [locate_data_file OCC26470-ClosedWire.brep] a
restore [locate_data_file OCC26470-wprof1.brep] b
evolved res a b o
evolved res -s a -p b -a

View File

@@ -8,5 +8,5 @@ puts ""
restore [locate_data_file OCC26470-ClosedWire.brep] a
restore [locate_data_file OCC26470-wprof2.brep] b
evolved res a b o
evolved res -s a -p b -a
checkshape res

View File

@@ -13,7 +13,8 @@ explode Box E
blend Fillet Box 1 Box_1 1 Box_2 1 Box_3 1 Box_4 1 Box_5 1 Box_6 1 Box_7 1 Box_8 1 Box_9 1 Box_10 1 Box_11 1 Box_12
if { [regexp "There were errors during the operation, so the list may be incomplete" [bopcheck Fillet]] == 1 } {
set bug_info [string trim [bopcheck Fillet]]
if {$bug_info != "This shape seems to be OK."} {
puts "Error : result of blend fails the bopcheck"
}

View File

@@ -0,0 +1,34 @@
puts "======="
puts "0029073"
puts "======="
puts ""
##################################################
# Regression: General Cut produces invalid shape
##################################################
brestore [locate_data_file bug29073_M6.brep] b1
brestore [locate_data_file bug29073_Shell.brep] b2
bclearobjects
bcleartools
baddobjects b1
baddtools b2
bfillds
# check the result of SECTION
bbop rsec 4
checknbshapes rsec -edge 1 -vertex 2
# check the result of GF
bbuild rgf
checkshape rgf
checkprops rgf -s 163.708 -v 115.912
checknbshapes rgf -wire 25 -face 24 -shell 3 -solid 1
# check the CUT
bbop result 3
checkshape result
checkprops result -s 0.000713987
checknbshapes result -wire 1 -face 1
checkview -display result -2d -path ${imagedir}/${test_image}.png

View File

@@ -0,0 +1,26 @@
puts "============"
puts "OCC29204"
puts "============"
puts ""
##################################################################################
# BRepOffsetAPI_MakePipeShell produces invalid result and raises exception in Draw
##################################################################################
restore [locate_data_file bug29204_sweep_spine.brep] sp
restore [locate_data_file bug29204_sweep_profile.brep] pr
mksweep sp
addsweep pr
buildsweep result -C -S
checkshape result
checknbshapes result -solid 1 -shell 1 -face 28 -wire 28 -edge 64 -vertex 36 -shape 158
set tolres [checkmaxtol result]
if { ${tolres} > 0.001} {
puts "Error: bad tolerance of result"
}
checkprops result -v 1.16577e+007

View File

@@ -0,0 +1,28 @@
puts "========"
puts "OCC29663"
puts "========"
puts ""
#################################################
# Exception in BRepFill_PipeShell algorithm
#################################################
restore [locate_data_file bug29523_cut_extrudewire08.brep] sw
restore [locate_data_file bug29523_cut_toolwire08.brep] tw
mksweep sw
addsweep tw
if { [catch {buildsweep rr -R} catch_result] } {
puts "Faulty OCC29663"
}
fixshape result rr
checkshape result
checkprops result -s 2.14316e+011
checkmaxtol result -ref 0.070055357229360987
checknbshapes result -shell 1 -face 201 -wire 201
checkview -display result -2d -path ${imagedir}/${test_image}.png

View File

@@ -10,7 +10,8 @@ puts ""
restore [locate_data_file bug25693_path3035.brep] result
if { [regexp "There were errors during the operation, so the list may be incomplete" [bopcheck result]] == 1 } {
set bug_info [string trim [bopcheck result]]
if {$bug_info != "This shape seems to be OK."} {
puts "Error : Wire of BSplines fails bopcheck"
}

View File

@@ -12,11 +12,13 @@ restore [locate_data_file bug25693_path3039.brep] path3039
prism Extrude_path3039 path3039 0 0 50
if { [regexp "There were errors during the operation, so the list may be incomplete" [bopcheck path3039]] == 1 } {
set log1 [string trim [bopcheck path3039]]
if {$log1 != "This shape seems to be OK."} {
puts "Error : bad shape"
}
if { [regexp "There were errors during the operation, so the list may be incomplete" [bopcheck Extrude_path3039]] == 1 } {
set log2 [string trim [bopcheck Extrude_path3039]]
if {$log2 != "This shape seems to be OK."} {
puts "Error : Wire of BSplines fails bopcheck"
}

13
tests/evolved/begin Normal file
View File

@@ -0,0 +1,13 @@
# To prevent loops limit to 10 minutes
cpulimit 60
if { [array get Draw_Groups "TOPOLOGY Feature commands"] == "" } {
pload TOPTEST
}
if { [info exists imagedir] == 0 } {
set imagedir .
}
if { [info exists test_image ] == 0 } {
set test_image photo
}

2
tests/evolved/end Normal file
View File

@@ -0,0 +1,2 @@
# to end a test script
puts "TEST COMPLETED"

View File

@@ -0,0 +1 @@
set subgroup evolved

View File

@@ -0,0 +1,11 @@
puts "========"
puts "OCC26470"
puts "========"
puts ""
##################################################
# BRepFill_Evolved: exception and invalid result
##################################################
restore [locate_data_file OCC26470-ClosedWire.brep] a
restore [locate_data_file OCC26470-wprof1.brep] b
evolved res -s a -p b -a

View File

@@ -0,0 +1,12 @@
puts "========"
puts "OCC26470"
puts "========"
puts ""
##################################################
# BRepFill_Evolved: exception and invalid result
##################################################
restore [locate_data_file OCC26470-ClosedWire.brep] a
restore [locate_data_file OCC26470-wprof2.brep] b
evolved res -s a -p b -a
checkshape res

Some files were not shown because too many files have changed in this diff Show More