MantisBT
Mantis Bug Tracker Workflow

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0032103Community[OCCT] OCCT:Modeling Algorithmspublic2021-02-01 19:242021-08-29 19:12
ReporterBenjaminBihler 
Assigned Tomsv 
PrioritynormalSeverityminor 
StatusnewResolutionopen 
PlatformAOSLOS VersionL
Product Version[OCCT] 7.5.0 
Target Version[OCCT] 7.7.0Fixed in Version 
Summary0032103: Modeling Algorithms - Geom2dAPI_PointsToBSpline produces oscillating spline curve
DescriptionI am interpolating 2D points on TopoDS_Faces to get curves on these faces. Now I have found a case where the resulting curve is highly oscillating with no apparent reason. I have written some code to transfer the 2D points into space and interpolate there -> there the curve is smooth.

Is there a fault in the 2D spline interpolation routine?
Steps To ReproducePlease use the following code with the attached file Face.brep. The expectation is to have no error messages.
#include <Adaptor3d_CurveOnSurface.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <CPnts_AbscissaPoint.hxx>
#include <Geom2dAPI_PointsToBSpline.hxx>
#include <Geom2dAdaptor_HCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_HSurface.hxx>
#include <GeomLib.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Precision.hxx>
#include <ShapeAnalysis_Curve.hxx>
#include <TColgp_HArray1OfPnt.hxx>
#include <TColgp_HArray1OfPnt2d.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>

#include <iostream>
#include <vector>

gp_Pnt getSpacePoint(const TopoDS_Face& face, const gp_Pnt2d& point)
{
    const Handle(Geom_Surface) surface = BRep_Tool::Surface(face);

    gp_Pnt spacePoint;
    surface->D0(point.X(), point.Y(), spacePoint);

    return spacePoint;
}

std::vector<gp_Pnt2d> get2dPoints()
{
    std::vector<gp_Pnt2d> points;

    points.push_back(gp_Pnt2d(0.4999999999988816, 105.4014098415948));
    points.push_back(gp_Pnt2d(0.4320264616075457, 100.0423698065018));
    points.push_back(gp_Pnt2d(0.2939892671201626, 91.74565262561642));
    points.push_back(gp_Pnt2d(0.1066991623666981, 84.47664193670857));
    points.push_back(gp_Pnt2d(-0.06172436566722802, 80.77902763327997));
    points.push_back(gp_Pnt2d(-0.2065650745679524, 79.3243125043185));
    points.push_back(gp_Pnt2d(-0.3708925637386218, 79.42317053607587));
    points.push_back(gp_Pnt2d(-0.5304808436616609, 81.31403379707817));
    points.push_back(gp_Pnt2d(-0.685040759895962, 85.03428315131636));
    points.push_back(gp_Pnt2d(-0.8360996701423912, 90.88831418622379));
    points.push_back(gp_Pnt2d(-0.9712280657449973, 98.60642504358016));
    points.push_back(gp_Pnt2d(-1.107473340201843, 109.8128499136364));
    points.push_back(gp_Pnt2d(-1.235287222620387, 125.2176218856868));
    points.push_back(gp_Pnt2d(-1.336694214516567, 143.1292577640535));
    points.push_back(gp_Pnt2d(-1.422279617817822, 165.3530615092768));
    points.push_back(gp_Pnt2d(-1.482736871704577, 188.4800074377642));
    points.push_back(gp_Pnt2d(-1.517600666986478, 207.1284783455371));
    points.push_back(gp_Pnt2d(-1.539076109744018, 222.0802673453285));
    points.push_back(gp_Pnt2d(-1.552689937266964, 233.7871752000689));
    points.push_back(gp_Pnt2d(-1.563053751322408, 244.4757708002793));
    points.push_back(gp_Pnt2d(-1.571039287405315, 254.2613218922325));
    points.push_back(gp_Pnt2d(-1.577281393834402, 263.2876678184592));
    points.push_back(gp_Pnt2d(-1.582247816786106, 271.7255934531588));
    points.push_back(gp_Pnt2d(-1.586292499748858, 279.7878539164695));
    points.push_back(gp_Pnt2d(-1.589719915784794, 287.8274015592376));
    points.push_back(gp_Pnt2d(-1.592984242822523, 296.9869611980702));
    points.push_back(gp_Pnt2d(-1.59556463714567, 305.7145935695123));
    points.push_back(gp_Pnt2d(-1.596881417258233, 310.8260663225046));
    points.push_back(gp_Pnt2d(-1.59844230048339, 317.5416783018154));
    points.push_back(gp_Pnt2d(-1.600092911512606, 325.3952168790041));
    points.push_back(gp_Pnt2d(-1.601736056841309, 333.7885771313531));
    points.push_back(gp_Pnt2d(-1.603525231347935, 343.2349115827637));
    points.push_back(gp_Pnt2d(-1.605312846923844, 352.7396608452729));
    points.push_back(gp_Pnt2d(-1.605465872322137, 353.5533905929998));

    return points;
}

