mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-07-20 12:45:50 +03:00
- Refactored `ProjectOnSegments`: renamed parameters, added early exit, and detailed doxygen-style docs. - Updated `ProjectAct`: renamed local variables, stored initial projection values for fallback, and streamlined closed-curve handling. - Removed `#ifdef OCCT_DEBUG` blocks in `ValidateRange`.
1397 lines
49 KiB
C++
1397 lines
49 KiB
C++
// Copyright (c) 1999-2014 OPEN CASCADE SAS
|
|
//
|
|
// This file is part of Open CASCADE Technology software library.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License version 2.1 as published
|
|
// by the Free Software Foundation, with special exception defined in the file
|
|
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
|
// distribution for complete text of the license and disclaimer of any warranty.
|
|
//
|
|
// Alternatively, this file may be used under the terms of Open CASCADE
|
|
// commercial license or contractual agreement.
|
|
|
|
// pdn 04.12.98 Add method using Adaptor_Curve
|
|
//: j8 abv 10.12.98 TR10 r0501_db.stp #9423
|
|
// pdn 25.12.98 private method ProjectAct
|
|
// szv#4 S4163
|
|
//: s5 abv 22.04.99 Adding debug printouts in catch {} blocks
|
|
// abv 14.05.99 S4174: Adding method for exact computing of the boundary box
|
|
// gka 21.06.99 S4208: adding method NextProject(Adaptor_Curve)
|
|
// msv 30.05.00 correct IsPlanar for a conic curve
|
|
|
|
#include <Adaptor3d_Curve.hxx>
|
|
#include <Bnd_Box2d.hxx>
|
|
#include <ElCLib.hxx>
|
|
#include <Extrema_ExtPC.hxx>
|
|
#include <Extrema_LocateExtPC.hxx>
|
|
#include <Geom2d_BezierCurve.hxx>
|
|
#include <Geom2d_BoundedCurve.hxx>
|
|
#include <Geom2d_BSplineCurve.hxx>
|
|
#include <Geom2d_Conic.hxx>
|
|
#include <Geom2d_Curve.hxx>
|
|
#include <Geom2d_Line.hxx>
|
|
#include <Geom2d_OffsetCurve.hxx>
|
|
#include <Geom2d_TrimmedCurve.hxx>
|
|
#include <Geom2dAdaptor_Curve.hxx>
|
|
#include <Geom2dInt_Geom2dCurveTool.hxx>
|
|
#include <Geom_BezierCurve.hxx>
|
|
#include <Geom_BoundedCurve.hxx>
|
|
#include <Geom_BSplineCurve.hxx>
|
|
#include <Geom_Circle.hxx>
|
|
#include <Geom_Conic.hxx>
|
|
#include <Geom_Curve.hxx>
|
|
#include <Geom_Line.hxx>
|
|
#include <Geom_OffsetCurve.hxx>
|
|
#include <Geom_TrimmedCurve.hxx>
|
|
#include <GeomAdaptor_Curve.hxx>
|
|
#include <gp_Pnt.hxx>
|
|
#include <gp_XYZ.hxx>
|
|
#include <Precision.hxx>
|
|
#include <ShapeAnalysis.hxx>
|
|
#include <ShapeAnalysis_Curve.hxx>
|
|
#include <ShapeExtend_ComplexCurve.hxx>
|
|
#include <Standard_ErrorHandler.hxx>
|
|
#include <Standard_Failure.hxx>
|
|
#include <TColgp_SequenceOfPnt.hxx>
|
|
|
|
//=================================================================================================
|
|
|
|
// This function projects a point onto a curve by evaluating the curve at several points
|
|
// within the specified parameter range. It finds the closest point on the curve to @p thePoint
|
|
// and updates the projection distance, projection point, and projection parameter accordingly.
|
|
// It also adjusts the start and end parameters.
|
|
// @param theCurve The curve to project on.
|
|
// @param thePoint The point to project.
|
|
// @param theSegmentCount The number of segments to consider for projection.
|
|
// @param aStartParam The start parameter of the curve. It will be updated to the start parameter
|
|
// of the segment containing the projection point even if distance less than
|
|
// theProjectionDistance was not found.
|
|
// @param anEndParam The end parameter of the curve. It will be updated to the end parameter of the
|
|
// segment containing the projection point even if distance less than
|
|
// theProjectionDistance was not found.
|
|
// @param aProjDistance The distance between the point and the closest point on the curve.
|
|
// If distance less than theProjectionDistance was found, it will be updated
|
|
// to the distance to the projection point.
|
|
// @param aProjPoint The closest point on the curve to the given point. It will be updated to the
|
|
// projection point if a closer point is found during the iterations.
|
|
// @param aProjParam The parameter of the closest point on the curve to the given point.
|
|
// It will be updated to the parameter of the projection point if a closer point
|
|
// is found during the iterations.
|
|
static void ProjectOnSegments(const Adaptor3d_Curve& theCurve,
|
|
const gp_Pnt& thePoint,
|
|
const Standard_Integer theSegmentCount,
|
|
Standard_Real& aStartParam,
|
|
Standard_Real& anEndParam,
|
|
Standard_Real& aProjDistance,
|
|
gp_Pnt& aProjPoint,
|
|
Standard_Real& aProjParam)
|
|
{
|
|
// We consider <nbseg> points on [uMin,uMax]
|
|
// Which is the closest? And what is the new interval?
|
|
// (it cannot overflow the old one)
|
|
|
|
if (theSegmentCount <= 0)
|
|
{
|
|
return; // No segments to project on
|
|
}
|
|
|
|
const Standard_Real aParamStep = (anEndParam - aStartParam) / theSegmentCount;
|
|
Standard_Real aMinSqDistance = aProjDistance * aProjDistance;
|
|
Standard_Boolean aHasChanged = Standard_False;
|
|
for (Standard_Integer i = 0; i <= theSegmentCount; i++)
|
|
{
|
|
const Standard_Real aCurrentParam = aStartParam + (aParamStep * i);
|
|
const gp_Pnt aCurrentPoint = theCurve.Value(aCurrentParam);
|
|
const Standard_Real aCurrentSqDistance = aCurrentPoint.SquareDistance(thePoint);
|
|
if (aCurrentSqDistance < aMinSqDistance)
|
|
{
|
|
aMinSqDistance = aCurrentSqDistance;
|
|
aProjPoint = aCurrentPoint;
|
|
aProjParam = aCurrentParam;
|
|
aHasChanged = Standard_True;
|
|
}
|
|
}
|
|
if (aHasChanged)
|
|
{
|
|
aProjDistance = Sqrt(aMinSqDistance);
|
|
}
|
|
|
|
anEndParam = Min(anEndParam, aProjParam + aParamStep);
|
|
aStartParam = Max(aStartParam, aProjParam - aParamStep);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
|
|
const gp_Pnt& P3D,
|
|
const Standard_Real preci,
|
|
gp_Pnt& proj,
|
|
Standard_Real& param,
|
|
const Standard_Boolean AdjustToEnds) const
|
|
{
|
|
Standard_Real uMin = C3D->FirstParameter();
|
|
Standard_Real uMax = C3D->LastParameter();
|
|
if (uMin < uMax)
|
|
return Project(C3D, P3D, preci, proj, param, uMin, uMax, AdjustToEnds);
|
|
else
|
|
return Project(C3D, P3D, preci, proj, param, uMax, uMin, AdjustToEnds);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
|
|
const gp_Pnt& P3D,
|
|
const Standard_Real preci,
|
|
gp_Pnt& proj,
|
|
Standard_Real& param,
|
|
const Standard_Real cf,
|
|
const Standard_Real cl,
|
|
const Standard_Boolean AdjustToEnds) const
|
|
{
|
|
Standard_Real distmin;
|
|
Standard_Real uMin = (cf < cl ? cf : cl);
|
|
Standard_Real uMax = (cf < cl ? cl : cf);
|
|
|
|
GeomAdaptor_Curve GAC(C3D, uMin, uMax);
|
|
if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve)))
|
|
{
|
|
// clang-format off
|
|
Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end
|
|
// clang-format on
|
|
gp_Pnt LowBound = GAC.Value(uMin);
|
|
gp_Pnt HigBound = GAC.Value(uMax);
|
|
distmin = LowBound.Distance(P3D);
|
|
if (distmin <= prec)
|
|
{
|
|
param = uMin;
|
|
proj = LowBound;
|
|
return distmin;
|
|
}
|
|
distmin = HigBound.Distance(P3D);
|
|
if (distmin <= prec)
|
|
{
|
|
param = uMax;
|
|
proj = HigBound;
|
|
return distmin;
|
|
}
|
|
}
|
|
|
|
if (!C3D->IsClosed())
|
|
{
|
|
// modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
|
|
// the VIso was not closed (according to C3D->IsClosed()) while it "almost"
|
|
// was (the distance between ends of the curve was a little bit more than
|
|
// Precision::Confusion())
|
|
// in that case value 0.1 was too much and this method returned not correct parameter
|
|
// uMin = uMin - 0.1;
|
|
// uMax = uMax + 0.1;
|
|
// modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
|
|
Standard_Real delta = Min(GAC.Resolution(preci), (uMax - uMin) * 0.1);
|
|
uMin -= delta;
|
|
uMax += delta;
|
|
GAC.Load(C3D, uMin, uMax);
|
|
}
|
|
|
|
return ProjectAct(GAC, P3D, preci, proj, param);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Real ShapeAnalysis_Curve::Project(const Adaptor3d_Curve& C3D,
|
|
const gp_Pnt& P3D,
|
|
const Standard_Real preci,
|
|
gp_Pnt& proj,
|
|
Standard_Real& param,
|
|
const Standard_Boolean AdjustToEnds) const
|
|
|
|
{
|
|
|
|
Standard_Real uMin = C3D.FirstParameter();
|
|
Standard_Real uMax = C3D.LastParameter();
|
|
|
|
if (Precision::IsInfinite(uMin) && Precision::IsInfinite(uMax))
|
|
return ProjectAct(C3D, P3D, preci, proj, param);
|
|
|
|
Standard_Real distmin_L = Precision::Infinite(), distmin_H = Precision::Infinite();
|
|
// clang-format off
|
|
Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end
|
|
// clang-format on
|
|
gp_Pnt LowBound = C3D.Value(uMin);
|
|
gp_Pnt HigBound = C3D.Value(uMax);
|
|
distmin_L = LowBound.Distance(P3D);
|
|
distmin_H = HigBound.Distance(P3D);
|
|
|
|
if (distmin_L <= prec)
|
|
{
|
|
param = uMin;
|
|
proj = LowBound;
|
|
return distmin_L;
|
|
}
|
|
|
|
if (distmin_H <= prec)
|
|
{
|
|
param = uMax;
|
|
proj = HigBound;
|
|
return distmin_H;
|
|
}
|
|
|
|
Standard_Real distProj = ProjectAct(C3D, P3D, preci, proj, param);
|
|
if (distProj < distmin_L + Precision::Confusion()
|
|
&& distProj < distmin_H + Precision::Confusion())
|
|
return distProj;
|
|
|
|
if (distmin_L < distmin_H)
|
|
{
|
|
param = uMin;
|
|
proj = LowBound;
|
|
return distmin_L;
|
|
}
|
|
param = uMax;
|
|
proj = HigBound;
|
|
return distmin_H;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Real ShapeAnalysis_Curve::ProjectAct(const Adaptor3d_Curve& theCurve,
|
|
const gp_Pnt& thePoint,
|
|
const Standard_Real theTolerance,
|
|
gp_Pnt& theProjPoint,
|
|
Standard_Real& theProjParam) const
|
|
|
|
{
|
|
Standard_Boolean OK = Standard_False;
|
|
theProjParam = 0.;
|
|
try
|
|
{
|
|
OCC_CATCH_SIGNALS
|
|
Extrema_ExtPC aCurveExtrema(thePoint, theCurve);
|
|
Standard_Real aMinExtremaDistance = RealLast();
|
|
Standard_Integer aMinExtremaIndex = 0;
|
|
if (aCurveExtrema.IsDone() && (aCurveExtrema.NbExt() > 0))
|
|
{
|
|
for (Standard_Integer i = 1; i <= aCurveExtrema.NbExt(); i++)
|
|
{
|
|
if (!aCurveExtrema.IsMin(i))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const Standard_Real aCurrentDistance = aCurveExtrema.SquareDistance(i);
|
|
if (aCurrentDistance < aMinExtremaDistance)
|
|
{
|
|
aMinExtremaDistance = aCurrentDistance;
|
|
aMinExtremaIndex = i;
|
|
}
|
|
}
|
|
|
|
if (aMinExtremaIndex != 0)
|
|
{
|
|
theProjParam = (aCurveExtrema.Point(aMinExtremaIndex)).Parameter();
|
|
theProjPoint = (aCurveExtrema.Point(aMinExtremaIndex)).Value();
|
|
OK = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
catch (const Standard_Failure& anException)
|
|
{
|
|
(void)anException;
|
|
OK = Standard_False;
|
|
}
|
|
|
|
// szv#4:S4163:12Mar99 moved
|
|
Standard_Real uMin = theCurve.FirstParameter();
|
|
Standard_Real uMax = theCurve.LastParameter();
|
|
Standard_Boolean anIsClosedCurve = Standard_False;
|
|
Standard_Real aCurvePeriod = 0.;
|
|
// Distance between the point and the projection point.
|
|
Standard_Real aProjDistance = Precision::Infinite();
|
|
Standard_Real aModMin = Precision::Infinite();
|
|
|
|
// Remember the computed values.
|
|
// These values will be used in case the projection is not successful.
|
|
const Standard_Real aComputedParam = theProjParam;
|
|
const gp_Pnt aComputedProj = theProjPoint;
|
|
|
|
// PTV 29.05.2002 remember the old solution, cause it could be better
|
|
Standard_Boolean anIsHaveOldSolution = Standard_False;
|
|
Standard_Real anOldParam = 0.;
|
|
gp_Pnt anOldProj;
|
|
if (OK)
|
|
{
|
|
anIsHaveOldSolution = Standard_True;
|
|
anOldProj = theProjPoint;
|
|
anOldParam = theProjParam;
|
|
aProjDistance = theProjPoint.Distance(thePoint);
|
|
aModMin = aProjDistance;
|
|
if (aProjDistance > theTolerance)
|
|
{
|
|
OK = Standard_False;
|
|
}
|
|
if (theCurve.IsClosed())
|
|
{
|
|
anIsClosedCurve = Standard_True;
|
|
aCurvePeriod = uMax - uMin; // szv#4:S4163:12Mar99 optimized
|
|
}
|
|
}
|
|
|
|
if (!OK)
|
|
{
|
|
// BUG NICOLAS - If the point is on the curve 0 Solutions. This works with ElCLib
|
|
|
|
// Generally speaking, we try to ALWAYS return a result that's NOT EVEN GOOD. The caller can
|
|
// then decide what to do.
|
|
theProjParam = 0.;
|
|
|
|
switch (theCurve.GetType())
|
|
{
|
|
case GeomAbs_Circle: {
|
|
const gp_Circ& aCirc = theCurve.Circle();
|
|
theProjPoint = aCirc.Position().Location();
|
|
if (aCirc.Radius() <= gp::Resolution()
|
|
|| thePoint.SquareDistance(theProjPoint) <= gp::Resolution())
|
|
{
|
|
theProjParam = theCurve.FirstParameter();
|
|
theProjPoint = theProjPoint.XYZ() + aCirc.XAxis().Direction().XYZ() * aCirc.Radius();
|
|
}
|
|
else
|
|
{
|
|
theProjParam = ElCLib::Parameter(aCirc, thePoint);
|
|
theProjPoint = ElCLib::Value(theProjParam, aCirc);
|
|
}
|
|
anIsClosedCurve = Standard_True;
|
|
aCurvePeriod = 2. * M_PI;
|
|
}
|
|
break;
|
|
|
|
case GeomAbs_Hyperbola: {
|
|
theProjParam = ElCLib::Parameter(theCurve.Hyperbola(), thePoint);
|
|
theProjPoint = ElCLib::Value(theProjParam, theCurve.Hyperbola());
|
|
}
|
|
break;
|
|
|
|
case GeomAbs_Parabola: {
|
|
theProjParam = ElCLib::Parameter(theCurve.Parabola(), thePoint);
|
|
theProjPoint = ElCLib::Value(theProjParam, theCurve.Parabola());
|
|
}
|
|
break;
|
|
|
|
case GeomAbs_Line: {
|
|
theProjParam = ElCLib::Parameter(theCurve.Line(), thePoint);
|
|
theProjPoint = ElCLib::Value(theProjParam, theCurve.Line());
|
|
}
|
|
break;
|
|
|
|
case GeomAbs_Ellipse: {
|
|
theProjParam = ElCLib::Parameter(theCurve.Ellipse(), thePoint);
|
|
theProjPoint = ElCLib::Value(theProjParam, theCurve.Ellipse());
|
|
anIsClosedCurve = Standard_True;
|
|
aCurvePeriod = 2. * M_PI;
|
|
}
|
|
break;
|
|
|
|
default: {
|
|
// Bspline or something, no easy solution.
|
|
// Here this algorithm tries to find the closest point on the curve
|
|
// by evaluating the distance between the point and the curve
|
|
// at several points within the parameter range.
|
|
aProjDistance = Precision::Infinite();
|
|
ProjectOnSegments(theCurve,
|
|
thePoint,
|
|
25,
|
|
uMin,
|
|
uMax,
|
|
aProjDistance,
|
|
theProjPoint,
|
|
theProjParam);
|
|
if (aProjDistance <= theTolerance)
|
|
{
|
|
return aProjDistance;
|
|
}
|
|
|
|
Extrema_LocateExtPC aProjector(thePoint,
|
|
theCurve,
|
|
theProjParam /*U0*/,
|
|
uMin,
|
|
uMax,
|
|
theTolerance /*TolU*/);
|
|
if (aProjector.IsDone())
|
|
{
|
|
theProjParam = aProjector.Point().Parameter();
|
|
theProjPoint = aProjector.Point().Value();
|
|
const Standard_Real aDistNewton = thePoint.Distance(theProjPoint);
|
|
if (aDistNewton < aModMin)
|
|
{
|
|
return aDistNewton;
|
|
}
|
|
}
|
|
|
|
// Here we are trying to find the closest point on the curve
|
|
// by repeatedly evaluating the distance between the point
|
|
// and the curve at several points within the parameter range.
|
|
// After each call to ProjectOnSegments, uMin and uMax
|
|
// are updated to the start and end parameters of the segment
|
|
// containing the projection point. So, the range of probing
|
|
// is reduced in each iteration.
|
|
// The particular number of segments to probe was
|
|
// chosen to be 40, 20, 25, and 40 again. It is unknown why
|
|
// these particular values were chosen, probably just because
|
|
// they were found to be sufficient in practice.
|
|
for (const Standard_Integer aSegmentCount : {40, 20, 25, 40})
|
|
{
|
|
ProjectOnSegments(theCurve,
|
|
thePoint,
|
|
aSegmentCount,
|
|
uMin,
|
|
uMax,
|
|
aProjDistance,
|
|
theProjPoint,
|
|
theProjParam);
|
|
if (aProjDistance <= theTolerance)
|
|
{
|
|
return aProjDistance;
|
|
}
|
|
}
|
|
|
|
// Did not find a point on the curve
|
|
// that is closer than the tolerance.
|
|
// So, we return the closest point found so far.
|
|
if (aProjDistance > aModMin)
|
|
{
|
|
aProjDistance = aModMin;
|
|
theProjParam = aComputedParam;
|
|
theProjPoint = aComputedProj;
|
|
}
|
|
|
|
return aProjDistance;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (anIsClosedCurve && (theProjParam < uMin || theProjParam > uMax))
|
|
{
|
|
theProjParam += ShapeAnalysis::AdjustByPeriod(theProjParam, 0.5 * (uMin + uMax), aCurvePeriod);
|
|
}
|
|
|
|
if (anIsHaveOldSolution)
|
|
{
|
|
// PTV 29.05.2002 Compare old solution and new;
|
|
const Standard_Real anOldDist = anOldProj.SquareDistance(thePoint);
|
|
const Standard_Real aNewDist = theProjPoint.SquareDistance(thePoint);
|
|
if (anOldDist < aNewDist)
|
|
{
|
|
theProjPoint = anOldProj;
|
|
theProjParam = anOldParam;
|
|
}
|
|
}
|
|
return theProjPoint.Distance(thePoint);
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : NextProject
|
|
// purpose : Newton algo for projecting point on curve (S4030)
|
|
//=======================================================================
|
|
|
|
Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
|
|
const Handle(Geom_Curve)& C3D,
|
|
const gp_Pnt& P3D,
|
|
const Standard_Real preci,
|
|
gp_Pnt& proj,
|
|
Standard_Real& param,
|
|
const Standard_Real cf,
|
|
const Standard_Real cl,
|
|
const Standard_Boolean AdjustToEnds) const
|
|
{
|
|
Standard_Real uMin = (cf < cl ? cf : cl);
|
|
Standard_Real uMax = (cf < cl ? cl : cf);
|
|
Standard_Real distmin = Precision::Infinite();
|
|
GeomAdaptor_Curve GAC(C3D, uMin, uMax);
|
|
if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve)))
|
|
{
|
|
// clang-format off
|
|
Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end
|
|
// clang-format on
|
|
gp_Pnt LowBound = GAC.Value(uMin);
|
|
gp_Pnt HigBound = GAC.Value(uMax);
|
|
distmin = LowBound.Distance(P3D);
|
|
if (distmin <= prec)
|
|
{
|
|
param = uMin;
|
|
proj = LowBound;
|
|
return distmin;
|
|
}
|
|
distmin = HigBound.Distance(P3D);
|
|
if (distmin <= prec)
|
|
{
|
|
param = uMax;
|
|
proj = HigBound;
|
|
return distmin;
|
|
}
|
|
}
|
|
|
|
if (!C3D->IsClosed())
|
|
{
|
|
// modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
|
|
// the VIso was not closed (according to C3D->IsClosed()) while it "almost"
|
|
// was (the distance between ends of the curve was a little bit more than
|
|
// Precision::Confusion())
|
|
// in that case value 0.1 was too much and this method returned not correct parameter
|
|
// uMin = uMin - 0.1;
|
|
// uMax = uMax + 0.1;
|
|
// modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
|
|
Standard_Real delta = Min(GAC.Resolution(preci), (uMax - uMin) * 0.1);
|
|
uMin -= delta;
|
|
uMax += delta;
|
|
GAC.Load(C3D, uMin, uMax);
|
|
}
|
|
return NextProject(paramPrev, GAC, P3D, preci, proj, param);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
|
|
const Adaptor3d_Curve& C3D,
|
|
const gp_Pnt& P3D,
|
|
const Standard_Real preci,
|
|
gp_Pnt& proj,
|
|
Standard_Real& param) const
|
|
{
|
|
Standard_Real uMin = C3D.FirstParameter();
|
|
Standard_Real uMax = C3D.LastParameter();
|
|
|
|
Extrema_LocateExtPC aProjector(P3D, C3D, paramPrev /*U0*/, uMin, uMax, preci /*TolU*/);
|
|
if (aProjector.IsDone())
|
|
{
|
|
param = aProjector.Point().Parameter();
|
|
proj = aProjector.Point().Value();
|
|
return P3D.Distance(proj);
|
|
}
|
|
return Project(C3D, P3D, preci, proj, param, Standard_False);
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : AdjustParameters
|
|
// purpose : Copied from StepToTopoDS_GeometricTuul::UpdateParam3d (Aug 2001)
|
|
//=======================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::ValidateRange(const Handle(Geom_Curve)& theCurve,
|
|
Standard_Real& First,
|
|
Standard_Real& Last,
|
|
const Standard_Real preci) const
|
|
{
|
|
// First et/ou Last peuvent etre en dehors des bornes naturelles de la courbe.
|
|
// On donnera alors la valeur en bout a First et/ou Last
|
|
|
|
Standard_Real cf = theCurve->FirstParameter();
|
|
Standard_Real cl = theCurve->LastParameter();
|
|
// Standard_Real preci = BRepAPI::Precision();
|
|
|
|
if (theCurve->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && !theCurve->IsClosed())
|
|
{
|
|
if (First < cf)
|
|
{
|
|
First = cf;
|
|
}
|
|
else if (First > cl)
|
|
{
|
|
First = cl;
|
|
}
|
|
if (Last < cf)
|
|
{
|
|
Last = cf;
|
|
}
|
|
else if (Last > cl)
|
|
{
|
|
Last = cl;
|
|
}
|
|
}
|
|
|
|
// 15.11.2002 PTV OCC966
|
|
if (ShapeAnalysis_Curve::IsPeriodic(theCurve))
|
|
{
|
|
// clang-format off
|
|
ElCLib::AdjustPeriodic(cf,cl,Precision::PConfusion(),First,Last); //:a7 abv 11 Feb 98: preci -> PConfusion()
|
|
// clang-format on
|
|
}
|
|
else if (First < Last)
|
|
{
|
|
// nothing to fix
|
|
}
|
|
else if (theCurve->IsClosed())
|
|
{
|
|
// l'un des points projecte se trouve sur l'origine du parametrage
|
|
// de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
|
|
// DANGER precision 3d applique a une espace 1d
|
|
|
|
// Last = cf au lieu de Last = cl
|
|
if (Abs(Last - cf) < Precision::PConfusion() /*preci*/)
|
|
Last = cl;
|
|
// First = cl au lieu de First = cf
|
|
else if (Abs(First - cl) < Precision::PConfusion() /*preci*/)
|
|
First = cf;
|
|
|
|
// on se trouve dans un cas ou l origine est traversee
|
|
// illegal sur une courbe fermee non periodique
|
|
// on inverse quand meme les parametres !!!!!!
|
|
else
|
|
{
|
|
//: S4136 abv 20 Apr 99: r0701_ug.stp #6230: add check in 3d
|
|
if (theCurve->Value(First).Distance(theCurve->Value(cf)) < preci)
|
|
First = cf;
|
|
if (theCurve->Value(Last).Distance(theCurve->Value(cl)) < preci)
|
|
Last = cl;
|
|
if (First > Last)
|
|
{
|
|
Standard_Real tmp = First;
|
|
First = Last;
|
|
Last = tmp;
|
|
}
|
|
}
|
|
}
|
|
// The curve is closed within the 3D tolerance
|
|
else if (theCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
|
|
{
|
|
Handle(Geom_BSplineCurve) aBSpline = Handle(Geom_BSplineCurve)::DownCast(theCurve);
|
|
if (aBSpline->StartPoint().Distance(aBSpline->EndPoint()) <= preci)
|
|
{
|
|
//: S4136 <= BRepAPI::Precision()) {
|
|
// l'un des points projecte se trouve sur l'origine du parametrage
|
|
// de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
|
|
// DANGER precision 3d applique a une espace 1d
|
|
|
|
// Last = cf au lieu de Last = cl
|
|
if (Abs(Last - cf) < Precision::PConfusion() /*preci*/)
|
|
Last = cl;
|
|
// First = cl au lieu de First = cf
|
|
else if (Abs(First - cl) < Precision::PConfusion() /*preci*/)
|
|
First = cf;
|
|
|
|
// on se trouve dans un cas ou l origine est traversee
|
|
// illegal sur une courbe fermee non periodique
|
|
// on inverse quand meme les parametres !!!!!!
|
|
else
|
|
{
|
|
Standard_Real tmp = First;
|
|
First = Last;
|
|
Last = tmp;
|
|
}
|
|
}
|
|
// abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
|
|
else if (First > Last)
|
|
{
|
|
First = theCurve->ReversedParameter(First);
|
|
Last = theCurve->ReversedParameter(Last);
|
|
theCurve->Reverse();
|
|
}
|
|
//: j9 abv 11 Dec 98: PRO7747 #4875, after :j8: else
|
|
if (First == Last)
|
|
{ // gka 10.07.1998 file PRO7656 entity 33334
|
|
First = cf;
|
|
Last = cl;
|
|
return Standard_False;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
|
|
if (First > Last)
|
|
{
|
|
First = theCurve->ReversedParameter(First);
|
|
Last = theCurve->ReversedParameter(Last);
|
|
theCurve->Reverse();
|
|
}
|
|
// pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw
|
|
if (First == Last)
|
|
{
|
|
First -= Precision::PConfusion();
|
|
Last += Precision::PConfusion();
|
|
}
|
|
return Standard_False;
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : FillBndBox
|
|
// purpose : WORK-AROUND for methods brom BndLib which give not exact bounds
|
|
//=======================================================================
|
|
|
|
// search for extremum using Newton
|
|
static Standard_Integer SearchForExtremum(const Handle(Geom2d_Curve)& C2d,
|
|
const Standard_Real First,
|
|
const Standard_Real Last,
|
|
const gp_Vec2d& dir,
|
|
Standard_Real& par,
|
|
gp_Pnt2d& res)
|
|
{
|
|
Standard_Real prevpar;
|
|
Standard_Integer nbOut = 0;
|
|
for (Standard_Integer i = 0; i < 10; i++)
|
|
{
|
|
prevpar = par;
|
|
|
|
gp_Vec2d D1, D2;
|
|
C2d->D2(par, res, D1, D2);
|
|
Standard_Real Det = (D2 * dir);
|
|
if (Abs(Det) < 1e-10)
|
|
return Standard_True;
|
|
|
|
par -= (D1 * dir) / Det;
|
|
if (Abs(par - prevpar) < Precision::PConfusion())
|
|
return Standard_True;
|
|
|
|
if (par < First)
|
|
{
|
|
if (nbOut++ > 2 || prevpar == First)
|
|
return Standard_False;
|
|
par = First;
|
|
}
|
|
if (par > Last)
|
|
{
|
|
if (nbOut++ > 2 || prevpar == Last)
|
|
return Standard_False;
|
|
par = Last;
|
|
}
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
void ShapeAnalysis_Curve::FillBndBox(const Handle(Geom2d_Curve)& C2d,
|
|
const Standard_Real First,
|
|
const Standard_Real Last,
|
|
const Standard_Integer NPoints,
|
|
const Standard_Boolean Exact,
|
|
Bnd_Box2d& Box) const
|
|
{
|
|
if (!Exact)
|
|
{
|
|
Standard_Integer nseg = (NPoints < 2 ? 1 : NPoints - 1);
|
|
Standard_Real step = (Last - First) / nseg;
|
|
for (Standard_Integer i = 0; i <= nseg; i++)
|
|
{
|
|
Standard_Real par = First + i * step;
|
|
gp_Pnt2d pnt = C2d->Value(par);
|
|
Box.Add(pnt);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// We should solve the task on intervals of C2 continuity.
|
|
Geom2dAdaptor_Curve anAC(C2d, First, Last);
|
|
Standard_Integer nbInt = anAC.NbIntervals(GeomAbs_C2);
|
|
// If we have only 1 interval then use input NPoints parameter to get samples.
|
|
Standard_Integer nbSamples = (nbInt < 2 ? NPoints - 1 : nbInt);
|
|
TColStd_Array1OfReal aParams(1, nbSamples + 1);
|
|
if (nbSamples == nbInt)
|
|
anAC.Intervals(aParams, GeomAbs_C2);
|
|
else
|
|
{
|
|
Standard_Real step = (Last - First) / nbSamples;
|
|
for (Standard_Integer i = 0; i <= nbSamples; i++)
|
|
aParams(i + 1) = First + i * step;
|
|
}
|
|
for (Standard_Integer i = 1; i <= nbSamples + 1; i++)
|
|
{
|
|
Standard_Real aPar1 = aParams(i);
|
|
gp_Pnt2d aPnt = C2d->Value(aPar1);
|
|
Box.Add(aPnt);
|
|
if (i <= nbSamples)
|
|
{
|
|
Standard_Real aPar2 = aParams(i + 1);
|
|
Standard_Real par = (aPar1 + aPar2) * 0.5;
|
|
gp_Pnt2d pextr;
|
|
Standard_Real parextr = par;
|
|
if (SearchForExtremum(C2d, aPar1, aPar2, gp_Vec2d(1, 0), parextr, pextr))
|
|
{
|
|
Box.Add(pextr);
|
|
}
|
|
parextr = par;
|
|
if (SearchForExtremum(C2d, aPar1, aPar2, gp_Vec2d(0, 1), parextr, pextr))
|
|
{
|
|
Box.Add(pextr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Integer ShapeAnalysis_Curve::SelectForwardSeam(const Handle(Geom2d_Curve)& C1,
|
|
const Handle(Geom2d_Curve)& C2) const
|
|
{
|
|
// SelectForward est destine a devenir un outil distinct
|
|
// Il est sans doute optimisable !
|
|
|
|
Standard_Integer theCurveIndice = 0;
|
|
|
|
Handle(Geom2d_Line) L1 = Handle(Geom2d_Line)::DownCast(C1);
|
|
if (L1.IsNull())
|
|
{
|
|
// if we have BoundedCurve, create a line from C1
|
|
Handle(Geom2d_BoundedCurve) BC1 = Handle(Geom2d_BoundedCurve)::DownCast(C1);
|
|
if (BC1.IsNull())
|
|
return theCurveIndice;
|
|
gp_Pnt2d StartBC1 = BC1->StartPoint();
|
|
gp_Pnt2d EndBC1 = BC1->EndPoint();
|
|
gp_Vec2d VecBC1(StartBC1, EndBC1);
|
|
if (VecBC1.SquareMagnitude() < gp::Resolution())
|
|
return theCurveIndice;
|
|
L1 = new Geom2d_Line(StartBC1, VecBC1);
|
|
}
|
|
|
|
Handle(Geom2d_Line) L2 = Handle(Geom2d_Line)::DownCast(C2);
|
|
if (L2.IsNull())
|
|
{
|
|
// if we have BoundedCurve, creates a line from C2
|
|
Handle(Geom2d_BoundedCurve) BC2 = Handle(Geom2d_BoundedCurve)::DownCast(C2);
|
|
if (BC2.IsNull())
|
|
return theCurveIndice;
|
|
gp_Pnt2d StartBC2 = BC2->StartPoint();
|
|
gp_Pnt2d EndBC2 = BC2->EndPoint();
|
|
gp_Vec2d VecBC2(StartBC2, EndBC2);
|
|
if (VecBC2.SquareMagnitude() < gp::Resolution())
|
|
return theCurveIndice;
|
|
L2 = new Geom2d_Line(StartBC2, VecBC2);
|
|
}
|
|
|
|
Standard_Boolean UdirPos, UdirNeg, VdirPos, VdirNeg;
|
|
UdirPos = UdirNeg = VdirPos = VdirNeg = Standard_False;
|
|
|
|
gp_Dir2d theDir = L1->Direction();
|
|
gp_Pnt2d theLoc1 = L1->Location();
|
|
gp_Pnt2d theLoc2 = L2->Location();
|
|
|
|
if (theDir.X() > 0.)
|
|
{
|
|
UdirPos = Standard_True; // szv#4:S4163:12Mar99 Udir unused
|
|
}
|
|
else if (theDir.X() < 0.)
|
|
{
|
|
UdirNeg = Standard_True; // szv#4:S4163:12Mar99 Udir unused
|
|
}
|
|
else if (theDir.Y() > 0.)
|
|
{
|
|
VdirPos = Standard_True; // szv#4:S4163:12Mar99 Vdir unused
|
|
}
|
|
else if (theDir.Y() < 0.)
|
|
{
|
|
VdirNeg = Standard_True; // szv#4:S4163:12Mar99 Vdir unused
|
|
}
|
|
|
|
if (VdirPos)
|
|
{
|
|
// max of Loc1.X() Loc2.X()
|
|
if (theLoc1.X() > theLoc2.X())
|
|
theCurveIndice = 1;
|
|
else
|
|
theCurveIndice = 2;
|
|
}
|
|
else if (VdirNeg)
|
|
{
|
|
if (theLoc1.X() > theLoc2.X())
|
|
theCurveIndice = 2;
|
|
else
|
|
theCurveIndice = 1;
|
|
}
|
|
else if (UdirPos)
|
|
{
|
|
// min of Loc1.X() Loc2.X()
|
|
if (theLoc1.Y() < theLoc2.Y())
|
|
theCurveIndice = 1;
|
|
else
|
|
theCurveIndice = 2;
|
|
}
|
|
else if (UdirNeg)
|
|
{
|
|
if (theLoc1.Y() < theLoc2.Y())
|
|
theCurveIndice = 2;
|
|
else
|
|
theCurveIndice = 1;
|
|
}
|
|
|
|
return theCurveIndice;
|
|
}
|
|
|
|
//%11 pdn 12.01.98
|
|
//=============================================================================
|
|
// Static methods for IsPlanar
|
|
// IsPlanar
|
|
//=============================================================================
|
|
|
|
static gp_XYZ GetAnyNormal(const gp_XYZ& orig)
|
|
{
|
|
gp_XYZ Norm;
|
|
if (Abs(orig.Z()) < Precision::Confusion())
|
|
Norm.SetCoord(0, 0, 1);
|
|
else
|
|
{
|
|
Norm.SetCoord(orig.Z(), 0, -orig.X());
|
|
Standard_Real nrm = Norm.Modulus();
|
|
if (nrm < Precision::Confusion())
|
|
Norm.SetCoord(0, 0, 1);
|
|
else
|
|
Norm = Norm / nrm;
|
|
}
|
|
return Norm;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static void AppendControlPoles(TColgp_SequenceOfPnt& seq, const Handle(Geom_Curve)& curve)
|
|
{
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_Line)))
|
|
{
|
|
seq.Append(curve->Value(0));
|
|
seq.Append(curve->Value(1));
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_Conic)))
|
|
{
|
|
seq.Append(curve->Value(0));
|
|
seq.Append(curve->Value(M_PI / 2));
|
|
seq.Append(curve->Value(M_PI));
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
|
|
Handle(Geom_TrimmedCurve) Trimmed = Handle(Geom_TrimmedCurve)::DownCast(curve);
|
|
// AppendControlPoles(seq,Trimmed->BasisCurve());
|
|
Handle(Geom_Curve) aBaseCrv = Trimmed->BasisCurve();
|
|
Standard_Boolean done = Standard_False;
|
|
if (aBaseCrv->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
|
|
{
|
|
try
|
|
{
|
|
OCC_CATCH_SIGNALS
|
|
Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
|
|
Handle(Geom_BSplineCurve) bslp = Handle(Geom_BSplineCurve)::DownCast(Ctmp);
|
|
bslp->Segment(curve->FirstParameter(), curve->LastParameter());
|
|
AppendControlPoles(seq, bslp);
|
|
done = Standard_True;
|
|
}
|
|
catch (Standard_Failure const&)
|
|
{
|
|
}
|
|
}
|
|
else if (aBaseCrv->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
|
|
{
|
|
try
|
|
{
|
|
OCC_CATCH_SIGNALS
|
|
Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
|
|
Handle(Geom_BezierCurve) bz = Handle(Geom_BezierCurve)::DownCast(Ctmp);
|
|
bz->Segment(curve->FirstParameter(), curve->LastParameter());
|
|
AppendControlPoles(seq, bz);
|
|
done = Standard_True;
|
|
}
|
|
catch (Standard_Failure const&)
|
|
{
|
|
}
|
|
}
|
|
if (!done)
|
|
{
|
|
seq.Append(curve->Value(curve->FirstParameter()));
|
|
seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter()) / 2.));
|
|
seq.Append(curve->Value(curve->LastParameter()));
|
|
}
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
|
|
Handle(Geom_OffsetCurve) OffsetC = Handle(Geom_OffsetCurve)::DownCast(curve);
|
|
// AppendControlPoles(seq,OffsetC->BasisCurve());
|
|
seq.Append(curve->Value(curve->FirstParameter()));
|
|
seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter()) / 2.));
|
|
seq.Append(curve->Value(curve->LastParameter()));
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
|
|
Handle(Geom_BSplineCurve) BSpline = Handle(Geom_BSplineCurve)::DownCast(curve);
|
|
TColgp_Array1OfPnt Poles(1, BSpline->NbPoles());
|
|
BSpline->Poles(Poles);
|
|
for (Standard_Integer i = 1; i <= BSpline->NbPoles(); i++)
|
|
seq.Append(Poles(i));
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_BezierCurve, Bezier, curve);
|
|
// Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve);
|
|
Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve);
|
|
TColgp_Array1OfPnt Poles(1, Bezier->NbPoles());
|
|
Bezier->Poles(Poles);
|
|
for (Standard_Integer i = 1; i <= Bezier->NbPoles(); i++)
|
|
seq.Append(Poles(i));
|
|
}
|
|
}
|
|
|
|
//%11 pdn 12.01.98
|
|
// szv modified
|
|
//=======================================================================
|
|
// function : IsPlanar
|
|
// purpose : Detects if points lie in some plane and returns normal
|
|
//=======================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::IsPlanar(const TColgp_Array1OfPnt& pnts,
|
|
gp_XYZ& Normal,
|
|
const Standard_Real preci)
|
|
{
|
|
Standard_Real precision = (preci > 0.0) ? preci : Precision::Confusion();
|
|
Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
|
|
|
|
if (pnts.Length() < 3)
|
|
{
|
|
gp_XYZ N1 = pnts(1).XYZ() - pnts(2).XYZ();
|
|
if (noNorm)
|
|
{
|
|
Normal = GetAnyNormal(N1);
|
|
return Standard_True;
|
|
}
|
|
return Abs(N1 * Normal) < Precision::Confusion();
|
|
}
|
|
|
|
gp_XYZ aMaxDir;
|
|
if (noNorm)
|
|
{
|
|
// define a center point
|
|
gp_XYZ aCenter(0, 0, 0);
|
|
Standard_Integer i = 1;
|
|
for (; i <= pnts.Length(); i++)
|
|
aCenter += pnts(i).XYZ();
|
|
aCenter /= pnts.Length();
|
|
|
|
aMaxDir = pnts(1).XYZ() - aCenter;
|
|
Normal = (pnts(pnts.Length()).XYZ() - aCenter) ^ aMaxDir;
|
|
|
|
for (i = 1; i < pnts.Length(); i++)
|
|
{
|
|
gp_XYZ aTmpDir = pnts(i + 1).XYZ() - aCenter;
|
|
if (aTmpDir.SquareModulus() > aMaxDir.SquareModulus())
|
|
aMaxDir = aTmpDir;
|
|
|
|
gp_XYZ aDelta = (pnts(i).XYZ() - aCenter) ^ (pnts(i + 1).XYZ() - aCenter);
|
|
if (Normal * aDelta < 0)
|
|
aDelta *= -1;
|
|
Normal += aDelta;
|
|
}
|
|
}
|
|
|
|
// check if points are linear
|
|
Standard_Real nrm = Normal.Modulus();
|
|
if (nrm < Precision::Confusion())
|
|
{
|
|
Normal = GetAnyNormal(aMaxDir);
|
|
return Standard_True;
|
|
}
|
|
Normal = Normal / nrm;
|
|
|
|
Standard_Real mind = RealLast(), maxd = -RealLast(), dev;
|
|
for (Standard_Integer i = 1; i <= pnts.Length(); i++)
|
|
{
|
|
dev = pnts(i).XYZ() * Normal;
|
|
if (dev < mind)
|
|
mind = dev;
|
|
if (dev > maxd)
|
|
maxd = dev;
|
|
}
|
|
|
|
return ((maxd - mind) <= precision);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::IsPlanar(const Handle(Geom_Curve)& curve,
|
|
gp_XYZ& Normal,
|
|
const Standard_Real preci)
|
|
{
|
|
Standard_Real precision = (preci > 0.0) ? preci : Precision::Confusion();
|
|
Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_Line)))
|
|
{
|
|
// DeclareAndCast(Geom_Line, Line, curve);
|
|
Handle(Geom_Line) Line = Handle(Geom_Line)::DownCast(curve);
|
|
gp_XYZ N1 = Line->Position().Direction().XYZ();
|
|
if (noNorm)
|
|
{
|
|
Normal = GetAnyNormal(N1);
|
|
return Standard_True;
|
|
}
|
|
return Abs(N1 * Normal) < Precision::Confusion();
|
|
}
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_Conic)))
|
|
{
|
|
// DeclareAndCast(Geom_Conic, Conic, curve);
|
|
Handle(Geom_Conic) Conic = Handle(Geom_Conic)::DownCast(curve);
|
|
gp_XYZ N1 = Conic->Axis().Direction().XYZ();
|
|
if (noNorm)
|
|
{
|
|
Normal = N1;
|
|
return Standard_True;
|
|
}
|
|
gp_XYZ aVecMul = N1 ^ Normal;
|
|
return aVecMul.SquareModulus() < Precision::SquareConfusion();
|
|
}
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
|
|
Handle(Geom_TrimmedCurve) Trimmed = Handle(Geom_TrimmedCurve)::DownCast(curve);
|
|
return IsPlanar(Trimmed->BasisCurve(), Normal, precision);
|
|
}
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
|
|
Handle(Geom_OffsetCurve) OffsetC = Handle(Geom_OffsetCurve)::DownCast(curve);
|
|
return IsPlanar(OffsetC->BasisCurve(), Normal, precision);
|
|
}
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
|
|
Handle(Geom_BSplineCurve) BSpline = Handle(Geom_BSplineCurve)::DownCast(curve);
|
|
TColgp_Array1OfPnt Poles(1, BSpline->NbPoles());
|
|
BSpline->Poles(Poles);
|
|
return IsPlanar(Poles, Normal, precision);
|
|
}
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
|
|
{
|
|
// DeclareAndCast(Geom_BezierCurve, Bezier, curve);
|
|
Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve);
|
|
TColgp_Array1OfPnt Poles(1, Bezier->NbPoles());
|
|
Bezier->Poles(Poles);
|
|
return IsPlanar(Poles, Normal, precision);
|
|
}
|
|
|
|
if (curve->IsKind(STANDARD_TYPE(ShapeExtend_ComplexCurve)))
|
|
{
|
|
// DeclareAndCast(ShapeExtend_ComplexCurve, Complex, curve);
|
|
Handle(ShapeExtend_ComplexCurve) Complex = Handle(ShapeExtend_ComplexCurve)::DownCast(curve);
|
|
TColgp_SequenceOfPnt sequence;
|
|
Standard_Integer i; // svv Jan11 2000 : porting on DEC
|
|
for (i = 1; i <= Complex->NbCurves(); i++)
|
|
AppendControlPoles(sequence, Complex->Curve(i));
|
|
TColgp_Array1OfPnt Poles(1, sequence.Length());
|
|
for (i = 1; i <= sequence.Length(); i++)
|
|
Poles(i) = sequence(i);
|
|
return IsPlanar(Poles, Normal, precision);
|
|
}
|
|
|
|
return Standard_False;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints(const Handle(Geom_Curve)& curve,
|
|
const Standard_Real first,
|
|
const Standard_Real last,
|
|
TColgp_SequenceOfPnt& seq)
|
|
{
|
|
Standard_Real adelta = curve->LastParameter() - curve->FirstParameter();
|
|
if (!adelta)
|
|
return Standard_False;
|
|
|
|
Standard_Integer aK = (Standard_Integer)ceil((last - first) / adelta);
|
|
Standard_Integer nbp = 100 * aK;
|
|
if (curve->IsKind(STANDARD_TYPE(Geom_Line)))
|
|
nbp = 2;
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_Circle)))
|
|
nbp = 360 * aK;
|
|
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
|
|
{
|
|
Handle(Geom_BSplineCurve) aBspl = Handle(Geom_BSplineCurve)::DownCast(curve);
|
|
|
|
nbp = aBspl->NbKnots() * aBspl->Degree() * aK;
|
|
if (nbp < 2.0)
|
|
nbp = 2;
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
|
|
{
|
|
Handle(Geom_BezierCurve) aB = Handle(Geom_BezierCurve)::DownCast(curve);
|
|
nbp = 3 + aB->NbPoles();
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
|
|
{
|
|
Handle(Geom_OffsetCurve) aC = Handle(Geom_OffsetCurve)::DownCast(curve);
|
|
return GetSamplePoints(aC->BasisCurve(), first, last, seq);
|
|
}
|
|
else if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
Handle(Geom_TrimmedCurve) aC = Handle(Geom_TrimmedCurve)::DownCast(curve);
|
|
return GetSamplePoints(aC->BasisCurve(), first, last, seq);
|
|
}
|
|
|
|
GeomAdaptor_Curve GAC(curve);
|
|
Standard_Real step = (last - first) / (Standard_Real)(nbp - 1);
|
|
for (Standard_Integer i = 0; i < nbp - 1; ++i)
|
|
seq.Append(GAC.Value(first + step * i));
|
|
seq.Append(GAC.Value(last));
|
|
return Standard_True;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints(const Handle(Geom2d_Curve)& curve,
|
|
const Standard_Real first,
|
|
const Standard_Real last,
|
|
TColgp_SequenceOfPnt2d& seq)
|
|
{
|
|
//: abv 05.06.02: TUBE.stp
|
|
// Use the same distribution of points as BRepTopAdaptor_FClass2d for consistency
|
|
Geom2dAdaptor_Curve C(curve, first, last);
|
|
Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C);
|
|
//-- Attention aux bsplines rationnelles de degree 3. (bouts de cercles entre autres)
|
|
if (nbs > 2)
|
|
nbs *= 4;
|
|
Standard_Real step = (last - first) / (Standard_Real)(nbs - 1);
|
|
for (Standard_Integer i = 0; i < nbs - 1; ++i)
|
|
seq.Append(C.Value(first + step * i));
|
|
seq.Append(C.Value(last));
|
|
return Standard_True;
|
|
/*
|
|
Standard_Integer i;
|
|
Standard_Real step;
|
|
gp_Pnt2d Ptmp;
|
|
if ( curve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
|
|
seq.Append(curve->Value(first));
|
|
seq.Append(curve->Value(last));
|
|
return Standard_True;
|
|
}
|
|
else if(curve->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
|
|
step = Min ( M_PI, last-first ) / 19; //:abv 05.06.02 TUBE.stp #19209...: M_PI/16
|
|
// if( step>(last-first) ) {
|
|
// seq.Append(curve->Value(first));
|
|
// seq.Append(curve->Value((last+first)/2));
|
|
// seq.Append(curve->Value(last));
|
|
// return Standard_True;
|
|
// }
|
|
// else {
|
|
Standard_Real par=first;
|
|
for(i=0; par<last; i++) {
|
|
seq.Append(curve->Value(par));
|
|
par += step;
|
|
}
|
|
seq.Append(curve->Value(last));
|
|
return Standard_True;
|
|
// }
|
|
}
|
|
else if ( curve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
|
|
DeclareAndCast(Geom2d_TrimmedCurve, Trimmed, curve);
|
|
return GetControlPoints(Trimmed->BasisCurve(), seq, first, last);
|
|
}
|
|
else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
|
|
DeclareAndCast(Geom2d_BSplineCurve, aBs, curve);
|
|
TColStd_SequenceOfReal aSeqParam;
|
|
if(!aBs.IsNull()) {
|
|
aSeqParam.Append(first);
|
|
for(i=1; i<=aBs->NbKnots(); i++) {
|
|
if( aBs->Knot(i)>first && aBs->Knot(i)<last )
|
|
aSeqParam.Append(aBs->Knot(i));
|
|
}
|
|
aSeqParam.Append(last);
|
|
Standard_Integer NbPoints=aBs->Degree();
|
|
if( (aSeqParam.Length()-1)*NbPoints>10 ) {
|
|
for(i=1; i<aSeqParam.Length(); i++) {
|
|
Standard_Real FirstPar = aSeqParam.Value(i);
|
|
Standard_Real LastPar = aSeqParam.Value(i+1);
|
|
step = (LastPar-FirstPar)/NbPoints;
|
|
for(Standard_Integer k=0; k<NbPoints; k++ ) {
|
|
aBs->D0(FirstPar+step*k, Ptmp);
|
|
seq.Append(Ptmp);
|
|
}
|
|
}
|
|
aBs->D0(last, Ptmp);
|
|
seq.Append(Ptmp);
|
|
return Standard_True;
|
|
}
|
|
else {
|
|
step = (last-first)/10;
|
|
for(Standard_Integer k=0; k<=10; k++ ) {
|
|
aBs->D0(first+step*k, Ptmp);
|
|
seq.Append(Ptmp);
|
|
}
|
|
return Standard_True;
|
|
}
|
|
}
|
|
}
|
|
else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) {
|
|
DeclareAndCast(Geom2d_BezierCurve, aBz, curve);
|
|
if(!aBz.IsNull()) {
|
|
Standard_Integer NbPoints=aBz->Degree();
|
|
step = (last-first)/NbPoints;
|
|
for(Standard_Integer k=0; k<NbPoints; k++ ) {
|
|
aBz->D0(first+step*k, Ptmp);
|
|
seq.Append(Ptmp);
|
|
}
|
|
aBz->D0(last, Ptmp);
|
|
seq.Append(Ptmp);
|
|
return Standard_True;
|
|
}
|
|
}
|
|
return Standard_False;
|
|
*/
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::IsClosed(const Handle(Geom_Curve)& theCurve,
|
|
const Standard_Real preci)
|
|
{
|
|
if (theCurve->IsClosed())
|
|
return Standard_True;
|
|
|
|
Standard_Real prec = Max(preci, Precision::Confusion());
|
|
|
|
Standard_Real f, l;
|
|
f = theCurve->FirstParameter();
|
|
l = theCurve->LastParameter();
|
|
|
|
if (Precision::IsInfinite(f) || Precision::IsInfinite(l))
|
|
return Standard_False;
|
|
|
|
Standard_Real aClosedVal = theCurve->Value(f).SquareDistance(theCurve->Value(l));
|
|
Standard_Real preci2 = prec * prec;
|
|
|
|
return (aClosedVal <= preci2);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom_Curve)& theCurve)
|
|
{
|
|
// 15.11.2002 PTV OCC966
|
|
// remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
|
|
// ask IsPeriodic on BasisCurve
|
|
Handle(Geom_Curve) aTmpCurve = theCurve;
|
|
while ((aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
|
|
|| (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))))
|
|
{
|
|
if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
|
|
aTmpCurve = Handle(Geom_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
|
|
if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
aTmpCurve = Handle(Geom_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
|
|
}
|
|
return aTmpCurve->IsPeriodic();
|
|
}
|
|
|
|
Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom2d_Curve)& theCurve)
|
|
{
|
|
// 15.11.2002 PTV OCC966
|
|
// remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
|
|
// ask IsPeriodic on BasisCurve
|
|
Handle(Geom2d_Curve) aTmpCurve = theCurve;
|
|
while ((aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
|
|
|| (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))))
|
|
{
|
|
if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
|
|
aTmpCurve = Handle(Geom2d_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
|
|
if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
|
|
aTmpCurve = Handle(Geom2d_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
|
|
}
|
|
return aTmpCurve->IsPeriodic();
|
|
}
|