mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-06-15 04:04:07 +08:00
Shape Healing - Optimize PCurve projection (#890)
- Implemented various test cases including projections of lines, circles, and B-splines on different surface types (planes, cylinders, spheres, and toroids). - Refactored ShapeConstruct_ProjectCurveOnSurface to improve handling of periodic surfaces and edge cases. - Updated header files to reflect new type aliases and improved structure for better readability and maintainability. - Added a new function `extractBSplineCurve` to streamline the extraction of B-spline curves from both trimmed and untrimmed curves. - Refactored `isBSplineCurveInvalid` to utilize the new extraction function, improving clarity and reducing code duplication. - Updated `generateCurvePoints` to leverage the new extraction method for better handling of B-spline curves. - Replaced std::vector with NCollection_Vector for better memory management in isBSplineCurveInvalid. - Enhanced rebuildBSpline function to improve knot adjustment logic while preserving curve geometry. - Introduced a new utility class, SurfaceProjectorWithCache, to enhance the projection of points onto B-spline surfaces by caching pole positions and their UV parameters.
This commit is contained in:
@@ -3,4 +3,5 @@ set(OCCT_TKShHealing_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
set(OCCT_TKShHealing_GTests_FILES
|
||||
ShapeAnalysis_CanonicalRecognition_Test.cxx
|
||||
ShapeConstruct_ProjectCurveOnSurface_Test.cxx
|
||||
)
|
||||
|
||||
@@ -0,0 +1,994 @@
|
||||
// Copyright (c) 2025 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 <ShapeConstruct_ProjectCurveOnSurface.hxx>
|
||||
#include <ShapeAnalysis_Surface.hxx>
|
||||
|
||||
#include <GC_MakeSegment.hxx>
|
||||
#include <Geom2d_Curve.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_ConicalSurface.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
#include <Geom_ToroidalSurface.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
#include <GeomAPI_PointsToBSpline.hxx>
|
||||
#include <gp_Ax2.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <ShapeExtend.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
|
||||
//==================================================================================================
|
||||
// Test fixture for ShapeConstruct_ProjectCurveOnSurface
|
||||
//==================================================================================================
|
||||
|
||||
class ShapeConstruct_ProjectCurveOnSurfaceTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
myProjector = new ShapeConstruct_ProjectCurveOnSurface();
|
||||
myTolerance = Precision::Confusion();
|
||||
}
|
||||
|
||||
//! Helper to create a simple B-spline curve lying on Z=0 plane
|
||||
Handle(Geom_BSplineCurve) createPlanarBSpline()
|
||||
{
|
||||
TColgp_Array1OfPnt aPoles(1, 5);
|
||||
aPoles(1) = gp_Pnt(0, 0, 0);
|
||||
aPoles(2) = gp_Pnt(2, 3, 0);
|
||||
aPoles(3) = gp_Pnt(5, 4, 0);
|
||||
aPoles(4) = gp_Pnt(8, 2, 0);
|
||||
aPoles(5) = gp_Pnt(10, 0, 0);
|
||||
|
||||
GeomAPI_PointsToBSpline aBuilder(aPoles);
|
||||
return aBuilder.Curve();
|
||||
}
|
||||
|
||||
//! Helper to create a helical B-spline on a cylinder
|
||||
Handle(Geom_BSplineCurve) createHelicalBSpline(const double theRadius, const int theNbPoints)
|
||||
{
|
||||
TColgp_Array1OfPnt aPoles(1, theNbPoints);
|
||||
for (int i = 1; i <= theNbPoints; ++i)
|
||||
{
|
||||
const double anAngle = (i - 1) * M_PI / 4.0;
|
||||
const double aZ = (i - 1) * 1.0;
|
||||
aPoles(i) = gp_Pnt(theRadius * cos(anAngle), theRadius * sin(anAngle), aZ);
|
||||
}
|
||||
GeomAPI_PointsToBSpline aBuilder(aPoles);
|
||||
return aBuilder.Curve();
|
||||
}
|
||||
|
||||
//! Verifies that pcurve correctly maps to 3D points on surface
|
||||
void verifyProjection(const Handle(Geom_Curve)& theCurve,
|
||||
const Handle(Geom2d_Curve)& thePCurve,
|
||||
const Handle(ShapeAnalysis_Surface)& theSurface,
|
||||
const double theTolerance)
|
||||
{
|
||||
const double aFirst = theCurve->FirstParameter();
|
||||
const double aLast = theCurve->LastParameter();
|
||||
|
||||
for (double t = 0.0; t <= 1.0; t += 0.25)
|
||||
{
|
||||
const double aParam = aFirst + t * (aLast - aFirst);
|
||||
gp_Pnt a3DPnt;
|
||||
theCurve->D0(aParam, a3DPnt);
|
||||
|
||||
const gp_Pnt2d a2DPnt = thePCurve->Value(aParam);
|
||||
gp_Pnt aSurfPnt = theSurface->Value(a2DPnt);
|
||||
|
||||
EXPECT_NEAR(a3DPnt.Distance(aSurfPnt), 0.0, theTolerance) << "Point mismatch at t=" << t;
|
||||
}
|
||||
}
|
||||
|
||||
Handle(ShapeConstruct_ProjectCurveOnSurface) myProjector;
|
||||
double myTolerance;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// Basic projection tests - lines and circles on analytical surfaces
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project diagonal line on horizontal plane, verify 2D coordinates match X,Y of 3D points
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, LineOnPlane_A1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0)).Value();
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aPlane);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const double aFirst = aLine->FirstParameter();
|
||||
const double aLast = aLine->LastParameter();
|
||||
const Standard_Boolean aResult = myProjector->Perform(aLine, aFirst, aLast, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// Verify start point maps to (0,0) and end point maps to (10,10)
|
||||
const gp_Pnt2d aStart = aPCurve->Value(aFirst);
|
||||
const gp_Pnt2d aEnd = aPCurve->Value(aLast);
|
||||
EXPECT_NEAR(aStart.X(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aStart.Y(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aEnd.X(), 10.0, 0.01);
|
||||
EXPECT_NEAR(aEnd.Y(), 10.0, 0.01);
|
||||
}
|
||||
|
||||
// Test: Project circle lying on cylinder surface, V-coordinate should be constant
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, CircleOnCylinder_A2)
|
||||
{
|
||||
const double aRadius = 5.0;
|
||||
Handle(Geom_CylindricalSurface) aCylinder =
|
||||
new Geom_CylindricalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
|
||||
// Circle at height Z=3 on the cylinder
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 3), gp_Dir(0, 0, 1)), aRadius);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aCylinder), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// On cylinder parametrization, V = Z, so circle at Z=3 should have V=3
|
||||
const gp_Pnt2d aMid = aPCurve->Value(M_PI);
|
||||
EXPECT_NEAR(aMid.Y(), 3.0, 0.01) << "V coordinate should be 3";
|
||||
}
|
||||
|
||||
// Test: Project vertical line on cylinder (isoparametric case), U should be constant
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, IsoparametricLineOnCylinder_A3)
|
||||
{
|
||||
const double aRadius = 5.0;
|
||||
Handle(Geom_CylindricalSurface) aCylinder =
|
||||
new Geom_CylindricalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
|
||||
// Line along cylinder axis at X=radius, Y=0 (U=0 on cylinder)
|
||||
Handle(Geom_TrimmedCurve) aLine =
|
||||
GC_MakeSegment(gp_Pnt(aRadius, 0, 0), gp_Pnt(aRadius, 0, 10)).Value();
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aCylinder);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const double aFirst = aLine->FirstParameter();
|
||||
const double aLast = aLine->LastParameter();
|
||||
const Standard_Boolean aResult = myProjector->Perform(aLine, aFirst, aLast, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// U should be constant (isoparametric curve)
|
||||
const gp_Pnt2d aStart = aPCurve->Value(aFirst);
|
||||
const gp_Pnt2d aEnd = aPCurve->Value(aLast);
|
||||
EXPECT_NEAR(aStart.X(), aEnd.X(), 0.01) << "U should be constant for isoparametric curve";
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// B-Spline curve projection tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project planar B-spline on plane, endpoints should match original curve
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, BSplineOnPlane_B1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_BSplineCurve) aBSpline = createPlanarBSpline();
|
||||
ASSERT_FALSE(aBSpline.IsNull());
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aBSpline, aBSpline->FirstParameter(), aBSpline->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// Verify endpoints
|
||||
const gp_Pnt2d aStart = aPCurve->Value(aBSpline->FirstParameter());
|
||||
const gp_Pnt2d aEnd = aPCurve->Value(aBSpline->LastParameter());
|
||||
EXPECT_NEAR(aStart.X(), 0.0, 0.1);
|
||||
EXPECT_NEAR(aStart.Y(), 0.0, 0.1);
|
||||
EXPECT_NEAR(aEnd.X(), 10.0, 0.1);
|
||||
EXPECT_NEAR(aEnd.Y(), 0.0, 0.1);
|
||||
}
|
||||
|
||||
// Test: Project helical B-spline on cylinder, verify all sample points lie on surface
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, HelicalBSplineOnCylinder_B2)
|
||||
{
|
||||
const double aRadius = 5.0;
|
||||
Handle(Geom_CylindricalSurface) aCylinder =
|
||||
new Geom_CylindricalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
|
||||
Handle(Geom_BSplineCurve) aBSpline = createHelicalBSpline(aRadius, 9);
|
||||
ASSERT_FALSE(aBSpline.IsNull());
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aCylinder);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aBSpline, aBSpline->FirstParameter(), aBSpline->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
verifyProjection(aBSpline, aPCurve, aSAS, 0.1);
|
||||
}
|
||||
|
||||
// Test: Project high-degree B-spline with many control points
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, HighDegreeBSpline_B3)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
// Create B-spline with 50 control points (sinusoidal shape)
|
||||
const int aNbPoles = 50;
|
||||
TColgp_Array1OfPnt aPoles(1, aNbPoles);
|
||||
for (int i = 1; i <= aNbPoles; ++i)
|
||||
{
|
||||
const double aX = (i - 1) * 0.5;
|
||||
const double aY = 5.0 * sin(aX * M_PI / 10.0);
|
||||
aPoles(i) = gp_Pnt(aX, aY, 0);
|
||||
}
|
||||
|
||||
GeomAPI_PointsToBSpline aBuilder(aPoles, 3, 8);
|
||||
Handle(Geom_BSplineCurve) aBSpline = aBuilder.Curve();
|
||||
ASSERT_FALSE(aBSpline.IsNull());
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aPlane);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aBSpline, aBSpline->FirstParameter(), aBSpline->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
verifyProjection(aBSpline, aPCurve, aSAS, 0.5);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Periodic surface tests - sphere, torus
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project equator circle on sphere
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, EquatorOnSphere_C1)
|
||||
{
|
||||
const double aRadius = 10.0;
|
||||
Handle(Geom_SphericalSurface) aSphere =
|
||||
new Geom_SphericalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aSphere), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
}
|
||||
|
||||
// Test: Project latitude circle on sphere at 45 degrees, V should be constant
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, LatitudeOnSphere_C2)
|
||||
{
|
||||
const double aRadius = 10.0;
|
||||
Handle(Geom_SphericalSurface) aSphere =
|
||||
new Geom_SphericalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
|
||||
// Latitude at 45 degrees
|
||||
const double aLatitude = M_PI / 4.0;
|
||||
const double aZ = aRadius * sin(aLatitude);
|
||||
const double aCircRadius = aRadius * cos(aLatitude);
|
||||
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, aZ), gp_Dir(0, 0, 1)), aCircRadius);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aSphere), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// V should be constant for latitude circle
|
||||
const gp_Pnt2d aStart = aPCurve->Value(0.0);
|
||||
const gp_Pnt2d aMid = aPCurve->Value(M_PI);
|
||||
EXPECT_NEAR(aStart.Y(), aMid.Y(), 0.01) << "V should be constant for latitude circle";
|
||||
}
|
||||
|
||||
// Test: Project on toroidal surface (both U and V periodic)
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, CircleOnTorus_C3)
|
||||
{
|
||||
const double aMajorRadius = 10.0;
|
||||
const double aMinorRadius = 2.0;
|
||||
Handle(Geom_ToroidalSurface) aTorus =
|
||||
new Geom_ToroidalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aMajorRadius, aMinorRadius);
|
||||
|
||||
// Circle in the minor cross-section plane at U=0
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(aMajorRadius + aMinorRadius, 0, 0), gp_Dir(0, 1, 0)), aMinorRadius);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aTorus), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Conical surface tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project circle on cone at specific height
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, CircleOnCone_D1)
|
||||
{
|
||||
const double aRadius = 5.0;
|
||||
const double aSemiAngle = M_PI / 6.0; // 30 degrees
|
||||
Handle(Geom_ConicalSurface) aCone =
|
||||
new Geom_ConicalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aSemiAngle, aRadius);
|
||||
|
||||
// Circle at height Z=5, radius increases with height
|
||||
const double aZ = 5.0;
|
||||
const double aRadiusAtZ = aRadius + aZ * tan(aSemiAngle);
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, aZ), gp_Dir(0, 0, 1)), aRadiusAtZ);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aCone), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Trimmed curve tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project 90-degree arc on plane
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, ArcOnPlane_E1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 5.0);
|
||||
Handle(Geom_Circle) aFullCircle = new Geom_Circle(aCirc);
|
||||
Handle(Geom_TrimmedCurve) aArc = new Geom_TrimmedCurve(aFullCircle, 0.0, M_PI / 2.0);
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aPlane);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const double aFirst = aArc->FirstParameter();
|
||||
const double aLast = aArc->LastParameter();
|
||||
const Standard_Boolean aResult = myProjector->Perform(aArc, aFirst, aLast, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// Arc from (5,0) to (0,5)
|
||||
const gp_Pnt2d aStart = aPCurve->Value(aFirst);
|
||||
const gp_Pnt2d aEnd = aPCurve->Value(aLast);
|
||||
EXPECT_NEAR(aStart.X(), 5.0, 0.01);
|
||||
EXPECT_NEAR(aStart.Y(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aEnd.X(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aEnd.Y(), 5.0, 0.01);
|
||||
}
|
||||
|
||||
// Test: Project doubly-trimmed curve (tests recursive unwrapping of trimmed curves)
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, DoublyTrimmedCurve_E2)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_BSplineCurve) aBSpline = createPlanarBSpline();
|
||||
ASSERT_FALSE(aBSpline.IsNull());
|
||||
|
||||
// First trim: take first half
|
||||
const double aFirst1 = aBSpline->FirstParameter();
|
||||
const double aLast1 = aBSpline->LastParameter();
|
||||
const double aMid = (aFirst1 + aLast1) / 2.0;
|
||||
Handle(Geom_TrimmedCurve) aTrim1 = new Geom_TrimmedCurve(aBSpline, aFirst1, aMid);
|
||||
|
||||
// Second trim (nested): take first quarter of the first trim
|
||||
const double aFirst2 = aTrim1->FirstParameter();
|
||||
const double aLast2 = aTrim1->LastParameter();
|
||||
const double aQuart = aFirst2 + (aLast2 - aFirst2) / 4.0;
|
||||
Handle(Geom_TrimmedCurve) aTrim2 = new Geom_TrimmedCurve(aTrim1, aFirst2, aQuart);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aTrim2, aTrim2->FirstParameter(), aTrim2->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection of doubly-trimmed curve should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Ellipse projection tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project ellipse on plane, verify quadrant points
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, EllipseOnPlane_F1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
// Ellipse with major radius 10, minor radius 5
|
||||
gp_Elips anElips(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 10.0, 5.0);
|
||||
Handle(Geom_Ellipse) anEllipse = new Geom_Ellipse(anElips);
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aPlane);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(anEllipse, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull()) << "PCurve should not be null";
|
||||
|
||||
// At parameter 0, ellipse is at (10, 0)
|
||||
gp_Pnt2d aP0 = aPCurve->Value(0.0);
|
||||
EXPECT_NEAR(aP0.X(), 10.0, 0.01);
|
||||
EXPECT_NEAR(aP0.Y(), 0.0, 0.01);
|
||||
|
||||
// At parameter PI/2, ellipse is at (0, 5)
|
||||
gp_Pnt2d aP1 = aPCurve->Value(M_PI / 2.0);
|
||||
EXPECT_NEAR(aP1.X(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aP1.Y(), 5.0, 0.01);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// API method tests - Init, SetSurface, SetPrecision
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Init with Geom_Surface directly (not wrapped in ShapeAnalysis_Surface)
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, InitWithGeomSurface_G1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0)).Value();
|
||||
|
||||
myProjector->Init(aPlane, Precision::Confusion());
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Init with Geom_Surface should work";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
// Test: SetSurface + SetPrecision separately
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, SetSurfaceAndPrecision_G2)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0)).Value();
|
||||
|
||||
myProjector->SetSurface(aPlane);
|
||||
myProjector->SetPrecision(Precision::Confusion());
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "SetSurface + SetPrecision should work";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
// Test: AdjustOverDegenMode accessor returns modifiable reference
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, AdjustOverDegenModeAccessor_G3)
|
||||
{
|
||||
// Default value should be 1
|
||||
EXPECT_EQ(myProjector->AdjustOverDegenMode(), 1);
|
||||
|
||||
// Modify through reference
|
||||
myProjector->AdjustOverDegenMode() = 0;
|
||||
EXPECT_EQ(myProjector->AdjustOverDegenMode(), 0);
|
||||
|
||||
// Restore
|
||||
myProjector->AdjustOverDegenMode() = 1;
|
||||
EXPECT_EQ(myProjector->AdjustOverDegenMode(), 1);
|
||||
}
|
||||
|
||||
// Test: Status method returns meaningful status after projection
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, StatusMethod_G4)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0)).Value();
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
// Status should indicate OK or DONE
|
||||
EXPECT_TRUE(myProjector->Status(ShapeExtend_OK) || myProjector->Status(ShapeExtend_DONE))
|
||||
<< "Status should indicate OK or DONE";
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Tolerance and precision tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Projection with very tight tolerance on exact curve
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, TightTolerance_H1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0)).Value();
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), 1e-15);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Tight tolerance should work for exact curve";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
// Test: Projection with different endpoint tolerances
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, DifferentEndpointTolerances_H2)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
// Curve slightly off plane at end
|
||||
TColgp_Array1OfPnt aPoles(1, 3);
|
||||
aPoles(1) = gp_Pnt(0, 0, 0);
|
||||
aPoles(2) = gp_Pnt(5, 5, 0.05);
|
||||
aPoles(3) = gp_Pnt(10, 10, 0.1);
|
||||
|
||||
GeomAPI_PointsToBSpline aBuilder(aPoles, 2, 2);
|
||||
Handle(Geom_BSplineCurve) aBSpline = aBuilder.Curve();
|
||||
ASSERT_FALSE(aBSpline.IsNull());
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const double aTolFirst = 0.01;
|
||||
const double aTolLast = 0.2;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aBSpline,
|
||||
aBSpline->FirstParameter(),
|
||||
aBSpline->LastParameter(),
|
||||
aPCurve,
|
||||
aTolFirst,
|
||||
aTolLast);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Projection with different endpoint tolerances should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Partial curve projection tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project only first quarter of full circle
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, PartialCircle_I1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 5.0);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aPlane);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
// Project only 0 to PI/2 (first quadrant)
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, M_PI / 2.0, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Partial projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
|
||||
// Verify endpoints: (5,0) to (0,5)
|
||||
gp_Pnt2d aStart = aPCurve->Value(0.0);
|
||||
gp_Pnt2d aEnd = aPCurve->Value(M_PI / 2.0);
|
||||
EXPECT_NEAR(aStart.X(), 5.0, 0.01);
|
||||
EXPECT_NEAR(aStart.Y(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aEnd.X(), 0.0, 0.01);
|
||||
EXPECT_NEAR(aEnd.Y(), 5.0, 0.01);
|
||||
}
|
||||
|
||||
// Test: Project middle portion of B-spline
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, MiddlePortionBSpline_I2)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(Geom_BSplineCurve) aBSpline = createPlanarBSpline();
|
||||
ASSERT_FALSE(aBSpline.IsNull());
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), myTolerance);
|
||||
|
||||
const double aFirst = aBSpline->FirstParameter();
|
||||
const double aLast = aBSpline->LastParameter();
|
||||
const double aRange = aLast - aFirst;
|
||||
|
||||
// Project middle 50%
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aBSpline, aFirst + 0.25 * aRange, aFirst + 0.75 * aRange, aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Middle portion projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Multiple projection and reinitialization tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Multiple projections on same surface reuse setup correctly
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, MultipleProjections_J1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aPlane);
|
||||
myProjector->Init(aSAS, myTolerance);
|
||||
|
||||
// Project 5 different curves
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
const double aOffset = i * 10.0;
|
||||
Handle(Geom_TrimmedCurve) aLine =
|
||||
GC_MakeSegment(gp_Pnt(aOffset, 0, 0), gp_Pnt(aOffset + 5, 5, 0)).Value();
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
EXPECT_TRUE(aResult) << "Projection " << i << " should succeed";
|
||||
EXPECT_FALSE(aPCurve.IsNull()) << "PCurve " << i << " should not be null";
|
||||
}
|
||||
}
|
||||
|
||||
// Test: Surface reinitialization between projections
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, SurfaceReinitialization_J2)
|
||||
{
|
||||
// First surface
|
||||
Handle(Geom_Plane) aPlane1 = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane1), myTolerance);
|
||||
|
||||
Handle(Geom_TrimmedCurve) aLine1 = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0)).Value();
|
||||
Handle(Geom2d_Curve) aPCurve1;
|
||||
myProjector->Perform(aLine1, aLine1->FirstParameter(), aLine1->LastParameter(), aPCurve1);
|
||||
ASSERT_FALSE(aPCurve1.IsNull());
|
||||
|
||||
// Second surface (different plane)
|
||||
Handle(Geom_Plane) aPlane2 = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 5), gp_Dir(0, 0, 1)));
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane2), myTolerance);
|
||||
|
||||
Handle(Geom_TrimmedCurve) aLine2 = GC_MakeSegment(gp_Pnt(0, 0, 5), gp_Pnt(10, 10, 5)).Value();
|
||||
Handle(Geom2d_Curve) aPCurve2;
|
||||
myProjector->Perform(aLine2, aLine2->FirstParameter(), aLine2->LastParameter(), aPCurve2);
|
||||
ASSERT_FALSE(aPCurve2.IsNull());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Near-singularity tests (poles, degenerate regions)
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Project small circle near north pole of sphere
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, NearPoleOnSphere_K1)
|
||||
{
|
||||
const double aRadius = 10.0;
|
||||
Handle(Geom_SphericalSurface) aSphere =
|
||||
new Geom_SphericalSurface(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
|
||||
|
||||
// Small circle very close to north pole (latitude = 89.4 degrees)
|
||||
const double aLatitude = M_PI / 2.0 - 0.01;
|
||||
const double aZ = aRadius * sin(aLatitude);
|
||||
const double aCircRadius = aRadius * cos(aLatitude);
|
||||
|
||||
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, aZ), gp_Dir(0, 0, 1)), aCircRadius);
|
||||
Handle(Geom_Circle) aCircle = new Geom_Circle(aCirc);
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aSphere), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aCircle, 0.0, 2.0 * M_PI, aPCurve);
|
||||
|
||||
// Should succeed even near pole
|
||||
ASSERT_TRUE(aResult) << "Projection near pole should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Edge case tests
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Very short curve projection should not crash
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, VeryShortCurve_L1)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
// Very short line segment (1e-6 length)
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0), gp_Pnt(1e-6, 0, 0)).Value();
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), 1e-4);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
// Result may vary but should not crash
|
||||
(void)myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
SUCCEED() << "Short curve projection completed without crash";
|
||||
}
|
||||
|
||||
// Test: Curve far from surface still projects
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, CurveFarFromSurface_L2)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
// Line at Z=100, far from plane at Z=0
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 100), gp_Pnt(10, 10, 100)).Value();
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), myTolerance);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
(void)myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
// Projection should still produce result (it projects onto the surface)
|
||||
EXPECT_FALSE(aPCurve.IsNull()) << "PCurve should be created even for distant curve";
|
||||
}
|
||||
|
||||
// Test: Large tolerance projection
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, LargeTolerance_L3)
|
||||
{
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
|
||||
// Line slightly off plane
|
||||
Handle(Geom_TrimmedCurve) aLine = GC_MakeSegment(gp_Pnt(0, 0, 0.1), gp_Pnt(10, 10, 0.1)).Value();
|
||||
|
||||
myProjector->Init(new ShapeAnalysis_Surface(aPlane), 1.0);
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult =
|
||||
myProjector->Perform(aLine, aLine->FirstParameter(), aLine->LastParameter(), aPCurve);
|
||||
|
||||
ASSERT_TRUE(aResult) << "Large tolerance projection should succeed";
|
||||
ASSERT_FALSE(aPCurve.IsNull());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Regression tests from bug reports
|
||||
//==================================================================================================
|
||||
|
||||
// Test: Bug 27569 - B-spline with many knots on B-spline surface
|
||||
// This test verifies that normal B-spline curves with many knots
|
||||
// (but uniform spacing) project correctly without triggering false
|
||||
// positive in knot spacing detection
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, Bug27569_ManyKnotsBSpline_M1)
|
||||
{
|
||||
// Create a B-spline curve with many knots by manually constructing it
|
||||
// with degree 3 and 15 knots (requiring 15 + 3 + 1 - 2*(3+1) = 11 internal knots)
|
||||
// For degree 3 with 15 knots (all simple): nbPoles = nbKnots + degree - 1 = 15 + 3 - 1 = 17
|
||||
const int aDegree = 3;
|
||||
const int aNbKnots = 15;
|
||||
const int aNbPoles = aNbKnots + aDegree - 1; // = 17
|
||||
|
||||
TColgp_Array1OfPnt aPoles(1, aNbPoles);
|
||||
for (int i = 1; i <= aNbPoles; ++i)
|
||||
{
|
||||
const double t = (i - 1.0) / (aNbPoles - 1.0);
|
||||
const double aAngle = t * 2.0 * M_PI;
|
||||
const double aRadius = 50.0 + 20.0 * cos(3.0 * aAngle);
|
||||
aPoles(i) = gp_Pnt(aRadius * cos(aAngle), -30.0 * t, aRadius * sin(aAngle));
|
||||
}
|
||||
|
||||
// Uniform knot vector from 0 to 1
|
||||
TColStd_Array1OfReal aKnots(1, aNbKnots);
|
||||
TColStd_Array1OfInteger aMults(1, aNbKnots);
|
||||
for (int i = 1; i <= aNbKnots; ++i)
|
||||
{
|
||||
aKnots(i) = (i - 1.0) / (aNbKnots - 1.0);
|
||||
aMults(i) = 1;
|
||||
}
|
||||
// Clamp end knots
|
||||
aMults(1) = aDegree + 1;
|
||||
aMults(aNbKnots) = aDegree + 1;
|
||||
|
||||
Handle(Geom_BSplineCurve) aBSplineCurve = new Geom_BSplineCurve(aPoles, aKnots, aMults, aDegree);
|
||||
ASSERT_FALSE(aBSplineCurve.IsNull()) << "B-Spline curve should be created";
|
||||
EXPECT_GE(aBSplineCurve->NbKnots(), 10) << "Curve should have at least 10 knots";
|
||||
|
||||
// Create a simple plane-like surface containing the curve
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pnt(0, -15, 0), gp_Dir(0, 1, 0));
|
||||
|
||||
// Test projection onto plane
|
||||
myProjector->Init(aPlane, Precision::Confusion());
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aBSplineCurve,
|
||||
aBSplineCurve->FirstParameter(),
|
||||
aBSplineCurve->LastParameter(),
|
||||
aPCurve);
|
||||
|
||||
EXPECT_TRUE(aResult) << "Projection should succeed for B-spline with many knots";
|
||||
EXPECT_FALSE(aPCurve.IsNull()) << "PCurve should be created";
|
||||
}
|
||||
|
||||
// Test: Bug 27569 - Actual bug reproduction with high-degree B-spline curve on B-spline surface
|
||||
// This test uses a B-spline curve of degree 7 with high multiplicities and a section of
|
||||
// repeated poles (degenerate section), which is the actual problematic geometry from bug27569.
|
||||
// The curve is projected onto a B-spline surface.
|
||||
TEST_F(ShapeConstruct_ProjectCurveOnSurfaceTest, Bug27569_HighMultiplicityBSpline_M2)
|
||||
{
|
||||
// Construct a degree 7 B-spline curve with structure similar to bug27569:
|
||||
// - 7 unique knots with high multiplicities: 15, 14, 14, 14, 14, 14, 15
|
||||
// - Total knot count (with mults) = 15 + 14*5 + 15 = 100
|
||||
// - Number of poles = 100 - 7 - 1 = 92 (approximately, depends on exact formula)
|
||||
// For B-spline: sum of multiplicities = nbPoles + degree + 1
|
||||
// => nbPoles = sum(mults) - degree - 1 = (15 + 14*5 + 15) - 7 - 1 = 100 - 8 = 92... but file has
|
||||
// 85 Actually for non-periodic: sum(mults) = nbPoles + degree + 1
|
||||
// => 15 + 14 + 14 + 14 + 14 + 14 + 15 = 100 = 85 + 7 + 1 = 93... doesn't match
|
||||
// Looking at file: 85 poles, degree 7, knots with mults summing to 100
|
||||
// Actually file shows: "14 85 7" meaning 14 spans(?), 85 poles, degree 7
|
||||
|
||||
// Let's construct a simpler problematic case:
|
||||
// Degree 7 B-spline with a degenerate section (repeated identical poles)
|
||||
const int aDegree = 7;
|
||||
const int aNbKnots = 7;
|
||||
|
||||
// High multiplicities similar to bug27569 (adjusted for valid B-spline)
|
||||
TColStd_Array1OfInteger aMults(1, aNbKnots);
|
||||
aMults(1) = 8; // degree + 1 for clamped start
|
||||
aMults(2) = 7;
|
||||
aMults(3) = 7;
|
||||
aMults(4) = 7;
|
||||
aMults(5) = 7;
|
||||
aMults(6) = 7;
|
||||
aMults(7) = 8; // degree + 1 for clamped end
|
||||
// Sum = 8 + 7*5 + 8 = 51
|
||||
// nbPoles = sum(mults) - degree - 1 = 51 - 7 - 1 = 43
|
||||
|
||||
const int aNbPoles = 43;
|
||||
|
||||
// Uniform knot vector
|
||||
TColStd_Array1OfReal aKnots(1, aNbKnots);
|
||||
for (int i = 1; i <= aNbKnots; ++i)
|
||||
{
|
||||
aKnots(i) = (i - 1); // Knots: 0, 1, 2, 3, 4, 5, 6
|
||||
}
|
||||
|
||||
// Create poles with a degenerate section (repeated identical poles in the middle)
|
||||
TColgp_Array1OfPnt aPoles(1, aNbPoles);
|
||||
|
||||
// First section: smooth curve from start
|
||||
for (int i = 1; i <= 15; ++i)
|
||||
{
|
||||
const double t = (i - 1.0) / 14.0;
|
||||
const double aX = 144.0 - t * 74.0; // Decreasing from 144 to 70
|
||||
const double aY = -t * 0.0002;
|
||||
const double aZ = 8.3 + t * 51.7; // Increasing from 8.3 to 60
|
||||
aPoles(i) = gp_Pnt(aX, aY, aZ);
|
||||
}
|
||||
|
||||
// Middle section: degenerate (repeated identical poles) - like in bug27569
|
||||
for (int i = 16; i <= 28; ++i)
|
||||
{
|
||||
aPoles(i) = gp_Pnt(70.0, 0.0, 60.0); // All identical
|
||||
}
|
||||
|
||||
// Last section: smooth curve to end
|
||||
for (int i = 29; i <= aNbPoles; ++i)
|
||||
{
|
||||
const double t = (i - 29.0) / (aNbPoles - 29.0);
|
||||
const double aX = 70.0 - t * 80.0; // Decreasing from 70 to -10
|
||||
const double aY = -t * 32.0;
|
||||
const double aZ = 60.0 - t * 60.0; // Decreasing from 60 to 0
|
||||
aPoles(i) = gp_Pnt(aX, aY, aZ);
|
||||
}
|
||||
|
||||
Handle(Geom_BSplineCurve) aBSplineCurve;
|
||||
try
|
||||
{
|
||||
aBSplineCurve = new Geom_BSplineCurve(aPoles, aKnots, aMults, aDegree);
|
||||
}
|
||||
catch (Standard_Failure const&)
|
||||
{
|
||||
// If construction fails, the test documents the expected behavior
|
||||
GTEST_SKIP() << "Could not construct B-spline with high multiplicities";
|
||||
}
|
||||
ASSERT_FALSE(aBSplineCurve.IsNull()) << "B-Spline curve should be created";
|
||||
|
||||
// Create B-spline surface (simplified version of bug27569 surface)
|
||||
// 8x2 poles B-spline surface
|
||||
const int aNbUPoles = 8;
|
||||
const int aNbVPoles = 2;
|
||||
|
||||
TColgp_Array2OfPnt aSurfPoles(1, aNbUPoles, 1, aNbVPoles);
|
||||
// V=0 row
|
||||
aSurfPoles(1, 1) = gp_Pnt(70, 0, 60);
|
||||
aSurfPoles(2, 1) = gp_Pnt(85.01, 0, 60);
|
||||
aSurfPoles(3, 1) = gp_Pnt(98.87, 0, 55.07);
|
||||
aSurfPoles(4, 1) = gp_Pnt(111.6, 0, 46.57);
|
||||
aSurfPoles(5, 1) = gp_Pnt(123.15, 0, 35.68);
|
||||
aSurfPoles(6, 1) = gp_Pnt(133.46, 0, 23.56);
|
||||
aSurfPoles(7, 1) = gp_Pnt(142.46, 0, 11.32);
|
||||
aSurfPoles(8, 1) = gp_Pnt(150, 0, 0);
|
||||
// V=1 row (same with Y offset)
|
||||
aSurfPoles(1, 2) = gp_Pnt(54.99, 0, 60);
|
||||
aSurfPoles(2, 2) = gp_Pnt(41.13, 0, 55.07);
|
||||
aSurfPoles(3, 2) = gp_Pnt(28.4, 0, 46.57);
|
||||
aSurfPoles(4, 2) = gp_Pnt(16.85, 0, 35.68);
|
||||
aSurfPoles(5, 2) = gp_Pnt(6.54, 0, 23.56);
|
||||
aSurfPoles(6, 2) = gp_Pnt(-2.46, 0, 11.32);
|
||||
aSurfPoles(7, 2) = gp_Pnt(-10, 0, 0);
|
||||
aSurfPoles(8, 2) = gp_Pnt(-10, -35.91, 0);
|
||||
|
||||
TColStd_Array1OfReal aUKnots(1, 2);
|
||||
TColStd_Array1OfReal aVKnots(1, 2);
|
||||
TColStd_Array1OfInteger aUMults(1, 2);
|
||||
TColStd_Array1OfInteger aVMults(1, 2);
|
||||
|
||||
aUKnots(1) = 0;
|
||||
aUKnots(2) = 1;
|
||||
aVKnots(1) = 0;
|
||||
aVKnots(2) = 1;
|
||||
aUMults(1) = 8;
|
||||
aUMults(2) = 8;
|
||||
aVMults(1) = 2;
|
||||
aVMults(2) = 2;
|
||||
|
||||
Handle(Geom_BSplineSurface) aBSplineSurface;
|
||||
try
|
||||
{
|
||||
aBSplineSurface = new Geom_BSplineSurface(aSurfPoles, aUKnots, aVKnots, aUMults, aVMults, 7, 1);
|
||||
}
|
||||
catch (Standard_Failure const&)
|
||||
{
|
||||
// Fall back to a simple plane if surface construction fails
|
||||
Handle(Geom_Plane) aPlane = new Geom_Plane(gp_Pnt(70, 0, 30), gp_Dir(0, 1, 0));
|
||||
myProjector->Init(aPlane, Precision::Confusion());
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aBSplineCurve,
|
||||
aBSplineCurve->FirstParameter(),
|
||||
aBSplineCurve->LastParameter(),
|
||||
aPCurve);
|
||||
|
||||
// This test documents expected behavior - projection should succeed
|
||||
EXPECT_TRUE(aResult) << "Projection should succeed";
|
||||
EXPECT_FALSE(aPCurve.IsNull()) << "PCurve should be created";
|
||||
return;
|
||||
}
|
||||
|
||||
myProjector->Init(aBSplineSurface, Precision::Confusion());
|
||||
|
||||
Handle(Geom2d_Curve) aPCurve;
|
||||
const Standard_Boolean aResult = myProjector->Perform(aBSplineCurve,
|
||||
aBSplineCurve->FirstParameter(),
|
||||
aBSplineCurve->LastParameter(),
|
||||
aPCurve);
|
||||
|
||||
// This is the key assertion - the projection SHOULD succeed but currently may fail
|
||||
// for curves with degenerate sections (repeated poles)
|
||||
EXPECT_TRUE(aResult) << "Projection should succeed for B-spline with degenerate section";
|
||||
EXPECT_FALSE(aPCurve.IsNull()) << "PCurve should be created";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,24 +20,21 @@
|
||||
#include <Standard.hxx>
|
||||
#include <Standard_Type.hxx>
|
||||
|
||||
#include <Standard_Integer.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <Standard_Transient.hxx>
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <ShapeExtend_Status.hxx>
|
||||
#include <GeomAbs_Shape.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColgp_HArray1OfPnt2d.hxx>
|
||||
#include <TColgp_HArray1OfPnt.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TColgp_SequenceOfPnt2d.hxx>
|
||||
#include <TColStd_SequenceOfReal.hxx>
|
||||
class ShapeAnalysis_Surface;
|
||||
class Geom_Surface;
|
||||
class Geom_Curve;
|
||||
class Geom2d_Curve;
|
||||
#include <Standard_Transient.hxx>
|
||||
|
||||
// resolve name collisions with X11 headers
|
||||
#include <utility>
|
||||
|
||||
class Geom2d_Curve;
|
||||
class Geom_Curve;
|
||||
class Geom_Surface;
|
||||
class ShapeAnalysis_Surface;
|
||||
|
||||
// Resolve name collisions with X11 headers
|
||||
#ifdef Status
|
||||
#undef Status
|
||||
#endif
|
||||
@@ -57,6 +54,14 @@ DEFINE_STANDARD_HANDLE(ShapeConstruct_ProjectCurveOnSurface, Standard_Transient)
|
||||
//! the surface) are recognized with the given precision.
|
||||
class ShapeConstruct_ProjectCurveOnSurface : public Standard_Transient
|
||||
{
|
||||
public:
|
||||
// Type aliases for internal containers (1-based indexing for geometry arrays)
|
||||
using ArrayOfPnt = NCollection_Array1<gp_Pnt>;
|
||||
using ArrayOfPnt2d = NCollection_Array1<gp_Pnt2d>;
|
||||
using ArrayOfReal = NCollection_Array1<Standard_Real>;
|
||||
// Cache uses 0-based indexing (simple 2-element array)
|
||||
using CachePoint = std::pair<gp_Pnt, gp_Pnt2d>;
|
||||
using CacheArray = NCollection_Array1<CachePoint>;
|
||||
|
||||
public:
|
||||
//! Empty constructor.
|
||||
@@ -64,168 +69,235 @@ public:
|
||||
|
||||
//! Initializes the object with all necessary parameters,
|
||||
//! i.e. surface and precision
|
||||
Standard_EXPORT virtual void Init(const Handle(Geom_Surface)& surf, const Standard_Real preci);
|
||||
//! @param[in] theSurf the surface to project on
|
||||
//! @param[in] thePreci the precision for projection
|
||||
Standard_EXPORT virtual void Init(const Handle(Geom_Surface)& theSurf,
|
||||
const Standard_Real thePreci);
|
||||
|
||||
//! Initializes the object with all necessary parameters,
|
||||
//! i.e. surface and precision
|
||||
Standard_EXPORT virtual void Init(const Handle(ShapeAnalysis_Surface)& surf,
|
||||
const Standard_Real preci);
|
||||
//! @param[in] theSurf the surface to project on (ShapeAnalysis_Surface)
|
||||
//! @param[in] thePreci the precision for projection
|
||||
Standard_EXPORT virtual void Init(const Handle(ShapeAnalysis_Surface)& theSurf,
|
||||
const Standard_Real thePreci);
|
||||
|
||||
//! Loads a surface (in the form of Geom_Surface) to project on
|
||||
Standard_EXPORT void SetSurface(const Handle(Geom_Surface)& surf);
|
||||
//! @param[in] theSurf the surface to project on
|
||||
Standard_EXPORT void SetSurface(const Handle(Geom_Surface)& theSurf);
|
||||
|
||||
//! Loads a surface (in the form of ShapeAnalysis_Surface) to project on
|
||||
Standard_EXPORT void SetSurface(const Handle(ShapeAnalysis_Surface)& surf);
|
||||
//! @param[in] theSurf the surface to project on
|
||||
Standard_EXPORT void SetSurface(const Handle(ShapeAnalysis_Surface)& theSurf);
|
||||
|
||||
//! Sets value for current precision
|
||||
Standard_EXPORT void SetPrecision(const Standard_Real preci);
|
||||
|
||||
//! Returns (modifiable) the build-curve-3d mode, by default False
|
||||
//! If True, if the projected curve has been recomputed by
|
||||
//! interpolation, the 3d curve is also rebuild by interpolation
|
||||
Standard_EXPORT Standard_Boolean& BuildCurveMode();
|
||||
//! @param[in] thePreci the precision value
|
||||
Standard_EXPORT void SetPrecision(const Standard_Real thePreci);
|
||||
|
||||
//! Returns (modifiable) the flag specifying to which side of
|
||||
//! parametrical space adjust part of pcurve which lies on seam.
|
||||
//! This is required in very rare case when 3d curve which is
|
||||
//! to be projected goes partly along the seam on the closed
|
||||
//! surface with singularity (e.g. sphere), goes through the
|
||||
//! degenerated point and paerly lies on internal area of surface.
|
||||
//! degenerated point and partly lies on internal area of surface.
|
||||
//!
|
||||
//! If this flag is True, the seam part of such curve will be
|
||||
//! adjusted to the left side of parametric space (on sphere U=0),
|
||||
//! else to the right side (on sphere U=2*PI)
|
||||
//! Default value is True
|
||||
//! @return modifiable reference to the adjustment flag
|
||||
Standard_EXPORT Standard_Integer& AdjustOverDegenMode();
|
||||
|
||||
//! Returns the status of last Perform
|
||||
//! @param[in] theStatus the status to query
|
||||
//! @return true if the specified status is set
|
||||
Standard_EXPORT Standard_Boolean Status(const ShapeExtend_Status theStatus) const;
|
||||
|
||||
//! Computes the projection of 3d curve onto a surface using the
|
||||
//! specialized algorithm. Returns False if projector fails,
|
||||
//! otherwise, if pcurve computed successfully, returns True.
|
||||
//! The output curve 2D is guaranteed to be same-parameter
|
||||
//! with input curve 3D on the interval [First, Last]. If the output curve
|
||||
//! with input curve 3D on the interval [theFirst, theLast]. If the output curve
|
||||
//! lies on a direct line the infinite line is returned, in the case
|
||||
//! same-parameter condition is satisfied.
|
||||
//! TolFirst and TolLast are the tolerances at the ends of input curve 3D.
|
||||
Standard_EXPORT virtual Standard_Boolean Perform(Handle(Geom_Curve)& c3d,
|
||||
const Standard_Real First,
|
||||
const Standard_Real Last,
|
||||
Handle(Geom2d_Curve)& c2d,
|
||||
const Standard_Real TolFirst = -1,
|
||||
const Standard_Real TolLast = -1);
|
||||
//! @param[in] theC3D the 3D curve to project
|
||||
//! @param[in] theFirst the first parameter of the curve
|
||||
//! @param[in] theLast the last parameter of the curve
|
||||
//! @param[out] theC2D the resulting 2D curve
|
||||
//! @param[in] theTolFirst the tolerance at the first point (default: Precision::Confusion())
|
||||
//! @param[in] theTolLast the tolerance at the last point (default: Precision::Confusion())
|
||||
//! @return true if projection succeeded
|
||||
Standard_EXPORT virtual Standard_Boolean Perform(
|
||||
const Handle(Geom_Curve)& theC3D,
|
||||
const Standard_Real theFirst,
|
||||
const Standard_Real theLast,
|
||||
Handle(Geom2d_Curve)& theC2D,
|
||||
const Standard_Real theTolFirst = Precision::Confusion(),
|
||||
const Standard_Real theTolLast = Precision::Confusion());
|
||||
|
||||
DEFINE_STANDARD_RTTIEXT(ShapeConstruct_ProjectCurveOnSurface, Standard_Transient)
|
||||
|
||||
protected:
|
||||
//! Try to approximate 3D curve by Geom2d_Line
|
||||
//! or Geom2d_BSplineCurve with degree 1 with specified tolerance.
|
||||
//! @param[in] thePoints points obtained from 3d curve
|
||||
//! @param[in] theParams parameters corresponding points on 3d curve
|
||||
//! @param[out] thePoints2d 2d points lies on line in parametric space
|
||||
//! @param[in] theTol tolerance used for compare initial points 3d and
|
||||
//! 3d points obtained from line lying in parametric space of surface
|
||||
//! @param[out] theIsRecompute flag indicating if recomputation is needed
|
||||
//! @param[out] theIsFromCache flag indicating if result is from cache
|
||||
//! @return the resulting 2D curve or null if line fitting failed
|
||||
Standard_EXPORT Handle(Geom2d_Curve) getLine(const ArrayOfPnt& thePoints,
|
||||
const ArrayOfReal& theParams,
|
||||
ArrayOfPnt2d& thePoints2d,
|
||||
const Standard_Real theTol,
|
||||
Standard_Boolean& theIsRecompute,
|
||||
Standard_Boolean& theIsFromCache) const;
|
||||
|
||||
//! Computes the projection of 3d curve onto a surface using the
|
||||
//! standard algorithm from ProjLib. Returns False if standard
|
||||
//! projector fails or raises an exception or cuts the curve by
|
||||
//! parametrical bounds of the surface. Else, if pcurve computed
|
||||
//! successfully, returns True.
|
||||
//! The continuity, maxdeg and nbinterval are parameters of call
|
||||
//! to Approx_CurveOnSurface. If nbinterval is equal to -1
|
||||
//! (default), this value is computed depending on source 3d curve
|
||||
//! and surface.
|
||||
Standard_EXPORT Standard_Boolean PerformByProjLib(Handle(Geom_Curve)& c3d,
|
||||
const Standard_Real First,
|
||||
const Standard_Real Last,
|
||||
Handle(Geom2d_Curve)& c2d,
|
||||
const GeomAbs_Shape continuity = GeomAbs_C1,
|
||||
const Standard_Integer maxdeg = 12,
|
||||
const Standard_Integer nbinterval = -1);
|
||||
//! @param[in] theC3D the 3D curve to project
|
||||
//! @param[in] theFirst the first parameter of the curve
|
||||
//! @param[in] theLast the last parameter of the curve
|
||||
//! @param[out] theC2D the resulting 2D curve
|
||||
//! @return true if projection succeeded
|
||||
Standard_EXPORT Standard_Boolean PerformByProjLib(const Handle(Geom_Curve)& theC3D,
|
||||
const Standard_Real theFirst,
|
||||
const Standard_Real theLast,
|
||||
Handle(Geom2d_Curve)& theC2D);
|
||||
|
||||
DEFINE_STANDARD_RTTIEXT(ShapeConstruct_ProjectCurveOnSurface, Standard_Transient)
|
||||
//! Performs analytical projection for special cases (plane surfaces)
|
||||
//! @param[in] theC3D the 3D curve to project
|
||||
//! @return the resulting 2D curve or null if analytical projection not applicable
|
||||
Standard_EXPORT Handle(Geom2d_Curve) projectAnalytic(const Handle(Geom_Curve)& theC3D) const;
|
||||
|
||||
protected:
|
||||
//! Try to approximate 3D curve by Geom2d_Line
|
||||
//! or Geom2d_BsplineCurve with degree 1 with specified tolerance.
|
||||
//! points - points obtained from 3d curve.
|
||||
//! params - parameters corresponding points on 3d curves
|
||||
//! points2d - 2d points lies on line in parametric space
|
||||
//! theTol - tolerance used for compare initial points 3d and
|
||||
//! 3d points obtained from line lying in parameric space of surface
|
||||
Standard_EXPORT Handle(Geom2d_Curve) getLine(const TColgp_SequenceOfPnt& points,
|
||||
const TColStd_SequenceOfReal& params,
|
||||
TColgp_SequenceOfPnt2d& points2d,
|
||||
const Standard_Real theTol,
|
||||
Standard_Boolean& IsRecompute,
|
||||
Standard_Boolean& isFromCashe) const;
|
||||
//! Main approximation routine for pcurve computation
|
||||
//! @param[in] theNbPnt number of points
|
||||
//! @param[in] theC3D the 3D curve
|
||||
//! @param[in] theTolFirst tolerance at first point
|
||||
//! @param[in] theTolLast tolerance at last point
|
||||
//! @param[in,out] thePoints array of 3D points
|
||||
//! @param[in,out] theParams array of parameters
|
||||
//! @param[out] thePoints2d array of 2D points
|
||||
//! @param[out] theC2D resulting 2D curve
|
||||
//! @return true if approximation succeeded
|
||||
Standard_EXPORT Standard_Boolean approxPCurve(const Standard_Integer theNbPnt,
|
||||
const Handle(Geom_Curve)& theC3D,
|
||||
const Standard_Real theTolFirst,
|
||||
const Standard_Real theTolLast,
|
||||
ArrayOfPnt& thePoints,
|
||||
ArrayOfReal& theParams,
|
||||
ArrayOfPnt2d& thePoints2d,
|
||||
Handle(Geom2d_Curve)& theC2D);
|
||||
|
||||
Handle(ShapeAnalysis_Surface) mySurf;
|
||||
Standard_Real myPreci;
|
||||
Standard_Boolean myBuild;
|
||||
Standard_Integer myStatus;
|
||||
Standard_Integer myAdjustOverDegen;
|
||||
Standard_Integer myNbCashe;
|
||||
gp_Pnt myCashe3d[2];
|
||||
gp_Pnt2d myCashe2d[2];
|
||||
//! Corrects extremity point near singularity
|
||||
//! @param[in] theC3D the 3D curve
|
||||
//! @param[in] theParams array of parameters
|
||||
//! @param[in,out] thePoints2d array of 2D points
|
||||
//! @param[in] theIsFirstPoint true if correcting first point, false for last
|
||||
//! @param[in] thePointOnIsoLine point on isoline
|
||||
//! @param[in] theIsUIso true if U-isoline, false if V-isoline
|
||||
Standard_EXPORT void correctExtremity(const Handle(Geom_Curve)& theC3D,
|
||||
const ArrayOfReal& theParams,
|
||||
ArrayOfPnt2d& thePoints2d,
|
||||
const Standard_Boolean theIsFirstPoint,
|
||||
const gp_Pnt2d& thePointOnIsoLine,
|
||||
const Standard_Boolean theIsUIso);
|
||||
|
||||
//! Inserts additional point or adjusts coordinate to handle period jumps
|
||||
//! @param[in,out] theToAdjust flag indicating if adjustment should be done
|
||||
//! @param[in] theIndCoord coordinate index (1=U, 2=V)
|
||||
//! @param[in] thePeriod the period value
|
||||
//! @param[in] theTolOnPeriod tolerance on period
|
||||
//! @param[in,out] theCurCoord current coordinate value
|
||||
//! @param[in] thePrevCoord previous coordinate value
|
||||
//! @param[in] theC3D the 3D curve
|
||||
//! @param[in,out] theIndex current point index
|
||||
//! @param[in,out] thePoints array of 3D points
|
||||
//! @param[in,out] theParams array of parameters
|
||||
//! @param[in,out] thePoints2d array of 2D points
|
||||
Standard_EXPORT void insertAdditionalPointOrAdjust(Standard_Boolean& theToAdjust,
|
||||
const Standard_Integer theIndCoord,
|
||||
const Standard_Real thePeriod,
|
||||
const Standard_Real theTolOnPeriod,
|
||||
Standard_Real& theCurCoord,
|
||||
const Standard_Real thePrevCoord,
|
||||
const Handle(Geom_Curve)& theC3D,
|
||||
Standard_Integer& theIndex,
|
||||
ArrayOfPnt& thePoints,
|
||||
ArrayOfReal& theParams,
|
||||
ArrayOfPnt2d& thePoints2d);
|
||||
|
||||
//! Interpolates 2D curve from points
|
||||
//! @param[in] theNbPnt number of points
|
||||
//! @param[in] thePoints2d array of 2D points
|
||||
//! @param[in] theParams array of parameters
|
||||
//! @return the interpolated 2D curve or null on failure
|
||||
Standard_EXPORT Handle(Geom2d_Curve) interpolatePCurve(const Standard_Integer theNbPnt,
|
||||
const ArrayOfPnt2d& thePoints2d,
|
||||
const ArrayOfReal& theParams) const;
|
||||
|
||||
//! Approximates 2D curve from points
|
||||
//! @param[in] thePoints2d array of 2D points
|
||||
//! @param[in] theParams array of parameters
|
||||
//! @return the approximated 2D curve or null on failure
|
||||
Standard_EXPORT Handle(Geom2d_Curve) approximatePCurve(const ArrayOfPnt2d& thePoints2d,
|
||||
const ArrayOfReal& theParams) const;
|
||||
|
||||
//! Checks and removes coincident 3D points
|
||||
//! @param[in,out] thePoints array of 3D points
|
||||
//! @param[in,out] theParams array of parameters
|
||||
//! @param[in,out] thePreci precision (may be adjusted)
|
||||
Standard_EXPORT void checkPoints(ArrayOfPnt& thePoints,
|
||||
ArrayOfReal& theParams,
|
||||
Standard_Real& thePreci) const;
|
||||
|
||||
//! Checks and removes coincident 2D points
|
||||
//! @param[in,out] thePoints2d array of 2D points
|
||||
//! @param[in,out] theParams array of parameters
|
||||
//! @param[in,out] thePreci precision (may be adjusted)
|
||||
Standard_EXPORT void checkPoints2d(ArrayOfPnt2d& thePoints2d,
|
||||
ArrayOfReal& theParams,
|
||||
Standard_Real& thePreci) const;
|
||||
|
||||
//! Detects if curve is isoparametric (U=const or V=const)
|
||||
//! @param[in] theNbPnt number of points
|
||||
//! @param[in] thePoints array of 3D points
|
||||
//! @param[in] theParams array of parameters
|
||||
//! @param[out] theIsTypeU true if U-iso, false if V-iso
|
||||
//! @param[out] theP1OnIso true if first point is on iso
|
||||
//! @param[out] theValueP1 2D value of first point on iso
|
||||
//! @param[out] theP2OnIso true if last point is on iso
|
||||
//! @param[out] theValueP2 2D value of last point on iso
|
||||
//! @param[out] theIsoPar2d3d true if parametrization matches
|
||||
//! @param[out] theCIso the isoline curve
|
||||
//! @param[out] theT1 first iso parameter
|
||||
//! @param[out] theT2 last iso parameter
|
||||
//! @param[out] theParamsOut output parameters on isoline
|
||||
//! @return true if curve is isoparametric
|
||||
Standard_EXPORT Standard_Boolean isAnIsoparametric(const Standard_Integer theNbPnt,
|
||||
const ArrayOfPnt& thePoints,
|
||||
const ArrayOfReal& theParams,
|
||||
Standard_Boolean& theIsTypeU,
|
||||
Standard_Boolean& theP1OnIso,
|
||||
gp_Pnt2d& theValueP1,
|
||||
Standard_Boolean& theP2OnIso,
|
||||
gp_Pnt2d& theValueP2,
|
||||
Standard_Boolean& theIsoPar2d3d,
|
||||
Handle(Geom_Curve)& theCIso,
|
||||
Standard_Real& theT1,
|
||||
Standard_Real& theT2,
|
||||
ArrayOfReal& theParamsOut) const;
|
||||
|
||||
private:
|
||||
Standard_EXPORT Handle(Geom2d_Curve) ProjectAnalytic(const Handle(Geom_Curve)& c3d) const;
|
||||
|
||||
Standard_EXPORT Standard_Boolean ApproxPCurve(const Standard_Integer nbrPnt,
|
||||
const Handle(Geom_Curve)& c3d,
|
||||
const Standard_Real TolFirst,
|
||||
const Standard_Real TolLast,
|
||||
TColgp_SequenceOfPnt& points,
|
||||
TColStd_SequenceOfReal& params,
|
||||
TColgp_SequenceOfPnt2d& points2d,
|
||||
Handle(Geom2d_Curve)& c2d);
|
||||
|
||||
Standard_EXPORT void CorrectExtremity(const Handle(Geom_Curve)& theC3d,
|
||||
const TColStd_SequenceOfReal& theParams,
|
||||
TColgp_SequenceOfPnt2d& thePnt2d,
|
||||
const Standard_Boolean theIsFirstPoint,
|
||||
const gp_Pnt2d& thePointOnIsoLine,
|
||||
const Standard_Boolean theIsUiso);
|
||||
|
||||
Standard_EXPORT void InsertAdditionalPointOrAdjust(Standard_Boolean& ToAdjust,
|
||||
const Standard_Integer theIndCoord,
|
||||
const Standard_Real Period,
|
||||
const Standard_Real TolOnPeriod,
|
||||
Standard_Real& CurCoord,
|
||||
const Standard_Real prevCoord,
|
||||
const Handle(Geom_Curve)& c3d,
|
||||
Standard_Integer& theIndex,
|
||||
TColgp_SequenceOfPnt& points,
|
||||
TColStd_SequenceOfReal& params,
|
||||
TColgp_SequenceOfPnt2d& pnt2d);
|
||||
|
||||
Standard_EXPORT Handle(Geom2d_Curve) InterpolatePCurve(const Standard_Integer nbrPnt,
|
||||
Handle(TColgp_HArray1OfPnt2d)& points2d,
|
||||
Handle(TColStd_HArray1OfReal)& params,
|
||||
const Handle(Geom_Curve)& orig) const;
|
||||
|
||||
Standard_EXPORT Handle(Geom2d_Curve) ApproximatePCurve(const Standard_Integer nbrPnt,
|
||||
Handle(TColgp_HArray1OfPnt2d)& points2d,
|
||||
Handle(TColStd_HArray1OfReal)& params,
|
||||
const Handle(Geom_Curve)& orig) const;
|
||||
|
||||
Standard_EXPORT Handle(Geom_Curve) InterpolateCurve3d(const Standard_Integer nbrPnt,
|
||||
Handle(TColgp_HArray1OfPnt)& points,
|
||||
Handle(TColStd_HArray1OfReal)& params,
|
||||
const Handle(Geom_Curve)& orig) const;
|
||||
|
||||
Standard_EXPORT void CheckPoints(Handle(TColgp_HArray1OfPnt)& points,
|
||||
Handle(TColStd_HArray1OfReal)& params,
|
||||
Standard_Real& preci) const;
|
||||
|
||||
Standard_EXPORT void CheckPoints2d(Handle(TColgp_HArray1OfPnt2d)& points,
|
||||
Handle(TColStd_HArray1OfReal)& params,
|
||||
Standard_Real& preci) const;
|
||||
|
||||
Standard_EXPORT Standard_Boolean IsAnIsoparametric(const Standard_Integer nbrPnt,
|
||||
const TColgp_SequenceOfPnt& points,
|
||||
const TColStd_SequenceOfReal& params,
|
||||
Standard_Boolean& isoTypeU,
|
||||
Standard_Boolean& p1OnIso,
|
||||
gp_Pnt2d& valueP1,
|
||||
Standard_Boolean& p2OnIso,
|
||||
gp_Pnt2d& valueP2,
|
||||
Standard_Boolean& isoPar2d3d,
|
||||
Handle(Geom_Curve)& cIso,
|
||||
Standard_Real& t1,
|
||||
Standard_Real& t2,
|
||||
TColStd_Array1OfReal& pout) const;
|
||||
Handle(ShapeAnalysis_Surface) mySurf; //!< Surface to project on
|
||||
Standard_Real myPreci; //!< Current precision
|
||||
Standard_Integer myStatus; //!< Operation status
|
||||
Standard_Integer myAdjustOverDegen; //!< Seam adjustment flag
|
||||
CacheArray myCache; //!< Cached 3D/2D point pairs for projection optimization
|
||||
};
|
||||
|
||||
#endif // _ShapeConstruct_ProjectCurveOnSurface_HeaderFile
|
||||
|
||||
Reference in New Issue
Block a user