Testing - Migration QADraw tests to GTests (#1235)

- Removed multiple legacy DRAW test scripts and several QABugs DRAW command implementations.
- Added new GTest suites covering the migrated regressions in ModelingData/ModelingAlgorithms/FoundationClasses/DataExchange/ApplicationFramework.
- Updated multiple `FILES.cmake` lists to compile/link the new tests; introduced an additional `STEPControl_Writer::SetShapeFixParameters()` overload.
This commit is contained in:
Pasukhin Dmitry
2026-04-26 12:22:37 +01:00
committed by GitHub
parent 133fd8e228
commit 0804c2b3f9
111 changed files with 6821 additions and 7255 deletions
@@ -507,3 +507,31 @@ TEST_F(TObj_ObjectTest, FindObject_ByName)
ASSERT_FALSE(aFound.IsNull());
EXPECT_EQ(anObj.get(), aFound.get());
}
// OCC31320: TObj - method TObj_Object::GetFatherObject() is not protected against deleted object
// After detaching a parent object, GetFatherObject() on its child must return null.
TEST_F(TObj_ObjectTest, OCC31320_GetFatherObject_ReturnsNull_AfterParentDetach)
{
// Create the parent object inside the model partition.
myModel->OpenCommand();
occ::handle<TObj_TestObject> aParent = createObject();
ASSERT_FALSE(aParent.IsNull());
myModel->CommitCommand();
// Create a child object on a sub-label of the parent's child collection.
myModel->OpenCommand();
TDF_Label aChildLabel = aParent->GetChildLabel().NewChild();
occ::handle<TObj_TestObject> aChild = new TObj_TestObject(aChildLabel);
ASSERT_FALSE(aChild.IsNull());
myModel->CommitCommand();
// Detach the parent - this is what the original bug was about.
myModel->OpenCommand();
EXPECT_TRUE(aParent->Detach());
myModel->CommitCommand();
// After the parent is detached its TObj attributes are gone,
// so GetFatherObject() traversing up must return null, not crash.
occ::handle<TObj_Object> aFather = aChild->GetFatherObject();
EXPECT_TRUE(aFather.IsNull());
}
@@ -16,4 +16,5 @@ set(OCCT_TKDESTEP_GTests_FILES
StepTidy_VectorReducer_Test.cxx
StepToTopoDS_TranslateFace_Test.cxx
StepTransientReplacements_Test.cxx
STEPCAFControl_Controller_Test.cxx
)
@@ -0,0 +1,308 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <atomic>
#include <sstream>
#include <BRep_Tool.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <NCollection_Sequence.hxx>
#include <TDF_Label.hxx>
#include <DESTEP_Parameters.hxx>
#include <OSD_Parallel.hxx>
#include <Precision.hxx>
#include <Quantity_Color.hxx>
#include <ShapeAnalysis_ShapeContents.hxx>
#include <STEPCAFControl_Controller.hxx>
#include <STEPCAFControl_Reader.hxx>
#include <STEPCAFControl_Writer.hxx>
#include <STEPControl_Reader.hxx>
#include <STEPControl_StepModelType.hxx>
#include <STEPControl_Writer.hxx>
#include <TDataStd_Name.hxx>
#include <TDocStd_Document.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <XCAFDoc_ColorTool.hxx>
#include <XCAFDoc_DocumentTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <gp_Pnt.hxx>
#include <gp_Trsf.hxx>
// Test OCC33657 (case 1): STEPCAFControl_Reader and STEPCAFControl_Writer constructors
// can be created and destroyed in parallel without crashing.
TEST(STEPCAFControl_ControllerTest, OCC33657_ParallelConstructors)
{
STEPCAFControl_Controller::Init();
EXPECT_NO_FATAL_FAILURE(OSD_Parallel::For(0, 1000, [](int) {
STEPCAFControl_Reader aReader;
aReader.SetColorMode(true);
STEPCAFControl_Writer aWriter;
aWriter.SetDimTolMode(true);
}));
}
// Test OCC33657 (case 3): STEPControl_Writer can write in parallel to in-memory buffers.
// Each thread creates its own shape and writer to avoid shared-state issues.
TEST(STEPCAFControl_ControllerTest, OCC33657_ParallelWritersToBuffer)
{
STEPCAFControl_Controller::Init();
std::atomic<bool> allOk{true};
EXPECT_NO_FATAL_FAILURE(OSD_Parallel::For(0, 100, [&](int) {
const TopoDS_Shape aShape = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape();
STEPControl_Writer aWriter;
aWriter.SetShapeFixParameters(DESTEP_Parameters::GetDefaultShapeFixParameters());
aWriter.Transfer(aShape, STEPControl_StepModelType::STEPControl_AsIs, DESTEP_Parameters{});
std::ostringstream aStream;
aWriter.WriteStream(aStream);
if (aStream.str().empty())
allOk = false;
}));
EXPECT_TRUE(allOk);
}
// Test OCC33657 (case 2): STEPControl_Reader can read a STEP stream in parallel without crashing.
TEST(STEPCAFControl_ControllerTest, OCC33657_ParallelReadersFromStream)
{
STEPCAFControl_Controller::Init();
// Write a box to a STEP stream once, then read it in parallel.
const TopoDS_Shape aShape = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape();
STEPControl_Writer aWriter;
aWriter.Transfer(aShape, STEPControl_StepModelType::STEPControl_AsIs, DESTEP_Parameters{});
std::ostringstream anOutStream;
aWriter.WriteStream(anOutStream);
const std::string aStepContent = anOutStream.str();
ASSERT_FALSE(aStepContent.empty()) << "STEP content should not be empty";
EXPECT_NO_FATAL_FAILURE(OSD_Parallel::For(0, 100, [&](int) {
std::istringstream anInStream(aStepContent);
STEPControl_Reader aReader;
aReader.ReadStream("", DESTEP_Parameters{}, anInStream);
aReader.TransferRoots();
}));
}
// Test OCC33657 (case 4): STEPControl_Writer and STEPControl_Reader work in parallel
// and produce a shape with the same topology as the source.
TEST(STEPCAFControl_ControllerTest, OCC33657_ParallelReadersAndWriters)
{
STEPCAFControl_Controller::Init();
// Acquire source shape and analyze its topology.
const TopoDS_Shape aSourceShape = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape();
ShapeAnalysis_ShapeContents aSourceAnalyzer;
aSourceAnalyzer.Perform(aSourceShape);
std::atomic<bool> allOk{true};
EXPECT_NO_FATAL_FAILURE(OSD_Parallel::For(0, 100, [&](int) {
if (!allOk.load(std::memory_order_relaxed))
return;
// Write source shape to a per-thread stream.
STEPControl_Writer aWriter;
aWriter.Transfer(aSourceShape,
STEPControl_StepModelType::STEPControl_AsIs,
DESTEP_Parameters{});
std::ostringstream anOutStream;
aWriter.WriteStream(anOutStream);
// Read it back and compare topology counts.
std::istringstream anInStream(anOutStream.str());
STEPControl_Reader aReader;
aReader.ReadStream("", DESTEP_Parameters{}, anInStream);
aReader.TransferRoots();
const TopoDS_Shape aResultShape = aReader.OneShape();
ShapeAnalysis_ShapeContents aResultAnalyzer;
aResultAnalyzer.Perform(aResultShape);
if (aSourceAnalyzer.NbSolids() != aResultAnalyzer.NbSolids()
|| aSourceAnalyzer.NbShells() != aResultAnalyzer.NbShells()
|| aSourceAnalyzer.NbFaces() != aResultAnalyzer.NbFaces()
|| aSourceAnalyzer.NbWires() != aResultAnalyzer.NbWires()
|| aSourceAnalyzer.NbEdges() != aResultAnalyzer.NbEdges()
|| aSourceAnalyzer.NbVertices() != aResultAnalyzer.NbVertices())
{
allOk.store(false, std::memory_order_relaxed);
}
}));
EXPECT_TRUE(allOk);
}
// Test OCC23951: STEPCAFControl_Writer can write an XCAF document with a box
// whose visibility is set to false. Verifies the write completes successfully.
TEST(STEPCAFControl_ControllerTest, OCC23951_WriteDocumentWithVisibility)
{
STEPCAFControl_Controller::Init();
occ::handle<TDocStd_Document> aDoc = new TDocStd_Document("dummy");
const TopoDS_Shape aBox = BRepPrimAPI_MakeBox(1, 1, 1).Shape();
occ::handle<XCAFDoc_ShapeTool> aShapeTool = XCAFDoc_DocumentTool::ShapeTool(aDoc->Main());
TDF_Label aLab1 = aShapeTool->NewShape();
aShapeTool->SetShape(aLab1, aBox);
TDataStd_Name::Set(aLab1, "Box1");
Quantity_Color aYellow(Quantity_NOC_YELLOW);
XCAFDoc_DocumentTool::ColorTool(aDoc->Main())->SetColor(aLab1, aYellow, XCAFDoc_ColorGen);
XCAFDoc_DocumentTool::ColorTool(aDoc->Main())->SetVisibility(aLab1, false);
STEPCAFControl_Writer aWriter;
ASSERT_TRUE(aWriter.Transfer(aDoc)) << "Transfer failed";
std::ostringstream aStream;
const IFSelect_ReturnStatus aStatus = aWriter.WriteStream(aStream);
EXPECT_EQ(aStatus, IFSelect_RetDone) << "WriteStream did not return RetDone";
EXPECT_FALSE(aStream.str().empty()) << "Written STEP stream should not be empty";
// Verify yellow color and INVISIBILITY entity are encoded in the STEP stream.
// STEP writes predefined colors using DRAUGHTING_PRE_DEFINED_COLOUR, not COLOUR_RGB.
const std::string aContent = aStream.str();
EXPECT_NE(aContent.find("DRAUGHTING_PRE_DEFINED_COLOUR('yellow')"), std::string::npos)
<< "Yellow DRAUGHTING_PRE_DEFINED_COLOUR entity not found in STEP stream";
EXPECT_NE(aContent.find("INVISIBILITY"), std::string::npos)
<< "INVISIBILITY entity not found in STEP stream";
// Read back the written stream into an XCAF document and verify shape topology.
std::istringstream anInStream(aContent);
occ::handle<TDocStd_Document> aReadDoc = new TDocStd_Document("dummy");
STEPCAFControl_Reader aCafReader;
aCafReader.SetColorMode(true);
ASSERT_EQ(aCafReader.ReadStream("", anInStream), IFSelect_RetDone)
<< "ReadStream failed on written STEP content";
ASSERT_TRUE(aCafReader.Transfer(aReadDoc)) << "Transfer to XCAF document failed";
occ::handle<XCAFDoc_ShapeTool> aReadShapeTool = XCAFDoc_DocumentTool::ShapeTool(aReadDoc->Main());
NCollection_Sequence<TDF_Label> aRoots;
aReadShapeTool->GetFreeShapes(aRoots);
ASSERT_FALSE(aRoots.IsEmpty()) << "No shapes in read-back document";
const TopoDS_Shape aResult = aReadShapeTool->GetShape(aRoots.First());
ASSERT_FALSE(aResult.IsNull()) << "Read-back shape should not be null";
ShapeAnalysis_ShapeContents aSourceAnalyzer;
aSourceAnalyzer.Perform(aBox);
ShapeAnalysis_ShapeContents aResultAnalyzer;
aResultAnalyzer.Perform(aResult);
EXPECT_EQ(aResultAnalyzer.NbSolids(), aSourceAnalyzer.NbSolids()) << "Solid count mismatch";
EXPECT_EQ(aResultAnalyzer.NbFaces(), aSourceAnalyzer.NbFaces()) << "Face count mismatch";
EXPECT_EQ(aResultAnalyzer.NbEdges(), aSourceAnalyzer.NbEdges()) << "Edge count mismatch";
EXPECT_EQ(aResultAnalyzer.NbVertices(), aSourceAnalyzer.NbVertices()) << "Vertex count mismatch";
// Verify yellow color is present on faces of the read-back shape.
occ::handle<XCAFDoc_ColorTool> aColorTool = XCAFDoc_DocumentTool::ColorTool(aReadDoc->Main());
bool aFoundColor = false;
Quantity_Color aReadColor;
for (TopExp_Explorer anFaceExp(aResult, TopAbs_FACE); anFaceExp.More(); anFaceExp.Next())
{
if (aColorTool->GetColor(anFaceExp.Current(), XCAFDoc_ColorSurf, aReadColor)
|| aColorTool->GetColor(anFaceExp.Current(), XCAFDoc_ColorGen, aReadColor))
{
aFoundColor = true;
break;
}
}
if (!aFoundColor)
{
// If not found on faces, try on the solid shape itself
aFoundColor = aColorTool->GetColor(aResult, XCAFDoc_ColorGen, aReadColor)
|| aColorTool->GetColor(aResult, XCAFDoc_ColorSurf, aReadColor);
}
EXPECT_TRUE(aFoundColor) << "Yellow color not found on read-back shape";
if (aFoundColor)
{
EXPECT_NEAR(aReadColor.Red(), aYellow.Red(), 0.05) << "Color red channel mismatch";
EXPECT_NEAR(aReadColor.Green(), aYellow.Green(), 0.05) << "Color green channel mismatch";
EXPECT_NEAR(aReadColor.Blue(), aYellow.Blue(), 0.05) << "Color blue channel mismatch";
}
}
// Test OCC23950: STEPCAFControl_Writer writes vertex names when vertex mode is SingleVertex.
// Verifies that the STEP stream contains the expected "Point1" name.
TEST(STEPCAFControl_ControllerTest, OCC23950_WriteDocumentWithVertexName)
{
STEPCAFControl_Controller::Init();
occ::handle<TDocStd_Document> aDoc = new TDocStd_Document("dummy");
const TopoDS_Shape aVertex = BRepBuilderAPI_MakeVertex(gp_Pnt(75, 0, 0));
const gp_Trsf aTrsf;
const TopLoc_Location aLoc(aTrsf);
occ::handle<XCAFDoc_ShapeTool> aShapeTool = XCAFDoc_DocumentTool::ShapeTool(aDoc->Main());
TDF_Label aLab1 = aShapeTool->NewShape();
aShapeTool->SetShape(aLab1, aVertex);
TDataStd_Name::Set(aLab1, "Point1");
TDF_Label aAssemblyLabel = aShapeTool->NewShape();
TDataStd_Name::Set(aAssemblyLabel, "ASSEMBLY");
const TDF_Label aComponentLabel = aShapeTool->AddComponent(aAssemblyLabel, aLab1, aLoc);
aShapeTool->UpdateAssemblies();
Quantity_Color aYellow(Quantity_NOC_YELLOW);
XCAFDoc_DocumentTool::ColorTool(aDoc->Main())
->SetColor(aComponentLabel, aYellow, XCAFDoc_ColorGen);
XCAFDoc_DocumentTool::ColorTool(aDoc->Main())->SetVisibility(aComponentLabel, false);
// Enable writing of individual vertex names
DESTEP_Parameters aParams;
aParams.WriteVertexMode = DESTEP_Parameters::WriteMode_VertexMode_SingleVertex;
STEPCAFControl_Writer aWriter;
ASSERT_TRUE(aWriter.Transfer(aDoc, aParams)) << "Transfer failed";
std::ostringstream aStream;
const IFSelect_ReturnStatus aStatus = aWriter.WriteStream(aStream);
ASSERT_EQ(aStatus, IFSelect_RetDone) << "WriteStream did not return RetDone";
const std::string aContent = aStream.str();
EXPECT_FALSE(aContent.empty()) << "Written STEP stream should not be empty";
EXPECT_NE(aContent.find("Point1"), std::string::npos)
<< "Vertex name 'Point1' not found in STEP stream";
// Verify yellow color and INVISIBILITY entity are encoded in the STEP stream.
// STEP writes predefined colors using DRAUGHTING_PRE_DEFINED_COLOUR, not COLOUR_RGB.
EXPECT_NE(aContent.find("DRAUGHTING_PRE_DEFINED_COLOUR('yellow')"), std::string::npos)
<< "Yellow DRAUGHTING_PRE_DEFINED_COLOUR entity not found in STEP stream";
EXPECT_NE(aContent.find("INVISIBILITY"), std::string::npos)
<< "INVISIBILITY entity not found in STEP stream";
// Read back the written stream into an XCAF document and verify vertex position.
std::istringstream anInStream(aContent);
occ::handle<TDocStd_Document> aReadDoc = new TDocStd_Document("dummy");
STEPCAFControl_Reader aCafReader;
aCafReader.SetColorMode(true);
ASSERT_EQ(aCafReader.ReadStream("", anInStream), IFSelect_RetDone)
<< "ReadStream failed on written STEP content";
ASSERT_TRUE(aCafReader.Transfer(aReadDoc)) << "Transfer to XCAF document failed";
occ::handle<XCAFDoc_ShapeTool> aReadShapeTool = XCAFDoc_DocumentTool::ShapeTool(aReadDoc->Main());
NCollection_Sequence<TDF_Label> aRoots;
aReadShapeTool->GetFreeShapes(aRoots);
ASSERT_FALSE(aRoots.IsEmpty()) << "No shapes in read-back document";
const TopoDS_Shape aRootShape = aReadShapeTool->GetShape(aRoots.First());
ASSERT_FALSE(aRootShape.IsNull()) << "Read-back shape should not be null";
TopExp_Explorer anExp(aRootShape, TopAbs_VERTEX);
ASSERT_TRUE(anExp.More()) << "No vertex found in read-back shape";
const gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
EXPECT_NEAR(aPnt.X(), 75.0, Precision::Confusion()) << "Vertex X coordinate mismatch";
EXPECT_NEAR(aPnt.Y(), 0.0, Precision::Confusion()) << "Vertex Y coordinate mismatch";
EXPECT_NEAR(aPnt.Z(), 0.0, Precision::Confusion()) << "Vertex Z coordinate mismatch";
}
@@ -228,6 +228,17 @@ void STEPControl_Writer::SetShapeFixParameters(XSAlgo_ShapeProcessor::ParameterM
//=============================================================================
void STEPControl_Writer::SetShapeFixParameters(const DE_ShapeFixParameters& theParameters)
{
XSAlgo_ShapeProcessor::ParameterMap anAdditionalParameters;
if (occ::handle<Transfer_ActorOfFinderProcess> anActor = GetActor())
{
anActor->SetShapeFixParameters(theParameters, anAdditionalParameters);
}
}
//=============================================================================
void STEPControl_Writer::SetShapeFixParameters(
const DE_ShapeFixParameters& theParameters,
const XSAlgo_ShapeProcessor::ParameterMap& theAdditionalParameters)
@@ -142,6 +142,11 @@ public:
//! @param theParameters the parameters for shape processing.
Standard_EXPORT void SetShapeFixParameters(XSAlgo_ShapeProcessor::ParameterMap&& theParameters);
//! Sets parameters for shape processing.
//! Parameters from @p theParameters are converted and stored in the internal map.
//! @param theParameters the parameters for shape processing.
Standard_EXPORT void SetShapeFixParameters(const DE_ShapeFixParameters& theParameters);
//! Sets parameters for shape processing.
//! Parameters from @p theParameters are copied to the internal map.
//! Parameters from @p theAdditionalParameters are copied to the internal map
@@ -150,7 +155,7 @@ public:
//! @param theAdditionalParameters the additional parameters for shape processing.
Standard_EXPORT void SetShapeFixParameters(
const DE_ShapeFixParameters& theParameters,
const XSAlgo_ShapeProcessor::ParameterMap& theAdditionalParameters = {});
const XSAlgo_ShapeProcessor::ParameterMap& theAdditionalParameters);
//! Returns parameters for shape processing that was set by SetParameters() method.
//! @return the parameters for shape processing. Empty map if no parameters were set.
-1
View File
@@ -14,7 +14,6 @@ set(OCCT_QABugs_FILES
QABugs_9.cxx
QABugs_10.cxx
QABugs_11.cxx
QABugs_12.cxx
QABugs_13.cxx
QABugs_14.cxx
QABugs_16.cxx
-1
View File
@@ -27,7 +27,6 @@ void QABugs::Commands(Draw_Interpretor& theCommands)
QABugs::Commands_9(theCommands);
QABugs::Commands_10(theCommands);
QABugs::Commands_11(theCommands);
QABugs::Commands_12(theCommands);
QABugs::Commands_13(theCommands);
QABugs::Commands_14(theCommands);
QABugs::Commands_16(theCommands);
-2
View File
@@ -49,8 +49,6 @@ public:
Standard_EXPORT static void Commands_11(Draw_Interpretor& DI);
Standard_EXPORT static void Commands_12(Draw_Interpretor& DI);
Standard_EXPORT static void Commands_13(Draw_Interpretor& DI);
Standard_EXPORT static void Commands_14(Draw_Interpretor& DI);
+2 -426
View File
@@ -29,8 +29,6 @@
#include <gp_Ax1.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <TopExp_Explorer.hxx>
@@ -39,10 +37,11 @@
#include <BRep_Tool.hxx>
#include <Poly_Triangulation.hxx>
#include <TopExp.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Geom_BSplineSurface.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <ShapeUpgrade_UnifySameDomain.hxx>
static int OCC426(Draw_Interpretor& di, int argc, const char** argv)
@@ -478,247 +477,24 @@ int performTriangulation(const TopoDS_Shape& aShape, Draw_Interpretor& di)
return 0;
}
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepAlgoAPI_Cut.hxx>
//=================================================================================================
static int OCC822_1(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
{
di << "Usage : " << argv[0] << " name1 name2 result\n";
return 1;
}
int index = 1;
gp_Pnt P1(0, 0, 0);
gp_Dir D1(gp_Dir::D::Z);
gp_Ax2 A1(P1, D1);
BRepPrimAPI_MakeCylinder cylMakerIn(A1, 40, 110);
BRepPrimAPI_MakeCylinder cylMakerOut(A1, 50, 100);
TopoDS_Shape cylIn = cylMakerIn.Shape();
TopoDS_Shape cylOut = cylMakerOut.Shape();
gp_Pnt P2(0, 0, 0);
gp_Dir D2(gp_Dir::D::NZ);
gp_Ax2 A2(P2, D2);
BRepPrimAPI_MakeCone conMakerIn(A2, 40, 60, 110);
BRepPrimAPI_MakeCone conMakerOut(A2, 50, 70, 100);
TopoDS_Shape conIn = conMakerIn.Shape();
TopoDS_Shape conOut = conMakerOut.Shape();
di << "All primitives created..... Creating Boolean\n";
try
{
OCC_CATCH_SIGNALS
di << "theIn = BRepAlgoAPI_Fuse(cylIn, conIn)\n";
di << "theOut = BRepAlgoAPI_Fuse(cylOut, conOut)\n";
di << "theRes = BRepAlgoAPI_Cut(theOut, theIn)\n";
TopoDS_Shape theIn = BRepAlgoAPI_Fuse(cylIn, conIn).Shape();
TopoDS_Shape theOut = BRepAlgoAPI_Fuse(cylOut, conOut).Shape();
TopoDS_Shape theRes = BRepAlgoAPI_Cut(theOut, theIn).Shape();
if (index < argc)
DBRep::Set(argv[index++], theIn);
if (index < argc)
DBRep::Set(argv[index++], theOut);
if (index < argc)
DBRep::Set(argv[index++], theRes);
di << "Booleans Created ! Triangulating !\n";
performTriangulation(theRes, di);
}
catch (Standard_Failure const&)
{
di << "*********************************************************\n";
di << "***** ******\n";
di << "***** Standard_Failure : Exception in Shoe Function *****\n";
di << "***** ******\n";
di << "*********************************************************\n";
return 1;
}
return 0;
}
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
//=======================================================================
// OCC822_2
//=======================================================================
static int OCC822_2(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
{
di << "Usage : " << argv[0] << " name1 name2 result\n";
return 1;
}
int index = 1;
gp_Dir xDir(gp_Dir::D::X);
gp_Dir zDir(gp_Dir::D::Z);
gp_Pnt cen1(0, 0, 0);
gp_Ax2 cor1(cen1, zDir, xDir);
BRepPrimAPI_MakeBox boxMaker(cor1, 100, 100, 100);
TopoDS_Shape box = boxMaker.Shape();
if (index < argc)
DBRep::Set(argv[index++], box);
BRepPrimAPI_MakeSphere sphereMaker(gp_Pnt(100.0, 50.0, 50.0), 25.0);
TopoDS_Shape sph = sphereMaker.Shape();
if (index < argc)
DBRep::Set(argv[index++], sph);
di << "All primitives created..... Creating Cut Objects\n";
try
{
OCC_CATCH_SIGNALS
di << "fuse = BRepAlgoAPI_Fuse(box, sph)\n";
TopoDS_Shape fuse = BRepAlgoAPI_Fuse(box, sph).Shape();
if (index < argc)
DBRep::Set(argv[index++], fuse);
di << "Object Created ! Now Triangulating !";
performTriangulation(fuse, di);
}
catch (Standard_Failure const&)
{
di << "*********************************************************\n";
di << "***** ******\n";
di << "***** Standard_Failure : Exception in HSP Function ******\n";
di << "***** ******\n";
di << "*********************************************************\n";
return 1;
}
return 0;
}
//=======================================================================
// OCC823
//=======================================================================
static int OCC823(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
{
di << "Usage : " << argv[0] << " name1 name2 result\n";
return 1;
}
int index = 1;
double size = 0.001;
gp_Pnt P1(40, 50, 0);
gp_Dir D1(100, 0, 0);
gp_Ax2 A1(P1, D1);
BRepPrimAPI_MakeCylinder mkCyl1(A1, 20, 100);
TopoDS_Shape cyl1 = mkCyl1.Shape();
if (index < argc)
DBRep::Set(argv[index++], cyl1);
gp_Pnt P2(100, 50, size);
gp_Dir D2(0, size, 80);
gp_Ax2 A2(P2, D2);
BRepPrimAPI_MakeCylinder mkCyl2(A2, 20, 80);
TopoDS_Shape cyl2 = mkCyl2.Shape();
if (index < argc)
DBRep::Set(argv[index++], cyl2);
di << "All primitives created..... Creating Boolean\n";
try
{
OCC_CATCH_SIGNALS
di << "fuse = BRepAlgoAPI_Fuse(cyl2, cyl1)\n";
TopoDS_Shape fuse = BRepAlgoAPI_Fuse(cyl2, cyl1).Shape();
if (index < argc)
DBRep::Set(argv[index++], fuse);
di << "Fuse Created ! Triangulating !\n";
performTriangulation(fuse, di);
}
catch (Standard_Failure const&)
{
di << "*********************************************************\n";
di << "***** ******\n";
di << "***** Standard_Failure : Exception in TEE Function ******\n";
di << "***** ******\n";
di << "*********************************************************\n";
return 1;
}
return 0;
}
//=======================================================================
// OCC824
//=======================================================================
static int OCC824(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
{
di << "Usage : " << argv[0] << " name1 name2 result\n";
return 1;
}
int index = 1;
gp_Pnt P1(100, 0, 0);
gp_Dir D1(gp_Dir::D::NX);
gp_Ax2 A1(P1, D1);
BRepPrimAPI_MakeCylinder mkCyl(A1, 20, 100);
TopoDS_Shape cyl = mkCyl.Shape();
if (index < argc)
DBRep::Set(argv[index++], cyl);
BRepPrimAPI_MakeSphere sphere(P1, 20.0);
TopoDS_Shape sph = sphere.Shape();
if (index < argc)
DBRep::Set(argv[index++], sph);
di << "All primitives created..... Creating Boolean\n";
try
{
OCC_CATCH_SIGNALS
di << "fuse = BRepAlgoAPI_Fuse(cyl, sph)\n";
TopoDS_Shape fuse = BRepAlgoAPI_Fuse(cyl, sph).Shape();
di << "Fuse Created ! Triangulating !\n";
if (index < argc)
DBRep::Set(argv[index++], fuse);
performTriangulation(fuse, di);
}
catch (Standard_Failure const&)
{
di << "*********************************************************\n";
di << "***** ******\n";
di << "***** Standard_Failure : Exception in YOU Function ******\n";
di << "***** ******\n";
di << "*********************************************************\n";
return 1;
}
return 0;
}
#include <NCollection_Array2.hxx>
#include <GeomConvert.hxx>
#include <Geom_BezierSurface.hxx>
@@ -822,206 +598,12 @@ static int OCC825(Draw_Interpretor& di, int argc, const char** argv)
// OCC826
//=======================================================================
static int OCC826(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
{
di << "Usage : " << argv[0] << " name1 name2 result\n";
return 1;
}
int index = 1;
double x1 = 181.82808;
double x2 = 202.39390;
double y1 = 31.011970;
double y2 = 123.06856;
BRepBuilderAPI_MakePolygon W1;
W1.Add(gp_Pnt(x1, y1, 0));
W1.Add(gp_Pnt(x2, y1, 0));
W1.Add(gp_Pnt(x2, y2, 0));
W1.Add(gp_Pnt(x1, y2, 0));
W1.Add(gp_Pnt(x1, y1, 0));
bool myFalse = false;
TopoDS_Face F1 = BRepBuilderAPI_MakeFace(W1.Wire(), myFalse);
gp_Pnt P1(0, 0, 0);
gp_Dir D1(0, 30, 0);
gp_Ax1 A1(P1, D1);
double angle1 = 360 * (M_PI / 180.0);
TopoDS_Shape rev = BRepPrimAPI_MakeRevol(F1, A1, angle1);
if (index < argc)
DBRep::Set(argv[index++], rev);
BRepPrimAPI_MakeSphere sphere(gp_Pnt(166.373, 77.0402, 96.0555), 23.218586);
TopoDS_Shape sph = sphere.Shape();
if (index < argc)
DBRep::Set(argv[index++], sph);
di << "All primitives created..... Creating Boolean\n";
try
{
OCC_CATCH_SIGNALS
di << "fuse = BRepAlgoAPI_Fuse(rev, sph)\n";
TopoDS_Shape fuse = BRepAlgoAPI_Fuse(rev, sph).Shape();
if (index < argc)
DBRep::Set(argv[index++], fuse);
di << "Fuse Created ! Triangulating !\n";
performTriangulation(fuse, di);
}
catch (Standard_Failure const&)
{
di << "*********************************************************\n";
di << "***** ******\n";
di << "***** Standard_Failure : Exception in SPH Function ******\n";
di << "***** ******\n";
di << "*********************************************************\n";
return 1;
}
return 0;
}
#include <BRepPrimAPI_MakeTorus.hxx>
//=======================================================================
// OCC827
//=======================================================================
static int OCC827(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 6)
{
di << "Usage : " << argv[0] << " name1 name2 name3 result1 result2\n";
return 1;
}
int index = 1;
BRepBuilderAPI_MakePolygon W1;
W1.Add(gp_Pnt(10, 0, 0));
W1.Add(gp_Pnt(20, 0, 0));
W1.Add(gp_Pnt(20, 0, 50));
W1.Add(gp_Pnt(10, 0, 50));
W1.Add(gp_Pnt(10, 0, 0));
bool myFalse = false;
TopoDS_Face F1 = BRepBuilderAPI_MakeFace(W1.Wire(), myFalse);
gp_Pnt P1(0, 0, 0);
gp_Dir D1(0, 0, 30);
gp_Ax1 A1(P1, D1);
double angle1 = 360 * (M_PI / 180.0);
TopoDS_Shape rev = BRepPrimAPI_MakeRevol(F1, A1, angle1);
if (index < argc)
DBRep::Set(argv[index++], rev);
gp_Pnt P2(0, 0, 50);
gp_Dir D2(0, 0, 30);
gp_Ax2 A2(P2, D2);
double majRad = 15;
double minRad = 5;
BRepPrimAPI_MakeTorus Torus1(A2, majRad, minRad);
TopoDS_Shape tor1 = Torus1.Shape();
if (index < argc)
DBRep::Set(argv[index++], tor1);
gp_Pnt P3(0, 0, 10);
gp_Dir D3(0, 0, 30);
gp_Ax2 A3(P3, D3);
BRepPrimAPI_MakeTorus Torus2(A3, majRad, minRad);
TopoDS_Shape tor2 = Torus2.Shape();
if (index < argc)
DBRep::Set(argv[index++], tor2);
di << "All primitives created..... Creating Boolean\n";
try
{
OCC_CATCH_SIGNALS
di << "Fuse1 = BRepAlgoAPI_Fuse(tor1, rev)\n";
TopoDS_Shape fuse1 = BRepAlgoAPI_Fuse(tor1, rev).Shape();
if (index < argc)
DBRep::Set(argv[index++], fuse1);
di << "Fuse1 Created ! Creating Fuse 2\n";
di << "Fuse2 = BRepAlgoAPI_Fuse(tor2, fuse1)\n";
TopoDS_Shape fuse2 = BRepAlgoAPI_Fuse(tor2, fuse1).Shape();
if (index < argc)
DBRep::Set(argv[index++], fuse2);
di << "Fuse2 Created ! Triangulating !\n";
performTriangulation(fuse2, di);
}
catch (Standard_Failure const&)
{
di << "*********************************************************\n";
di << "***** ******\n";
di << "***** Standard_Failure : Exception in REV Function ******\n";
di << "***** ******\n";
di << "*********************************************************\n";
return 1;
}
return 0;
}
//=======================================================================
// performBlend
//=======================================================================
int performBlend(const TopoDS_Shape& aShape, double rad, TopoDS_Shape& bShape, Draw_Interpretor& di)
{
int status = 0;
TopoDS_Shape newShape;
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
edgemap;
TopExp::MapShapesAndAncestors(aShape, TopAbs_EDGE, TopAbs_SOLID, edgemap);
di << "Blending All Edges: No. of Edges: " << edgemap.Extent() << "\n";
ChFi3d_FilletShape FShape = ChFi3d_Rational;
BRepFilletAPI_MakeFillet blend(aShape, FShape);
for (int i = 1; i <= edgemap.Extent(); i++)
{
TopoDS_Edge edg = TopoDS::Edge(edgemap.FindKey(i));
if (!edg.IsNull())
blend.Add(rad, edg);
}
try
{
OCC_CATCH_SIGNALS
blend.Build();
if (!blend.HasResult() || blend.Shape().IsNull())
{
status = 1;
}
}
catch (Standard_Failure const&)
{
status = 1;
}
if (status)
{
di << "*******************************************************\n";
di << "****** *******\n";
di << "****** Blending Failed (Radius = " << rad << ") *******\n";
di << "****** *******\n";
di << "*******************************************************\n";
return 1;
}
else
{
di << "Blending successfully performed on all Edges: \n\n";
}
bShape = blend.Shape();
return 0;
}
#include <GC_MakeSegment.hxx>
@@ -1138,13 +720,7 @@ void QABugs::Commands_10(Draw_Interpretor& theCommands)
group);
theCommands.Add("OCC486", "Use : OCC486 surf x y z du dv ", __FILE__, OCC486, group);
theCommands.Add("OCC712", "OCC712 draftAngle slabThick", __FILE__, OCC712, group);
theCommands.Add("OCC822_1", "OCC822_1 name1 name2 result", __FILE__, OCC822_1, group);
theCommands.Add("OCC822_2", "OCC822_2 name1 name2 result", __FILE__, OCC822_2, group);
theCommands.Add("OCC823", "OCC823 name1 name2 result", __FILE__, OCC823, group);
theCommands.Add("OCC824", "OCC824 name1 name2 result", __FILE__, OCC824, group);
theCommands.Add("OCC825", "OCC825 name1 name2 name3 name4 name5", __FILE__, OCC825, group);
theCommands.Add("OCC826", "OCC826 name1 name2 result", __FILE__, OCC826, group);
theCommands.Add("OCC827", "OCC827 name1 name2 name3 result1 result2", __FILE__, OCC827, group);
theCommands.Add("OCC828", "OCC828 redius shape result ", __FILE__, OCC828, group);
return;
-224
View File
@@ -1252,63 +1252,6 @@ static int OCC369(Draw_Interpretor& di, int argc, const char** argv)
#include <math_Matrix.hxx>
#include <math_Vector.hxx>
static int OCC524(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 9)
{
di << "Usage : " << argv[0]
<< " LowerVector UpperVector InitialValueVector LowerRowMatrix UpperRowMatrix "
"LowerColMatrix UpperColMatrix InitialValueMatrix\n";
return 1;
}
int LowerVector = Draw::Atoi(argv[1]);
int UpperVector = Draw::Atoi(argv[2]);
double InitialValueVector = Draw::Atof(argv[3]);
int LowerRowMatrix = Draw::Atoi(argv[4]);
int UpperRowMatrix = Draw::Atoi(argv[5]);
int LowerColMatrix = Draw::Atoi(argv[6]);
int UpperColMatrix = Draw::Atoi(argv[7]);
double InitialValueMatrix = Draw::Atof(argv[8]);
math_Vector Vector1(LowerVector, UpperVector);
math_Vector Vector2(LowerVector, UpperVector);
math_Vector Vector(LowerVector, UpperVector, InitialValueVector);
math_Matrix Matrix(LowerRowMatrix,
UpperRowMatrix,
LowerColMatrix,
UpperColMatrix,
InitialValueMatrix);
// Vector.Dump(std::cout);
// std::cout<<std::endl;
// Matrix.Dump(std::cout);
// std::cout<<std::endl;
Vector1.Multiply(Vector, Matrix);
// Vector1.Dump(std::cout);
Standard_SStream aSStream1;
Vector1.Dump(aSStream1);
di << aSStream1;
di << "\n";
if (Matrix.RowNumber() > 1)
{
Matrix(Matrix.LowerRow() + 1, Matrix.LowerCol()) += 1.;
}
Vector2.TMultiply(Vector, Matrix);
// Vector2.Dump(std::cout);
Standard_SStream aSStream2;
Vector2.Dump(aSStream2);
di << aSStream2;
di << "\n";
return 0;
}
#include <GeomPlate_BuildPlateSurface.hxx>
//=================================================================================================
@@ -1967,50 +1910,6 @@ static int OCC5739_UniAbs(Draw_Interpretor& di, int argc, const char** argv)
return res;
}
static int OCC6046(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 3)
{
di << "Usage : " << argv[0] << " nb_of_vectors size\n";
return 1;
}
int nb = Draw::Atoi(argv[1]);
int sz = Draw::Atoi(argv[2]);
double val = 10;
math_Vector** pv = new math_Vector*[nb];
di << "creating " << nb << " vectors " << sz << " elements each...\n";
int i;
for (i = 0; i < nb; i++)
{
pv[i] = new math_Vector(1, sz, val);
if ((i % (nb / 10)) == 0)
{
di << " " << i;
// std::cout.flush();
di << "\n";
}
}
di << " done\n";
di << "deleting them ...\n";
for (i = 0; i < nb; i++)
{
delete pv[i];
if ((i % (nb / 10)) == 0)
{
di << " " << i;
// std::cout.flush();
di << "\n";
}
}
di << " done\n";
delete[] pv;
return 0;
}
static int OCC5698(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 2)
@@ -2845,99 +2744,6 @@ static int OCC10138(Draw_Interpretor& di, int argc, const char** argv)
return 0;
}
static int OCC7639(Draw_Interpretor& di, int argc, const char** argv)
{
bool IsEvenArgc = true;
IsEvenArgc = argc % 2 == 0;
if (argc < 3 || IsEvenArgc)
{
di << "Usage : " << argv[0] << " index1 value1 ... [indexN valueN]\n";
return 1;
}
int i, aValue, aPosition;
NCollection_DynamicArray<int> vec;
for (i = 0; i < argc - 1; i++)
{
i++;
aValue = Draw::Atoi(argv[i]);
aPosition = Draw::Atoi(argv[i + 1]);
vec.SetValue(aValue, aPosition);
}
NCollection_DynamicArray<int>::Iterator it(vec);
int j;
for (j = 0; it.More(); it.Next(), j++)
{
// di << it.Value() << "\n";
di << j << " " << it.Value() << "\n";
}
return 0;
}
static int OCC8797(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 1)
{
di << "Usage : " << argv[0] << "\n";
return 1;
}
gp_Pnt point(0.0, 0.0, 0.0);
NCollection_Array1<gp_Pnt> poles(0, 6);
poles(0) = point;
point.SetCoord(1.0, 1.0, 0.0);
poles(1) = point;
point.SetCoord(2.0, 1.0, 0.0);
poles(2) = point;
point.SetCoord(3.0, 0.0, 0.0);
poles(3) = point;
point.SetCoord(4.0, 1.0, 0.0);
poles(4) = point;
point.SetCoord(5.0, 1.0, 0.0);
poles(5) = point;
point.SetCoord(6.0, 0.0, 0.0);
poles(6) = point;
NCollection_Array1<double> knots(0, 2);
knots(0) = 0.0;
knots(1) = 0.5;
knots(2) = 1.0;
NCollection_Array1<int> multi(0, 2);
multi(0) = 4;
multi(1) = 3;
multi(2) = 4;
occ::handle<Geom_BSplineCurve> spline = new Geom_BSplineCurve(poles, knots, multi, 3);
// length!! 1.
double l_abcissa, l_gprop;
GeomAdaptor_Curve adaptor_spline(spline);
GCPnts_AbscissaPoint temp;
l_abcissa = GCPnts_AbscissaPoint::Length(adaptor_spline);
std::cout << "Length Spline(abcissa_Pnt): " << l_abcissa << std::endl;
// length!! 2.
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(spline);
GProp_GProps prop;
BRepGProp::LinearProperties(edge, prop);
l_gprop = prop.Mass();
std::cout << "Length Spline(GProp_GProps): " << l_gprop << std::endl;
std::cout << "Difference (abcissa_Pnt<->GProp_GProps): " << l_gprop - l_abcissa << std::endl;
return 0;
}
static int OCC7068(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 1)
@@ -3075,26 +2881,6 @@ int OCC14376(Draw_Interpretor& di, int argc, const char** argv)
return 0;
}
static int OCC15489(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
{
di << "Usage : " << argv[0] << " A B C\n";
return 1;
}
try
{
gp_Lin2d aLin2d(Draw::Atof(argv[1]), Draw::Atof(argv[2]), Draw::Atof(argv[3]));
gp_Pnt2d anOrigin = aLin2d.Location();
di << "X_0 = " << anOrigin.X() << " Y_0 = " << anOrigin.Y() << "\n";
}
catch (Standard_ConstructionError const&)
{
di << argv[0] << " Exception: Sqrt(A*A + B*B) <= Resolution from gp\n";
}
return 0;
}
static int OCC15755(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 3)
@@ -4925,12 +4711,6 @@ void QABugs::Commands_11(Draw_Interpretor& theCommands)
OCC24,
group);
theCommands.Add("OCC369", "OCC369 Shape", __FILE__, OCC369, group);
theCommands.Add("OCC524",
"OCC524 LowerVector UpperVector InitialValueVector LowerRowMatrix UpperRowMatrix "
"LowerColMatrix UpperColMatrix InitialValueMatrix",
__FILE__,
OCC524,
group);
// theCommands.Add("OCC578", "OCC578 shape1 shape2 shape3", __FILE__, OCC578, group);
theCommands.Add("OCC578", "OCC578 shape1 shape2 shape3", __FILE__, OCC578, group);
theCommands.Add("OCC708",
@@ -4978,7 +4758,6 @@ void QABugs::Commands_11(Draw_Interpretor& theCommands)
theCommands.Add("OCC1077", "OCC1077 result", __FILE__, OCC1077, group);
theCommands.Add("OCC5739", "OCC5739 name shape step", __FILE__, OCC5739_UniAbs, group);
theCommands.Add("OCC6046", "OCC6046 nb_of_vectors size", __FILE__, OCC6046, group);
theCommands.Add("OCC5698", "OCC5698 wire", __FILE__, OCC5698, group);
theCommands.Add("OCC6143", "OCC6143 catching signals", __FILE__, OCC6143, group);
theCommands.Add("OCC30762", "OCC30762 printing backtrace", __FILE__, OCC30762, group);
@@ -4986,8 +4765,6 @@ void QABugs::Commands_11(Draw_Interpretor& theCommands)
theCommands.Add("OCC7372", "OCC7372", __FILE__, OCC7372, group);
theCommands.Add("OCC8169", "OCC8169 edge1 edge2 plane", __FILE__, OCC8169, group);
theCommands.Add("OCC10138", "OCC10138 lower upper", __FILE__, OCC10138, group);
theCommands.Add("OCC7639", "OCC7639 index1 value1 ... [indexN valueN]", __FILE__, OCC7639, group);
theCommands.Add("OCC8797", "OCC8797", __FILE__, OCC8797, group);
theCommands.Add("OCC7068", "OCC7068", __FILE__, OCC7068, group);
theCommands.Add("OCC11457",
"OCC11457 polygon lastedge x1 y1 z1 x2 y2 z2 ...",
@@ -5000,7 +4777,6 @@ void QABugs::Commands_11(Draw_Interpretor& theCommands)
OCC13963,
group);
theCommands.Add("OCC14376", "OCC14376 shape [deflection]", __FILE__, OCC14376, group);
theCommands.Add("OCC15489", "OCC15489 A B C", __FILE__, OCC15489, group);
theCommands.Add("OCC15755", "OCC15755 file shape", __FILE__, OCC15755, group);
theCommands.Add("OCC16782", "OCC16782 file.std file.xml file.cbf", __FILE__, OCC16782, group);
theCommands.Add("OCC12584", "OCC12584 [mode = 0/1/2]", __FILE__, OCC12584, group);
-136
View File
@@ -1,136 +0,0 @@
// Created on: 2002-10-24
// Created by: Michael KUZMITCHEV
// Copyright (c) 2002-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 <QABugs.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <DBRep.hxx>
#include <AIS_InteractiveContext.hxx>
#include <TopoDS_Shape.hxx>
#include <gp_Pnt.hxx>
#include <gp_Ax2.hxx>
#include <gp.hxx>
#include <gp_Ax1.hxx>
#include <gce_MakeCirc.hxx>
#include <gp_Circ.hxx>
#include <GC_MakeArcOfCircle.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <TopoDS_Wire.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>
//=======================================================================
// OCC895
//=======================================================================
static int OCC895(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc < 2 || argc > 5)
{
di << "Usage : " << argv[0] << " result [angle [reverse [order]]]\n";
return 1;
}
const double rad = 1.0;
const double angle = (argc > 2) ? Draw::Atof(argv[2]) : 0.0;
const int reverse = (argc > 3) ? Draw::Atoi(argv[3]) : 0;
const int order = (argc > 4) ? Draw::Atoi(argv[4]) : 0;
// Make a wire from the first arc for ThruSections.
//
// This arc is rotated 5 degrees about the Z axis.
// I don't know why, but if we don't rotate it,
// the final shell is not twisted.
gp_Pnt center1(0, 10, 0);
gp_Ax2 axis1 =
reverse ? gp_Ax2(center1, gp::DY(), gp::DZ()) : gp_Ax2(center1, -gp::DY(), gp::DX());
if (std::abs(angle) > gp::Resolution())
axis1.Rotate(gp_Ax1(center1, gp::DZ()), angle * M_PI / 180.0);
gce_MakeCirc makeCirc1(axis1, rad);
if (!makeCirc1.IsDone())
return 1;
gp_Circ circ1 = makeCirc1.Value();
GC_MakeArcOfCircle makeArc1(circ1, 0, M_PI / 2, true);
if (!makeArc1.IsDone())
return 1;
occ::handle<Geom_TrimmedCurve> arc1 = makeArc1.Value();
// Create wire 1
BRepBuilderAPI_MakeEdge makeEdge1(arc1, arc1->StartPoint(), arc1->EndPoint());
if (!makeEdge1.IsDone())
return 1;
TopoDS_Edge edge1 = makeEdge1.Edge();
BRepBuilderAPI_MakeWire makeWire1;
makeWire1.Add(edge1);
if (!makeWire1.IsDone())
return 1;
TopoDS_Wire wire1 = makeWire1.Wire();
// Make a wire from the second arc for ThruSections.
gp_Pnt center2(10, 0, 0);
gp_Ax2 axis2(center2, -gp::DX(), gp::DZ());
gce_MakeCirc makeCirc2(axis2, rad);
if (!makeCirc2.IsDone())
return 1;
gp_Circ circ2 = makeCirc2.Value();
GC_MakeArcOfCircle makeArc2(circ2, 0, M_PI / 2, true);
if (!makeArc2.IsDone())
return 1;
occ::handle<Geom_TrimmedCurve> arc2 = makeArc2.Value();
// Create wire 2
BRepBuilderAPI_MakeEdge makeEdge2(arc2, arc2->StartPoint(), arc2->EndPoint());
if (!makeEdge2.IsDone())
return 1;
TopoDS_Edge edge2 = makeEdge2.Edge();
BRepBuilderAPI_MakeWire makeWire2;
makeWire2.Add(edge2);
if (!makeWire2.IsDone())
return 1;
TopoDS_Wire wire2 = makeWire2.Wire();
BRepOffsetAPI_ThruSections thruSect(false, true);
if (order)
{
thruSect.AddWire(wire1);
thruSect.AddWire(wire2);
}
else
{
thruSect.AddWire(wire2);
thruSect.AddWire(wire1);
}
thruSect.Build();
if (!thruSect.IsDone())
return 1;
TopoDS_Shape myShape = thruSect.Shape();
DBRep::Set(argv[1], myShape);
return 0;
}
void QABugs::Commands_12(Draw_Interpretor& theCommands)
{
const char* group = "QABugs";
theCommands.Add("OCC895", "OCC895 result [angle [reverse [order]]]", __FILE__, OCC895, group);
return;
}
-213
View File
@@ -783,215 +783,6 @@ static int OCC544(Draw_Interpretor& di, int argc, const char** argv)
return 0;
}
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepBndLib.hxx>
#include <NCollection_Array1.hxx>
#include <BRepBuilderAPI_Copy.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <Precision.hxx>
static int OCC817(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 3)
{
di << "Usage : " << argv[0] << " result mesh_delta\n";
return 1;
}
constexpr double delt = 5.0 * Precision::Confusion();
double mesh_delt = Draw::Atof(argv[2]);
if (mesh_delt <= 0.0)
{
di << "Error: mesh_delta must be positive value\n";
return -1;
}
// Create outer box solid
gp_Pnt P(0, 0, 0);
TopoDS_Solid fullSolid = BRepPrimAPI_MakeBox(P, 30.0, 30.0, 30.0).Solid();
// Create inner box solid
P.SetX(10);
P.SetY(10);
P.SetZ(10);
TopoDS_Solid internalSolid = BRepPrimAPI_MakeBox(P, 10.0, 10.0, 10.0).Solid();
// Cut inner from outer
di << "BRepAlgoAPI_Cut cut( fullSolid, internalSolid )\n";
BRepAlgoAPI_Cut cut(fullSolid, internalSolid);
if (!cut.IsDone())
{
di << "Error: Could not cut volumes\n";
return -1;
}
const TopoDS_Shape& cut_shape = cut.Shape();
// see if we have a solid
int found_solid = 0;
TopoDS_Solid cutSolid;
TopExp_Explorer Ex;
for (Ex.Init(cut_shape, TopAbs_SOLID); Ex.More(); Ex.Next())
{
TopoDS_Solid sol = TopoDS::Solid(Ex.Current());
if (!sol.IsNull())
{
cutSolid = sol;
found_solid++;
}
}
if (found_solid != 1)
{
di << "Error: Cut operation produced " << found_solid << " solids\n";
return -1;
}
DBRep::Set(argv[1], cutSolid);
// Calculate initial volume
GProp_GProps volumeVProps;
BRepGProp::VolumeProperties(cutSolid, volumeVProps);
di << "Info: Original volume = " << volumeVProps.Mass() << "\n";
//
// build bounding box and calculate bounds for initial mesh
//
Bnd_Box bndBox;
BRepBndLib::Add(cutSolid, bndBox);
double Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
bndBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
Xmin -= delt;
Ymin -= delt;
Zmin -= delt;
Xmax += delt;
Ymax += delt;
Zmax += delt;
di << "Info: Bounds\n (" << Xmin << "," << Ymin << "," << Zmin << ")\n (" << Xmax << "," << Ymax
<< "," << Zmax << ")\n";
// grid the bounding box
int NumXsubvolumes = (int)((Xmax - Xmin) / mesh_delt);
if (NumXsubvolumes <= 0)
NumXsubvolumes = 1;
int NumYsubvolumes = (int)((Ymax - Ymin) / mesh_delt);
if (NumYsubvolumes <= 0)
NumYsubvolumes = 1;
int NumZsubvolumes = (int)((Zmax - Zmin) / mesh_delt);
if (NumZsubvolumes <= 0)
NumZsubvolumes = 1;
const double StepX = (Xmax - Xmin) / NumXsubvolumes;
const double StepY = (Ymax - Ymin) / NumYsubvolumes;
const double StepZ = (Zmax - Zmin) / NumZsubvolumes;
const int NumSubvolumes = NumXsubvolumes * NumYsubvolumes * NumZsubvolumes;
di << "Info: NumSubvolumesX = " << NumXsubvolumes << "\n";
di << "Info: NumSubvolumesY = " << NumYsubvolumes << "\n";
di << "Info: NumSubvolumesZ = " << NumZsubvolumes << "\n";
di << "Info: NumSubvolumes = " << NumSubvolumes << "\n";
//
// construct initial mesh of cutSolid
//
NCollection_Array1<TopoDS_Shape> SubvolumeSolid(0, NumSubvolumes - 1);
NCollection_Array1<double> SubvolumeVol(0, NumSubvolumes - 1);
double accumulatedVolume = 0.0;
int i, j, k, l = 0;
double x = Xmin;
for (i = 0; i < NumXsubvolumes; i++)
{
double y = Ymin;
for (j = 0; j < NumYsubvolumes; j++)
{
double z = Zmin;
for (k = 0; k < NumZsubvolumes; k++)
{
P.SetX(x);
P.SetY(y);
P.SetZ(z);
TopoDS_Shape aSubvolume = BRepPrimAPI_MakeBox(P, StepX, StepY, StepZ).Solid();
di << "Info: box b_" << l << " " << P.X() << " " << P.Y() << " " << P.Z() << " " << StepX
<< " " << StepY << " " << StepZ << "\n";
if (aSubvolume.IsNull())
{
di << "Error: could not construct subvolume " << l << "\n";
return 1;
}
SubvolumeSolid.SetValue(l, aSubvolume);
GProp_GProps subvolumeVProps;
BRepGProp::VolumeProperties(SubvolumeSolid(l), subvolumeVProps);
const double vol = subvolumeVProps.Mass();
di << "Info: original subvolume " << l << " volume = " << vol << "\n";
SubvolumeVol.SetValue(l, vol);
accumulatedVolume += vol;
l++;
z += StepZ;
}
y += StepY;
}
x += StepX;
}
di << "Info: Accumulated mesh volume = " << accumulatedVolume << "\n";
//
// trim mesh to cutSolid
//
accumulatedVolume = 0.0;
for (l = 0; l < NumSubvolumes; l++)
{
TopoDS_Shape copySolid = BRepBuilderAPI_Copy(cutSolid).Shape();
// perform common
di << "BRepAlgoAPI_Common common(copySolid/*cutSolid*/, SubvolumeSolid(l))\n";
BRepAlgoAPI_Common common(copySolid /*cutSolid*/, SubvolumeSolid(l));
if (!common.IsDone())
{
di << "Error: could not construct a common solid " << l << "\n";
return 1;
}
const TopoDS_Shape& aCommonShape = common.Shape();
// see if we have a solid
found_solid = 0;
TopoDS_Shape commonShape;
//////////for (Ex.Init(common.Shape(), TopAbs_SOLID); Ex.More(); Ex.Next())
for (Ex.Init(aCommonShape, TopAbs_SOLID); Ex.More(); Ex.Next())
{
TopoDS_Solid sol = TopoDS::Solid(Ex.Current());
if (!sol.IsNull())
{
commonShape = sol;
found_solid++;
}
}
if (found_solid != 1)
{
di << "Info: Common operation " << l << " produced " << found_solid << " solids\n";
}
else
{
SubvolumeSolid.SetValue(l, commonShape);
GProp_GProps subvolumeVProps;
BRepGProp::VolumeProperties(SubvolumeSolid(l), subvolumeVProps);
const double vol = subvolumeVProps.Mass();
const bool err = (vol > SubvolumeVol(l)) || (vol <= 0.0);
// std::cout << (err? "ERROR" : "Info") << ": final subvolume " << l << " volume = " << vol <<
// std::endl;
if (err)
di << "ERROR: final subvolume " << l << " volume = " << vol << "\n";
else
di << "Info: final subvolume " << l << " volume = " << vol << "\n";
accumulatedVolume += vol;
if (err)
{
char astr[80];
Sprintf(astr, "e_%d", l);
DBRep::Set(astr, commonShape);
}
}
}
di << "Info: Accumulated meshed volume = " << accumulatedVolume << "\n";
return 0;
}
void QABugs::Commands_13(Draw_Interpretor& theCommands)
{
const char* group = "QABugs";
@@ -1001,15 +792,11 @@ void QABugs::Commands_13(Draw_Interpretor& theCommands)
__FILE__,
OCC332bug,
group);
//////theCommands.Add("OCC544", "OCC544 [[[[[wT [[[[d1 [[[d2 [[R [length]]]]]", __FILE__, OCC544,
/// group);
theCommands.Add("OCC544",
"OCC544 [[[[[wT [[[[d1 [[[d2 [[R [length ]]]]]",
__FILE__,
OCC544,
group);
//////theCommands.Add("OCC817", "OCC817 result mesh_delta", __FILE__, OCC817, group);
theCommands.Add("OCC817", "OCC817 result mesh_delta ", __FILE__, OCC817, group);
return;
}
-56
View File
@@ -25,13 +25,6 @@
#include <AIS_Shape.hxx>
#include <TopoDS_Shape.hxx>
#include <Geom2d_Line.hxx>
#include <gp_Pnt2d.hxx>
#include <NCollection_Array1.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2dGcc_QualifiedCurve.hxx>
#include <Geom2dGcc_Circ2d2TanRad.hxx>
#include <Geom2d_Circle.hxx>
#include <TopoDS.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <gp_Lin.hxx>
@@ -64,54 +57,6 @@
#include <TDF_Label.hxx>
#include <TDataStd_Expression.hxx>
static int BUC60897(Draw_Interpretor& di, int /*argc*/, const char** /*argv*/)
{
char abuf[16];
occ::handle<Geom2d_Line> aLine = new Geom2d_Line(gp_Pnt2d(100, 0), gp_Dir2d(gp_Dir2d::D::NX));
Sprintf(abuf, "line");
const char* st = abuf;
DrawTrSurf::Set(st, aLine);
NCollection_Array1<gp_Pnt2d> aPoints(1, 3);
aPoints.SetValue(1, gp_Pnt2d(0, 0));
aPoints.SetValue(2, gp_Pnt2d(50, 50));
aPoints.SetValue(3, gp_Pnt2d(0, 100));
occ::handle<Geom2d_BezierCurve> aCurve = new Geom2d_BezierCurve(aPoints);
Sprintf(abuf, "curve");
DrawTrSurf::Set(st, aCurve);
Geom2dAdaptor_Curve aCLine(aLine);
Geom2dAdaptor_Curve aCCurve(aCurve);
Geom2dGcc_QualifiedCurve aQualifCurve1(aCLine, GccEnt_outside);
Geom2dGcc_QualifiedCurve aQualifCurve2(aCCurve, GccEnt_outside);
Geom2dGcc_Circ2d2TanRad aGccCirc2d(aQualifCurve1, aQualifCurve2, 10, 1e-7);
if (!aGccCirc2d.IsDone())
{
di << "Faulty: can not create a circle.\n";
return 1;
}
for (int i = 1; i <= aGccCirc2d.NbSolutions(); i++)
{
gp_Circ2d aCirc2d = aGccCirc2d.ThisSolution(i);
di << "circle : X " << aCirc2d.Location().X() << " Y " << aCirc2d.Location().Y() << " R "
<< aCirc2d.Radius();
double aTmpR1, aTmpR2;
gp_Pnt2d aPnt2d1, aPnt2d2;
aGccCirc2d.Tangency1(i, aTmpR1, aTmpR2, aPnt2d1);
aGccCirc2d.Tangency2(i, aTmpR1, aTmpR2, aPnt2d2);
di << "\ntangency1 : X " << aPnt2d1.X() << " Y " << aPnt2d1.Y();
di << "\ntangency2 : X " << aPnt2d2.X() << " Y " << aPnt2d2.Y() << "\n";
Sprintf(abuf, "circle_%d", i);
occ::handle<Geom2d_Curve> circ_res = new Geom2d_Circle(aCirc2d);
DrawTrSurf::Set(st, circ_res);
}
di << "done\n";
return 0;
}
static int BUC60889(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 10)
@@ -1045,7 +990,6 @@ void QABugs::Commands_14(Draw_Interpretor& theCommands)
{
const char* group = "QABugs";
theCommands.Add("BUC60897", "BUC60897", __FILE__, BUC60897, group);
theCommands.Add("BUC60889",
"BUC60889 point_1 point_2 name_of_edge bndbox_X1 bndbox_Y1 bndbox_Z1 bndbox_X2 "
"bndbox_Y2 bndbox_Z2",
+1 -30
View File
@@ -50,7 +50,7 @@
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <Precision.hxx>
#include <GProp_PrincipalProps.hxx>
#include <GProp_GProps.hxx>
#include <OSD_Path.hxx>
#include <Standard_ProgramError.hxx>
@@ -374,34 +374,6 @@ static int OCC295(Draw_Interpretor& di, int argc, const char** argv)
return 1;
}
static int OCC49(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 2)
{
di << "Usage : " << argv[0] << " name\n";
return 1;
}
TopoDS_Shape S = DBRep::Get(argv[1]);
if (S.IsNull())
return 0;
GProp_GProps G;
BRepGProp::VolumeProperties(S, G);
GProp_PrincipalProps Pr = G.PrincipalProperties();
bool Result = Pr.HasSymmetryAxis();
if (Result)
{
di << "1\n";
}
else
{
di << "0\n";
}
return 0;
}
static int OCC405(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 4)
@@ -690,7 +662,6 @@ void QABugs::Commands_16(Draw_Interpretor& theCommands)
theCommands.Add("BUC60972", "BUC60972 edge edge plane val text ", __FILE__, BUC60972, group);
theCommands.Add("OCC218", "OCC218 name plane Xlabel Ylabel", __FILE__, OCC218bug, group);
theCommands.Add("OCC295", "OCC295 edge_result edge1 edge2", __FILE__, OCC295, group);
theCommands.Add("OCC49", "OCC49 name", __FILE__, OCC49, group);
theCommands.Add("OCC405",
"OCC405 edge_result edge1 edge2; merge two edges",
__FILE__,
+3 -318
View File
@@ -37,6 +37,9 @@
#include <Geom2dGcc_Lin2d2Tan.hxx>
#include <Geom2d_Line.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <ChFi3d_FilletShape.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <Geom2d_Circle.hxx>
#include <Geom2dGcc_QCurve.hxx>
@@ -466,72 +469,6 @@ static int OCC566(Draw_Interpretor& di, int n, const char** a)
return 0;
}
#include <BRepFilletAPI_MakeFillet.hxx>
//=================================================================================================
static int OCC570(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc < 2)
{
di << "Usage: " << argv[0] << " result\n";
return 1;
}
BRepPrimAPI_MakeBox mkBox(100., 100., 100.);
TopoDS_Shape aBox = mkBox.Shape();
TopExp_Explorer aExp;
aExp.Init(aBox, TopAbs_WIRE);
if (aExp.More())
{
TopoDS_Shape aWire = aExp.Current();
aExp.Init(aWire, TopAbs_EDGE);
TopoDS_Edge e1 = TopoDS::Edge(aExp.Current());
aExp.Next();
TopoDS_Edge e2 = TopoDS::Edge(aExp.Current());
aExp.Next();
TopoDS_Edge e3 = TopoDS::Edge(aExp.Current());
aExp.Next();
TopoDS_Edge e4 = TopoDS::Edge(aExp.Current());
try
{
OCC_CATCH_SIGNALS
BRepFilletAPI_MakeFillet mkFillet(aBox);
mkFillet.SetContinuity(GeomAbs_C1, .001);
// Setup variable fillet data
NCollection_Array1<gp_Pnt2d> t_pnt(1, 4);
t_pnt.SetValue(1, gp_Pnt2d(0.0, 5.0));
t_pnt.SetValue(2, gp_Pnt2d(0.3, 15.0));
t_pnt.SetValue(3, gp_Pnt2d(0.7, 15.0));
t_pnt.SetValue(4, gp_Pnt2d(1.0, 5.0));
// HERE:
// It is impossible to build fillet if at least one edge
// with variable radius is added!!! If all are constant, everything is ok.
mkFillet.Add(t_pnt, e1);
mkFillet.Add(5.0, e2);
mkFillet.Add(t_pnt, e3);
mkFillet.Add(5.0, e4);
mkFillet.Build();
TopoDS_Shape aFinalShape = mkFillet.Shape();
DBRep::Set(argv[1], aFinalShape);
}
catch (Standard_Failure const&)
{
di << argv[0] << ": Exception in fillet\n";
return 2;
}
}
return 0;
}
#include <Law_Interpol.hxx>
static double tesp = 1.e-4;
@@ -703,169 +640,6 @@ static int OCC606(Draw_Interpretor& di, int n, const char** a)
return 0;
}
//=================================================================================================
static int OCC813(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc < 3)
{
di << "Usage : " << argv[0] << " U V\n";
return 1;
}
const char* str;
double U = Draw::Atof(argv[1]);
double V = Draw::Atof(argv[2]);
// Between ellipse and point:
occ::handle<Geom_Ellipse> ell =
new Geom_Ellipse(gp_Ax2(gp_Pnt(1262.224429, 425.040878, 363.609716),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560)),
150,
100);
occ::handle<Geom_Plane> plne =
new Geom_Plane(gp_Ax3(gp_Ax2(gp_Pnt(1262.224429, 425.040878, 363.609716),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560))));
occ::handle<AIS_InteractiveContext> aContext = ViewerTest::GetAISContext();
gp_Pnt2d pt2d(U, V);
gp_Pln pln = plne->Pln();
str = "OCC813_pnt";
DrawTrSurf::Set(str, pt2d);
occ::handle<Geom2d_Curve> curve2d = GeomAPI::To2d(ell, pln);
Geom2dAdaptor_Curve acur(curve2d);
Geom2dGcc_QualifiedCurve qcur(acur, GccEnt_outside);
str = "OCC813_ell";
DrawTrSurf::Set(str, curve2d);
if (!aContext.IsNull())
{
occ::handle<AIS_Shape> aisp =
new AIS_Shape(BRepBuilderAPI_MakeEdge(GeomAPI::To3d(curve2d, pln)).Edge());
aContext->Display(aisp, false);
}
// This does not give any solutions.
Geom2dGcc_Lin2d2Tan lintan(qcur, pt2d, 0.1);
di << "OCC813 nb of solutions = " << lintan.NbSolutions() << "\n";
char abuf[16];
const char* st = abuf;
int i;
for (i = 1; i <= lintan.NbSolutions(); i++)
{
Sprintf(abuf, "lintan_%d", i);
occ::handle<Geom2d_Line> glin = new Geom2d_Line(lintan.ThisSolution(i));
DrawTrSurf::Set(st, glin);
if (!aContext.IsNull())
{
occ::handle<AIS_Shape> aisp =
new AIS_Shape(BRepBuilderAPI_MakeEdge(GeomAPI::To3d(glin, pln)).Edge());
aContext->Display(aisp, false);
}
}
if (!aContext.IsNull())
{
aContext->UpdateCurrentViewer();
}
return 0;
}
//=================================================================================================
static int OCC814(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc > 1)
{
di << "Usage : " << argv[0] << "\n";
return 1;
}
const char* str;
// Between Ellipse and Circle:
occ::handle<Geom_Circle> cir = new Geom_Circle(gp_Ax2(gp_Pnt(823.687192, 502.366825, 478.960440),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560)),
50);
occ::handle<Geom_Ellipse> ell =
new Geom_Ellipse(gp_Ax2(gp_Pnt(1262.224429, 425.040878, 363.609716),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560)),
150,
100);
occ::handle<Geom_Plane> plne =
new Geom_Plane(gp_Ax3(gp_Ax2(gp_Pnt(1262.224429, 425.040878, 363.609716),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560))));
occ::handle<AIS_InteractiveContext> aContext = ViewerTest::GetAISContext();
gp_Pln pln = plne->Pln();
occ::handle<Geom2d_Curve> curve2d = GeomAPI::To2d(ell, pln);
occ::handle<Geom2d_Curve> fromcurve2d = GeomAPI::To2d(cir, pln);
str = "OCC814_cir";
DrawTrSurf::Set(str, curve2d);
str = "OCC814_ell";
DrawTrSurf::Set(str, fromcurve2d);
if (!aContext.IsNull())
{
occ::handle<AIS_Shape> aisp =
new AIS_Shape(BRepBuilderAPI_MakeEdge(GeomAPI::To3d(curve2d, pln)).Edge());
aContext->Display(aisp, false);
}
if (!aContext.IsNull())
{
occ::handle<AIS_Shape> aisp =
new AIS_Shape(BRepBuilderAPI_MakeEdge(GeomAPI::To3d(fromcurve2d, pln)).Edge());
aContext->Display(aisp, false);
}
Geom2dAdaptor_Curve acur(curve2d), afromcur(fromcurve2d);
Geom2dGcc_QualifiedCurve qcur(acur, GccEnt_outside);
Geom2dGcc_QualifiedCurve qfromcur(afromcur, GccEnt_outside);
// This does not give any solutions.
Geom2dGcc_Lin2d2Tan lintan(qcur, qfromcur, 0.1);
di << "OCC814 nb of solutions = " << lintan.NbSolutions() << "\n";
char abuf[16];
const char* st = abuf;
int i;
for (i = 1; i <= lintan.NbSolutions(); i++)
{
Sprintf(abuf, "lintan_%d", i);
occ::handle<Geom2d_Line> glin = new Geom2d_Line(lintan.ThisSolution(i));
DrawTrSurf::Set(st, glin);
if (!aContext.IsNull())
{
occ::handle<AIS_Shape> aisp =
new AIS_Shape(BRepBuilderAPI_MakeEdge(GeomAPI::To3d(glin, pln)).Edge());
aContext->Display(aisp, false);
}
}
if (!aContext.IsNull())
{
aContext->UpdateCurrentViewer();
}
return 0;
}
#include <ShapeFix_Wire.hxx>
//=================================================================================================
@@ -1061,88 +835,6 @@ static int OCCN1(Draw_Interpretor& di, int argc, const char** argv)
return 0;
}
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepAlgoAPI_Section.hxx>
//=================================================================================================
static int OCCN2(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc > 2)
{
di << "Usage : " << argv[0] << "\n";
return 1;
}
occ::handle<AIS_InteractiveContext> aContext = ViewerTest::GetAISContext();
if (aContext.IsNull())
{
di << "use 'vinit' command before " << argv[0] << "\n";
return 1;
}
BRepPrimAPI_MakeCylinder cylinder(50, 200);
TopoDS_Shape cylinder_sh = cylinder.Shape();
BRepPrimAPI_MakeSphere sphere(gp_Pnt(60, 0, 100), 50);
TopoDS_Shape sphere_sh = sphere.Shape();
di << "BRepAlgoAPI_Section section(cylinder_sh, sphere_sh)\n";
BRepAlgoAPI_Section section(cylinder_sh, sphere_sh);
if (!section.IsDone())
{
di << "Error performing intersection: not done.\n";
}
const TopoDS_Shape& shape = section.Shape();
DBRep::Set("OCCN2_cylinder", cylinder_sh);
DBRep::Set("OCCN2_sphere", sphere_sh);
DBRep::Set("OCCN2_section", shape);
return 0;
}
#include <gp_Pnt.hxx>
#include <NCollection_Array1.hxx>
#include <Geom_BezierCurve.hxx>
static int OCC2569(Draw_Interpretor& di, int argc, const char** argv)
{
occ::handle<AIS_InteractiveContext> aContext = ViewerTest::GetAISContext();
if (aContext.IsNull())
{
di << "use 'vinit' command before " << argv[0] << "\n";
return 1;
}
if (argc != 3)
{
di << "Usage : " << argv[0] << " nbpoles result\n";
return 1;
}
int poles = Draw::Atoi(argv[1]);
NCollection_Array1<gp_Pnt> arr(1, poles);
for (int i = 1; i <= poles; i++)
arr.SetValue(i, gp_Pnt(i + 10, i * 2 + 20, i * 3 + 45));
occ::handle<Geom_BezierCurve> bez = new Geom_BezierCurve(arr);
if (bez.IsNull())
{
di << "\n The curve is not created.\n";
}
else
{
di << "\n Degree = " << bez->Degree() << "\n";
}
TopoDS_Edge sh = BRepBuilderAPI_MakeEdge(bez).Edge();
occ::handle<AIS_Shape> ais = new AIS_Shape(sh);
aContext->Display(ais, true);
DrawTrSurf::Set(argv[2], bez);
return 0;
}
#include <TopTools_ShapeMapHasher.hxx>
#include <NCollection_IndexedMap.hxx>
#include <TopExp.hxx>
@@ -1357,7 +1049,6 @@ void QABugs::Commands_17(Draw_Interpretor& theCommands)
__FILE__,
OCC566,
group);
theCommands.Add("OCC570", "OCC570 result", __FILE__, OCC570, group);
theCommands.Add("OCC570mkevol",
"OCC570mkevol result object (then use updatevol) [R/Q/P]; mkevol",
@@ -1382,8 +1073,6 @@ void QABugs::Commands_17(Draw_Interpretor& theCommands)
theCommands.Add("OCC606", "OCC606 result shape [-t]", __FILE__, OCC606, group);
theCommands.Add("OCC813", "OCC813 U V", __FILE__, OCC813, group);
theCommands.Add("OCC814", "OCC814", __FILE__, OCC814, group);
theCommands.Add("OCC884", "OCC884 result shape [toler [maxtoler]]", __FILE__, OCC884, group);
theCommands.Add("OCCN1",
@@ -1391,10 +1080,6 @@ void QABugs::Commands_17(Draw_Interpretor& theCommands)
__FILE__,
OCCN1,
group);
theCommands.Add("OCCN2", "OCCN2", __FILE__, OCCN2, group);
theCommands.Add("OCC2569", "OCC2569 nbpoles result", __FILE__, OCC2569, group);
theCommands.Add("OCC1642",
"OCC1642 FinalWare FinalFace InitWare InitFace shape FixReorder FixDegenerated "
"FixConnected FixSelfIntersection",
-79
View File
@@ -18,16 +18,11 @@
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <DBRep.hxx>
#include <AIS_InteractiveContext.hxx>
#include <AIS_Shape.hxx>
#include <V3d_View.hxx>
#include <TDocStd_Application.hxx>
#include <TDocStd_Document.hxx>
#include <DDocStd.hxx>
#include <Resource_Manager.hxx>
#include <TopoDS_Wire.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <TopoDS_Vertex.hxx>
@@ -37,9 +32,6 @@
#include <Geom_Curve.hxx>
#include <GCPnts_UniformAbscissa.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Standard_Assert.hxx>
#define DEFAULT_COLOR Quantity_NOC_GOLDENROD
static int OCC267(Draw_Interpretor& di, int argc, const char** argv)
{
@@ -68,71 +60,6 @@ static int OCC267(Draw_Interpretor& di, int argc, const char** argv)
return 0;
}
static int OCC181(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 5)
{
di << "ERROR OCC181: Usage : " << argv[0] << " FileName path1 path2 verbose=0/1\n";
return 1;
}
const char* aFileName = argv[1];
const char* aDir1 = argv[2];
const char* aDir2 = argv[3];
int verboseInt = Draw::Atoi(argv[4]);
bool verboseBool = false;
if (verboseInt != 0)
{
verboseBool = true;
}
TCollection_AsciiString Env1, Env2, CSF_ = "set env(CSF_";
Env1 = CSF_ + aFileName + "UserDefaults) " + aDir1;
Env2 = CSF_ + aFileName + "UserDefaults) " + aDir2;
di.Eval(Env1.ToCString());
Resource_Manager aManager(aFileName, verboseBool);
di.Eval(Env2.ToCString());
bool aStatus = aManager.Save();
if (aStatus)
{
di << "\nOCC181 : Status = TRUE\n";
}
else
{
di << "\nOCC181 : Status = FALSE\n";
}
return 0;
}
static int OCC27849(Draw_Interpretor& di, int argc, const char** argv)
{
if (argc != 3)
{
di << "Usage : " << argv[0] << " <environment variable name> <resource name>\n";
return 1;
}
const char* aEnvName = argv[1];
const char* aResName = argv[2];
Resource_Manager aManager(aEnvName);
if (aManager.Find(aResName))
{
di << aManager.Value(aResName);
}
else
{
di << "Error: could not find resource " << aResName;
}
return 0;
}
static double delta_percent(double a, double b)
{
double result;
@@ -262,12 +189,6 @@ void QABugs::Commands_18(Draw_Interpretor& theCommands)
const char* group = "QABugs";
theCommands.Add("OCC267", "OCC267 DOC path", __FILE__, OCC267, group);
theCommands.Add("OCC181", "OCC181 FileName path1 path2 verbose=0/1", __FILE__, OCC181, group);
theCommands.Add("OCC27849",
"OCC27849 <resource env name> <resource name>",
__FILE__,
OCC27849,
group);
theCommands.Add("OCC367",
"OCC367 shape step goodX goodY goodZ percent_tolerance",
__FILE__,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -50,6 +50,8 @@ set(OCCT_TKMath_GTests_FILES
gp_Pln_Test.cxx
gp_Pnt_Test.cxx
gp_Pnt2d_Test.cxx
gp_Quaternion_Test.cxx
gp_Torus_Test.cxx
gp_Trsf_Test.cxx
gp_Vec_Test.cxx
gp_Vec2d_Test.cxx
@@ -15,10 +15,13 @@
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
#include <gp_Lin.hxx>
#include <gp_Lin2d.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Vec.hxx>
#include <Precision.hxx>
#include <Standard_ConstructionError.hxx>
#include <gtest/gtest.h>
@@ -109,3 +112,26 @@ TEST(gp_LinTest, Transform)
gp_Lin aTransformed = aLin.Transformed(aTrsf);
EXPECT_NEAR(aTransformed.Location().Z(), 10.0, Precision::Confusion());
}
// OCC15489: gp_Lin2d construction from implicit line equation A*x + B*y + C = 0.
// The constructor must throw Standard_ConstructionError when the direction
// vector is zero (sqrt(A*A + B*B) <= gp::Resolution()).
TEST(gp_Lin2dTest, ConstructFromEquation_ZeroDirection_ThrowsException)
{
// A=0, B=0 -> direction vector is zero -> must throw
#ifndef No_Exception
EXPECT_THROW(gp_Lin2d(0.0, 0.0, 1.0), Standard_ConstructionError);
#endif
}
TEST(gp_Lin2dTest, ConstructFromEquation_ValidCoefficients_CorrectOrigin)
{
// A=1e-20, B=-1, C=2 gives the line 1e-20 * x - y + 2 = 0
// Origin (closest point to global origin on the line) must be
// X_0 ~= -1.9999999999999999e-20, Y_0 ~= 2
const gp_Lin2d aLin2d(1e-20, -1.0, 2.0);
const gp_Pnt2d anOrigin = aLin2d.Location();
EXPECT_NEAR(anOrigin.X(), -1.9999999999999999e-20, 1e-25);
EXPECT_NEAR(anOrigin.Y(), 2.0, 0.001);
}
@@ -0,0 +1,186 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <gp_Ax2.hxx>
#include <gp_Ax3.hxx>
#include <gp_Mat.hxx>
#include <gp_Quaternion.hxx>
#include <gp_Trsf.hxx>
#include <gp_Vec.hxx>
#include <gp_XYZ.hxx>
#include <Precision.hxx>
#include <cmath>
// Test OCC25574: gp_Quaternion Euler angle conversion is consistent and correct
// for all supported Euler sequences, including YawPitchRoll.
TEST(gp_QuaternionTest, OCC25574_EulerAnglesConsistency)
{
const char* aNames[] = {"Extrinsic_XYZ", "Extrinsic_XZY", "Extrinsic_YZX", "Extrinsic_YXZ",
"Extrinsic_ZXY", "Extrinsic_ZYX", "Intrinsic_XYZ", "Intrinsic_XZY",
"Intrinsic_YZX", "Intrinsic_YXZ", "Intrinsic_ZXY", "Intrinsic_ZYX",
"Extrinsic_XYX", "Extrinsic_XZX", "Extrinsic_YZY", "Extrinsic_YXY",
"Extrinsic_ZYZ", "Extrinsic_ZXZ", "Intrinsic_XYX", "Intrinsic_XZX",
"Intrinsic_YZY", "Intrinsic_YXY", "Intrinsic_ZXZ", "Intrinsic_ZYZ"};
gp_Quaternion aQuat;
aQuat.Set(0.06766916507860499, 0.21848101129786085, 0.11994599260380681, 0.9660744746954637);
gp_Mat aRinv = aQuat.GetMatrix().Inverted();
gp_Mat aI;
aI.SetIdentity();
// Check round-trip consistency: GetEulerAngles then SetEulerAngles should reproduce the matrix
for (int i = gp_Extrinsic_XYZ; i <= gp_Intrinsic_ZYZ; i++)
{
double alpha, beta, gamma;
aQuat.GetEulerAngles(gp_EulerSequence(i), alpha, beta, gamma);
gp_Quaternion aQuat2;
aQuat2.SetEulerAngles(gp_EulerSequence(i), alpha, beta, gamma);
gp_Mat aR = aQuat2.GetMatrix();
gp_Mat aDiff = aR * aRinv - aI;
EXPECT_LE(aDiff.Determinant(), 1e-5)
<< "Round-trip failed for Euler sequence " << aNames[i - gp_Extrinsic_XYZ];
}
}
// Test OCC25574: Each Euler angle rotation around a named axis should not change
// a point lying on that axis.
TEST(gp_QuaternionTest, OCC25574_EulerAxisRotationPreservesAxis)
{
const char* aNames[] = {"Extrinsic_XYZ", "Extrinsic_XZY", "Extrinsic_YZX", "Extrinsic_YXZ",
"Extrinsic_ZXY", "Extrinsic_ZYX", "Intrinsic_XYZ", "Intrinsic_XZY",
"Intrinsic_YZX", "Intrinsic_YXZ", "Intrinsic_ZXY", "Intrinsic_ZYX",
"Extrinsic_XYX", "Extrinsic_XZX", "Extrinsic_YZY", "Extrinsic_YXY",
"Extrinsic_ZYZ", "Extrinsic_ZXZ", "Intrinsic_XYX", "Intrinsic_XZX",
"Intrinsic_YZY", "Intrinsic_YXY", "Intrinsic_ZXZ", "Intrinsic_ZYZ"};
for (int i = gp_Extrinsic_XYZ; i <= gp_Intrinsic_ZYZ; i++)
{
for (int j = 0; j < 3; j++)
{
// Determine axis index from the sequence name (X=0, Y=1, Z=2)
const int anAxis = aNames[i - gp_Extrinsic_XYZ][10 + j] - 'X';
ASSERT_GE(anAxis, 0);
ASSERT_LE(anAxis, 2);
// 90-degree rotation around the j-th axis of the sequence
double anAngles[3] = {0., 0., 0.};
anAngles[j] = 0.5 * M_PI;
gp_Quaternion q2;
q2.SetEulerAngles(gp_EulerSequence(i), anAngles[0], anAngles[1], anAngles[2]);
// Unit vector on the rotation axis
gp_XYZ v(0., 0., 0.);
v.SetCoord(anAxis + 1, 1.);
gp_Trsf aT;
aT.SetRotation(q2);
gp_XYZ v2 = v;
aT.Transforms(v2);
EXPECT_LE((v - v2).SquareModulus(), Precision::SquareConfusion())
<< "Rotation around axis should not move a point on that axis. Sequence: "
<< aNames[i - gp_Extrinsic_XYZ] << ", angle index: " << j;
}
}
}
// Test OCC25574: Extrinsic and intrinsic Euler sequences produce compatible matrices.
TEST(gp_QuaternionTest, OCC25574_ExtrinsicIntrinsicCorrespondence)
{
const double alpha = 0.1517461713131;
const double beta = 1.5162198410141;
const double gamma = 1.9313156236541;
const gp_EulerSequence aPairs[][2] = {{gp_Extrinsic_XYZ, gp_Intrinsic_ZYX},
{gp_Extrinsic_XZY, gp_Intrinsic_YZX},
{gp_Extrinsic_YZX, gp_Intrinsic_XZY},
{gp_Extrinsic_YXZ, gp_Intrinsic_ZXY},
{gp_Extrinsic_ZXY, gp_Intrinsic_YXZ},
{gp_Extrinsic_ZYX, gp_Intrinsic_XYZ}};
const char* aPairNames[] = {"XYZ/ZYX", "XZY/YZX", "YZX/XZY", "YXZ/ZXY", "ZXY/YXZ", "ZYX/XYZ"};
gp_Quaternion aQuat;
for (int i = 0; i < 6; i++)
{
aQuat.SetEulerAngles(aPairs[i][0], alpha, beta, gamma);
double alpha2, beta2, gamma2;
aQuat.GetEulerAngles(aPairs[i][1], gamma2, beta2, alpha2);
EXPECT_NEAR(alpha, alpha2, 1e-5) << "alpha mismatch for pair " << aPairNames[i];
EXPECT_NEAR(beta, beta2, 1e-5) << "beta mismatch for pair " << aPairNames[i];
EXPECT_NEAR(gamma, gamma2, 1e-5) << "gamma mismatch for pair " << aPairNames[i];
}
}
// Test OCC25574 (YawPitchRoll): applying three sequential rotations and recovering
// angles via gp_YawPitchRoll must reproduce the original angles.
TEST(gp_QuaternionTest, OCC25574_YawPitchRollRoundTrip)
{
const gp_Ax2 aWorld;
const double aAlpha = 0.0;
const double aBeta = -35.0 / 180.0 * M_PI;
const double aGamma = 90.0 / 180.0 * M_PI;
// Build the rotated frame step by step (yaw-pitch-roll convention)
const gp_Quaternion aRotZ(aWorld.Direction(), aAlpha);
const gp_Vec aRotY = aRotZ.Multiply(aWorld.YDirection());
const gp_Vec aRotX = aRotZ.Multiply(aWorld.XDirection());
const gp_Quaternion aRotYaw(aRotY, aBeta);
const gp_Vec aRotZ2 = aRotYaw.Multiply(aWorld.Direction());
const gp_Vec aRotX2 = aRotYaw.Multiply(aRotX);
const gp_Quaternion aRotRoll(aRotX2, aGamma);
const gp_Vec aRotZ3 = aRotRoll.Multiply(aRotZ2);
const gp_Ax2 aResult(gp_Pnt(0., 0., 0.), aRotZ3, aRotX2);
gp_Trsf aTransformation;
aTransformation.SetDisplacement(gp_Ax2(), aResult);
double aComputedAlpha, aComputedBeta, aComputedGamma;
aTransformation.GetRotation().GetEulerAngles(gp_YawPitchRoll,
aComputedAlpha,
aComputedBeta,
aComputedGamma);
EXPECT_NEAR(aAlpha, aComputedAlpha, 1e-5) << "YawPitchRoll alpha mismatch";
EXPECT_NEAR(aBeta, aComputedBeta, 1e-5) << "YawPitchRoll beta mismatch";
EXPECT_NEAR(aGamma, aComputedGamma, 1e-5) << "YawPitchRoll gamma mismatch";
}
// Test OCC25574 (issue 25946): gp_Intrinsic_ZYX and gp_Extrinsic_XYZ yield the
// same Euler angles in reversed order.
TEST(gp_QuaternionTest, OCC25574_IntrinsicZYX_vs_ExtrinsicXYZ)
{
gp_Quaternion aQuat;
aQuat.Set(0.06766916507860499, 0.21848101129786085, 0.11994599260380681, 0.9660744746954637);
double aAlpha, aBeta, aGamma;
aQuat.GetEulerAngles(gp_Intrinsic_ZYX, aAlpha, aBeta, aGamma);
double aAlpha2, aBeta2, aGamma2;
aQuat.GetEulerAngles(gp_Extrinsic_XYZ, aAlpha2, aBeta2, aGamma2);
EXPECT_NEAR(aAlpha, aGamma2, 1e-5) << "Intrinsic ZYX alpha should equal Extrinsic XYZ gamma";
EXPECT_NEAR(aBeta, aBeta2, 1e-5) << "beta should match";
EXPECT_NEAR(aGamma, aAlpha2, 1e-5) << "Intrinsic ZYX gamma should equal Extrinsic XYZ alpha";
}
@@ -0,0 +1,118 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <Geom_ToroidalSurface.hxx>
#include <gp_Ax3.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <gp_Torus.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <cmath>
// Test OCC26746: gp_Torus::Coefficients() computes correct implicit equation coefficients.
// Verifies that evaluating the 35-coefficient polynomial at many points on the torus surface
// gives values close to zero within tolerance.
TEST(gp_TorusTest, OCC26746_CoefficientsCorrect)
{
// Torus constructed from the original Draw script:
// torus tr 55.52514413 2.070076585 73.83409062
// 0.37231784651136368 0.58886674834874120 0.71736697293527607
// 0.80682335496555135 0.17666016102759910 -0.56376170618524390
// 87.08479625 23.14682176
const gp_Ax3 anAx3(gp_Pnt(55.52514413, 2.070076585, 73.83409062),
gp_Dir(0.37231784651136368, 0.58886674834874120, 0.71736697293527607),
gp_Dir(0.80682335496555135, 0.17666016102759910, -0.56376170618524390));
Handle(Geom_ToroidalSurface) aTorus = new Geom_ToroidalSurface(anAx3, 87.08479625, 23.14682176);
const double aTolerance = 3.0e-7;
const int aNbPtsMax = 5;
const int aLowIndex = 5;
const double aStep = 2.0 * M_PI / aNbPtsMax;
NCollection_Array1<double> aCoeffs(aLowIndex, aLowIndex + 34);
aTorus->Torus().Coefficients(aCoeffs);
double aUPar = 0.0;
for (int aUind = 0; aUind <= aNbPtsMax; aUind++)
{
double aVPar = 0.0;
for (int aVind = 0; aVind <= aNbPtsMax; aVind++)
{
const gp_Pnt aPt = aTorus->Value(aUPar, aVPar);
const double aX1 = aPt.X();
const double aX2 = aX1 * aX1;
const double aX3 = aX2 * aX1;
const double aX4 = aX2 * aX2;
const double aY1 = aPt.Y();
const double aY2 = aY1 * aY1;
const double aY3 = aY2 * aY1;
const double aY4 = aY2 * aY2;
const double aZ1 = aPt.Z();
const double aZ2 = aZ1 * aZ1;
const double aZ3 = aZ2 * aZ1;
const double aZ4 = aZ2 * aZ2;
int i = aLowIndex;
double aDelta = aCoeffs(i++) * aX4;
aDelta += aCoeffs(i++) * aY4;
aDelta += aCoeffs(i++) * aZ4;
aDelta += aCoeffs(i++) * aX3 * aY1;
aDelta += aCoeffs(i++) * aX3 * aZ1;
aDelta += aCoeffs(i++) * aY3 * aX1;
aDelta += aCoeffs(i++) * aY3 * aZ1;
aDelta += aCoeffs(i++) * aZ3 * aX1;
aDelta += aCoeffs(i++) * aZ3 * aY1;
aDelta += aCoeffs(i++) * aX2 * aY2;
aDelta += aCoeffs(i++) * aX2 * aZ2;
aDelta += aCoeffs(i++) * aY2 * aZ2;
aDelta += aCoeffs(i++) * aX2 * aY1 * aZ1;
aDelta += aCoeffs(i++) * aX1 * aY2 * aZ1;
aDelta += aCoeffs(i++) * aX1 * aY1 * aZ2;
aDelta += aCoeffs(i++) * aX3;
aDelta += aCoeffs(i++) * aY3;
aDelta += aCoeffs(i++) * aZ3;
aDelta += aCoeffs(i++) * aX2 * aY1;
aDelta += aCoeffs(i++) * aX2 * aZ1;
aDelta += aCoeffs(i++) * aY2 * aX1;
aDelta += aCoeffs(i++) * aY2 * aZ1;
aDelta += aCoeffs(i++) * aZ2 * aX1;
aDelta += aCoeffs(i++) * aZ2 * aY1;
aDelta += aCoeffs(i++) * aX1 * aY1 * aZ1;
aDelta += aCoeffs(i++) * aX2;
aDelta += aCoeffs(i++) * aY2;
aDelta += aCoeffs(i++) * aZ2;
aDelta += aCoeffs(i++) * aX1 * aY1;
aDelta += aCoeffs(i++) * aX1 * aZ1;
aDelta += aCoeffs(i++) * aY1 * aZ1;
aDelta += aCoeffs(i++) * aX1;
aDelta += aCoeffs(i++) * aY1;
aDelta += aCoeffs(i++) * aZ1;
aDelta += aCoeffs(i++);
EXPECT_NEAR(aDelta, 0.0, aTolerance)
<< "Torus coefficient equation not satisfied at (u=" << aUPar << ", v=" << aVPar
<< "), delta=" << aDelta;
aVPar = (aVind == aNbPtsMax) ? 2.0 * M_PI : aVPar + aStep;
}
aVPar = 0.0;
aUPar = (aUind == aNbPtsMax) ? 2.0 * M_PI : aUPar + aStep;
}
}
@@ -163,3 +163,18 @@ TEST(gp_Vec2dTest, SetLinearForm)
EXPECT_NEAR(aResult.X(), 2.0, Precision::Confusion());
EXPECT_NEAR(aResult.Y(), 3.0, Precision::Confusion());
}
TEST(gp_Vec2dTest, OCC26750_IsNormal_NegativeAngle)
{
// OCC26750: gp_Vec2d::IsNormal() returned FALSE when the angle is -PI/2 (not only +PI/2).
const gp_Vec2d aVec1(1.0, 0.0);
const gp_Vec2d aVec2(0.0, -1.0); // -90 degrees
EXPECT_TRUE(aVec1.IsNormal(aVec2, Precision::Angular()))
<< "Vectors at -90 degrees should be recognized as normal";
// Verify gp_Dir2d as well
const gp_Dir2d aD1(gp_Dir2d::D::X);
const gp_Dir2d aD2(gp_Dir2d::D::NY);
EXPECT_TRUE(aD1.IsNormal(aD2, Precision::Angular()))
<< "Direction X and direction -Y should be recognized as normal";
}
@@ -13,6 +13,8 @@
#include <math_GlobOptMin.hxx>
#include <math_MultipleVarFunction.hxx>
#include <math_MultipleVarFunctionWithHessian.hxx>
#include <math_Matrix.hxx>
#include <math_Vector.hxx>
#include <gtest/gtest.h>
@@ -100,6 +102,71 @@ public:
}
};
// Branin function: standard global optimization benchmark with 3 global minima.
// f(x,y) = a*(y - b*x^2 + c*x - r)^2 + s*(1-t)*cos(x) + s
// Standard parameters: a=1, b=5.1/(4pi^2), c=5/pi, r=6, s=10, t=1/(8pi)
// Global minimum value: ~0.397887 at 3 locations: (-pi,12.275), (pi,2.275), (9.42478,2.475)
class BraninFunction : public math_MultipleVarFunctionWithHessian
{
public:
BraninFunction()
{
a = 1.0;
b = 5.1 / (4.0 * M_PI * M_PI);
c = 5.0 / M_PI;
r = 6.0;
s = 10.0;
t = 1.0 / (8.0 * M_PI);
}
int NbVariables() const override { return 2; }
bool Value(const math_Vector& theX, double& theF) override
{
const double u = theX(1);
const double v = theX(2);
const double aSqPt = (v - b * u * u + c * u - r);
const double aLnPt = s * (1 - t) * cos(u);
theF = a * aSqPt * aSqPt + aLnPt + s;
return true;
}
bool Gradient(const math_Vector& theX, math_Vector& theG) override
{
const double u = theX(1);
const double v = theX(2);
const double aSqPt = (v - b * u * u + c * u - r);
theG(1) = 2 * a * aSqPt * (c - 2 * b * u) - s * (1 - t) * sin(u);
theG(2) = 2 * a * aSqPt;
return true;
}
bool Values(const math_Vector& theX, double& theF, math_Vector& theG) override
{
Value(theX, theF);
Gradient(theX, theG);
return true;
}
bool Values(const math_Vector& theX, double& theF, math_Vector& theG, math_Matrix& theH) override
{
Value(theX, theF);
Gradient(theX, theG);
const double u = theX(1);
const double v = theX(2);
const double aSqPt = (v - b * u * u + c * u - r);
const double aTmpPt = c - 2 * b * u;
theH(1, 1) = 2 * a * aTmpPt * aTmpPt - 4 * a * b * aSqPt - s * (1 - t) * cos(u);
theH(1, 2) = 2 * a * aTmpPt;
theH(2, 1) = theH(1, 2);
theH(2, 2) = 2 * a;
return true;
}
private:
double a, b, c, r, s, t;
};
} // anonymous namespace
TEST(MathGlobOptMinTest, QuadraticFunctionOptimization)
@@ -513,4 +580,67 @@ TEST(MathGlobOptMinTest, SmallSearchSpace)
aSolver.Points(1, aSol);
EXPECT_NEAR(aSol(1), 1.0, 0.02) << "Should find solution close to global minimum";
EXPECT_NEAR(aSol(2), 2.0, 0.02) << "Should find solution close to global minimum";
}
}
TEST(MathGlobOptMinTest, OCC25004_BraninFunctionGlobalOptimum)
{
// OCC25004: Extrema_ExtCC incorrect result. Tests math_GlobOptMin on Branin benchmark.
// The Branin function has exactly 3 global minima at ~(-pi,12.275), (pi,2.275), (9.42478,2.475).
// Expected minimum value: ~0.39788735772.
BraninFunction aFunc;
math_Vector aLower(1, 2), aUpper(1, 2);
aLower(1) = -5;
aLower(2) = 0;
aUpper(1) = 10;
aUpper(2) = 15;
// Estimate Lipschitz constant on a regular 16x16 grid.
const int aGridOrder = 16;
math_Vector aFuncValues(1, aGridOrder * aGridOrder);
double aLipConst = 0;
math_Vector aCurrPnt1(1, 2), aCurrPnt2(1, 2);
int idx = 1;
for (int i = 1; i <= aGridOrder; i++)
{
for (int j = 1; j <= aGridOrder; j++)
{
aCurrPnt1(1) = aLower(1) + (aUpper(1) - aLower(1)) * (i - 1) / (aGridOrder - 1.0);
aCurrPnt1(2) = aLower(2) + (aUpper(2) - aLower(2)) * (j - 1) / (aGridOrder - 1.0);
aFunc.Value(aCurrPnt1, aFuncValues(idx));
idx++;
}
}
for (int i = 1; i <= aGridOrder; i++)
for (int j = 1; j <= aGridOrder; j++)
for (int k = 1; k <= aGridOrder; k++)
for (int l = 1; l <= aGridOrder; l++)
{
if (i == k && j == l)
continue;
aCurrPnt1(1) = aLower(1) + (aUpper(1) - aLower(1)) * (i - 1) / (aGridOrder - 1.0);
aCurrPnt1(2) = aLower(2) + (aUpper(2) - aLower(2)) * (j - 1) / (aGridOrder - 1.0);
aCurrPnt2(1) = aLower(1) + (aUpper(1) - aLower(1)) * (k - 1) / (aGridOrder - 1.0);
aCurrPnt2(2) = aLower(2) + (aUpper(2) - aLower(2)) * (l - 1) / (aGridOrder - 1.0);
const int idx1 = (i - 1) * aGridOrder + j;
const int idx2 = (k - 1) * aGridOrder + l;
// Use subtracted vector norm for Lipschitz estimation
aCurrPnt1.Add(-aCurrPnt2);
const double aDist = aCurrPnt1.Norm();
if (aDist > 0.0)
{
const double aC = std::abs(aFuncValues(idx1) - aFuncValues(idx2)) / aDist;
if (aC > aLipConst)
aLipConst = aC;
}
}
math_GlobOptMin aFinder(&aFunc, aLower, aUpper, aLipConst);
aFinder.Perform();
EXPECT_TRUE(aFinder.isDone()) << "Optimizer must converge on Branin function";
EXPECT_NEAR(aFinder.GetF(), 0.39788735772, 0.1) << "Minimum value of Branin function";
EXPECT_EQ(aFinder.NbExtrema(), 3) << "Branin function has exactly 3 global minima";
}
@@ -861,3 +861,45 @@ TEST(MathVectorTest, Resize_NegativeLowerBound)
EXPECT_DOUBLE_EQ(aVec(i), static_cast<double>(i));
}
}
// OCC524: math_Vector::Multiply(vector, matrix) and TMultiply(vector, matrix).
// Reference values from the original Draw Harness test:
// Vector(1..6) filled with 5.0, Matrix(1..6, 1..6) filled with 4.0
// Vector1 = Vector * Matrix -> each component = 6 * 5 * 4 = 120
// After Matrix(2,1) += 1 (-> 5):
// Vector2 = Vector * Matrix^T -> component 2 = 5*5 + 5*4*5 = 25+100 = 125, rest = 120
TEST(MathVectorTest, Multiply_RowVectorByMatrix_AllComponentsEqual)
{
const int aLow = 1, aHigh = 6;
math_Vector aVec(aLow, aHigh, 5.0);
math_Matrix aMat(aLow, aHigh, aLow, aHigh, 4.0);
math_Vector aResult(aLow, aHigh);
aResult.Multiply(aVec, aMat);
for (int i = aLow; i <= aHigh; ++i)
{
EXPECT_DOUBLE_EQ(aResult(i), 120.0);
}
}
TEST(MathVectorTest, TMultiply_RowVectorByTransposedMatrix_ModifiedComponent)
{
const int aLow = 1, aHigh = 6;
math_Vector aVec(aLow, aHigh, 5.0);
math_Matrix aMat(aLow, aHigh, aLow, aHigh, 4.0);
math_Vector aResult(aLow, aHigh);
// Modify one element to create an asymmetry in the transposed multiply
aMat(aLow + 1, aLow) += 1.0;
aResult.TMultiply(aVec, aMat);
EXPECT_DOUBLE_EQ(aResult(1), 120.0);
EXPECT_DOUBLE_EQ(aResult(2), 125.0);
for (int i = 3; i <= aHigh; ++i)
{
EXPECT_DOUBLE_EQ(aResult(i), 120.0);
}
}
@@ -2,6 +2,7 @@
set(OCCT_TKernel_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKernel_GTests_FILES
FSD_BinaryFile_Test.cxx
Handle_Advanced_Test.cxx
Handle_Operations_Test.cxx
Message_Messenger_Test.cxx
@@ -30,8 +31,10 @@ set(OCCT_TKernel_GTests_FILES
NCollection_SparseArray_Test.cxx
NCollection_UBTree_Test.cxx
NCollection_Vec4_Test.cxx
OSD_Parallel_Test.cxx
OSD_Path_Test.cxx
OSD_PerfMeter_Test.cxx
Resource_Manager_Test.cxx
Quantity_Color_Test.cxx
Quantity_ColorRGBA_Test.cxx
Quantity_Date_Test.cxx
@@ -0,0 +1,160 @@
// Copyright (c) 2026 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 <FSD_BinaryFile.hxx>
#include <cstring>
#include <gtest/gtest.h>
namespace
{
// Reference for size_t inversion depending on sizeof(size_t).
template <int size>
inline const unsigned char* SizeRef();
template <>
[[maybe_unused]] inline const unsigned char* SizeRef<8>()
{
static const unsigned char aSizeRef[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return aSizeRef;
}
template <>
[[maybe_unused]] inline const unsigned char* SizeRef<4>()
{
static const unsigned char aSizeRef[] = {
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00};
return aSizeRef;
}
} // namespace
// OCC24537: GCC compiler warnings in byte order reversion code.
// Tests correctness of InverseInt, InverseReal, InverseShortReal, InverseSize
// on a little-endian platform.
TEST(FSD_BinaryFileTest, OCC24537_InverseInt_Sequential)
{
const unsigned char anIntRef[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00};
const int anIntArr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseInt(anIntArr[i]);
EXPECT_EQ(0, memcmp(anInv, anIntRef, sizeof(anIntRef)));
}
TEST(FSD_BinaryFileTest, OCC24537_InverseInt_Random)
{
const unsigned char aRndIntRef[] = {0xFF, 0xC2, 0xF7, 0x00, 0xFF, 0xFF, 0xFB, 0x2E, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0xD2,
0x00, 0x00, 0x04, 0xD3, 0xFF, 0xFF, 0xFD, 0x1E, 0xFF, 0xFF,
0xFF, 0xFB, 0x00, 0x00, 0x03, 0x8D, 0x00, 0x3D, 0x09, 0x00};
const int aRndIntArr[] = {-4000000, -1234, 0, 1, 1234, 1235, -738, -5, 909, 4000000};
int anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseInt(aRndIntArr[i]);
EXPECT_EQ(0, memcmp(anInv, aRndIntRef, sizeof(aRndIntRef)));
}
TEST(FSD_BinaryFileTest, OCC24537_InverseReal_Sequential)
{
const unsigned char aRealRef[] = {
0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const double aRealArr[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0};
double anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseReal(aRealArr[i]);
EXPECT_EQ(0, memcmp(anInv, aRealRef, sizeof(aRealRef)));
}
TEST(FSD_BinaryFileTest, OCC24537_InverseReal_Random)
{
const unsigned char aRndRealRef[] = {
0xFE, 0x37, 0xE4, 0x3C, 0x88, 0x00, 0x75, 0x9C, 0xBE, 0x11, 0x2E, 0x0B, 0xE8, 0x26, 0xD6, 0x95,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x11, 0x2E, 0x0B, 0xE8, 0x26, 0xD6, 0x95,
0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x21, 0xDA, 0x45, 0x5B, 0x53, 0xE4,
0x54, 0xB2, 0x49, 0xAD, 0x25, 0x94, 0xC3, 0x7D, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x23, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, 0x40, 0x23, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD};
const double aRndRealArr[] = {-1e300, -1.e-9, 0., 1.e-9, 1., 3.1415296, 1.e100, 8.0, -9.9, 9.9};
double anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseReal(aRndRealArr[i]);
EXPECT_EQ(0, memcmp(anInv, aRndRealRef, sizeof(aRndRealRef)));
}
TEST(FSD_BinaryFileTest, OCC24537_InverseShortReal_Sequential)
{
const unsigned char aShortRealRef[] = {
0x3F, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x80,
0x00, 0x00, 0x40, 0xA0, 0x00, 0x00, 0x40, 0xC0, 0x00, 0x00, 0x40, 0xE0, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const float aShortRealArr[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 0.0f};
float anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseShortReal(aShortRealArr[i]);
EXPECT_EQ(0, memcmp(anInv, aShortRealRef, sizeof(aShortRealRef)));
}
TEST(FSD_BinaryFileTest, OCC24537_InverseShortReal_Random)
{
const unsigned char aRndShortRealRef[] = {
0xB0, 0x89, 0x70, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x30, 0x89, 0x70, 0x5F, 0x3F, 0x80,
0x00, 0x00, 0x40, 0x49, 0x0E, 0x56, 0xC0, 0xD6, 0x66, 0x66, 0x40, 0xD6, 0x66, 0x66,
0x42, 0xC5, 0xCC, 0xCD, 0xC2, 0xC7, 0xCC, 0xCD, 0x42, 0xC7, 0xCC, 0xCD};
const float aRndShortRealArr[] =
{-1.e-9f, 0.f, 1.e-9f, 1.f, 3.1415f, -6.7f, 6.7f, 98.9f, -99.9f, 99.9f};
float anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseShortReal(aRndShortRealArr[i]);
EXPECT_EQ(0, memcmp(anInv, aRndShortRealRef, sizeof(aRndShortRealRef)));
}
TEST(FSD_BinaryFileTest, OCC24537_InverseSize_Sequential)
{
const size_t aSizeArr[] = {1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul, 8ul, 9ul, 0ul};
const unsigned char* aSizeRef = SizeRef<sizeof(size_t)>();
size_t anInv[10];
for (int i = 0; i < 10; ++i)
anInv[i] = FSD_BinaryFile::InverseSize(aSizeArr[i]);
EXPECT_EQ(0, memcmp(anInv, aSizeRef, sizeof(size_t) * 10));
}
@@ -910,4 +910,23 @@ TEST(NCollection_DynamicArrayTest, IntAndSizeTOverloadsAgree)
{
EXPECT_EQ(aVecInt.Value(i), aVecSize.Value(static_cast<size_t>(i)));
}
}
}
// OCC7639: NCollection_DynamicArray must handle out-of-order SetValue calls
// (sparse / rare data) correctly and preserve all assigned values.
// The draw test called: OCC7639 0 1 2 500 1 2
// SetValue(0, 1), SetValue(2, 500), SetValue(1, 2)
// Expected iterator output (j, value): 0->1, 1->2, 2->500
TEST(NCollection_DynamicArrayTest, SetValue_OutOfOrderIndices_CorrectValues)
{
NCollection_DynamicArray<int> aVec;
aVec.SetValue(0, 1);
aVec.SetValue(2, 500);
aVec.SetValue(1, 2);
ASSERT_EQ(aVec.Size(), 3);
EXPECT_EQ(aVec.Value(0), 1);
EXPECT_EQ(aVec.Value(1), 2);
EXPECT_EQ(aVec.Value(2), 500);
}
@@ -0,0 +1,240 @@
// Copyright (c) 2026 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 <NCollection_Array1.hxx>
#include <NCollection_Array2.hxx>
#include <OSD_Parallel.hxx>
#include <OSD_ThreadPool.hxx>
#include <gtest/gtest.h>
#include <cmath>
#include <random>
namespace
{
// SAXPY functor: Y[i] = scalar * X[i] + Y[i]
class SaxpyFunctor
{
public:
SaxpyFunctor(const NCollection_Array1<double>& theX,
NCollection_Array1<double>& theY,
double theScalar)
: myX(theX),
myY(theY),
myScalar(theScalar)
{
}
int Begin() const { return 0; }
int End() const { return myX.Length(); }
void operator()(int theIndex) const { myY(theIndex) = myScalar * myX(theIndex) + myY(theIndex); }
void operator()(int /*theThreadIndex*/, int theIndex) const { (*this)(theIndex); }
private:
SaxpyFunctor(const SaxpyFunctor&) = delete;
SaxpyFunctor& operator=(SaxpyFunctor&) = delete;
const NCollection_Array1<double>& myX;
NCollection_Array1<double>& myY;
double myScalar;
};
// Batched SAXPY functor for large vectors
class SaxpyBatchFunctor
{
public:
static const int THE_BATCH_SIZE = 100000;
SaxpyBatchFunctor(const NCollection_Array1<double>& theX,
NCollection_Array1<double>& theY,
double theScalar)
: myX(theX),
myY(theY),
myScalar(theScalar),
myNbBatches((int)std::ceil((double)theX.Size() / THE_BATCH_SIZE))
{
}
int Begin() const { return 0; }
int End() const { return myNbBatches; }
void operator()(int theBatchIndex) const
{
const int aLower = theBatchIndex * THE_BATCH_SIZE;
const int anUpper = std::min(aLower + THE_BATCH_SIZE - 1, myX.Upper());
for (int i = aLower; i <= anUpper; ++i)
myY(i) = myScalar * myX(i) + myY(i);
}
void operator()(int /*theThreadIndex*/, int theBatchIndex) const { (*this)(theBatchIndex); }
private:
SaxpyBatchFunctor(const SaxpyBatchFunctor&) = delete;
SaxpyBatchFunctor& operator=(SaxpyBatchFunctor&) = delete;
const NCollection_Array1<double>& myX;
NCollection_Array1<double>& myY;
double myScalar;
int myNbBatches;
};
// Matrix multiplication functor: result(i,j) = sum_k mat1(i,k)*mat2(k,j)
class MatMultFunctor
{
public:
MatMultFunctor(const NCollection_Array2<double>& theMat1,
const NCollection_Array2<double>& theMat2,
NCollection_Array2<double>& theResult,
int theSize)
: myMat1(theMat1),
myMat2(theMat2),
myResult(theResult),
mySize(theSize)
{
}
int Begin() const { return 0; }
int End() const { return mySize; }
void operator()(int theIndex) const
{
for (int j = 0; j < mySize; ++j)
{
double aTmp = 0.0;
for (int k = 0; k < mySize; ++k)
aTmp += myMat1(theIndex, k) * myMat2(k, j);
myResult(theIndex, j) = aTmp;
}
}
void operator()(int /*theThreadIndex*/, int theIndex) const { (*this)(theIndex); }
private:
MatMultFunctor(const MatMultFunctor&) = delete;
MatMultFunctor& operator=(MatMultFunctor&) = delete;
const NCollection_Array2<double>& myMat1;
const NCollection_Array2<double>& myMat2;
NCollection_Array2<double>& myResult;
int mySize;
};
} // namespace
// Tests that OSD_Parallel::For and OSD_ThreadPool::Launcher produce the same
// result as sequential SAXPY Y[i] = scalar * X[i] + Y[i] (OCC24826).
TEST(OSD_ParallelTest, OCC24826_SaxpyParallelMatchesSequential)
{
const int aLength = 500000;
NCollection_Array1<double> aX(0, aLength - 1);
NCollection_Array1<double> anYRef(0, aLength - 1);
for (int i = 0; i < aLength; ++i)
aX(i) = anYRef(i) = static_cast<double>(i);
// Sequential reference
{
const SaxpyFunctor aFunctor(aX, anYRef, 1e-6);
for (int i = 0; i < aLength; ++i)
aFunctor(i);
}
// OSD_Parallel::For
{
NCollection_Array1<double> anY = aX;
for (int i = 0; i < aLength; ++i)
anY(i) = static_cast<double>(i);
SaxpyFunctor aFunctor(aX, anY, 1e-6);
OSD_Parallel::For(aFunctor.Begin(), aFunctor.End(), aFunctor);
for (int i = 0; i < aLength; ++i)
EXPECT_DOUBLE_EQ(anY(i), anYRef(i)) << "Mismatch at index " << i;
}
// OSD_ThreadPool::Launcher
{
NCollection_Array1<double> anY = aX;
for (int i = 0; i < aLength; ++i)
anY(i) = static_cast<double>(i);
SaxpyFunctor aFunctor(aX, anY, 1e-6);
OSD_ThreadPool::Launcher aLauncher(*OSD_ThreadPool::DefaultPool());
aLauncher.Perform(aFunctor.Begin(), aFunctor.End(), aFunctor);
for (int i = 0; i < aLength; ++i)
EXPECT_DOUBLE_EQ(anY(i), anYRef(i)) << "Mismatch at index " << i;
}
// OSD_Parallel::For with batched functor
{
NCollection_Array1<double> anY = aX;
for (int i = 0; i < aLength; ++i)
anY(i) = static_cast<double>(i);
SaxpyBatchFunctor aFunctor(aX, anY, 1e-6);
OSD_Parallel::For(aFunctor.Begin(), aFunctor.End(), aFunctor);
for (int i = 0; i < aLength; ++i)
EXPECT_DOUBLE_EQ(anY(i), anYRef(i)) << "Mismatch at index " << i;
}
}
// Tests that OSD_Parallel::For and OSD_ThreadPool::Launcher produce the same
// result as sequential matrix multiplication (OCC29935).
TEST(OSD_ParallelTest, OCC29935_MatrixMultiplyParallelMatchesSequential)
{
const int aSize = 50;
std::mt19937 aGen(42);
NCollection_Array2<double> aMat1(0, aSize - 1, 0, aSize - 1);
NCollection_Array2<double> aMat2(0, aSize - 1, 0, aSize - 1);
NCollection_Array2<double> aMatRef(0, aSize - 1, 0, aSize - 1);
NCollection_Array2<double> aMatRes(0, aSize - 1, 0, aSize - 1);
for (int i = 0; i < aSize; ++i)
for (int j = 0; j < aSize; ++j)
{
aMat1(i, j) = static_cast<double>(aGen() % 1000);
aMat2(i, j) = static_cast<double>(aGen() % 1000);
}
// Sequential reference
{
MatMultFunctor aFunctor(aMat1, aMat2, aMatRef, aSize);
for (int i = aFunctor.Begin(); i < aFunctor.End(); ++i)
aFunctor(i);
}
// OSD_Parallel::For
{
aMatRes.Init(0.0);
MatMultFunctor aFunctor(aMat1, aMat2, aMatRes, aSize);
OSD_Parallel::For(aFunctor.Begin(), aFunctor.End(), aFunctor);
for (int i = 0; i < aSize; ++i)
for (int j = 0; j < aSize; ++j)
EXPECT_DOUBLE_EQ(aMatRes(i, j), aMatRef(i, j));
}
// OSD_ThreadPool::Launcher
{
aMatRes.Init(0.0);
MatMultFunctor aFunctor(aMat1, aMat2, aMatRes, aSize);
OSD_ThreadPool::Launcher aLauncher(*OSD_ThreadPool::DefaultPool());
aLauncher.Perform(aFunctor.Begin(), aFunctor.End(), aFunctor);
for (int i = 0; i < aSize; ++i)
for (int j = 0; j < aSize; ++j)
EXPECT_DOUBLE_EQ(aMatRes(i, j), aMatRef(i, j));
}
}
@@ -0,0 +1,138 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <OSD_Environment.hxx>
#include <Resource_Manager.hxx>
#include <TCollection_AsciiString.hxx>
#include <filesystem>
#include <fstream>
namespace
{
//! Returns a platform-independent temp base directory for tests.
std::filesystem::path getTempBase()
{
return std::filesystem::temp_directory_path() / "occt_resource_manager_test";
}
//! Writes a minimal resource file containing one entry: key : value
void writeResourceFile(const std::filesystem::path& theDir,
const std::string& theFileName,
const std::string& theKey,
const std::string& theValue)
{
std::filesystem::create_directories(theDir);
std::ofstream aFile(theDir / theFileName);
aFile << theKey << " : " << theValue << "\n";
}
} // namespace
class Resource_ManagerTest : public testing::Test
{
protected:
void SetUp() override { std::filesystem::remove_all(getTempBase()); }
void TearDown() override { std::filesystem::remove_all(getTempBase()); }
};
//! Sets CSF_<theFileName>UserDefaults environment variable to theDir.
static void setUserDefaultsEnv(const std::string& theFileName, const std::filesystem::path& theDir)
{
const std::string anEnvName = "CSF_" + theFileName + "UserDefaults";
OSD_Environment anEnv(anEnvName.c_str());
anEnv.SetValue(TCollection_AsciiString(theDir.string().c_str()));
anEnv.Build();
}
// Test OCC27849: Resource_Manager correctly reads resource files located in
// directories whose names contain dots, spaces, or multiple path segments.
TEST_F(Resource_ManagerTest, OCC27849_PathsWithSpecialChars)
{
const std::string aResourceName = "TestResource";
const std::string aKey = "test.resource";
const std::string aExpected = "ok";
const std::vector<std::string> aPaths = {
"path",
"path.with.dots",
"path with spaces",
"nested/dirs/path with spaces",
};
for (const std::string& aRelPath : aPaths)
{
std::filesystem::path aDir = getTempBase() / aRelPath;
writeResourceFile(aDir, aResourceName, aKey, aExpected);
// Point the env variable to the directory containing the resource file
OSD_Environment anEnv("CSF_TestResourceDefaults");
anEnv.SetValue(TCollection_AsciiString(aDir.string().c_str()));
anEnv.Build();
Resource_Manager aManager(aResourceName.c_str());
EXPECT_TRUE(aManager.Find(aKey.c_str())) << "Resource key not found in path: " << aDir.string();
if (aManager.Find(aKey.c_str()))
{
EXPECT_STREQ(aManager.Value(aKey.c_str()), aExpected.c_str())
<< "Wrong resource value for path: " << aDir.string();
}
}
}
// Test OCC181 (case 1): Resource_Manager::Save() succeeds when the target user-defaults
// directory already exists (flat path).
TEST_F(Resource_ManagerTest, OCC181_SaveToExistingDirectory)
{
const std::string aFileName = "OCC181";
const std::filesystem::path aSourceDir = getTempBase() / "source";
const std::filesystem::path aSaveDir = getTempBase() / "save_flat";
writeResourceFile(aSourceDir, aFileName, "test.key", "test_value");
std::filesystem::create_directories(aSaveDir);
setUserDefaultsEnv(aFileName, aSourceDir);
Resource_Manager aManager(aFileName.c_str());
// Redirect Save() to a different directory
setUserDefaultsEnv(aFileName, aSaveDir);
EXPECT_TRUE(aManager.Save());
EXPECT_TRUE(std::filesystem::exists(aSaveDir / aFileName))
<< "Saved resource file not found in " << aSaveDir.string();
}
// Test OCC181 (case 2): Resource_Manager::Save() succeeds and creates intermediate
// directories when the target user-defaults path does not yet exist (nested path).
TEST_F(Resource_ManagerTest, OCC181_SaveToNestedNonExistentDirectory)
{
const std::string aFileName = "OCC181";
const std::filesystem::path aSourceDir = getTempBase() / "source2";
const std::filesystem::path aSaveDir = getTempBase() / "nested" / "deep" / "dir";
writeResourceFile(aSourceDir, aFileName, "test.key", "test_value");
setUserDefaultsEnv(aFileName, aSourceDir);
Resource_Manager aManager(aFileName.c_str());
// Redirect Save() to a nested path that does not yet exist
setUserDefaultsEnv(aFileName, aSaveDir);
EXPECT_TRUE(aManager.Save());
EXPECT_TRUE(std::filesystem::exists(aSaveDir / aFileName))
<< "Saved resource file not found in nested path " << aSaveDir.string();
}
@@ -1086,3 +1086,39 @@ TEST(TCollection_ExtendedStringTest, EndsWith_ZeroLength)
// Any string ends with empty string
EXPECT_TRUE(aString.EndsWith(nullptr, 0));
}
// ========================================
// Tests for StartsWith/EndsWith bug fix (0030536)
// ========================================
TEST(TCollection_ExtendedStringTest, StartsWith_NoMatchLongerPrefix)
{
// "hello" does NOT start with "help"
const TCollection_ExtendedString aStr("hello");
const TCollection_ExtendedString aPrefix("help");
EXPECT_FALSE(aStr.StartsWith(aPrefix));
}
TEST(TCollection_ExtendedStringTest, StartsWith_Match)
{
// "hello" DOES start with "he"
const TCollection_ExtendedString aStr("hello");
const TCollection_ExtendedString aPrefix("he");
EXPECT_TRUE(aStr.StartsWith(aPrefix));
}
TEST(TCollection_ExtendedStringTest, EndsWith_NoMatchMiddlePart)
{
// "hello" does NOT end with "ll"
const TCollection_ExtendedString aStr("hello");
const TCollection_ExtendedString aSuffix("ll");
EXPECT_FALSE(aStr.EndsWith(aSuffix));
}
TEST(TCollection_ExtendedStringTest, EndsWith_Match)
{
// "hello" DOES end with "lo"
const TCollection_ExtendedString aStr("hello");
const TCollection_ExtendedString aSuffix("lo");
EXPECT_TRUE(aStr.EndsWith(aSuffix));
}
@@ -0,0 +1,204 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <Bnd_Box.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepBndLib.hxx>
#include <BRepBuilderAPI_Copy.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepGProp.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <GProp_GProps.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Solid.hxx>
//! Runs OCC817 test: creates hollow box (30x30x30 outer minus 10x10x10 inner),
//! grids the bounding box into cells of theMeshDelta size, computes
//! BRepAlgoAPI_Common of the solid with each cell, and returns
//! the ratio of accumulated meshed volume to original volume.
//! Returns -1.0 on failure.
static double runHollowBoxMeshTest(double theMeshDelta)
{
constexpr double aDelt = 5.0 * Precision::Confusion();
// Create outer box solid
const TopoDS_Solid aFullSolid = BRepPrimAPI_MakeBox(gp_Pnt(0, 0, 0), 30.0, 30.0, 30.0).Solid();
// Create inner box solid
const TopoDS_Solid anInnerSolid =
BRepPrimAPI_MakeBox(gp_Pnt(10, 10, 10), 10.0, 10.0, 10.0).Solid();
// Cut inner from outer
BRepAlgoAPI_Cut aCut(aFullSolid, anInnerSolid);
if (!aCut.IsDone())
return -1.0;
// Extract the single solid from the cut result
TopoDS_Solid aCutSolid;
int aNbSolids = 0;
TopExp_Explorer anExp;
for (anExp.Init(aCut.Shape(), TopAbs_SOLID); anExp.More(); anExp.Next())
{
const TopoDS_Solid& aSol = TopoDS::Solid(anExp.Current());
if (!aSol.IsNull())
{
aCutSolid = aSol;
aNbSolids++;
}
}
if (aNbSolids != 1)
return -1.0;
// Calculate original volume
GProp_GProps aVProps;
BRepGProp::VolumeProperties(aCutSolid, aVProps);
const double anOriginalVolume = aVProps.Mass();
if (anOriginalVolume <= 0.0)
return -1.0;
// Build bounding box and extend by small delta
Bnd_Box aBndBox;
BRepBndLib::Add(aCutSolid, aBndBox);
double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
aBndBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
aXmin -= aDelt;
aYmin -= aDelt;
aZmin -= aDelt;
aXmax += aDelt;
aYmax += aDelt;
aZmax += aDelt;
// Grid the bounding box
int aNx = (int)((aXmax - aXmin) / theMeshDelta);
if (aNx <= 0)
aNx = 1;
int aNy = (int)((aYmax - aYmin) / theMeshDelta);
if (aNy <= 0)
aNy = 1;
int aNz = (int)((aZmax - aZmin) / theMeshDelta);
if (aNz <= 0)
aNz = 1;
const double aStepX = (aXmax - aXmin) / aNx;
const double aStepY = (aYmax - aYmin) / aNy;
const double aStepZ = (aZmax - aZmin) / aNz;
const int aNbSubvols = aNx * aNy * aNz;
NCollection_Array1<TopoDS_Shape> aSubvols(0, aNbSubvols - 1);
NCollection_Array1<double> aSubvolVols(0, aNbSubvols - 1);
// Build grid cells
int l = 0;
for (int i = 0; i < aNx; i++)
{
for (int j = 0; j < aNy; j++)
{
for (int k = 0; k < aNz; k++)
{
const gp_Pnt aPnt(aXmin + i * aStepX, aYmin + j * aStepY, aZmin + k * aStepZ);
aSubvols.SetValue(l, BRepPrimAPI_MakeBox(aPnt, aStepX, aStepY, aStepZ).Solid());
BRepGProp::VolumeProperties(aSubvols(l), aVProps);
aSubvolVols.SetValue(l, aVProps.Mass());
l++;
}
}
}
// Compute common of solid with each grid cell, accumulate volumes
double anAccumulated = 0.0;
for (l = 0; l < aNbSubvols; l++)
{
const TopoDS_Shape aCopySolid = BRepBuilderAPI_Copy(aCutSolid).Shape();
BRepAlgoAPI_Common aCommon(aCopySolid, aSubvols(l));
if (!aCommon.IsDone())
continue;
int aNbCommon = 0;
TopoDS_Shape aFoundSolid;
for (anExp.Init(aCommon.Shape(), TopAbs_SOLID); anExp.More(); anExp.Next())
{
const TopoDS_Solid& aSol = TopoDS::Solid(anExp.Current());
if (!aSol.IsNull())
{
aFoundSolid = aSol;
aNbCommon++;
}
}
if (aNbCommon == 1)
{
BRepGProp::VolumeProperties(aFoundSolid, aVProps);
const double aVol = aVProps.Mass();
if (aVol > 0.0 && aVol <= aSubvolVols(l))
anAccumulated += aVol;
}
}
return anAccumulated / anOriginalVolume;
}
// OCC817: BRepAlgoAPI_Common result accuracy with hollow box using mesh_delta=10.
TEST(BRepAlgoAPI_CutTest, HollowBox_VolumeAccuracy_Delta10)
{
const double aRatio = runHollowBoxMeshTest(10.0);
ASSERT_GE(aRatio, 0.0) << "Cut or Common operation failed";
EXPECT_NEAR(aRatio, 1.0, 0.001) << "Accumulated meshed volume differs from original by > 0.1%";
}
// OCC817: BRepAlgoAPI_Common result accuracy with hollow box using mesh_delta=15.
TEST(BRepAlgoAPI_CutTest, HollowBox_VolumeAccuracy_Delta15)
{
const double aRatio = runHollowBoxMeshTest(15.0);
ASSERT_GE(aRatio, 0.0) << "Cut or Common operation failed";
EXPECT_NEAR(aRatio, 1.0, 0.001) << "Accumulated meshed volume differs from original by > 0.1%";
}
// OCC817: BRepAlgoAPI_Common result accuracy with hollow box using mesh_delta=30.
TEST(BRepAlgoAPI_CutTest, HollowBox_VolumeAccuracy_Delta30)
{
const double aRatio = runHollowBoxMeshTest(30.0);
ASSERT_GE(aRatio, 0.0) << "Cut or Common operation failed";
EXPECT_NEAR(aRatio, 1.0, 0.001) << "Accumulated meshed volume differs from original by > 0.1%";
}
// OCC817: hollow box has correct surface area and valid shape.
// Outer 30x30x30 has area 6*900=5400; inner 10x10x10 hole adds 6*100=600; total=6000.
TEST(BRepAlgoAPI_CutTest, HollowBox_SurfaceAreaAndValidity)
{
const TopoDS_Solid aFullSolid = BRepPrimAPI_MakeBox(gp_Pnt(0, 0, 0), 30.0, 30.0, 30.0).Solid();
const TopoDS_Solid anInnerSolid =
BRepPrimAPI_MakeBox(gp_Pnt(10, 10, 10), 10.0, 10.0, 10.0).Solid();
BRepAlgoAPI_Cut aCut(aFullSolid, anInnerSolid);
ASSERT_TRUE(aCut.IsDone());
// Extract solid
TopoDS_Solid aCutSolid;
TopExp_Explorer anExp;
for (anExp.Init(aCut.Shape(), TopAbs_SOLID); anExp.More(); anExp.Next())
aCutSolid = TopoDS::Solid(anExp.Current());
ASSERT_FALSE(aCutSolid.IsNull());
// Surface area: outer box 6*900=5400, inner box adds 6*100=600 => total=6000
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aCutSolid, aSProps);
EXPECT_NEAR(aSProps.Mass(), 6000.0, 6.0); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aCutSolid);
EXPECT_TRUE(aChecker.IsValid());
}
@@ -0,0 +1,204 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepGProp.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeTorus.hxx>
#include <GProp_GProps.hxx>
#include <gp_Ax1.hxx>
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <TopoDS_Shape.hxx>
// OCC822_1: BRepMesh_IncrementalMesh correctness test - boolean operations with cylinders and
// cones. Creates two pairs (inner/outer) of cylinders and cones, fuses each pair, then cuts inner
// from outer.
TEST(BRepAlgoAPI_FuseTest, CylinderAndCone_FuseThenCut)
{
const gp_Ax2 anAxis1(gp_Pnt(0, 0, 0), gp_Dir(gp_Dir::D::Z));
const TopoDS_Shape aCylIn = BRepPrimAPI_MakeCylinder(anAxis1, 40, 110).Shape();
const TopoDS_Shape aCylOut = BRepPrimAPI_MakeCylinder(anAxis1, 50, 100).Shape();
const gp_Ax2 anAxis2(gp_Pnt(0, 0, 0), gp_Dir(gp_Dir::D::NZ));
const TopoDS_Shape aConIn = BRepPrimAPI_MakeCone(anAxis2, 40, 60, 110).Shape();
const TopoDS_Shape aConOut = BRepPrimAPI_MakeCone(anAxis2, 50, 70, 100).Shape();
BRepAlgoAPI_Fuse aFuseIn(aCylIn, aConIn);
ASSERT_TRUE(aFuseIn.IsDone());
BRepAlgoAPI_Fuse aFuseOut(aCylOut, aConOut);
ASSERT_TRUE(aFuseOut.IsDone());
BRepAlgoAPI_Cut aCut(aFuseOut.Shape(), aFuseIn.Shape());
ASSERT_TRUE(aCut.IsDone());
const TopoDS_Shape aResult = aCut.Shape();
ASSERT_FALSE(aResult.IsNull());
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aResult, aSProps);
EXPECT_NEAR(aSProps.Mass(), 133931.0, 133.931); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aResult);
EXPECT_TRUE(aChecker.IsValid());
}
// OCC822_2: BRepMesh_IncrementalMesh correctness test - fuse of box and sphere.
TEST(BRepAlgoAPI_FuseTest, BoxAndSphere)
{
const TopoDS_Shape aBox = BRepPrimAPI_MakeBox(gp_Pnt(0, 0, 0), gp_Pnt(100, 100, 100)).Shape();
const TopoDS_Shape aSphere = BRepPrimAPI_MakeSphere(gp_Pnt(100, 50, 50), 25.0).Shape();
BRepAlgoAPI_Fuse aFuse(aBox, aSphere);
ASSERT_TRUE(aFuse.IsDone());
const TopoDS_Shape aResult = aFuse.Shape();
ASSERT_FALSE(aResult.IsNull());
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aResult, aSProps);
EXPECT_NEAR(aSProps.Mass(), 61963.5, 61.9635); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aResult);
EXPECT_TRUE(aChecker.IsValid());
}
// OCC823: BRepAlgoAPI_Fuse correctness test - fuse of two nearly-parallel cylinders.
TEST(BRepAlgoAPI_FuseTest, TwoCylinders)
{
const gp_Ax2 anAxis1(gp_Pnt(40, 50, 0), gp_Dir(100, 0, 0));
const TopoDS_Shape aCyl1 = BRepPrimAPI_MakeCylinder(anAxis1, 20, 100).Shape();
constexpr double aSize = 0.001;
const gp_Ax2 anAxis2(gp_Pnt(100, 50, aSize), gp_Dir(0, aSize, 80));
const TopoDS_Shape aCyl2 = BRepPrimAPI_MakeCylinder(anAxis2, 20, 80).Shape();
BRepAlgoAPI_Fuse aFuse(aCyl2, aCyl1);
ASSERT_TRUE(aFuse.IsDone());
const TopoDS_Shape aResult = aFuse.Shape();
ASSERT_FALSE(aResult.IsNull());
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aResult, aSProps);
EXPECT_NEAR(aSProps.Mass(), 23189.5, 23.1895); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aResult);
EXPECT_TRUE(aChecker.IsValid());
}
// OCC824: BRepAlgoAPI_Fuse correctness test - fuse of cylinder and sphere.
TEST(BRepAlgoAPI_FuseTest, CylinderAndSphere)
{
const gp_Pnt aCenter(100, 0, 0);
const gp_Ax2 anAxis(aCenter, gp_Dir(gp_Dir::D::NX));
const TopoDS_Shape aCyl = BRepPrimAPI_MakeCylinder(anAxis, 20, 100).Shape();
const TopoDS_Shape aSphere = BRepPrimAPI_MakeSphere(aCenter, 20.0).Shape();
BRepAlgoAPI_Fuse aFuse(aCyl, aSphere);
ASSERT_TRUE(aFuse.IsDone());
const TopoDS_Shape aResult = aFuse.Shape();
ASSERT_FALSE(aResult.IsNull());
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aResult, aSProps);
EXPECT_NEAR(aSProps.Mass(), 16336.3, 16.3363); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aResult);
EXPECT_TRUE(aChecker.IsValid());
}
// OCC826: BRepAlgoAPI_Fuse correctness test - fuse of revolved face and sphere.
// Intersection line passes near the pole of the sphere.
TEST(BRepAlgoAPI_FuseTest, RevolvedFaceAndSphere)
{
BRepBuilderAPI_MakePolygon aWire;
const double aX1 = 181.82808, aX2 = 202.39390;
const double aY1 = 31.011970, aY2 = 123.06856;
aWire.Add(gp_Pnt(aX1, aY1, 0));
aWire.Add(gp_Pnt(aX2, aY1, 0));
aWire.Add(gp_Pnt(aX2, aY2, 0));
aWire.Add(gp_Pnt(aX1, aY2, 0));
aWire.Add(gp_Pnt(aX1, aY1, 0));
const TopoDS_Face aFace = BRepBuilderAPI_MakeFace(aWire.Wire(), false);
const gp_Ax1 anAxis(gp_Pnt(0, 0, 0), gp_Dir(0, 30, 0));
const TopoDS_Shape aRevol = BRepPrimAPI_MakeRevol(aFace, anAxis, 2.0 * M_PI).Shape();
const TopoDS_Shape aSphere =
BRepPrimAPI_MakeSphere(gp_Pnt(166.373, 77.0402, 96.0555), 23.218586).Shape();
BRepAlgoAPI_Fuse aFuse(aRevol, aSphere);
ASSERT_TRUE(aFuse.IsDone());
const TopoDS_Shape aResult = aFuse.Shape();
ASSERT_FALSE(aResult.IsNull());
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aResult, aSProps);
EXPECT_NEAR(aSProps.Mass(), 272935.0, 272.935); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aResult);
EXPECT_TRUE(aChecker.IsValid());
}
// OCC827: BRepAlgoAPI_Fuse correctness test - fuse of revolved solid with two tori.
TEST(BRepAlgoAPI_FuseTest, RevolvedSolidAndTwoTori)
{
BRepBuilderAPI_MakePolygon aWire;
aWire.Add(gp_Pnt(10, 0, 0));
aWire.Add(gp_Pnt(20, 0, 0));
aWire.Add(gp_Pnt(20, 0, 50));
aWire.Add(gp_Pnt(10, 0, 50));
aWire.Add(gp_Pnt(10, 0, 0));
const TopoDS_Face aFace = BRepBuilderAPI_MakeFace(aWire.Wire(), false);
const gp_Ax1 anAxis(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 30));
const TopoDS_Shape aRevol = BRepPrimAPI_MakeRevol(aFace, anAxis, 2.0 * M_PI).Shape();
constexpr double aMajRad = 15.0;
constexpr double aMinRad = 5.0;
const TopoDS_Shape aTor1 =
BRepPrimAPI_MakeTorus(gp_Ax2(gp_Pnt(0, 0, 50), gp_Dir(0, 0, 30)), aMajRad, aMinRad).Shape();
const TopoDS_Shape aTor2 =
BRepPrimAPI_MakeTorus(gp_Ax2(gp_Pnt(0, 0, 10), gp_Dir(0, 0, 30)), aMajRad, aMinRad).Shape();
BRepAlgoAPI_Fuse aFuse1(aTor1, aRevol);
ASSERT_TRUE(aFuse1.IsDone());
BRepAlgoAPI_Fuse aFuse2(aTor2, aFuse1.Shape());
ASSERT_TRUE(aFuse2.IsDone());
const TopoDS_Shape aResult = aFuse2.Shape();
ASSERT_FALSE(aResult.IsNull());
GProp_GProps aSProps;
BRepGProp::SurfaceProperties(aResult, aSProps);
EXPECT_NEAR(aSProps.Mass(), 11847.7, 11.8477); // 0.1% tolerance
BRepCheck_Analyzer aChecker(aResult);
EXPECT_TRUE(aChecker.IsValid());
}
@@ -0,0 +1,35 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <BRepAlgoAPI_Section.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <gp_Pnt.hxx>
#include <TopoDS_Shape.hxx>
// Test OCCN2: BRepAlgoAPI_Section of a cylinder intersecting a sphere.
// Migrated from QABugs_17.cxx OCCN2
TEST(BRepAlgoAPI_SectionTest, OCCN2_CylinderSphereSectionIsDone)
{
BRepPrimAPI_MakeCylinder aCylMaker(50., 200.);
const TopoDS_Shape& aCylinder = aCylMaker.Shape();
BRepPrimAPI_MakeSphere aSphereMaker(gp_Pnt(60., 0., 100.), 50.);
const TopoDS_Shape& aSphere = aSphereMaker.Shape();
BRepAlgoAPI_Section aSection(aCylinder, aSphere);
EXPECT_TRUE(aSection.IsDone());
EXPECT_FALSE(aSection.Shape().IsNull());
}
@@ -2,5 +2,9 @@
set(OCCT_TKBool_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKBool_GTests_FILES
BRepAlgoAPI_Cut_Test.cxx
BRepAlgoAPI_Fuse_Test.cxx
BRepAlgoAPI_Section_Test.cxx
BRepFill_PipeShell_Test.cxx
IntTools_FaceFace_Test.cxx
)
@@ -0,0 +1,61 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <BRep_Builder.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_Plane.hxx>
#include <IntTools_Curve.hxx>
#include <IntTools_FaceFace.hxx>
#include <IntTools_PntOn2Faces.hxx>
#include <NCollection_Sequence.hxx>
#include <Precision.hxx>
#include <TopoDS_Face.hxx>
#include <gp_Ax3.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
// Test OCC24005: IntTools_FaceFace should complete quickly and correctly when
// intersecting a slightly off-angle plane with a cylinder. Previously took 7+ seconds.
TEST(IntTools_FaceFaceTest, OCC24005_PlaneCylinderIntersection)
{
// Hardcoded geometry from the original regression test
Handle(Geom_Plane) aPlane = new Geom_Plane(
gp_Ax3(gp_Pnt(-72.948737453424499, 754.30437716359393, 259.52151854671678),
gp_Dir(6.2471473085930200e-007, -0.99999999999980493, 0.00000000000000000),
gp_Dir(0.99999999999980493, 6.2471473085930200e-007, 0.00000000000000000)));
Handle(Geom_CylindricalSurface) aCylinder = new Geom_CylindricalSurface(
gp_Ax3(gp_Pnt(-6.4812490053250649, 753.39408794522092, 279.16400974257465),
gp_Dir(1.0000000000000000, 0.0, 0.00000000000000000),
gp_Dir(0.0, 1.0000000000000000, 0.00000000000000000)),
19.712534607908712);
BRep_Builder aBuilder;
TopoDS_Face aFace1, aFace2;
aBuilder.MakeFace(aFace1, aPlane, Precision::Confusion());
aBuilder.MakeFace(aFace2, aCylinder, Precision::Confusion());
IntTools_FaceFace anInters;
anInters.SetParameters(false, true, true, Precision::Confusion());
anInters.Perform(aFace1, aFace2);
ASSERT_TRUE(anInters.IsDone()) << "IntTools_FaceFace::Perform did not complete";
// The original test verified that intersection completes without hanging.
// Check that we get at least one intersection curve.
const NCollection_Sequence<IntTools_Curve>& aCurves = anInters.Lines();
EXPECT_GE(aCurves.Length() + anInters.Points().Length(), 1)
<< "Expected at least one intersection result (curve or point)";
}
@@ -52,3 +52,40 @@ TEST(Expr_GeneralExpression_Test, OCC902_ExpressionDerivative)
EXPECT_TRUE(isCorrect) << "Derivative result was: " << aDerivativeStr.ToCString()
<< ", expected either 'Exp(5*x)*5' or '5*Exp(5*x)'";
}
// Test OCC31697: Expr_GeneralExpression::Derivative for Exp(2*Sin(x^2))
// Expected derivative: Exp(2*Sin(x^2))*Cos(x^2)*x*4
TEST(Expr_GeneralExpression_Test, OCC31697_DerivativeOfComplexExpression)
{
occ::handle<ExprIntrp_GenExp> anExprIntrp = ExprIntrp_GenExp::Create();
anExprIntrp->Process(TCollection_AsciiString("Exp(2*Sin(x^2))"));
ASSERT_TRUE(anExprIntrp->IsDone()) << "Expression parsing should succeed";
occ::handle<Expr_GeneralExpression> anExpr = anExprIntrp->Expression();
ASSERT_FALSE(anExpr.IsNull()) << "Expression should not be null";
occ::handle<Expr_NamedUnknown> aVar = new Expr_NamedUnknown("x");
ASSERT_TRUE(anExpr->Contains(aVar)) << "Expression should contain variable x";
occ::handle<Expr_GeneralExpression> aDer = anExpr->Derivative(aVar);
ASSERT_FALSE(aDer.IsNull()) << "Derivative should not be null";
const TCollection_AsciiString aDerStr = aDer->String();
EXPECT_EQ(aDerStr, TCollection_AsciiString("Exp(2*Sin(x^2))*Cos(x^2)*x*4"))
<< "Derivative result was: " << aDerStr.ToCString();
}
// Test OCC22611: ExprIntrp_GenExp must not leak and must parse numeric literal correctly.
// Migrated from QABugs_19.cxx OCC22611
TEST(Expr_GeneralExpression_Test, OCC22611_ParseNumericLiteral)
{
occ::handle<ExprIntrp_GenExp> aGen = ExprIntrp_GenExp::Create();
for (int i = 0; i < 10; ++i)
{
aGen->Process(TCollection_AsciiString("0.1214343"));
ASSERT_TRUE(aGen->IsDone()) << "Parsing should succeed on iteration " << i;
occ::handle<Expr_GeneralExpression> aExpr = aGen->Expression();
EXPECT_FALSE(aExpr.IsNull()) << "Expression should not be null on iteration " << i;
}
}
@@ -13,12 +13,16 @@
#include <BRepCheck_Analyzer.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepGProp.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <GProp_GProps.hxx>
#include <NCollection_Array1.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Shape.hxx>
#include <gp_Pnt2d.hxx>
#include <gtest/gtest.h>
@@ -99,3 +103,54 @@ TEST(BRepFilletAPI_MakeFilletTest, FilletVariableRadius)
BRepCheck_Analyzer anAnalyzer(aResult);
EXPECT_TRUE(anAnalyzer.IsValid());
}
// Test OCC570: BRepFilletAPI_MakeFillet with mixed constant and variable radius.
// Migrated from QABugs_17.cxx OCC570
TEST(BRepFilletAPI_MakeFilletTest, OCC570_MixedVariableConstantRadius)
{
BRepPrimAPI_MakeBox aBoxMaker(100., 100., 100.);
const TopoDS_Shape& aBox = aBoxMaker.Shape();
// Take the first wire of the box and its 4 edges
TopExp_Explorer aWireExp(aBox, TopAbs_WIRE);
ASSERT_TRUE(aWireExp.More());
TopExp_Explorer anEdgeExp(aWireExp.Current(), TopAbs_EDGE);
ASSERT_TRUE(anEdgeExp.More());
TopoDS_Edge anE1 = TopoDS::Edge(anEdgeExp.Current());
anEdgeExp.Next();
ASSERT_TRUE(anEdgeExp.More());
TopoDS_Edge anE2 = TopoDS::Edge(anEdgeExp.Current());
anEdgeExp.Next();
ASSERT_TRUE(anEdgeExp.More());
TopoDS_Edge anE3 = TopoDS::Edge(anEdgeExp.Current());
anEdgeExp.Next();
ASSERT_TRUE(anEdgeExp.More());
TopoDS_Edge anE4 = TopoDS::Edge(anEdgeExp.Current());
// Variable radius law: 4 (parameter, radius) control points
NCollection_Array1<gp_Pnt2d> aVarRadius(1, 4);
aVarRadius.SetValue(1, gp_Pnt2d(0.0, 5.0));
aVarRadius.SetValue(2, gp_Pnt2d(0.3, 15.0));
aVarRadius.SetValue(3, gp_Pnt2d(0.7, 15.0));
aVarRadius.SetValue(4, gp_Pnt2d(1.0, 5.0));
BRepFilletAPI_MakeFillet aFillet(aBox);
aFillet.SetContinuity(GeomAbs_C1, 0.001);
aFillet.Add(aVarRadius, anE1);
aFillet.Add(5.0, anE2);
aFillet.Add(aVarRadius, anE3);
aFillet.Add(5.0, anE4);
ASSERT_NO_THROW(aFillet.Build()) << "BRepFilletAPI_MakeFillet::Build should not throw";
ASSERT_TRUE(aFillet.IsDone()) << "Fillet operation should succeed";
const TopoDS_Shape& aResult = aFillet.Shape();
BRepCheck_Analyzer anAnalyzer(aResult);
EXPECT_TRUE(anAnalyzer.IsValid()) << "Result shape should be valid";
GProp_GProps aProps;
BRepGProp::SurfaceProperties(aResult, aProps);
EXPECT_NEAR(aProps.Mass(), 58500., 58500. * 0.01) << "Surface area should be approximately 58500";
}
@@ -3,12 +3,17 @@ set(OCCT_TKGeomAlgo_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKGeomAlgo_GTests_FILES
Geom2dAPI_InterCurveCurve_Test.cxx
Geom2dAPI_Interpolate_Test.cxx
Geom2dAPI_PointsToBSpline_Test.cxx
GeomFill_BSplineCurves_Test.cxx
GeomFill_NSections_Test.cxx
Geom2dHatch_Elements_Test.cxx
Geom2dHatch_Intersector_Test.cxx
GeomAPI_PointsToBSplineSurface_Test.cxx
GeomAPI_PointsToBSpline_Test.cxx
Geom2dGcc_Circ2d2TanRad_Test.cxx
Geom2dGcc_Circ2d3Tan_Test.cxx
Geom2dGcc_Lin2d2Tan_Test.cxx
GeomFill_CorrectedFrenet_Test.cxx
GeomFill_Gordon_Test.cxx
GeomFill_GuideTrihedronAC_Test.cxx
@@ -25,5 +30,6 @@ set(OCCT_TKGeomAlgo_GTests_FILES
IntPolyh_Point_Test.cxx
IntSurf_LineOn2S_Test.cxx
IntSurf_Quadric_Test.cxx
GeomAPI_IntSS_Test.cxx
TopTrans_SurfaceTransition_Test.cxx
)
@@ -0,0 +1,80 @@
// Copyright (c) 2026 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 <Geom2dAPI_Interpolate.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <NCollection_HArray1.hxx>
#include <Precision.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec2d.hxx>
#include <gtest/gtest.h>
// OCC28594: Geom2dAPI_Interpolate with and without tangent scale produces different curves.
// Tests that interpolation with tangent vectors (with scale and without scale) both produce
// valid B-Spline curves passing through the given points.
TEST(Geom2dAPI_InterpolateTest, OCC28594_InterpolateWithAndWithoutTangentScale)
{
occ::handle<NCollection_HArray1<gp_Pnt2d>> aPoints = new NCollection_HArray1<gp_Pnt2d>(1, 6);
NCollection_Array1<gp_Pnt2d>& aPointsArray = aPoints->ChangeArray1();
aPointsArray(1) = gp_Pnt2d(-30.4, 8);
aPointsArray(2) = gp_Pnt2d(-16.689912, 17.498217);
aPointsArray(3) = gp_Pnt2d(-23.803064, 24.748543);
aPointsArray(4) = gp_Pnt2d(-16.907466, 32.919615);
aPointsArray(5) = gp_Pnt2d(-8.543829, 26.549421);
aPointsArray(6) = gp_Pnt2d(0, 39.200000);
NCollection_Array1<gp_Vec2d> aTangents(1, 6);
aTangents(1) = gp_Vec2d(0.3, 0.4);
aTangents(2) = gp_Vec2d(0, 0);
aTangents(3) = gp_Vec2d(0, 0);
aTangents(4) = gp_Vec2d(0, 0);
aTangents(5) = gp_Vec2d(0, 0);
aTangents(6) = gp_Vec2d(1, 0);
occ::handle<NCollection_HArray1<bool>> aTangentFlags = new NCollection_HArray1<bool>(1, 6);
NCollection_Array1<bool>& aTangentFlagsArray = aTangentFlags->ChangeArray1();
aTangentFlagsArray(1) = true;
aTangentFlagsArray(2) = false;
aTangentFlagsArray(3) = false;
aTangentFlagsArray(4) = false;
aTangentFlagsArray(5) = false;
aTangentFlagsArray(6) = true;
// Interpolation with tangent scale
Geom2dAPI_Interpolate anInterpWithScale(aPoints, false, Precision::Confusion());
anInterpWithScale.Load(aTangents, aTangentFlags);
anInterpWithScale.Perform();
EXPECT_TRUE(anInterpWithScale.IsDone());
const occ::handle<Geom2d_BSplineCurve> aCurveWithScale = anInterpWithScale.Curve();
EXPECT_FALSE(aCurveWithScale.IsNull());
// Interpolation without tangent scale
Geom2dAPI_Interpolate anInterpWithoutScale(aPoints, false, Precision::Confusion());
anInterpWithoutScale.Load(aTangents, aTangentFlags, false);
anInterpWithoutScale.Perform();
EXPECT_TRUE(anInterpWithoutScale.IsDone());
const occ::handle<Geom2d_BSplineCurve> aCurveWithoutScale = anInterpWithoutScale.Curve();
EXPECT_FALSE(aCurveWithoutScale.IsNull());
// Both curves must pass through all given points
const double aTol = Precision::Confusion() * 10;
for (int anIndex = 1; anIndex <= aPoints->Length(); ++anIndex)
{
const gp_Pnt2d aPtOnCurveWithScale = aCurveWithScale->EvalD0(aCurveWithScale->Knot(anIndex));
const gp_Pnt2d& aPt = aPointsArray(anIndex);
EXPECT_NEAR(aPt.X(), aPtOnCurveWithScale.X(), aTol) << " at point index " << anIndex;
EXPECT_NEAR(aPt.Y(), aPtOnCurveWithScale.Y(), aTol) << " at point index " << anIndex;
}
}
@@ -0,0 +1,81 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <GccEnt.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dGcc_Circ2d2TanRad.hxx>
#include <Geom2dGcc_QualifiedCurve.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_Line.hxx>
#include <NCollection_Array1.hxx>
#include <gp_Circ2d.hxx>
#include <gp_Dir2d.hxx>
#include <gp_Pnt2d.hxx>
// Test BUC60897: Geom2dGcc_Circ2d2TanRad finds circles tangent to a line and
// a Bezier curve. Verifies that each tangency point lies at the circle radius
// from the circle center (within 1% relative tolerance).
TEST(Geom2dGcc_Circ2d2TanRadTest, BUC60897_TangentToLineAndBezier)
{
// Create a Geom2d_Line from point (100, 0) going in the -X direction
occ::handle<Geom2d_Line> aLine = new Geom2d_Line(gp_Pnt2d(100, 0), gp_Dir2d(gp_Dir2d::D::NX));
// Create a Geom2d_BezierCurve from three control points
NCollection_Array1<gp_Pnt2d> aPoints(1, 3);
aPoints.SetValue(1, gp_Pnt2d(0, 0));
aPoints.SetValue(2, gp_Pnt2d(50, 50));
aPoints.SetValue(3, gp_Pnt2d(0, 100));
occ::handle<Geom2d_BezierCurve> aCurve = new Geom2d_BezierCurve(aPoints);
// Build qualified curves (outside tangency)
Geom2dAdaptor_Curve aCLine(aLine);
Geom2dAdaptor_Curve aCCurve(aCurve);
Geom2dGcc_QualifiedCurve aQualifCurve1(aCLine, GccEnt_outside);
Geom2dGcc_QualifiedCurve aQualifCurve2(aCCurve, GccEnt_outside);
// Find circles with radius 10 tangent to both curves
const double aRadius = 10.0;
const double aTolerance = 1e-7;
Geom2dGcc_Circ2d2TanRad aGccCirc2d(aQualifCurve1, aQualifCurve2, aRadius, aTolerance);
ASSERT_TRUE(aGccCirc2d.IsDone()) << "Geom2dGcc_Circ2d2TanRad failed to compute";
ASSERT_GT(aGccCirc2d.NbSolutions(), 0) << "No tangent circles found";
// For each solution, verify tangency points are at the circle radius from its center
const double aMaxDeltaPercent = 1.0; // 1% tolerance as used in the original Draw test
for (int i = 1; i <= aGccCirc2d.NbSolutions(); i++)
{
const gp_Circ2d aCirc2d = aGccCirc2d.ThisSolution(i);
const gp_Pnt2d aCenter = aCirc2d.Location();
const double aR = aCirc2d.Radius();
double aParSol1, aParArg1, aParSol2, aParArg2;
gp_Pnt2d aPntSol1, aPntSol2;
aGccCirc2d.Tangency1(i, aParSol1, aParArg1, aPntSol1);
aGccCirc2d.Tangency2(i, aParSol2, aParArg2, aPntSol2);
// Distance from tangency point 1 to circle center must equal radius within 1%
const double aD1 = aPntSol1.Distance(aCenter);
const double aDelta1 = std::abs(aD1 - aR) / aR * 100.0;
EXPECT_LE(aDelta1, aMaxDeltaPercent)
<< "Solution " << i << ": tangency1 distance error " << aDelta1 << "% exceeds 1%";
// Distance from tangency point 2 to circle center must equal radius within 1%
const double aD2 = aPntSol2.Distance(aCenter);
const double aDelta2 = std::abs(aD2 - aR) / aR * 100.0;
EXPECT_LE(aDelta2, aMaxDeltaPercent)
<< "Solution " << i << ": tangency2 distance error " << aDelta2 << "% exceeds 1%";
}
}
@@ -0,0 +1,82 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <GccEnt.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dGcc_Lin2d2Tan.hxx>
#include <Geom2dGcc_QualifiedCurve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_Plane.hxx>
#include <GeomAPI.hxx>
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
// Test OCC813: Geom2dGcc_Lin2d2Tan - tangent line between a 2D ellipse and a point.
// Migrated from QABugs_17.cxx OCC813
TEST(Geom2dGcc_Lin2d2TanTest, OCC813_EllipseAndPoint)
{
// Construct 3D ellipse and projection plane
const gp_Ax2 anAx2(gp_Pnt(1262.224429, 425.040878, 363.609716),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560));
Handle(Geom_Ellipse) anEll = new Geom_Ellipse(anAx2, 150, 100);
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Ax3(anAx2));
const gp_Pln aPln = aPlane->Pln();
// Project ellipse onto the plane and build 2D qualified curve
Handle(Geom2d_Curve) aCurve2d = GeomAPI::To2d(anEll, aPln);
Geom2dAdaptor_Curve anAdapt(aCurve2d);
Geom2dGcc_QualifiedCurve aQCurve(anAdapt, GccEnt_outside);
// Query tangent line from 2D point to the projected ellipse
const gp_Pnt2d aPnt2d(200.0, 200.0);
Geom2dGcc_Lin2d2Tan aLinTan(aQCurve, aPnt2d, 0.1);
EXPECT_GT(aLinTan.NbSolutions(), 0) << "Expected at least one tangent line solution";
}
// Test OCC814: Geom2dGcc_Lin2d2Tan - tangent line between a 2D circle and a 2D ellipse.
// Migrated from QABugs_17.cxx OCC814
TEST(Geom2dGcc_Lin2d2TanTest, OCC814_CircleAndEllipse)
{
const gp_Ax2 anAx2(gp_Pnt(1262.224429, 425.040878, 363.609716),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560));
Handle(Geom_Circle) aCir = new Geom_Circle(gp_Ax2(gp_Pnt(823.687192, 502.366825, 478.960440),
gp_Dir(0.173648, 0.984808, 0.000000),
gp_Dir(-0.932169, 0.164367, -0.322560)),
50);
Handle(Geom_Ellipse) anEll = new Geom_Ellipse(anAx2, 150, 100);
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Ax3(anAx2));
const gp_Pln aPln = aPlane->Pln();
// Project both curves onto the plane and build qualified curves
Handle(Geom2d_Curve) aCurve2d = GeomAPI::To2d(anEll, aPln);
Handle(Geom2d_Curve) aFromCurve2d = GeomAPI::To2d(aCir, aPln);
Geom2dAdaptor_Curve anAdaptEll(aCurve2d);
Geom2dAdaptor_Curve anAdaptCir(aFromCurve2d);
Geom2dGcc_QualifiedCurve aQEll(anAdaptEll, GccEnt_outside);
Geom2dGcc_QualifiedCurve aQCir(anAdaptCir, GccEnt_outside);
Geom2dGcc_Lin2d2Tan aLinTan(aQEll, aQCir, 0.1);
EXPECT_GT(aLinTan.NbSolutions(), 0) << "Expected at least one tangent line solution";
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,173 @@
// Copyright (c) 2026 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 <BRepBuilderAPI_MakeFace.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepGProp.hxx>
#include <BRepOffset_MakeOffset.hxx>
#include <BRepOffsetAPI_MakeOffsetShape.hxx>
#include <BRep_Tool.hxx>
#include <GProp_GProps.hxx>
#include <Geom2dAPI_Interpolate.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <GeomAPI.hxx>
#include <GeomConvert.hxx>
#include <GeomFill_BSplineCurves.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_BezierCurve.hxx>
#include <NCollection_Array1.hxx>
#include <NCollection_HArray1.hxx>
#include <Precision.hxx>
#include <ShapeFix_Shape.hxx>
#include <Standard_Handle.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <gp_Ax3.hxx>
#include <gp_Dir.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec2d.hxx>
#include <gtest/gtest.h>
// OCC28131: BRepOffset_MakeOffset can't create offset with a face made by filling 3 BSpline curves.
namespace
{
//! Builds the filled face from 3 boundary BSpline/Bezier curves (common setup for all OCC28131
//! tests).
TopoDS_Shape createOCC28131Face()
{
const double aHeight = 8.5;
const gp_Pnt aV0(-17.6, 0.0, 0.0);
const gp_Pnt aV1(0, 32.8, 0.0);
// Outline Bezier curve
NCollection_Array1<gp_Pnt> aBezierPoles(1, 4);
aBezierPoles(1) = aV0;
aBezierPoles(4) = aV1;
aBezierPoles(2) = gp_Pnt(aV0.X(), (5.4 / 13.2) * aV1.Y(), 0);
aBezierPoles(3) = gp_Pnt((6.0 / 6.8) * aV0.X(), aV1.Y(), 0);
occ::handle<Geom_BezierCurve> aBezier = new Geom_BezierCurve(aBezierPoles);
occ::handle<Geom_BSplineCurve> anOutlineCurve = GeomConvert::CurveToBSplineCurve(aBezier);
// First side curve from 2D interpolation projected on YZ plane
occ::handle<Geom_BSplineCurve> aCurve1;
{
occ::handle<NCollection_HArray1<gp_Pnt2d>> aHArray = new NCollection_HArray1<gp_Pnt2d>(1, 2);
aHArray->SetValue(1, gp_Pnt2d(-aV1.Y(), 0));
aHArray->SetValue(2, gp_Pnt2d(0, aHeight + aHeight / 2));
Geom2dAPI_Interpolate anInterp(aHArray, false, 1e-6);
anInterp.Load(gp_Vec2d(0, 1), gp_Vec2d(1, 0));
anInterp.Perform();
const gp_Pln aPln{gp_Ax3(gp_Pnt(), gp_Dir(gp_Dir::D::X), gp_Dir(gp_Dir::D::NY))};
aCurve1 = occ::down_cast<Geom_BSplineCurve>(GeomAPI::To3d(anInterp.Curve(), aPln));
}
// Second side curve from 2D interpolation projected on XZ plane
occ::handle<Geom_BSplineCurve> aCurve2;
{
occ::handle<NCollection_HArray1<gp_Pnt2d>> aHArray = new NCollection_HArray1<gp_Pnt2d>(1, 3);
aHArray->SetValue(1, gp_Pnt2d(-aV0.X(), 0));
aHArray->SetValue(2, gp_Pnt2d(-aV0.X() - 2.6, aHeight));
aHArray->SetValue(3, gp_Pnt2d(0, aHeight + aHeight / 2));
Geom2dAPI_Interpolate anInterp(aHArray, false, 1e-6);
anInterp.Perform();
const gp_Pln aPln{gp_Ax3(gp_Pnt(), gp_Dir(gp_Dir::D::NY), gp_Dir(gp_Dir::D::NX))};
aCurve2 = occ::down_cast<Geom_BSplineCurve>(GeomAPI::To3d(anInterp.Curve(), aPln));
}
GeomFill_BSplineCurves aFill;
aFill.Init(anOutlineCurve, aCurve1, aCurve2, GeomFill_CoonsStyle);
BRepBuilderAPI_MakeFace aFaceBuilder(aFill.Surface(), 0);
return aFaceBuilder.IsDone() ? aFaceBuilder.Shape() : TopoDS_Shape();
}
//! Returns the maximum BRep tolerance across all vertices, edges, and faces of theShape.
double maxTolerance(const TopoDS_Shape& theShape)
{
double aMaxTol = 0.0;
for (TopExp_Explorer anExp(theShape, TopAbs_VERTEX); anExp.More(); anExp.Next())
aMaxTol = std::max(aMaxTol, BRep_Tool::Tolerance(TopoDS::Vertex(anExp.Current())));
for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More(); anExp.Next())
aMaxTol = std::max(aMaxTol, BRep_Tool::Tolerance(TopoDS::Edge(anExp.Current())));
for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More(); anExp.Next())
aMaxTol = std::max(aMaxTol, BRep_Tool::Tolerance(TopoDS::Face(anExp.Current())));
return aMaxTol;
}
//! Returns the surface area of theShape.
double surfaceArea(const TopoDS_Shape& theShape)
{
GProp_GProps aProps;
BRepGProp::SurfaceProperties(theShape, aProps);
return aProps.Mass();
}
} // namespace
TEST(GeomFill_BSplineCurvesTest, OCC28131_FillSurfaceFromBezierAndInterpolatedCurves)
{
const TopoDS_Shape aFace = createOCC28131Face();
ASSERT_FALSE(aFace.IsNull());
EXPECT_TRUE(BRepCheck_Analyzer(aFace).IsValid());
}
TEST(GeomFill_BSplineCurvesTest, OCC28131_SimpleOffsetOfFilledFace)
{
const TopoDS_Shape aFace = createOCC28131Face();
ASSERT_FALSE(aFace.IsNull());
BRepOffsetAPI_MakeOffsetShape aMaker;
aMaker.PerformBySimple(aFace, 10.0);
ASSERT_TRUE(aMaker.IsDone());
const TopoDS_Shape aResult = aMaker.Shape();
ASSERT_FALSE(aResult.IsNull());
EXPECT_TRUE(BRepCheck_Analyzer(aResult).IsValid());
// checkmaxtol -ref 0.205 (1% relative tolerance)
EXPECT_NEAR(maxTolerance(aResult), 0.205, 0.205 * 0.01);
// checkprops -s 1693.7 (1% relative tolerance)
EXPECT_NEAR(surfaceArea(aResult), 1693.7, 1693.7 * 0.01);
}
TEST(GeomFill_BSplineCurvesTest, OCC28131_StandardOffsetOfFilledFace)
{
const TopoDS_Shape aFace = createOCC28131Face();
ASSERT_FALSE(aFace.IsNull());
BRepOffset_MakeOffset aMaker;
aMaker
.Initialize(aFace, 10.0, Precision::Confusion(), BRepOffset_Skin, false, false, GeomAbs_Arc);
aMaker.MakeOffsetShape();
ASSERT_FALSE(aMaker.Shape().IsNull());
// The Draw test runs fixshape before checking - apply ShapeFix_Shape likewise
occ::handle<ShapeFix_Shape> aFixer = new ShapeFix_Shape(aMaker.Shape());
aFixer->Perform();
const TopoDS_Shape aResult = aFixer->Shape();
ASSERT_FALSE(aResult.IsNull());
EXPECT_TRUE(BRepCheck_Analyzer(aResult).IsValid());
// checkmaxtol -ref 0.408
EXPECT_NEAR(maxTolerance(aResult), 0.408, 0.408 * 0.01);
// checkprops -s 1693.76
EXPECT_NEAR(surfaceArea(aResult), 1693.76, 1693.76 * 0.01);
}
@@ -0,0 +1,59 @@
// Copyright (c) 2026 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 <GeomFill_NSections.hxx>
#include <Geom_BSplineCurve.hxx>
#include <NCollection_Array1.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Sequence.hxx>
#include <gp_Pnt.hxx>
#include <gtest/gtest.h>
namespace
{
//! Builds a simple degree-1 BSpline line segment from (0,0,0) to (1,0,0).
static Handle(Geom_BSplineCurve) makeSimpleLinearCurve()
{
NCollection_Array1<gp_Pnt> aPoles(1, 2);
aPoles(1) = gp_Pnt(0.0, 0.0, 0.0);
aPoles(2) = gp_Pnt(1.0, 0.0, 0.0);
NCollection_Array1<double> aKnots(1, 2);
aKnots(1) = 0.0;
aKnots(2) = 1.0;
NCollection_Array1<int> aMults(1, 2);
aMults(1) = 2;
aMults(2) = 2;
return new Geom_BSplineCurve(aPoles, aKnots, aMults, 1);
}
} // namespace
// Tests that GeomFill_NSections with a single-curve sequence does not throw.
// The resulting BSplineSurface may be null for a degenerate single-section case,
// but no exception should be raised (OCC27875).
TEST(GeomFill_NSectionsTest, OCC27875_SingleCurveDoesNotThrow)
{
Handle(Geom_BSplineCurve) aCurve = makeSimpleLinearCurve();
ASSERT_FALSE(aCurve.IsNull());
NCollection_Sequence<Handle(Geom_Curve)> aNC(new NCollection_IncAllocator());
aNC.Append(Handle(Geom_Curve)(aCurve));
// Must not throw even though result may be degenerate
EXPECT_NO_THROW({ GeomFill_NSections aNS(aNC); });
}
@@ -0,0 +1,78 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <BRepMesh_CircleTool.hxx>
#include <Precision.hxx>
#include <gp_XY.hxx>
#include <cmath>
#include <cstdlib>
#include <ctime>
namespace
{
// Returns true if thePoint lies on the circle defined by theCenter and theRadius.
bool isOnCircle(const gp_XY& thePoint, const gp_XY& theCenter, const double theRadius)
{
static const double aSqPrec = Precision::PConfusion() * Precision::PConfusion();
const gp_XY aDiff = thePoint - theCenter;
return aDiff.SquareModulus() - theRadius * theRadius < aSqPrec;
}
} // namespace
// OCC24923: BRepMesh_CircleTool produces bad circles
// For a large set of random non-degenerate triangles, every circumscribed circle
// computed by BRepMesh_CircleTool::MakeCircle must pass through all three input points.
TEST(BRepMesh_CircleTool_Test, OCC24923_CircumCirclePassesThroughAllVertices)
{
srand(42);
static const double aSqPrec = Precision::PConfusion() * Precision::PConfusion();
const double aMinArea = 5.0 * M_PI / 180.0; // same threshold as the original command
const int aNbTests = 100000;
int aNbFailed = 0;
int i = 0;
while (i < aNbTests)
{
gp_XY p[3];
for (int j = 0; j < 3; ++j)
p[j].SetCoord(static_cast<double>(rand()) / RAND_MAX, static_cast<double>(rand()) / RAND_MAX);
// Skip degenerate (nearly collinear) triangles - retry like the original.
const gp_XY aV1 = p[1] - p[0];
const gp_XY aV2 = p[2] - p[0];
if (aV1.SquareModulus() <= aSqPrec || aV2.SquareModulus() <= aSqPrec || (aV1 ^ aV2) <= aMinArea)
continue;
++i;
gp_XY aCenter;
double aRadius = 0.0;
if (!BRepMesh_CircleTool::MakeCircle(p[0], p[1], p[2], aCenter, aRadius))
continue;
if (!isOnCircle(p[0], aCenter, aRadius) || !isOnCircle(p[1], aCenter, aRadius)
|| !isOnCircle(p[2], aCenter, aRadius))
{
++aNbFailed;
}
}
// Allow at most 1% failure rate (same threshold as the original Draw test).
const double aFailRate = static_cast<double>(aNbFailed) / static_cast<double>(aNbTests);
EXPECT_LE(aFailRate, 0.01) << "Too many bad circumscribed circles: " << aNbFailed << " / "
<< aNbTests;
}
@@ -0,0 +1,73 @@
// Copyright (c) 2026 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 <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <gtest/gtest.h>
// Test OCC26407: BRepMesh_Delaun must not fail on a planar polygon with frontier edges.
// The key check is that GetStatusFlags() == 0 (success) after meshing.
// Migrated from QABugs_19.cxx OCC26407
TEST(BRepMesh_IncrementalMeshTest, OCC26407_PlanarPolygonMeshStatus)
{
// Hardcoded octagon-like polygon lying in the Z=88.5 plane
std::vector<gp_Pnt> aPnts = {
gp_Pnt(587.90000000000009094947, 40.6758179230516248026106, 88.5),
gp_Pnt(807.824182076948432040808, 260.599999999999965893949, 88.5),
gp_Pnt(644.174182076948454778176, 424.249999999999943156581, 88.5000000000000142108547),
gp_Pnt(629.978025792618950617907, 424.25, 88.5),
gp_Pnt(793.628025792618700506864, 260.599999999999852207111, 88.5),
gp_Pnt(587.900000000000204636308, 54.8719742073813492311274, 88.5),
gp_Pnt(218.521974207381418864315, 424.250000000000056843419, 88.5),
gp_Pnt(204.325817923051886282337, 424.249999999999943156581, 88.5)};
std::vector<TopoDS_Vertex> aVertices;
aVertices.reserve(aPnts.size());
for (const gp_Pnt& aPnt : aPnts)
{
aVertices.push_back(BRepBuilderAPI_MakeVertex(aPnt));
}
BRepBuilderAPI_MakeWire aWireBuilder;
for (size_t i = 0; i < aVertices.size(); ++i)
{
const TopoDS_Vertex& aV = aVertices[i];
const TopoDS_Vertex& aW = aVertices[(i + 1) % aVertices.size()];
aWireBuilder.Add(BRepBuilderAPI_MakeEdge(aV, aW));
}
ASSERT_TRUE(aWireBuilder.IsDone()) << "Wire construction failed";
const gp_Pnt& aV0 = aPnts[0];
const gp_Pnt& aV1 = aPnts[1];
const gp_Pnt& aV2 = aPnts[aPnts.size() - 1];
const gp_Vec aFaceNormal = gp_Vec(aV0, aV1).Crossed(gp_Vec(aV0, aV2));
const TopoDS_Face aFace = BRepBuilderAPI_MakeFace(gp_Pln(aV0, aFaceNormal), aWireBuilder.Wire());
BRepMesh_IncrementalMesh aMesher(aFace, 1.e-7);
EXPECT_EQ(aMesher.GetStatusFlags(), 0)
<< "Meshing of the planar polygon face should succeed (status 0)";
}
@@ -3,7 +3,9 @@ set(OCCT_TKMesh_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKMesh_GTests_FILES
BRepMesh_BaseMeshAlgo_Test.cxx
BRepMesh_CircleTool_Test.cxx
BRepMesh_Delaun_Test.cxx
BRepMesh_DiscretAlgoFactory_Test.cxx
BRepMesh_GeomTool_Test.cxx
BRepMesh_IncrementalMesh_Test.cxx
)
@@ -11,13 +11,21 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepGProp.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Geom_BSplineCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <gp_Pnt.hxx>
#include <GProp_GProps.hxx>
#include <GProp_PrincipalProps.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <Standard_Handle.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
@@ -115,3 +123,75 @@ TEST(BRepGPropTest, LinearProperties_SkipShared)
EXPECT_NEAR(aPropsNotSkipped.Mass(), 240.0, Precision::Confusion())
<< "Total edge length with SkipShared=false should be double";
}
// Test OCC49: GProp_PrincipalProps::HasSymmetryAxis - cylinder has symmetry, cut does not.
// Migrated from QABugs_16.cxx OCC49
TEST(BRepGPropTest, OCC49_CylinderHasSymmetryAxis)
{
const TopoDS_Shape aCylinder = BRepPrimAPI_MakeCylinder(10., 20.).Shape();
GProp_GProps aProps;
BRepGProp::VolumeProperties(aCylinder, aProps);
const GProp_PrincipalProps aPrincipal = aProps.PrincipalProperties();
EXPECT_TRUE(aPrincipal.HasSymmetryAxis());
}
TEST(BRepGPropTest, OCC49_CutShapeHasNoSymmetryAxis)
{
const TopoDS_Shape aCylinder = BRepPrimAPI_MakeCylinder(10., 20.).Shape();
const TopoDS_Shape aBox = BRepPrimAPI_MakeBox(10., 10., 10.).Shape();
BRepAlgoAPI_Cut aCut(aCylinder, aBox);
ASSERT_TRUE(aCut.IsDone());
GProp_GProps aProps;
BRepGProp::VolumeProperties(aCut.Shape(), aProps);
const GProp_PrincipalProps aPrincipal = aProps.PrincipalProperties();
EXPECT_FALSE(aPrincipal.HasSymmetryAxis());
}
// OCC8797: Verify that GCPnts_AbscissaPoint::Length and BRepGProp::LinearProperties
// produce consistent arc-length values for a degree-3 BSpline curve with 7 poles.
// Both methods must agree within a tight relative tolerance.
TEST(BRepGPropTest, OCC8797_BSplineLengthConsistencyAbscissaVsLinearProperties)
{
NCollection_Array1<gp_Pnt> aPoles(0, 6);
aPoles(0) = gp_Pnt(0.0, 0.0, 0.0);
aPoles(1) = gp_Pnt(1.0, 1.0, 0.0);
aPoles(2) = gp_Pnt(2.0, 1.0, 0.0);
aPoles(3) = gp_Pnt(3.0, 0.0, 0.0);
aPoles(4) = gp_Pnt(4.0, 1.0, 0.0);
aPoles(5) = gp_Pnt(5.0, 1.0, 0.0);
aPoles(6) = gp_Pnt(6.0, 0.0, 0.0);
NCollection_Array1<double> aKnots(0, 2);
aKnots(0) = 0.0;
aKnots(1) = 0.5;
aKnots(2) = 1.0;
NCollection_Array1<int> aMults(0, 2);
aMults(0) = 4;
aMults(1) = 3;
aMults(2) = 4;
occ::handle<Geom_BSplineCurve> aSpline = new Geom_BSplineCurve(aPoles, aKnots, aMults, 3);
ASSERT_FALSE(aSpline.IsNull());
EXPECT_EQ(aSpline->NbPoles(), 7);
EXPECT_EQ(aSpline->NbKnots(), 3);
// Method 1: GCPnts_AbscissaPoint::Length
GeomAdaptor_Curve anAdaptor(aSpline);
const double aLengthAbscissa = GCPnts_AbscissaPoint::Length(anAdaptor);
EXPECT_GT(aLengthAbscissa, 0.0);
// Method 2: BRepGProp::LinearProperties on the equivalent edge
const TopoDS_Edge aEdge = BRepBuilderAPI_MakeEdge(aSpline);
GProp_GProps aEdgeProps;
BRepGProp::LinearProperties(aEdge, aEdgeProps);
const double aLengthGProp = aEdgeProps.Mass();
EXPECT_GT(aLengthGProp, 0.0);
// Both methods must agree within 0.1 %
EXPECT_NEAR(aLengthAbscissa, aLengthGProp, aLengthGProp * 1e-3);
}
@@ -17,9 +17,18 @@
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepGProp.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>
#include <BSplCLib.hxx>
#include <GC_MakeArcOfCircle.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GProp_GProps.hxx>
#include <gce_MakeCirc.hxx>
#include <gp.hxx>
#include <gp_Ax1.hxx>
#include <gp_Ax2.hxx>
#include <gp_Circ.hxx>
#include <gp_Pnt.hxx>
#include <NCollection_Array1.hxx>
#include <Standard_Integer.hxx>
@@ -324,3 +333,61 @@ TEST(BRepOffsetAPI_ThruSections_Test, BSplineProfilesWithDifferentPoleCount)
EXPECT_FALSE(aThruSections.Shape().IsNull()) << "ThruSections should produce a valid shape";
}
}
// Test OCC895: BRepOffsetAPI_ThruSections with two circular arc wires.
// Regression test for incorrect computation of mutual orientations of wire segments
// that caused a twisted surface to be created.
TEST(BRepOffsetAPI_ThruSections_Test, OCC895_TwoCircularArcWires_NoTwist)
{
// Build the two wires using circular arcs at different positions,
// reproducing exactly the OCC895 DRAW command with angle=5, reverse=0, order=0.
const double aRad = 1.0;
const double aAngle = 5.0 * M_PI / 180.0;
// Wire 1: arc from a circle whose axis is rotated 5 degrees around Z
gp_Pnt aCenter1(0, 10, 0);
gp_Ax2 aAxis1(aCenter1, -gp::DY(), gp::DX());
aAxis1.Rotate(gp_Ax1(aCenter1, gp::DZ()), aAngle);
gce_MakeCirc aMakeCirc1(aAxis1, aRad);
ASSERT_TRUE(aMakeCirc1.IsDone());
GC_MakeArcOfCircle aMakeArc1(aMakeCirc1.Value(), 0, M_PI / 2, true);
ASSERT_TRUE(aMakeArc1.IsDone());
const occ::handle<Geom_TrimmedCurve>& aArc1 = aMakeArc1.Value();
BRepBuilderAPI_MakeEdge aMakeEdge1(aArc1, aArc1->StartPoint(), aArc1->EndPoint());
ASSERT_TRUE(aMakeEdge1.IsDone());
BRepBuilderAPI_MakeWire aMakeWire1(aMakeEdge1.Edge());
ASSERT_TRUE(aMakeWire1.IsDone());
const TopoDS_Wire& aWire1 = aMakeWire1.Wire();
// Wire 2: arc from a circle at a different center with fixed axis
gp_Pnt aCenter2(10, 0, 0);
gp_Ax2 aAxis2(aCenter2, -gp::DX(), gp::DZ());
gce_MakeCirc aMakeCirc2(aAxis2, aRad);
ASSERT_TRUE(aMakeCirc2.IsDone());
GC_MakeArcOfCircle aMakeArc2(aMakeCirc2.Value(), 0, M_PI / 2, true);
ASSERT_TRUE(aMakeArc2.IsDone());
const occ::handle<Geom_TrimmedCurve>& aArc2 = aMakeArc2.Value();
BRepBuilderAPI_MakeEdge aMakeEdge2(aArc2, aArc2->StartPoint(), aArc2->EndPoint());
ASSERT_TRUE(aMakeEdge2.IsDone());
BRepBuilderAPI_MakeWire aMakeWire2(aMakeEdge2.Edge());
ASSERT_TRUE(aMakeWire2.IsDone());
const TopoDS_Wire& aWire2 = aMakeWire2.Wire();
// Build ThruSections shell with order=0: wire2 first, then wire1
BRepOffsetAPI_ThruSections aThruSect(false, true);
aThruSect.AddWire(aWire2);
aThruSect.AddWire(aWire1);
aThruSect.Build();
ASSERT_TRUE(aThruSect.IsDone()) << "ThruSections must succeed";
ASSERT_FALSE(aThruSect.Shape().IsNull()) << "ThruSections must produce a non-null shape";
// Verify surface area is approximately 18.1614 (reference value from DRAW test)
GProp_GProps aProps;
BRepGProp::SurfaceProperties(aThruSect.Shape(), aProps);
EXPECT_NEAR(aProps.Mass(), 18.1614, 0.01) << "Surface area should be approximately 18.1614";
}
@@ -13,12 +13,24 @@
#include <gtest/gtest.h>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <GC_MakeArcOfCircle.hxx>
#include <Geom_Circle.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <gp_Ax2.hxx>
#include <gp_Circ.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <NCollection_List.hxx>
#include <TopAbs_Orientation.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <TopExp_Explorer.hxx>
// Test OCC5696: BRepAdaptor_CompCurve::Edge() method
// Migrated from QABugs_5.cxx
@@ -57,3 +69,111 @@ TEST(BRepAdaptor_CompCurve_Test, OCC5696_EdgeMethod)
// The parameter should be approximately half of the edge length
EXPECT_NEAR(1.0, aParEdge, 0.01) << "Edge parameter should be approximately 1.0";
}
// Test OCC29430: BRepAdaptor_CompCurve::Value() at boundary parameters matches wire vertices.
// The bug was that evaluating a composite curve at its First/LastParameter
// did not return the correct endpoint.
TEST(BRepAdaptor_CompCurve_Test, OCC29430_ArcBoundaryPoints)
{
const double r45 = M_PI / 4.0, r225 = 3.0 * M_PI / 4.0;
GC_MakeArcOfCircle arcMaker(
gp_Circ(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(gp_Dir::D::Z), gp_Dir(gp_Dir::D::X)), 1.0),
r45,
r225,
true);
BRepBuilderAPI_MakeEdge edgeMaker(arcMaker.Value());
BRepBuilderAPI_MakeWire wireMaker(edgeMaker.Edge());
const TopoDS_Wire aWire = wireMaker.Wire();
BRepAdaptor_CompCurve aCurve(aWire);
const gp_Pnt aStartPt = aCurve.Value(aCurve.FirstParameter());
const gp_Pnt anEndPt = aCurve.Value(aCurve.LastParameter());
// Collect wire vertices
NCollection_List<gp_Pnt> aVertices;
for (TopExp_Explorer anExp(aWire, TopAbs_VERTEX); anExp.More(); anExp.Next())
{
aVertices.Append(BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())));
}
ASSERT_GE(aVertices.Size(), 1);
// Start point should match one of the wire vertices (within 1e-7 tolerance)
bool aStartMatchesAnyVertex = false;
bool anEndMatchesAnyVertex = false;
for (const gp_Pnt& aV : aVertices)
{
if (aStartPt.Distance(aV) < 1.0e-7)
aStartMatchesAnyVertex = true;
if (anEndPt.Distance(aV) < 1.0e-7)
anEndMatchesAnyVertex = true;
}
EXPECT_TRUE(aStartMatchesAnyVertex) << "Start point does not match any wire vertex";
EXPECT_TRUE(anEndMatchesAnyVertex) << "End point does not match any wire vertex";
EXPECT_GT(aStartPt.Distance(anEndPt), 1.0e-7) << "Start and end points should be different";
}
// Test OCC30869: BRepAdaptor_CompCurve D1 at boundary parameters of a wire with reversed edge.
// The bug was that a wire with a single reversed-orientation trimmed-circle edge returned
// incorrect boundary point coordinates and tangent directions.
// Migrated from QABugs_20.cxx OCC30869
TEST(BRepAdaptor_CompCurve_Test, OCC30869_ReversedEdgeBoundaryPoints)
{
// Build a circle: center(1,0,0), Z-axis(0,-1,0), X-axis(0,0,-1), radius=1
const gp_Ax2 anAx2(gp_Pnt(1., 0., 0.), gp_Dir(0., -1., 0.), gp_Dir(0., 0., -1.));
Handle(Geom_Circle) aCircle = new Geom_Circle(anAx2, 1.0);
const double t1 = M_PI / 2.0; // 1.5707963267949
const double t2 = 3.0 * M_PI / 2.0; // 4.71238898038469
Handle(Geom_TrimmedCurve) aTrimmed = new Geom_TrimmedCurve(aCircle, t1, t2);
TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(aTrimmed).Edge();
// Reverse the edge, then wrap it in a wire
anEdge.Orientation(TopAbs_REVERSED);
TopoDS_Wire aWire = BRepBuilderAPI_MakeWire(anEdge).Wire();
BRepAdaptor_CompCurve aBACC(aWire);
const double aFirst = aBACC.FirstParameter();
const double aLast = aBACC.LastParameter();
gp_Pnt aPFirst, aPLast;
gp_Vec aVFirst, aVLast;
aBACC.D1(aFirst, aPFirst, aVFirst);
aBACC.D1(aLast, aPLast, aVLast);
if (aVFirst.SquareMagnitude() > gp::Resolution())
aVFirst.Normalize();
if (aVLast.SquareMagnitude() > gp::Resolution())
aVLast.Normalize();
// Reference: inverse circle (normal = (0,1,0)), evaluated at the same parameters
const gp_Ax2 anAx2Ref(gp_Pnt(1., 0., 0.), gp_Dir(0., 1., 0.), gp_Dir(0., 0., -1.));
Handle(Geom_Circle) aCircleRef = new Geom_Circle(anAx2Ref, 1.0);
gp_Pnt aRefP1, aRefP2;
gp_Vec aRefV1, aRefV2;
aCircleRef->D1(t1, aRefP1, aRefV1);
aCircleRef->D1(t2, aRefP2, aRefV2);
if (aRefV1.SquareMagnitude() > gp::Resolution())
aRefV1.Normalize();
if (aRefV2.SquareMagnitude() > gp::Resolution())
aRefV2.Normalize();
const double aTol = 1.e-7;
EXPECT_NEAR(aPFirst.X(), aRefP1.X(), aTol) << "First point X";
EXPECT_NEAR(aPFirst.Y(), aRefP1.Y(), aTol) << "First point Y";
EXPECT_NEAR(aPFirst.Z(), aRefP1.Z(), aTol) << "First point Z";
EXPECT_NEAR(aVFirst.X(), aRefV1.X(), aTol) << "First tangent X";
EXPECT_NEAR(aVFirst.Y(), aRefV1.Y(), aTol) << "First tangent Y";
EXPECT_NEAR(aVFirst.Z(), aRefV1.Z(), aTol) << "First tangent Z";
EXPECT_NEAR(aPLast.X(), aRefP2.X(), aTol) << "Last point X";
EXPECT_NEAR(aPLast.Y(), aRefP2.Y(), aTol) << "Last point Y";
EXPECT_NEAR(aPLast.Z(), aRefP2.Z(), aTol) << "Last point Z";
EXPECT_NEAR(aVLast.X(), aRefV2.X(), aTol) << "Last tangent X";
EXPECT_NEAR(aVLast.Y(), aRefV2.Y(), aTol) << "Last tangent Y";
EXPECT_NEAR(aVLast.Z(), aRefV2.Z(), aTol) << "Last tangent Z";
}
@@ -17,6 +17,7 @@
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Trsf.hxx>
@@ -932,3 +933,95 @@ TEST_F(Geom_BSplineSurface_Test, WeightsArray_Rational_ReturnsOwning)
EXPECT_DOUBLE_EQ(aWeights(1, 1), 1.0);
EXPECT_EQ(&aWeights, &aRational->WeightsArray());
}
// OCC30990: Foundation Classes - unexpected change in numerical results on bsplines after 0029769
// Verify that evaluating a B-Spline surface at a knot gives consistent results regardless of
// which span was evaluated beforehand (i.e., the cache is updated correctly).
TEST_F(Geom_BSplineSurface_Test, OCC30990_CacheConsistencyAtKnots)
{
// Build a degree-3 B-Spline surface with 3 interior knots in U (4 spans) and 2 in V (3 spans).
// Poles: 7 x 5
const int aNbU = 7;
const int aNbV = 5;
NCollection_Array2<gp_Pnt> aPoles(1, aNbU, 1, aNbV);
for (int i = 1; i <= aNbU; ++i)
for (int j = 1; j <= aNbV; ++j)
aPoles(i, j) =
gp_Pnt(static_cast<double>(i - 1),
static_cast<double>(j - 1),
std::sin(static_cast<double>(i) * 0.5) * std::cos(static_cast<double>(j) * 0.7));
// Knot vector in U: [0, 0.25, 0.5, 0.75, 1] with multiplicities [4, 1, 1, 1, 4]
NCollection_Array1<double> aUKnots(1, 5);
aUKnots(1) = 0.0;
aUKnots(2) = 0.25;
aUKnots(3) = 0.5;
aUKnots(4) = 0.75;
aUKnots(5) = 1.0;
NCollection_Array1<int> aUMults(1, 5);
aUMults(1) = 4;
aUMults(2) = 1;
aUMults(3) = 1;
aUMults(4) = 1;
aUMults(5) = 4;
// Knot vector in V: [0, 0.5, 1] with multiplicities [4, 1, 4]
NCollection_Array1<double> aVKnots(1, 3);
aVKnots(1) = 0.0;
aVKnots(2) = 0.5;
aVKnots(3) = 1.0;
NCollection_Array1<int> aVMults(1, 3);
aVMults(1) = 4;
aVMults(2) = 1;
aVMults(3) = 4;
const occ::handle<Geom_BSplineSurface> aSurf =
new Geom_BSplineSurface(aPoles, aUKnots, aVKnots, aUMults, aVMults, 3, 3);
ASSERT_FALSE(aSurf.IsNull());
GeomAdaptor_Surface aAdaptor(aSurf);
// For each interior U knot, verify that evaluation at the knot is consistent
// regardless of whether the previous evaluation was in the span before or after.
int aNbErr = 0;
for (int i = 2; i < aSurf->NbUKnots(); ++i)
{
const double aUknot = aSurf->UKnot(i);
const double aUprev = 0.5 * (aUknot + aSurf->UKnot(i - 1));
const double aUnext = 0.5 * (aUknot + aSurf->UKnot(i + 1));
for (int j = 1; j < aSurf->NbVKnots(); ++j)
{
const double aV = 0.5 * (aSurf->VKnot(j) + aSurf->VKnot(j + 1));
aAdaptor.Value(aUprev, aV); // populate cache from span before
const gp_Pnt aP1 = aAdaptor.Value(aUknot, aV);
aAdaptor.Value(aUnext, aV); // populate cache from span after
const gp_Pnt aP2 = aAdaptor.Value(aUknot, aV);
if (aP1.X() != aP2.X() || aP1.Y() != aP2.Y() || aP1.Z() != aP2.Z())
++aNbErr;
}
}
// Same check for interior V knots
for (int j = 2; j < aSurf->NbVKnots(); ++j)
{
const double aVknot = aSurf->VKnot(j);
const double aVprev = 0.5 * (aVknot + aSurf->VKnot(j - 1));
const double aVnext = 0.5 * (aVknot + aSurf->VKnot(j + 1));
for (int i = 1; i < aSurf->NbUKnots(); ++i)
{
const double aU = 0.5 * (aSurf->UKnot(i) + aSurf->UKnot(i + 1));
aAdaptor.Value(aU, aVprev);
const gp_Pnt aP1 = aAdaptor.Value(aU, aVknot);
aAdaptor.Value(aU, aVnext);
const gp_Pnt aP2 = aAdaptor.Value(aU, aVknot);
if (aP1.X() != aP2.X() || aP1.Y() != aP2.Y() || aP1.Z() != aP2.Z())
++aNbErr;
}
}
EXPECT_EQ(0, aNbErr) << "BSpline surface cache is inconsistent at span knots";
}
@@ -21,6 +21,7 @@
#include <gp_Trsf.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <Standard_Failure.hxx>
class Geom_BezierCurve_Test : public ::testing::Test
{
@@ -524,3 +525,29 @@ TEST_F(Geom_BezierCurve_Test, WeightsArray_Rational_ReturnsOwning)
EXPECT_DOUBLE_EQ(aWeights(3), 1.0);
EXPECT_EQ(&aWeights, &aRational->WeightsArray());
}
// Test OCC2569: Geom_BezierCurve degree equals NbPoles - 1.
// Migrated from QABugs_17.cxx OCC2569
TEST(Geom_BezierCurveTest, OCC2569_DegreeEqualsNbPolesMinusOne)
{
const int aNbPoles = 26;
NCollection_Array1<gp_Pnt> aPoles(1, aNbPoles);
for (int i = 1; i <= aNbPoles; ++i)
aPoles.SetValue(i, gp_Pnt(i + 10, i * 2 + 20, i * 3 + 45));
Handle(Geom_BezierCurve) aCurve = new Geom_BezierCurve(aPoles);
ASSERT_FALSE(aCurve.IsNull());
EXPECT_EQ(aCurve->Degree(), aNbPoles - 1);
}
// Test OCC2569: Geom_BezierCurve throws when NbPoles exceeds maximum allowed.
// Migrated from QABugs_17.cxx OCC2569 (bug2569_2)
TEST(Geom_BezierCurveTest, OCC2569_ThrowsForTooManyPoles)
{
const int aNbPoles = 29;
NCollection_Array1<gp_Pnt> aPoles(1, aNbPoles);
for (int i = 1; i <= aNbPoles; ++i)
aPoles.SetValue(i, gp_Pnt(i + 10, i * 2 + 20, i * 3 + 45));
EXPECT_THROW(new Geom_BezierCurve(aPoles), Standard_Failure);
}
@@ -35,9 +35,11 @@ set(OCCT_TKGeomBase_GTests_FILES
GC_MakeCircle2d_Test.cxx
GC_MakeConicalSurface_Test.cxx
GC_MakePlane_Test.cxx
GC_MakeParabola2d_Test.cxx
GC_MakeSegment2d_Test.cxx
GCPnts_AbscissaPoint_Test.cxx
GeomConvert_CompCurveToBSplineCurve_Test.cxx
Geom2dConvert_CompCurveToBSplineCurve_Test.cxx
GeomConvert_Test.cxx
Hermit_Test.cxx
IntAna_IntQuadQuad_Test.cxx
@@ -0,0 +1,88 @@
// Copyright (c) 2026 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 <gtest/gtest.h>
#include <GC_MakeParabola2d.hxx>
#include <gp_Ax2d.hxx>
#include <gp_Dir2d.hxx>
#include <gp_Parab2d.hxx>
#include <gp_Pnt2d.hxx>
namespace
{
// Helper: verify a parabola built from directrix+focus against expected values.
void CheckParabola2d(const gp_Ax2d& theAxes,
const gp_Pnt2d& theFocus,
bool theSense,
double theExpectedFocal,
double theExpectedVertX,
double theExpectedVertY,
double theExpectedParam,
const double theExpectedCoeffs[6])
{
const double aCompareTol = 1.0e-12;
GC_MakeParabola2d aPrb(theAxes, theFocus, theSense);
ASSERT_FALSE(aPrb.Value().IsNull()) << "GC_MakeParabola2d should produce a non-null result";
const gp_Parab2d& aParab = aPrb.Value()->Parab2d();
const gp_Pnt2d aVert(aParab.Location());
EXPECT_NEAR(aParab.Focal(), theExpectedFocal, aCompareTol) << "Wrong focal length";
EXPECT_NEAR(aVert.X(), theExpectedVertX, aCompareTol) << "Wrong vertex X";
EXPECT_NEAR(aVert.Y(), theExpectedVertY, aCompareTol) << "Wrong vertex Y";
EXPECT_NEAR(aParab.Parameter(), theExpectedParam, aCompareTol) << "Wrong parameter";
double aF[6];
aParab.Coefficients(aF[0], aF[1], aF[2], aF[3], aF[4], aF[5]);
for (int i = 0; i < 6; ++i)
{
EXPECT_NEAR(aF[i], theExpectedCoeffs[i], aCompareTol)
<< "Wrong coefficient [" << i << "]: got " << aF[i] << ", expected " << theExpectedCoeffs[i];
}
}
} // namespace
// Test OCC26747 (case 1): parabola with vertex at (0.5, 3.0) opening in +X direction.
// Directrix Y-axis at x=0, y=3; focus at (1.0, 3.0); sense=true.
// Equation: (y-3)^2 = 2*(x-0.5), i.e. 1*Y^2 + 2*(-1)*X + 2*(-3)*Y + 10 = 0.
TEST(GC_MakeParabola2d_Test, OCC26747_1_ParabolaOpeningRight)
{
const gp_Ax2d anAxes(gp_Pnt2d(0.0, 3.0), gp_Dir2d(gp_Dir2d::D::Y));
const gp_Pnt2d aFocus(1.0, 3.0);
const double aCoeffs[6] = {0.0, 1.0, 0.0, -1.0, -3.0, 10.0};
CheckParabola2d(anAxes, aFocus, true, 0.5, 0.5, 3.0, 1.0, aCoeffs);
}
// Test OCC26747 (case 2): parabola with vertex at (-0.5, 3.0) opening in -X direction.
// Directrix Y-axis at origin; focus at (-1.0, 3.0); sense=false.
// Equation (WCS): (y-3)^2 = 2*(-x-0.5), i.e. 1*Y^2 + 2*1*X + 2*(-3)*Y + 10 = 0.
TEST(GC_MakeParabola2d_Test, OCC26747_2_ParabolaOpeningLeft)
{
const gp_Ax2d anAxes(gp_Pnt2d(0.0, 0.0), gp_Dir2d(gp_Dir2d::D::Y));
const gp_Pnt2d aFocus(-1.0, 3.0);
const double aCoeffs[6] = {0.0, 1.0, 0.0, 1.0, -3.0, 10.0};
CheckParabola2d(anAxes, aFocus, false, 0.5, -0.5, 3.0, 1.0, aCoeffs);
}
// Test OCC26747 (case 3): degenerate parabola where focus coincides with vertex.
// Directrix Y-axis at origin; focus at (0.0, 3.0); sense=false.
// Focal length = 0, parameter = 0. Equation: Y^2 + 2*(-3)*Y + 9 = 0 (line y=3).
TEST(GC_MakeParabola2d_Test, OCC26747_3_DegenerateParabola)
{
const gp_Ax2d anAxes(gp_Pnt2d(0.0, 0.0), gp_Dir2d(gp_Dir2d::D::Y));
const gp_Pnt2d aFocus(0.0, 3.0);
const double aCoeffs[6] = {0.0, 1.0, 0.0, 0.0, -3.0, 9.0};
CheckParabola2d(anAxes, aFocus, false, 0.0, 0.0, 3.0, 0.0, aCoeffs);
}
@@ -0,0 +1,58 @@
// Copyright (c) 2026 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 <GC_MakeCircle2d.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Circle.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
#include <Precision.hxx>
#include <Standard_Handle.hxx>
#include <gp_Pnt2d.hxx>
#include <gtest/gtest.h>
TEST(Geom2dConvert_CompCurveToBSplineCurveTest, OCC30747_ClosedContourFromCircleArcs)
{
// OCC30747: 2d Curves concatenator must properly handle closed contours.
// Split a full circle into 10 arcs and assemble them into a closed BSpline.
const occ::handle<Geom2d_Circle> aCirc = GC_MakeCircle2d(gp_Pnt2d(0, 0), 50);
ASSERT_FALSE(aCirc.IsNull());
const double aF = aCirc->FirstParameter();
const double aL = aCirc->LastParameter();
const int aNb = 10;
const double aDelta = (aF + aL) / aNb;
occ::handle<Geom2d_TrimmedCurve> aFTrim = new Geom2d_TrimmedCurve(aCirc, aF, aDelta);
Geom2dConvert_CompCurveToBSplineCurve aRes(aFTrim);
for (int anId = 1; anId < aNb; anId++)
{
occ::handle<Geom2d_TrimmedCurve> aLTrim;
if (anId == (aNb - 1))
{
aLTrim = new Geom2d_TrimmedCurve(aCirc, anId * aDelta, aF);
}
else
{
aLTrim = new Geom2d_TrimmedCurve(aCirc, anId * aDelta, (anId + 1) * aDelta);
}
aRes.Add(aLTrim, Precision::PConfusion());
}
const occ::handle<Geom2d_BSplineCurve> aBSpline = aRes.BSplineCurve();
ASSERT_FALSE(aBSpline.IsNull());
EXPECT_TRUE(aBSpline->IsClosed())
<< "Assembled BSpline curve from closed circle arcs must be closed";
}
-13
View File
@@ -1,13 +0,0 @@
puts "============"
puts "0031320: TObj - method TObj_Object::GetFatherObject() is not protected against deleted object"
puts "============"
puts ""
pload TOBJ QAcommands
# create document with object and sub-object
TObjNew TD1
TObjAddObj TD1 obj
TObjAddChild TD1 obj subobj1
OCC31320 TD1 obj
-25
View File
@@ -1,25 +0,0 @@
puts "==========="
puts "OCC15489"
puts "==========="
set BugNumber OCC15489
######################################################
# Constructor gp_Lin2d(A, B, C) creates line with origin point in infinity
######################################################
pload QAcommands
set A 1e-20
set B -1.
set C 2.
set OriginList [OCC15489 $A $B $C]
regexp {X_0 += +([-0-9.+eE]+)} $OriginList full X_0
regexp {Y_0 += +([-0-9.+eE]+)} $OriginList full Y_0
set good_X_0 -1.9999999999999999e-20
set good_Y_0 2
checkreal "X_0" ${X_0} ${good_X_0} 0 0.001
checkreal "Y_0" ${Y_0} ${good_Y_0} 0 0.001
-34
View File
@@ -1,34 +0,0 @@
puts "========"
puts "OCC181"
puts "OCC701"
puts "========"
######################################################
# Resource_Manager class doesn't return status of saving resources in a file.
######################################################
# Add method BuildPath to OSD_Directory
######################################################
# Clear tmp-data
######################################################################
set tmp ${imagedir}
######################################################################
pload QAcommands
set log [OCC181 OCC181 ${imagedir} ${tmp}/1 0]
set list [split ${log}]
set ll [llength ${list}]
set status [lindex ${list} [expr ${ll} - 2] ]
if { ${status} == "TRUE"} then {
puts "OCC181: OK"
} else {
puts "OCC181: Error"
}
if { ! [file exists ${tmp}/1/OCC181] } {
puts "Error: user resource file is not found!"
}
file delete -force ${tmp}/1
-34
View File
@@ -1,34 +0,0 @@
puts "========"
puts "OCC181"
puts "OCC701"
puts "========"
######################################################
# Resource_Manager class doesn't return status of saving resources in a file.
######################################################
# Add method BuildPath to OSD_Directory
######################################################
# Clear tmp-data
######################################################################
set tmp ${imagedir}
######################################################################
pload QAcommands
set log [OCC181 OCC181 ${imagedir} ${tmp}/2/2/3 0]
set list [split ${log}]
set ll [llength ${list}]
set status [lindex ${list} [expr ${ll} - 2] ]
if { ${status} == "TRUE"} then {
puts "OCC181: OK"
} else {
puts "OCC181: Error"
}
if { ! [file exists ${tmp}/2/2/3/OCC181] } {
puts "Error: user resource file is not found!"
}
file delete -force ${tmp}/2
-19
View File
@@ -1,19 +0,0 @@
puts "========"
puts "OCC22611"
puts "========"
puts ""
#######################################################################
# Memory leak in expression interpreter
#######################################################################
pload QAcommands
set BugNumber OCC22611
set listmem {}
for {set i 1} {$i < 10} {incr i} {
OCC22611 "0.1214343" 10
lappend listmem [meminfo h]
checktrend $listmem 0 1 "Memory leak detected"
}
-15
View File
@@ -1,15 +0,0 @@
puts "================"
puts "OCC24537"
puts "================"
puts ""
#######################################################################
# GCC compiler warnings in byte order reversion code.
# The matter of this test is to ensure correctness of work of the methods
# (in the file FSD_FileHeader.hxx) of inversion of numbers between little/big endian.
# Attention! The test is created for working on a little endian platform.
#######################################################################
pload QAcommands
# The following command gives an error output if conversion is wrong
OCC24537
-11
View File
@@ -1,11 +0,0 @@
puts "============"
puts "OCC25329"
puts "============"
puts ""
#######################################################################
# ExprIntrp_GenExp can not parse unary plus
#######################################################################
pload QAcommands
OCC22611 "+1" 1
-9
View File
@@ -1,9 +0,0 @@
puts "=========="
puts "0025574: gp_YawPitchRoll Euler Angle computation gives wrong results"
puts "=========="
pload QAcommands
puts "Checking conversions of Euler angles in gp_Quaternion"
OCC25574
-32
View File
@@ -1,32 +0,0 @@
puts "Test loading of resources from different paths"
puts "0027849: ResourceManager path computations fail for the folders containing dots"
pload QAcommands
set paths {
"path"
"path.with.dots"
"path with spaces"
"nested/dirs/path with spaces"
}
# key word to be saved in resource file and then checked
set keyw ok
foreach p $paths {
set path [file join $imagedir $p]
file mkdir $path
set fd [open $path/TestResource w]
puts $fd "test.resource : $keyw"
close $fd
dsetenv CSF_TestResourceDefaults $path
if { [OCC27849 TestResource test.resource] != "$keyw" } {
puts "Error: cannot read resource file in $path"
}
}
-12
View File
@@ -1,12 +0,0 @@
puts "========"
puts " 0029064: Copying of empty NCollection map takes excessive memory"
puts "========"
puts ""
pload QAcommands
OCC29064 map
OCC29064 doublemap
OCC29064 datamap
OCC29064 indexedmap
OCC29064 indexeddatamap
-25
View File
@@ -1,25 +0,0 @@
puts "============"
puts "0030536: Foundation Classes - TCollection_ExtendedString::StartsWith() and EndsWith() have a mistake"
puts "============"
pload QAcommands
set ret1 [QAStartsWith hello help]
if { ${ret1} == "Yes" } {
puts "Error"
}
set ret2 [QAStartsWith hello he]
if { ${ret2} == "No" } {
puts "Error"
}
set ret3 [QAEndsWith hello ll]
if { ${ret3} == "Yes" } {
puts "Error"
}
set ret4 [QAEndsWith hello lo]
if { ${ret4} == "No" } {
puts "Error"
}
-12
View File
@@ -1,12 +0,0 @@
puts "# ======================================================================"
puts "# 0030990: Foundation Classes - unexpected change in numerical results on bsplines after 0029769"
puts "# ======================================================================"
puts ""
pload QAcommands
restore [locate_data_file bug30990.brep] face
mksurface surf face
puts "Check consistency of evaluation of BSpline surface at knots"
OCC30990 surf
-25
View File
@@ -1,25 +0,0 @@
puts "======="
puts "OCC31697 - Expr_GeneralExpression::Derivative does not seem to work"
puts "======="
puts ""
pload QAcommands
set exp Exp(2*Sin(x^2))
set var x
set list [OCC31697 $exp $var]
set we_have [lindex $list 10]
puts "we_have = $we_have"
set must_be "Exp(2*Sin(x^2))*Cos(x^2)*x*4"
puts "must_be = $must_be"
if {[string compare $we_have $must_be] == 0} {
puts "OCC31697 OK"
} else {
puts "OCC31697 Faulty"
}
-27
View File
@@ -1,27 +0,0 @@
puts "============"
puts "OCC7639"
puts "============"
puts ""
#######################################################################
# NCollection_Vector works incorrectly with rare data
#######################################################################
pload QAcommands
set BugNumber OCC7639
set List [OCC7639 0 1 2 500 1 2]
set Length [llength $List]
if { ${Length} != 6} {
puts "Faulty (1) ${BugNumber}"
} else {
if { [regexp "1" $List] != 1 } {
puts "Faulty (2) ${BugNumber}"
}
if { [regexp "2" $List] != 1 } {
puts "Faulty (3) ${BugNumber}"
}
if { [regexp "500" $List] != 1 } {
puts "Faulty (4) ${BugNumber}"
}
}
-16
View File
@@ -1,16 +0,0 @@
puts "========"
puts "OCC24923"
puts "========"
puts ""
############################################
# BRepMesh_CircleTool produces bad circles
############################################
pload QAcommands
set bug_info [OCC24923]
set num_failed [string range [lindex $bug_info 12] 0 [expr {[string first "%" [lindex $bug_info 12]] - 1}]]
set max_failed [string range [lindex $bug_info 14] 0 [expr {[string first "%" [lindex $bug_info 14]] - 1}]]
if {$num_failed > $max_failed} {
puts "ERROR: OCC24923 is reproduced. Number of incorrect tests is too large ($num_failed > $max_failed)."
}
-11
View File
@@ -1,11 +0,0 @@
puts "========"
puts "OCC26407"
puts "========"
puts ""
##########################################################################################
# BRepMesh_Delaun should not take into account frontier edges on first pass of algorithm
##########################################################################################
pload QAcommands
OCC26407 result
-12
View File
@@ -1,12 +0,0 @@
pload QAcommands
puts "========"
puts "OCC570"
puts "========"
puts ""
OCC570 result
checkprops result -s 58500
checkshape result
checkview -display result -3d -path ${imagedir}/${test_image}.png
-30
View File
@@ -1,30 +0,0 @@
pload QAcommands
puts "============"
puts "OCC817"
puts "============"
puts ""
#############################
## Bad results of BRepAlgoAPI_Common
#############################
set InfoList [OCC817 result 10]
set OriginalVolume 0
regexp {Info: Original volume = ([-0-9.+eE]+)} $InfoList full OriginalVolume
set AccumulatedMeshedVolume 0
regexp {Info: Accumulated meshed volume = ([-0-9.+eE]+)} $InfoList full AccumulatedMeshedVolume
set percent_max 0.1
set percent [expr abs(${AccumulatedMeshedVolume} - ${OriginalVolume}) / (${OriginalVolume}) * 100.]
if {${percent} > ${percent_max}} {
puts "OCC817: Error"
} else {
puts "OCC817: OK"
}
checkview -display result -2d -path ${imagedir}/${test_image}.png
checkprops result -s 6000
checkshape result
-29
View File
@@ -1,29 +0,0 @@
pload QAcommands
puts "============"
puts "OCC817"
puts "============"
puts ""
#############################
## Bad results of BRepAlgoAPI_Common
#############################
set InfoList [OCC817 result 15]
set OriginalVolume 0
regexp {Info: Original volume = ([-0-9.+eE]+)} $InfoList full OriginalVolume
set AccumulatedMeshedVolume 0
regexp {Info: Accumulated meshed volume = ([-0-9.+eE]+)} $InfoList full AccumulatedMeshedVolume
set percent_max 0.1
set percent [expr abs(${AccumulatedMeshedVolume} - ${OriginalVolume}) / (${OriginalVolume}) * 100.]
if {${percent} > ${percent_max}} {
puts "OCC817: Error"
} else {
puts "OCC817: OK"
}
checkview -display result -2d -path ${imagedir}/${test_image}.png
checkprops result -s 6000
checkshape result
-30
View File
@@ -1,30 +0,0 @@
pload QAcommands
puts "============"
puts "OCC817"
puts "============"
puts ""
#############################
## Bad results of BRepAlgoAPI_Common
#############################
set InfoList [OCC817 result 30]
set OriginalVolume 0
regexp {Info: Original volume = ([-0-9.+eE]+)} $InfoList full OriginalVolume
set AccumulatedMeshedVolume 0
regexp {Info: Accumulated meshed volume = ([-0-9.+eE]+)} $InfoList full AccumulatedMeshedVolume
set percent_max 0.1
set percent [expr abs(${AccumulatedMeshedVolume} - ${OriginalVolume}) / (${OriginalVolume}) * 100.]
if {${percent} > ${percent_max}} {
puts "OCC817: Error"
} else {
puts "OCC817: OK"
}
checkview -display result -2d -path ${imagedir}/${test_image}.png
checkprops result -s 6000
checkshape result
-26
View File
@@ -1,26 +0,0 @@
pload QAcommands
puts "========"
puts "OCC822"
puts "========"
puts ""
#####################################
## BRepMesh_IncrementalMesh fails on some faces
#####################################
if {[ catch { set info_result [OCC822_1 a1 a2 result] } ] } {
puts "Faulty OCC822"
} else {
if { [regexp {FAILED} $info_result] } {
puts "Faulty OCC822"
}
set ExplodeList [explode result]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty OCC822"
}
}
checkprops result -s 133931
checkshape result
checkview -display result -2d -path ${imagedir}/${test_image}.png
-27
View File
@@ -1,27 +0,0 @@
pload QAcommands
puts "======="
puts "OCC822"
puts "======="
puts ""
#####################################
## BRepMesh_IncrementalMesh fails on some faces
#####################################
## (old topology)
#####################################
if { [ catch { set info_result [OCC822_2 a1 a2 result] } ] } {
puts "Faulty OCC822"
} else {
if { [regexp {FAILED} $info_result] } {
puts "Faulty OCC822"
}
set ExplodeList [explode result]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty OCC822"
}
}
checkprops result -s 61963.5
checkshape result
checkview -display result -3d -path ${imagedir}/${test_image}.png
-25
View File
@@ -1,25 +0,0 @@
pload QAcommands
puts "======="
puts "OCC823"
puts "======="
puts ""
###############################
## BRepAlgoAPI_Fuse fails on two cylinders
###############################
if { [ catch { set info_result [OCC823 a1 a2 result] } ] } {
puts "Faulty OCC823"
} else {
if { [regexp {FAILED} $info_result] } {
puts "Faulty OCC823"
}
set ExplodeList [explode result]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty OCC823 : Resulting shape is empty COMPOUND"
}
}
checkprops result -s 23189.5
checkshape result
checkview -display result -2d -path ${imagedir}/${test_image}.png
-26
View File
@@ -1,26 +0,0 @@
pload QAcommands
puts "============"
puts "OCC824"
puts "============"
puts ""
####################################
## BRepAlgoAPI_Fuse fails on cylinder and sphere
####################################
if { [ catch { set info_result [OCC824 a1 a2 result] } ] } {
puts "Faulty OCC824"
} else {
if { [regexp {FAILED} $info_result] } {
puts "Faulty OCC824"
}
set ExplodeList [explode result]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty OCC824"
}
}
checkprops result -s 16336.3
checkshape result
checkview -display result -2d -path ${imagedir}/${test_image}.png
-37
View File
@@ -1,37 +0,0 @@
pload QAcommands
puts "============"
puts "OCC826"
puts "============"
puts ""
###################################
## BRepAlgoAPI_Fuse fails on revolved and sphere
###################################
## Now this test uses BOPAlgo.
## Intersection of cylinder and sphere. At that,
## the intersection line goes near to the pole
## of the sphere (near, but not through).
## Walking-line has a point in the seam of
## the sphere and neighbour point. Both sections of the
## sphere (through every of these points and parallel to
## equatorial plane) are circles with small radii. As result,
## in 2D-space U-coordinates of these points are too different
## (may be even ~60 degrees) in spite of its neighbourhood.
#####################################
if { [ catch { set info_result [OCC826 a1 a2 result] } ] } {
puts "Faulty OCC826"
} else {
if { [regexp {FAILED} $info_result] } {
puts "Faulty OCC826"
}
set ExplodeList [explode result]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty OCC826"
}
}
checkprops result -s 272935
checkshape result
checkview -display result -2d -path ${imagedir}/${test_image}.png
-46
View File
@@ -1,46 +0,0 @@
pload QAcommands
puts "========"
puts "OCC827"
puts "========"
puts ""
###################################
## BRepAlgoAPI_Fuse fails on cylinder and torus
###################################
#
# a1 - Cylinder
# a2 - Torus1
# a3 - Torus1
# res1 - Fuse(Torus1 & Cylinder)
# res2 - Fuse(Torus2 & res1)
#
if { [ catch { set info_result [OCC827 a1 a2 a3 result1 result2] } ] } {
puts "Faulty : an exception was caught"
} else {
if { [lsearch ${info_result} FAILED] > -1} {
puts "Faulty OCC827 (case 1)"
}
checkshape a1
checkshape a2
checkshape a3
checkshape result1
checkshape result2
set ExplodeList [explode result1]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty : Resulting shape is empty COMPOUND"
}
set ExplodeList [explode result2]
if {[llength ${ExplodeList}] < 1} {
puts "Faulty : Resulting shape is empty COMPOUND"
}
renamevar result2 result
}
checkprops result -s 11847.7
checkshape result
checkview -display result -2d -path ${imagedir}/${test_image}.png
-52
View File
@@ -1,52 +0,0 @@
puts "============"
puts "OCC895"
puts "============"
puts ""
#########################################################
## In one case, twisted surface is created.
## The problem is in incorrect computation of mutual orientations of wire segments.
#########################################################
pload QAcommands
set scale 73.609
set proj_X 0.523995
set proj_Y 0.359655
set proj_Z 0.77206
set up_X -0.739036
set up_Y -0.258607
set up_Z 0.622051
set at_X 5.51184366274157
set at_Y 5.10968389884332
set at_Z 0.581665443993578
set x_coord 210
set y_coord 210
set status 0
set angle 5
set reverse 0
set order 0
if { [ catch { OCC895 result ${angle} ${reverse} ${order} } ] } {
puts "Faulty : an exception was caught"
}
if { ${status} == 0} {
vinit
vsetdispmode 1
vdisplay result
vviewparams -scale ${scale} -proj ${proj_X} ${proj_Y} ${proj_Z} -up ${up_X} ${up_Y} ${up_Z} -at ${at_X} ${at_Y} ${at_Z}
checkcolor $x_coord $y_coord 0.98 0.72 0.13
if { ${stat} != 1 } {
puts "Faulty OCC895 (case 2)"
}
}
checkprops result -s 18.1614
checkshape result
checkview -display result -3d -path ${imagedir}/${test_image}.png
-22
View File
@@ -1,22 +0,0 @@
puts "============"
puts "OCC25004"
puts "============"
puts ""
##########################################################################################################
# Extrema_ExtCC::Extrema curve/curve incorrect result
##########################################################################################################
pload QAcommands
set info [OCC25004]
regexp {F += +([-0-9.+eE]+)} $info full aF
regexp {NbExtrema += +([-0-9.+eE]+)} $info full aNb
set expected_F 0.39788735772
set expected_aNb 3
set tol_abs_dist 1.0e-12
set tol_rel_dist 0.1
checkreal "value F" ${aF} ${expected_F} ${tol_abs_dist} ${tol_rel_dist}
checkreal "Nbextrema" ${aNb} ${expected_aNb} ${tol_abs_dist} ${tol_rel_dist}
-15
View File
@@ -1,15 +0,0 @@
puts "========"
puts "OCC26746"
puts "========"
puts ""
#################################################
# 0026746: Method gp_Torus::Coefficients(...) returns incorrect value.
#################################################
pload QAcommands
set Tol 3.0e-7
torus tr 55.52514413 2.070076585 73.83409062 0.37231784651136368 0.58886674834874120 0.71736697293527607 0.80682335496555135, 0.17666016102759910, -0.56376170618524390 87.08479625 23.14682176
OCC26746 tr $Tol 5
-17
View File
@@ -1,17 +0,0 @@
puts "========"
puts "OCC25605"
puts "========"
puts ""
#################################################
# 0026747: Some constructors of gp_Parab2d classes have not understandable interface and create wrong parabola
#################################################
pload QAcommands
OCC26747_1 result
v2d
don result
2dfit
checkview -screenshot -2d -l -path ${imagedir}/${test_image}.png
-17
View File
@@ -1,17 +0,0 @@
puts "========"
puts "OCC26747"
puts "========"
puts ""
#################################################
# 0026747: Some constructors of gp_Parab2d classes have not understandable interface and create wrong parabola
#################################################
pload QAcommands
OCC26747_2 result
v2d
don result
2dfit
checkview -screenshot -2d -l -path ${imagedir}/${test_image}.png
-17
View File
@@ -1,17 +0,0 @@
puts "========"
puts "OCC26747"
puts "========"
puts ""
#################################################
# 0026747: Some constructors of gp_Parab2d classes have not understandable interface and create wrong parabola
#################################################
pload QAcommands
OCC26747_3 result
v2d
don result
2dfit
checkview -screenshot -2d -l -path ${imagedir}/${test_image}.png
-11
View File
@@ -1,11 +0,0 @@
puts "============"
puts "OCC26750"
puts "============"
puts ""
#############################################################################################
## Method IsNormal(...) for gp_Vec2d returns FALSE if the angle between two vectors is equal to -90 degree (-M_PI/2 radian)
#############################################################################################
pload QAcommands
OCC26750
-19
View File
@@ -1,19 +0,0 @@
puts "================"
puts "OCC27875"
puts "================"
puts ""
###############################
## GeomFill_NSections constructor crash on sequence of curve containing only one curve
###############################
# GeomFill_NSections does not work if the sequence of curves contains only single curve.
# Therefore, we should not expect any correct result from this operation. However, the
# exception must not be thrown.
pload QAcommands
restore [locate_data_file OCC606_2.brep] w2
explode w2 e
mkcurve cc w2_1
trim cc cc
OCC27875 cc
-25
View File
@@ -1,25 +0,0 @@
puts "========"
puts "OCC28594"
puts "========"
puts ""
####################################################################
# Geom2dAPI_Interpolate generated curve is not the same as proe
####################################################################
pload QAcommands
set anImageWithScale ${imagedir}/${test_image}_c1.png
set anImageWithoutScale ${imagedir}/${test_image}_c2.png
OCC28594 c1 c2
smallview -2D-
donly c1
2dfit
checkview -screenshot -2d -path ${anImageWithScale}
donly c2
checkview -screenshot -2d -path ${anImageWithoutScale}
set aDiffImageResult [diffimage $anImageWithScale $anImageWithoutScale 0.1 0 0]
if {$aDiffImageResult == 0} {
puts "Error: curves are equal"
}
-38
View File
@@ -1,38 +0,0 @@
puts "# ==============================================================="
puts "# 0028131: BRepOffset_MakeOffset can't create offset with a face which created by filling 3 bsplinecurve"
puts "# ==============================================================="
puts ""
puts "# Create face to be offset, by dedicated command"
pload QAcommands
OCC28131 f
puts "# Try simple offset"
offsetshapesimple result_simple f 10.
checkshape result_simple
checkmaxtol result_simple -ref 0.205
checkprops result_simple -s 1693.7
puts "# Try standard offset"
offsetshape result_std f 10.
fixshape result_std result_std ;# need to fix it....
checkshape result_std
checkmaxtol result_std -ref 0.408
checkprops result_std -s 1693.76
puts "# Make snapshots (overall and zoom to degenerated point)"
smallview -Y+Z
fit
checkview -2d -screenshot -path ${imagedir}/${test_image}.png
smallview -Y+Z
zoom 400
pu; pu; pu
pr; pr; pr
donly result_simple
checkview -2d -screenshot -path ${imagedir}/${test_image}_zoom_simple.png
donly result_std
checkview -2d -screenshot -path ${imagedir}/${test_image}_zoom_standard.png
-46
View File
@@ -1,46 +0,0 @@
puts "========"
puts "OCC29430"
puts "========"
puts ""
#################################################
# [Regression] Curve evaluation at boundary point.
#################################################
pload QAcommands
# After launching the command below we will obtain
# some wire (stored in "result" variable) containing
# a single edge based on arc of circle and its first and last
# 3D-points (p1 and p2 correspondingly) taken from
# composite curve (BRepAdaptor_CompCurve) built on this wire.
OCC29430 result p1 p2
vertex v1 p1
vertex v2 p2
explode result v
# Now, let's check
# 1. whether p1 and p2 match the vertices of the wire;
# 2. whether p1 and p2 are different points.
distmini d11 result_1 v1
distmini d12 result_1 v2
distmini d21 result_2 v1
distmini d22 result_2 v2
distmini dv12 v1 v2
if { ([dval d11_val] > 1.0e-7) && ([dval d21_val] > 1.0e-7) } {
puts "Error: Start point of the wire does not match any its vertex."
}
if { ([dval d12_val] > 1.0e-7) && ([dval d22_val] > 1.0e-7) } {
puts "Error: End point of the wire does not match any its vertex."
}
if { [dval dv12_val] < 1.0e-7 } {
puts "Error: Start and End points of the wire are the same."
}
-8
View File
@@ -1,8 +0,0 @@
puts "================================================================="
puts "OCC30747: Modeling Algorithms - 2d Curves concatenator doesn't properly process closed contours."
puts "================================================================="
puts ""
pload QAcommands
OCC30747 res
-55
View File
@@ -1,55 +0,0 @@
puts "========"
puts "0030869: Modeling Data - BRepAdaptor_CompCurve incorrectly evaluates the boundary points"
puts "========"
puts ""
pload QAcommands
# create wire consisting of a single edge based on a trimmed circle
circle c 1 0 0 0 -1 0 0 0 -1 1
trim c c 1.5707963267949 4.71238898038469
mkedge e c
orientation e R
wire w e
# compute boundary points using BRepAdaptor_CompCurve
set log [OCC30869 w]
set lines [split $log "\n"]
if {![regexp {([-0-9.+eE]*): point ([-0-9.+eE]*) ([-0-9.+eE]*) ([-0-9.+eE]*), tangent ([-0-9.+eE]*) ([-0-9.+eE]*) ([-0-9.+eE]*)} [lindex $lines 0] full t1 x1 y1 z1 dx1 dy1 dz1]} {
puts "Error: first point is not computed"
}
if {![regexp {([-0-9.+eE]*): point ([-0-9.+eE]*) ([-0-9.+eE]*) ([-0-9.+eE]*), tangent ([-0-9.+eE]*) ([-0-9.+eE]*) ([-0-9.+eE]*)} [lindex $lines 1] full t2 x2 y2 z2 dx2 dy2 dz2]} {
puts "Error: last point is not computed"
}
# compute reference values
# inverse the curve as the edge in the wire is reversed
circle ci 1 0 0 0 1 0 0 0 -1 1
trim ci ci 1.5707963267949 4.71238898038469
cvalue ci 1.5707963267949 x1_ref y1_ref z1_ref dx1_ref dy1_ref dz1_ref
cvalue ci 4.71238898038469 x2_ref y2_ref z2_ref dx2_ref dy2_ref dz2_ref
# compare the values
set tol_abs 1.e-7
set tol_rel 1.e-7
checkreal first_pnt_x $x1 [dval x1_ref] $tol_abs $tol_rel
checkreal first_pnt_y $y1 [dval y1_ref] $tol_abs $tol_rel
checkreal first_pnt_z $z1 [dval z1_ref] $tol_abs $tol_rel
checkreal first_tgt_x $dx1 [dval dx1_ref] $tol_abs $tol_rel
checkreal first_tgt_y $dy1 [dval dy1_ref] $tol_abs $tol_rel
checkreal first_tgt_z $dz1 [dval dz1_ref] $tol_abs $tol_rel
checkreal last_pnt_x $x2 [dval x2_ref] $tol_abs $tol_rel
checkreal last_pnt_y $y2 [dval y2_ref] $tol_abs $tol_rel
checkreal last_pnt_z $z2 [dval z2_ref] $tol_abs $tol_rel
checkreal last_tgt_x $dx2 [dval dx2_ref] $tol_abs $tol_rel
checkreal last_tgt_y $dy2 [dval dy2_ref] $tol_abs $tol_rel
checkreal last_tgt_z $dz2 [dval dz2_ref] $tol_abs $tol_rel
-68
View File
@@ -1,68 +0,0 @@
puts "========"
puts "BUC60897"
puts "========"
pload QAcommands
if [catch { set result [BUC60897] } ] {
puts "BUC60897: Error; (case 1)"
} else {
set len [llength ${result}]
if {${len} < 21} {
puts "length = ${len}"
puts "BUC60897: Error; (case 2)"
} else {
set circle_X [lindex ${result} 3]
set circle_Y [lindex ${result} 5]
set circle_R [lindex ${result} 7]
set tangency1_X [lindex ${result} 11]
set tangency1_Y [lindex ${result} 13]
set tangency2_X [lindex ${result} 17]
set tangency2_Y [lindex ${result} 19]
set x1 [expr abs(${tangency1_X} - ${circle_X})]
set y1 [expr abs(${tangency1_Y} - ${circle_Y})]
set R1 [expr sqrt(${x1} * ${x1} + ${y1} * ${y1})]
set x2 [expr abs(${tangency2_X} - ${circle_X})]
set y2 [expr abs(${tangency2_Y} - ${circle_Y})]
set R2 [expr sqrt(${x2} * ${x2} + ${y2} * ${y2})]
set maxdelta 1.0
set delta_R1 [expr abs(${R1} - ${circle_R}) / ${circle_R} * 100.]
set delta_R2 [expr abs(${R2} - ${circle_R}) / ${circle_R} * 100.]
if {${delta_R1} > ${maxdelta}} {
puts "circle_X = ${circle_X}"
puts "circle_Y = ${circle_Y}"
puts "circle_R = ${circle_R}"
puts "tangency1_X = ${tangency1_X}"
puts "tangency1_Y = ${tangency1_Y}"
puts "x1 = ${x1}"
puts "y1 = ${y1}"
puts "R1 = ${R1}"
puts "delta_R1 = ${delta_R1}"
puts "maxdelta = ${maxdelta}"
puts "BUC60897: Error; (case 3)"
} else {
puts "BUC60897: OK; (case 1)"
}
if {${delta_R2} > ${maxdelta}} {
puts "circle_X = ${circle_X}"
puts "circle_Y = ${circle_Y}"
puts "circle_R = ${circle_R}"
puts "tangency2_X = ${tangency2_X}"
puts "tangency2_Y = ${tangency2_Y}"
puts "x2 = ${x2}"
puts "y2 = ${y2}"
puts "R2 = ${R2}"
puts "delta_R2 = ${delta_R2}"
puts "maxdelta = ${maxdelta}"
puts "BUC60897: Error; (case 4)"
} else {
puts "BUC60897: OK; (case 2)"
}
}
}
-20
View File
@@ -1,20 +0,0 @@
pload QAcommands
puts "============"
puts "OCC2569"
puts "============"
puts ""
######################################################
# If it is not possible to create the bezier curve,
# it should throw an exception.
######################################################
cpulimit 60
vinit
set out [OCC2569 26 result]
if {[string compare $out "\n Degree = 25\n"] == 0} {
puts "OCC2569: OK"
} else {
puts "OCC2569: Faulty"
}
vfit
checkview -screenshot -3d -path ${imagedir}/${test_image}.png
-20
View File
@@ -1,20 +0,0 @@
# Incompleted behavior of test case is OK.
# Exception should be thrown.
puts "TODO OCC11111 ALL: An exception was caught"
pload QAcommands
puts "============"
puts "0002569: If it is not possible to create the bezier curve, it should throw an e x c e p t i o n."
puts "============"
puts ""
cpulimit 60
vinit
if { [catch {OCC2569 29 result} anException] } {
puts "OCC2569 : OK"
} else {
puts "Error : OCC2569"
}
-18
View File
@@ -1,18 +0,0 @@
puts "========"
puts "OCC49"
puts "========"
pload QAcommands
pcylinder c 10 20
set result [OCC49 c]
if {$result == 1} {
puts "OCC49: OK"
} else {
puts "Error : OCC49"
}
checkview -display result -2d -path ${imagedir}/${test_image}.png
-21
View File
@@ -1,21 +0,0 @@
puts "========"
puts "OCC49"
puts "========"
pload QAcommands
pcylinder c 10 20
box b 10 10 10
bcut b_c_cut b c
checkshape b_c_cut
set result [OCC49 b_c_cut]
if {$result == 1} {
puts "Error : OCC49"
} else {
puts "OCC49: OK"
}
checkview -display result -2d -path ${imagedir}/${test_image}.png

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