mirror of
https://git.salome-platform.org/gitpub/modules/geom.git
synced 2024-12-26 17:30:35 +05:00
0022885: EDF 10392 HYDRO + GEOM: Spline of a polyline is not possible and returns an error.
This commit is contained in:
parent
334ef9aff1
commit
cd24269e8c
@ -52,6 +52,59 @@
|
|||||||
|
|
||||||
#include <Standard_NullObject.hxx>
|
#include <Standard_NullObject.hxx>
|
||||||
|
|
||||||
|
// Below macro specifies how the closed point set is processed (issue 0022885).
|
||||||
|
// See below for more information.
|
||||||
|
// Currently solution 4 is chosen!
|
||||||
|
#define BSPLINE_PROCESS_CLOSED_PNTSET 4
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
\brief Generate list of points from the list of (x,y,z) coordinates
|
||||||
|
\param coords list of values specifying (x y z) coordinates of points
|
||||||
|
\return list of points
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
Handle(TColgp_HArray1OfPnt) pointsFromCoords(Handle(TColStd_HArray1OfReal) coords)
|
||||||
|
{
|
||||||
|
Standard_Integer length = coords->Length() / 3;
|
||||||
|
|
||||||
|
Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, length);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i ++) {
|
||||||
|
Standard_Real x = coords->Value( i*3+1 );
|
||||||
|
Standard_Real y = coords->Value( i*3+2 );
|
||||||
|
Standard_Real z = coords->Value( i*3+3 );
|
||||||
|
points->SetValue(i+1, gp_Pnt(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Generate list of points from the sequence of input objects
|
||||||
|
\param coords list of objects as it is stored within the CAF tree
|
||||||
|
\return list of points
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
Handle(TColgp_HArray1OfPnt) pointsFromObjs(Handle(TColStd_HSequenceOfTransient) objects)
|
||||||
|
{
|
||||||
|
Standard_Integer length = objects->Length();
|
||||||
|
|
||||||
|
Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, length);
|
||||||
|
|
||||||
|
for (int i = 1; i <= length; i ++) {
|
||||||
|
TopoDS_Shape shape = Handle(GEOM_Function)::DownCast(objects->Value(i))->GetValue();
|
||||||
|
if (shape.ShapeType() != TopAbs_VERTEX)
|
||||||
|
// error: only vertices are allowed in the input
|
||||||
|
Standard_ConstructionError::Raise("Input should contain only vertices");
|
||||||
|
points->SetValue(i, BRep_Tool::Pnt(TopoDS::Vertex(shape)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : GetID
|
//function : GetID
|
||||||
//purpose :
|
//purpose :
|
||||||
@ -91,173 +144,166 @@ Standard_Integer GEOMImpl_SplineDriver::Execute(TFunction_Logbook& log) const
|
|||||||
|
|
||||||
bool useCoords = aCI.GetConstructorType() == COORD_CONSTRUCTOR;
|
bool useCoords = aCI.GetConstructorType() == COORD_CONSTRUCTOR;
|
||||||
|
|
||||||
Handle(TColStd_HArray1OfReal) aCoordsArray; // parametric case
|
// collect points from input parameters: objects or coordinates
|
||||||
Handle(TColStd_HSequenceOfTransient) aPoints; // points case
|
Handle(TColgp_HArray1OfPnt) points = useCoords ? pointsFromCoords(aCI.GetCoordinates()) : pointsFromObjs(aCI.GetPoints());
|
||||||
|
int length = points->Length();
|
||||||
|
|
||||||
int aLen = 0;
|
if (length < 2) return 0; // error: not enough points in the input list
|
||||||
if (useCoords) {
|
|
||||||
aCoordsArray = aCI.GetCoordinates();
|
|
||||||
aLen = aCoordsArray->Length() / 3;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
aPoints = aCI.GetPoints();
|
|
||||||
aLen = aPoints->Length();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aLen < 2) return 0;
|
// reorder points if required (bspline only)
|
||||||
|
if ((aType == SPLINE_INTERPOLATION || aType == SPLINE_INTERPOL_TANGENTS) && aCI.GetDoReordering()) {
|
||||||
TColgp_Array1OfPnt points (1, (useCoords ? aLen : 1));
|
for (int i = 1; i < length - 1; i++) {
|
||||||
if (useCoords) {
|
gp_Pnt pi = points->Value(i);
|
||||||
int anArrayLength = aCoordsArray->Length();
|
int nearest = 0;
|
||||||
for (int i = 0, j = 1; i <= (anArrayLength-3); i += 3) {
|
double minDist = RealLast();
|
||||||
gp_Pnt aPnt = gp_Pnt(aCoordsArray->Value(i+1), aCoordsArray->Value(i+2), aCoordsArray->Value(i+3));
|
for (int j = i+1; j <= length; j++) {
|
||||||
points.SetValue(j, aPnt);
|
double dist = pi.SquareDistance(points->Value(j));
|
||||||
j++;
|
if (dist < minDist && (minDist - dist) > Precision::Confusion()) {
|
||||||
|
nearest = j;
|
||||||
|
minDist = dist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (nearest > 0 && nearest != i + 1) {
|
||||||
int aRealLen = aLen;
|
|
||||||
|
|
||||||
if (aType == SPLINE_BEZIER && aCI.GetIsClosed()) {
|
|
||||||
TopoDS_Vertex aV1;
|
|
||||||
if (useCoords) {
|
|
||||||
aV1 = BRepBuilderAPI_MakeVertex(points.Value(1));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Handle(GEOM_Function) aFPoint = Handle(GEOM_Function)::DownCast(aPoints->Value(1));
|
|
||||||
TopoDS_Shape aFirstPnt = aFPoint->GetValue();
|
|
||||||
aV1 = TopoDS::Vertex(aFirstPnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
TopoDS_Vertex aV2;
|
|
||||||
if (useCoords) {
|
|
||||||
aV2 = BRepBuilderAPI_MakeVertex(points.Value(aLen));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Handle(GEOM_Function) aLPoint = Handle(GEOM_Function)::DownCast(aPoints->Value(aLen));
|
|
||||||
TopoDS_Shape aLastPnt = aLPoint->GetValue();
|
|
||||||
aV2 = TopoDS::Vertex(aLastPnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aV1.IsNull() && !aV2.IsNull() && !aV1.IsSame(aV2)) {
|
|
||||||
aRealLen++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ind;
|
|
||||||
Standard_Boolean isSeveral = Standard_False;
|
|
||||||
gp_Pnt aPrevP;
|
|
||||||
|
|
||||||
TColgp_Array1OfPnt CurvePoints (1, aRealLen);
|
|
||||||
for (ind = 1; ind <= aLen; ind++) {
|
|
||||||
gp_Pnt aP;
|
|
||||||
if (useCoords) {
|
|
||||||
aP = points.Value(ind);
|
|
||||||
if (!isSeveral && ind > 1) {
|
|
||||||
if (aP.Distance(aPrevP) > Precision::Confusion()) {
|
|
||||||
isSeveral = Standard_True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CurvePoints.SetValue(ind, aP);
|
|
||||||
aPrevP = aP;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Handle(GEOM_Function) aRefPoint = Handle(GEOM_Function)::DownCast(aPoints->Value(ind));
|
|
||||||
TopoDS_Shape aShapePnt = aRefPoint->GetValue();
|
|
||||||
if (aShapePnt.ShapeType() == TopAbs_VERTEX) {
|
|
||||||
aP = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt));
|
|
||||||
if (!isSeveral && ind > 1) {
|
|
||||||
if (aP.Distance(aPrevP) > Precision::Confusion()) {
|
|
||||||
isSeveral = Standard_True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CurvePoints.SetValue(ind, aP);
|
|
||||||
aPrevP = aP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aType == SPLINE_BEZIER) {
|
|
||||||
if (!isSeveral) {
|
|
||||||
Standard_ConstructionError::Raise("Points for Bezier Curve are too close");
|
|
||||||
}
|
|
||||||
if (aRealLen > aLen) { // set last point equal to first for the closed curve
|
|
||||||
CurvePoints.SetValue(aRealLen, CurvePoints.Value(1));
|
|
||||||
}
|
|
||||||
Handle(Geom_BezierCurve) GBC = new Geom_BezierCurve (CurvePoints);
|
|
||||||
aShape = BRepBuilderAPI_MakeEdge(GBC).Edge();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//GeomAPI_PointsToBSpline GBC (CurvePoints);
|
|
||||||
//aShape = BRepBuilderAPI_MakeEdge(GBC).Edge();
|
|
||||||
|
|
||||||
if (aCI.GetDoReordering()) {
|
|
||||||
for (int curInd = 1; curInd < aLen - 1; curInd++) {
|
|
||||||
gp_Pnt curPnt = CurvePoints.Value(curInd);
|
|
||||||
int nearInd = 0;
|
|
||||||
double nearDist = RealLast();
|
|
||||||
for (ind = curInd + 1; ind <= aLen; ind++) {
|
|
||||||
double dist = curPnt.SquareDistance(CurvePoints.Value(ind));
|
|
||||||
if (dist < nearDist && (nearDist - dist) > Precision::Confusion()) {
|
|
||||||
nearInd = ind;
|
|
||||||
nearDist = dist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nearInd > 0 && nearInd != curInd + 1) {
|
|
||||||
// Keep given order of points to use it in case of equidistant candidates
|
// Keep given order of points to use it in case of equidistant candidates
|
||||||
// .-<---<-.
|
// .-<---<-.
|
||||||
// / \
|
// / \
|
||||||
// o o o c o->o->o->o->n o o
|
// o o o c o->o->o->o->n o o
|
||||||
// | | |
|
// | | |
|
||||||
// curInd curInd+1 nearInd
|
// i i+1 nearest
|
||||||
gp_Pnt nearPnt = CurvePoints.Value(nearInd);
|
gp_Pnt p = points->Value(nearest);
|
||||||
for (ind = nearInd; ind > curInd + 1; ind--) {
|
for (int j = nearest; j > i+1; j--)
|
||||||
CurvePoints.SetValue(ind, CurvePoints.Value(ind - 1));
|
points->SetValue(j, points->Value(j-1));
|
||||||
}
|
points->SetValue(i+1, p);
|
||||||
CurvePoints.SetValue(curInd + 1, nearPnt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // end of reordering
|
||||||
|
|
||||||
|
bool closed = points->Value(1).Distance(points->Value(length)) <= gp::Resolution();
|
||||||
|
|
||||||
|
if (aType == SPLINE_BEZIER) {
|
||||||
|
// for Bezier curve we should append first point to the list if:
|
||||||
|
// a) "closed" flag is set, and
|
||||||
|
// b) first and last vertices are not too close
|
||||||
|
bool addFirst = aCI.GetIsClosed() && !closed;
|
||||||
|
|
||||||
|
// re-fill points and check that there's enough points to create a curve
|
||||||
|
bool isValid = false;
|
||||||
|
TColgp_Array1OfPnt curvePoints(1, length + (addFirst ? 1 : 0));
|
||||||
|
gp_Pnt pp;
|
||||||
|
for (int i = 1; i <= length; i++) {
|
||||||
|
gp_Pnt p = points->Value(i);
|
||||||
|
if (!isValid && i > 1 && p.Distance(pp) > Precision::Confusion())
|
||||||
|
isValid = true;
|
||||||
|
curvePoints.SetValue(i, p);
|
||||||
|
pp = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle(TColgp_HArray1OfPnt) aHCurvePoints = new TColgp_HArray1OfPnt (1, aLen);
|
if (!isValid)
|
||||||
for (ind = 1; ind <= aLen; ind++) {
|
// error: not enough points to create curve
|
||||||
aHCurvePoints->SetValue(ind, CurvePoints.Value(ind));
|
Standard_ConstructionError::Raise("Points for Bezier Curve are too close");
|
||||||
|
|
||||||
|
// set last point equal to first for the closed Bezier curve
|
||||||
|
if (addFirst) curvePoints.SetValue(length+1, curvePoints.Value(1));
|
||||||
|
|
||||||
|
// create Bezier curve
|
||||||
|
Handle(Geom_BezierCurve) GBC = new Geom_BezierCurve(curvePoints);
|
||||||
|
aShape = BRepBuilderAPI_MakeEdge(GBC).Edge();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Below described processing of closed points set case
|
||||||
|
// is not done for constrained bsplined
|
||||||
|
bool typeok = aType == SPLINE_INTERPOLATION;
|
||||||
|
#if BSPLINE_PROCESS_CLOSED_PNTSET == 1
|
||||||
|
// Last point is removed from the list if:
|
||||||
|
// a) first and last vertices are equal;
|
||||||
|
// b) "closed" flag is not taken into account.
|
||||||
|
// If first and last points are equal, we force "closed" flag to be set to true.
|
||||||
|
// For the case when first and last vertices are equal, this approach causes
|
||||||
|
// result different that would be if last point had NOT be removed and "closed" flag is false.
|
||||||
|
bool isClosed = typeok && (aCI.GetIsClosed() || closed);
|
||||||
|
bool removeLast = typeok && closed;
|
||||||
|
bool addFirst = false;
|
||||||
|
#elif BSPLINE_PROCESS_CLOSED_PNTSET == 2
|
||||||
|
// Last point is removed from the list if:
|
||||||
|
// a) first and last vertices are equal;
|
||||||
|
// b) "closed" flag is set to true.
|
||||||
|
// Flag "closed" is taken "as is".
|
||||||
|
// For the case when first and last vertices are equal, this approach causes
|
||||||
|
// different results with "closed" flag set to true and false.
|
||||||
|
bool isClosed = typeok && aCI.GetIsClosed();
|
||||||
|
bool removeLast = typeok && aCI.GetIsClosed() && closed;
|
||||||
|
bool addFirst = false;
|
||||||
|
#elif BSPLINE_PROCESS_CLOSED_PNTSET == 3
|
||||||
|
// Points are passed "as is" to the creator.
|
||||||
|
// If first and last points are equal, we force "closed" flag to be set to false.
|
||||||
|
// For the case when first and last vertices are equal, this approach gives
|
||||||
|
// the same results with "closed" flag set to true and false.
|
||||||
|
bool isClosed = typeok && aCI.GetIsClosed() && !closed;
|
||||||
|
bool removeLast = false;
|
||||||
|
bool addFirst = false;
|
||||||
|
#elif BSPLINE_PROCESS_CLOSED_PNTSET == 4
|
||||||
|
// First point is added to the list if:
|
||||||
|
// a) first and last vertices are not equal;
|
||||||
|
// b) "closed" flag is set to true.
|
||||||
|
// In this case "closed" flag is forcidly set to false - bspline creator is
|
||||||
|
// capable to create closed edge in this case.
|
||||||
|
// This approach gives the same results with "closed" flag set to true not
|
||||||
|
// depending on if set of points is closed or no.
|
||||||
|
// Also, it gives equal reqults in both case if set of points is closed or not
|
||||||
|
// and "closed" flag is set to true, in contrast to solution 3 above.
|
||||||
|
bool isClosed = false;
|
||||||
|
bool removeLast = false;
|
||||||
|
bool addFirst = typeok && aCI.GetIsClosed() && !closed;
|
||||||
|
#else
|
||||||
|
// Points are passed "as is" to the creator.
|
||||||
|
// This causes an error when first point is equal to last one and
|
||||||
|
// "closed" flag is set to true; see bug 0022885.
|
||||||
|
bool isClosed = typeok && aCI.GetIsClosed();
|
||||||
|
bool removeLast = false;
|
||||||
|
bool addFirst = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// remove last point or append first one if the conditions are observed (see above)
|
||||||
|
if (removeLast || addFirst) {
|
||||||
|
int extra = removeLast ? -1 : (addFirst ? 1 : 0 );
|
||||||
|
int nb = removeLast ? length-1 : length;
|
||||||
|
Handle(TColgp_HArray1OfPnt) curvePoints = new TColgp_HArray1OfPnt (1, length+extra);
|
||||||
|
for (int i = 1; i <= nb; i++)
|
||||||
|
curvePoints->SetValue(i, points->Value(i));
|
||||||
|
if (addFirst) curvePoints->SetValue(length+1, points->Value(1));
|
||||||
|
points = curvePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isClosed = Standard_False;
|
// initial set-up of curve creator
|
||||||
if (aType == SPLINE_INTERPOLATION)
|
GeomAPI_Interpolate GBC(points, isClosed, gp::Resolution());
|
||||||
isClosed = aCI.GetIsClosed();
|
|
||||||
|
|
||||||
GeomAPI_Interpolate GBC (aHCurvePoints, isClosed, gp::Resolution());
|
|
||||||
|
|
||||||
|
// add tangent vectors constraints
|
||||||
if (aType == SPLINE_INTERPOL_TANGENTS) {
|
if (aType == SPLINE_INTERPOL_TANGENTS) {
|
||||||
Handle(GEOM_Function) aVec1Ref = aCI.GetFirstVector();
|
Handle(GEOM_Function) aVec1Ref = aCI.GetFirstVector();
|
||||||
Handle(GEOM_Function) aVec2Ref = aCI.GetLastVector();
|
Handle(GEOM_Function) aVec2Ref = aCI.GetLastVector();
|
||||||
|
|
||||||
if (aVec1Ref.IsNull() || aVec2Ref.IsNull())
|
if (aVec1Ref.IsNull() || aVec2Ref.IsNull())
|
||||||
|
// error: bad vector parameter is specified
|
||||||
Standard_NullObject::Raise("Null object is given for a vector");
|
Standard_NullObject::Raise("Null object is given for a vector");
|
||||||
|
|
||||||
TopoDS_Shape aVec1Sh = aVec1Ref->GetValue();
|
|
||||||
TopoDS_Shape aVec2Sh = aVec2Ref->GetValue();
|
|
||||||
|
|
||||||
// take orientation of edge into account to avoid regressions, as it was implemented so
|
// take orientation of edge into account to avoid regressions, as it was implemented so
|
||||||
gp_Vec aV1 = GEOMUtils::GetVector(aVec1Sh, Standard_True);
|
gp_Vec aV1 = GEOMUtils::GetVector(aVec1Ref->GetValue(), Standard_True);
|
||||||
gp_Vec aV2 = GEOMUtils::GetVector(aVec2Sh, Standard_True);
|
gp_Vec aV2 = GEOMUtils::GetVector(aVec2Ref->GetValue(), Standard_True);
|
||||||
|
|
||||||
|
// push constraint vectors to the curve creator
|
||||||
GBC.Load(aV1, aV2, /*Scale*/Standard_True);
|
GBC.Load(aV1, aV2, /*Scale*/Standard_True);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create bspline curve
|
||||||
GBC.Perform();
|
GBC.Perform();
|
||||||
if (GBC.IsDone())
|
if (GBC.IsDone())
|
||||||
aShape = BRepBuilderAPI_MakeEdge(GBC.Curve()).Edge();
|
aShape = BRepBuilderAPI_MakeEdge(GBC.Curve()).Edge();
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aShape.IsNull()) return 0;
|
if (aShape.IsNull()) return 0; // error: bad result
|
||||||
|
|
||||||
aFunction->SetValue(aShape);
|
aFunction->SetValue(aShape);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user