bool checkCurveDistance(const Handle(Geom_BSplineCurve)& curve1,
        const Handle(Geom_BSplineCurve)& curve2)
{
    constexpr int numberOfCheckPoints = 100;
    constexpr double distanceTrigger = 1.0;

    for (int index = 0; index < numberOfCheckPoints; ++index)
    {
        const double parameter =
                curve1->FirstParameter() +
                (curve1->LastParameter() - curve1->FirstParameter()) *
                        static_cast<double>(index) /
                        static_cast<double>(numberOfCheckPoints - 1);

        const gp_Pnt curve1Point = curve1->Value(parameter);

        gp_Pnt projection;
        ShapeAnalysis_Curve analyzer;
        double curve2Parameter;

        analyzer.Project(curve2, curve1Point, Precision::Confusion(), projection,
                curve2Parameter, Standard_False);

        std::cout << "Distance: " << curve1Point.Distance(projection) << 
std::endl;

        if (curve1Point.Distance(projection) > distanceTrigger)
        {
            std::cerr << "Point on curve 1 is far away from curve 2." << std::endl;
            
return false;
        }
    }

    return true;
}

int main(int, char**)
{
    BRep_Builder builder;

    TopoDS_Face face;

    {
        TopoDS_Shape shape;
        bool result = BRepTools::Read(shape, "Face.brep", builder);

        if (!result)
        {
            std::cerr << "There was a problem when reading in the BREP file."
                                << std::endl;
            exit(1);
        }

        for (TopExp_Explorer faceExplorer(shape, TopAbs_FACE); faceExplorer.More();
                 faceExplorer.Next())
        {
            face = TopoDS::Face(faceExplorer.Current());
            break;
        }

        if (face.IsNull())
        {
            std::cerr << "Face is null." << std::endl;
            exit(1);
        }

        BRepCheck_Analyzer faceAnalyzer(face);

        if (!faceAnalyzer.IsValid())
        {
            std::cerr << "Face is invalid." << std::endl;
            exit(1);
        }
    }

    const std::vector<gp_Pnt2d> points = get2dPoints();

    // Now interpolate on the surface and in space.

    TColgp_HArray1OfPnt2d poles(1, static_cast<Standard_Integer>(points.size()));
    TColgp_HArray1OfPnt poles3d(1, static_cast<Standard_Integer>(points.size()));

    for (size_t index = 0; index < points.size(); ++index)
    {
        poles.SetValue(index + 1, points.at(index));
        poles3d.SetValue(index + 1, getSpacePoint(face, points.at(index)));
    }

    Geom2dAPI_PointsToBSpline interpolator(poles);
    GeomAPI_PointsToBSpline interpolatorInSpace(poles3d);

    if (!interpolator.IsDone())
    {
        std::cerr << "Interpolation on face has failed." << std::endl;
        exit(1);
    }

    if (!interpolatorInSpace.IsDone())
    {
        std::cerr << "Interpolation in space has failed." << std::endl;
        exit(1);
    }

    Handle(Geom_BSplineCurve) curveOnFace;
    double maxDeviation;
    double averageDeviation;

    const Handle(Geom2dAdaptor_HCurve) curve2dAdaptor =
            new Geom2dAdaptor_HCurve(interpolator.Curve());
    const Handle(Geom_Surface) surface = BRep_Tool::Surface(face);
    const Handle(GeomAdaptor_HSurface) surfaceAdaptor =
            new GeomAdaptor_HSurface(surface);
    Adaptor3d_CurveOnSurface curveOnSurface(curve2dAdaptor, surfaceAdaptor);

    GeomLib::BuildCurve3d(Precision::Intersection(), curveOnSurface,
            curveOnSurface.FirstParameter(), curveOnSurface.LastParameter(),
            curveOnFace, maxDeviation, averageDeviation);

    const double lengthOnFace =
            CPnts_AbscissaPoint::Length(GeomAdaptor_Curve(curveOnFace));
    const double lengthInSpace = CPnts_AbscissaPoint::Length(
            GeomAdaptor_Curve(interpolatorInSpace.Curve()));

    std::cout << "Length of curve on face: " << lengthOnFace
                        << " length of curve in space: " << lengthInSpace << 
std::endl;

    const bool distanceCheckResult1 =
            checkCurveDistance(interpolatorInSpace.Curve(), curveOnFace);

    if (!distanceCheckResult1)
    {
        exit(1);
    }

    const bool distanceCheckResult2 =
            checkCurveDistance(curveOnFace, interpolatorInSpace.Curve());

    if (!distanceCheckResult2)
    {
        exit(1);
    }

    return 0;
}
TagsNo tags attached.
Test case number
Attached Files? file icon Face.brep (399,416 bytes) 2021-02-01 19:24

- Relationships

-  Notes
There are no notes attached to this issue.

- Issue History
Date Modified Username Field Change
2021-02-01 19:24 BenjaminBihler New Issue
2021-02-01 19:24 BenjaminBihler Assigned To => msv
2021-02-01 19:24 BenjaminBihler File Added: Face.brep
2021-02-01 19:53 kgv Steps to Reproduce Updated View Revisions
2021-08-29 19:12 msv Target Version 7.6.0* => 7.7.0


Copyright © 2000 - 2021 MantisBT Team
Powered by Mantis Bugtracker