X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGEOMImpl%2FGEOMImpl_SplineDriver.cxx;h=76b58c8aa59d866323aaa3daa3c2e2c89f8150e1;hb=693e5f65fe0f4868fe2e0f2923aef6a3afb20d67;hp=a94f0a2797182fd96d403d702d6bb586bb8ef439;hpb=465e84c52edb243fa36d581abc659b1c97156c64;p=modules%2Fgeom.git diff --git a/src/GEOMImpl/GEOMImpl_SplineDriver.cxx b/src/GEOMImpl/GEOMImpl_SplineDriver.cxx index a94f0a279..76b58c8aa 100644 --- a/src/GEOMImpl/GEOMImpl_SplineDriver.cxx +++ b/src/GEOMImpl/GEOMImpl_SplineDriver.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -6,7 +6,7 @@ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,14 +18,16 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// -#include +#include "GEOMImpl_SplineDriver.hxx" -#include -#include +#include "GEOMImpl_ISpline.hxx" +#include "GEOMImpl_Types.hxx" +#include "GEOMImpl_ICurveParametric.hxx" -#include -#include +#include "GEOM_Function.hxx" +#include "GEOMUtils.hxx" #include #include @@ -39,7 +41,6 @@ #include #include -//#include #include #include @@ -49,10 +50,61 @@ #include #include -#include - #include +// 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 2 + +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 //purpose : @@ -76,7 +128,7 @@ GEOMImpl_SplineDriver::GEOMImpl_SplineDriver() //function : Execute //purpose : //======================================================================= -Standard_Integer GEOMImpl_SplineDriver::Execute(TFunction_Logbook& log) const +Standard_Integer GEOMImpl_SplineDriver::Execute(Handle(TFunction_Logbook)& log) const { if (Label().IsNull()) return 0; Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label()); @@ -92,219 +144,257 @@ Standard_Integer GEOMImpl_SplineDriver::Execute(TFunction_Logbook& log) const bool useCoords = aCI.GetConstructorType() == COORD_CONSTRUCTOR; - Handle(TColStd_HArray1OfReal) aCoordsArray; // parametric case - Handle(TColStd_HSequenceOfTransient) aPoints; // points case - - int aLen = 0; - if (useCoords) { - aCoordsArray = aCI.GetCoordinates(); - aLen = aCoordsArray->Length() / 3; - } - else { - aPoints = aCI.GetPoints(); - aLen = aPoints->Length(); - } - - if (aLen < 2) return 0; - - TColgp_Array1OfPnt points (1, (useCoords ? aLen : 1)); - if (useCoords) { - int anArrayLength = aCoordsArray->Length(); - for (int i = 0, j = 1; i <= (anArrayLength-3); i += 3) { - gp_Pnt aPnt = gp_Pnt(aCoordsArray->Value(i+1), aCoordsArray->Value(i+2), aCoordsArray->Value(i+3)); - points.SetValue(j, aPnt); - j++; - } - } - - 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; + // collect points from input parameters: objects or coordinates + Handle(TColgp_HArray1OfPnt) points = useCoords ? pointsFromCoords(aCI.GetCoordinates()) : pointsFromObjs(aCI.GetPoints()); + int length = points->Length(); + + if (length < 2) return 0; // error: not enough points in the input list + + // reorder points if required (bspline only) + if ((aType == SPLINE_INTERPOLATION || aType == SPLINE_INTERPOL_TANGENTS) && aCI.GetDoReordering()) { + int nbDup = 0; + gp_Pnt pPrev = points->Value(1); + for (int i = 1; i < length - 1; i++) { + gp_Pnt pi = points->Value(i); + int nearest = 0; + double minDist = RealLast(); + for (int j = i+1; j <= length; j++) { + double dist = pi.SquareDistance(points->Value(j)); + if (dist < minDist && (minDist - dist) > Precision::Confusion()) { + nearest = j; + minDist = dist; } } - CurvePoints.SetValue(ind, aP); - aPrevP = aP; + if (nearest > 0 && nearest != i + 1) { + // Keep given order of points to use it in case of equidistant candidates + // .-<---<-. + // / \ + // o o o c o->o->o->o->n o o + // | | | + // i i+1 nearest + gp_Pnt p = points->Value(nearest); + for (int j = nearest; j > i+1; j--) + points->SetValue(j, points->Value(j-1)); + points->SetValue(i+1, p); + } + if ( pPrev.Distance(points->Value(i+1)) <= Precision::Confusion() ) + nbDup++; + else + pPrev = points->Value(i+1); } - 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 ( nbDup > 0 ) { + Handle(TColgp_HArray1OfPnt) tmpPoints = new TColgp_HArray1OfPnt(1, length-nbDup); + int j = 1; + for (int i = 1; i <= length; i++) { + if (i == 1 || pPrev.Distance(points->Value(i)) > Precision::Confusion() ) { + tmpPoints->SetValue(j++, points->Value(i)); + pPrev = points->Value(i); + } + } + points = tmpPoints; + length = points->Length(); } - } + } // end of reordering + + bool closed = points->Value(1).Distance(points->Value(length)) <= gp::Resolution(); 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)); + // 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(Geom_BezierCurve) GBC = new Geom_BezierCurve (CurvePoints); + + if (!isValid) + // error: not enough points to create curve + 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 { - //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 - // .-<---<-. - // / \ - // o o o c o->o->o->o->n o o - // | | | - // curInd curInd+1 nearInd - gp_Pnt nearPnt = CurvePoints.Value(nearInd); - for (ind = nearInd; ind > curInd + 1; ind--) { - CurvePoints.SetValue(ind, CurvePoints.Value(ind - 1)); - } - CurvePoints.SetValue(curInd + 1, nearPnt); - } - } - } - - Handle(TColgp_HArray1OfPnt) aHCurvePoints = new TColgp_HArray1OfPnt (1, aLen); - for (ind = 1; ind <= aLen; ind++) { - aHCurvePoints->SetValue(ind, CurvePoints.Value(ind)); + // 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; - if (aType == SPLINE_INTERPOLATION) - isClosed = aCI.GetIsClosed(); - - GeomAPI_Interpolate GBC (aHCurvePoints, isClosed, gp::Resolution()); + // initial set-up of curve creator + GeomAPI_Interpolate GBC(points, isClosed, gp::Resolution()); + // add tangent vectors constraints if (aType == SPLINE_INTERPOL_TANGENTS) { - Handle(GEOM_Function) aVec1Ref = aCI.GetFirstVector(); - Handle(GEOM_Function) aVec2Ref = aCI.GetLastVector(); + Handle(GEOM_Function) aVec1Ref = aCI.GetFirstVector(); + Handle(GEOM_Function) aVec2Ref = aCI.GetLastVector(); if (aVec1Ref.IsNull() || aVec2Ref.IsNull()) + // error: bad vector parameter is specified Standard_NullObject::Raise("Null object is given for a vector"); - TopoDS_Shape aVec1Sh = aVec1Ref->GetValue(); - TopoDS_Shape aVec2Sh = aVec2Ref->GetValue(); - - gp_Vec aV1 = GEOMUtils::GetVector(aVec1Sh); - gp_Vec aV2 = GEOMUtils::GetVector(aVec2Sh); + // take orientation of edge into account to avoid regressions, as it was implemented so + gp_Vec aV1 = GEOMUtils::GetVector(aVec1Ref->GetValue(), 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); } + // create bspline curve GBC.Perform(); if (GBC.IsDone()) aShape = BRepBuilderAPI_MakeEdge(GBC.Curve()).Edge(); - else - return 0; } } else { } - if (aShape.IsNull()) return 0; + if (aShape.IsNull()) return 0; // error: bad result aFunction->SetValue(aShape); - log.SetTouched(Label()); + log->SetTouched(Label()); return 1; } +//================================================================================ +/*! + * \brief Returns a name of creation operation and names and values of creation parameters + */ +//================================================================================ -//======================================================================= -//function : GEOMImpl_SplineDriver_Type_ -//purpose : -//======================================================================= -Standard_EXPORT Handle_Standard_Type& GEOMImpl_SplineDriver_Type_() +bool GEOMImpl_SplineDriver:: +GetCreationInformation(std::string& theOperationName, + std::vector& theParams) { - - static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver); - if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver); - static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared); - if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared); - static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient); - if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient); - - - static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL}; - static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_SplineDriver", - sizeof(GEOMImpl_SplineDriver), - 1, - (Standard_Address)_Ancestors, - (Standard_Address)NULL); - - return _aType; -} - -//======================================================================= -//function : DownCast -//purpose : -//======================================================================= -const Handle(GEOMImpl_SplineDriver) Handle(GEOMImpl_SplineDriver)::DownCast(const Handle(Standard_Transient)& AnObject) -{ - Handle(GEOMImpl_SplineDriver) _anOtherObject; - - if (!AnObject.IsNull()) { - if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_SplineDriver))) { - _anOtherObject = Handle(GEOMImpl_SplineDriver)((Handle(GEOMImpl_SplineDriver)&)AnObject); - } + if (Label().IsNull()) return 0; + Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label()); + + GEOMImpl_ISpline aCI( function ); + GEOMImpl_ICurveParametric aPI( function ); + Standard_Integer aType = function->GetType(); + + theOperationName = "CURVE"; + + switch ( aType ) { + case SPLINE_BEZIER: + case SPLINE_INTERPOLATION: + case SPLINE_INTERPOL_TANGENTS: + + AddParam( theParams, "Type", ( aType == SPLINE_BEZIER ? "Bezier" : "Interpolation")); + + if ( aPI.HasData() ) + { + AddParam( theParams, "X(t) equation", aPI.GetExprX() ); + AddParam( theParams, "Y(t) equation", aPI.GetExprY() ); + AddParam( theParams, "Z(t) equation", aPI.GetExprZ() ); + AddParam( theParams, "Min t", aPI.GetParamMin() ); + AddParam( theParams, "Max t", aPI.GetParamMax() ); + if ( aPI.GetParamNbStep() ) + AddParam( theParams, "Number of steps", aPI.GetParamNbStep() ); + else + AddParam( theParams, "t step", aPI.GetParamStep() ); + } + else + { + if ( aCI.GetConstructorType() == COORD_CONSTRUCTOR ) + { + Handle(TColStd_HArray1OfReal) coords = aCI.GetCoordinates(); + GEOM_Param& pntParam = AddParam( theParams, "Points"); + pntParam << ( coords->Length() / 3 ) << " points: "; + for ( int i = coords->Lower(), nb = coords->Upper(); i <= nb; i += 3 ) + pntParam << "( " << coords->Value( i+0 ) + << ", " << coords->Value( i+1 ) + << ", " << coords->Value( i+2 ) << " ) "; + } + else + { + AddParam( theParams, "Points", aCI.GetPoints() ); + } + Handle(GEOM_Function) v1 = aCI.GetFirstVector(); + Handle(GEOM_Function) v2 = aCI.GetLastVector(); + if ( !v1.IsNull() ) AddParam( theParams, "First tangent vector", v1 ); + if ( !v2.IsNull() ) AddParam( theParams, "Last tangent vector", v2 ); + } + break; + default: + return false; } - return _anOtherObject ; + return true; } + +IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_SplineDriver,GEOM_BaseDriver);