/***************************************************************************
 *   Copyright (c) 2007                                                    *
 *   Joachim Zettler <Joachim.Zettler@gmx.de>                  *
 *   Human Rezai <Human@web.de>                                            *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 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        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#include "SpringbackCorrection.h"
#include "best_fit.h"


#include <Mod/Mesh/App/Core/Builder.h>
#include <Mod/Mesh/App/WildMagic4/Wm4MeshCurvature.h>

#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <Base/Builder3D.h>
#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <TopExp_Explorer.hxx>
#include <TopExp.hxx>
#include <TopoDS_Vertex.hxx>
#include <BRep_Tool.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <TopoDS.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <Geom_Surface.hxx>




///*********BINDINGS********/
#include <boost/numeric/bindings/traits/ublas_matrix.hpp>
#include <boost/numeric/bindings/atlas/clapack.hpp>

using namespace boost::numeric::bindings;

using namespace boost::numeric;


SpringbackCorrection::SpringbackCorrection()
{
}

SpringbackCorrection::SpringbackCorrection(const TopoDS_Shape& aShape, const MeshCore::MeshKernel& aMesh)
        :m_Shape(aShape),m_Mesh(aMesh)
{
    m_EdgeStruct.clear();
    EdgeMap.clear();
    MeshMap.clear();
    //Remove any existing Triangulation on the Shape
    BRepTools::Clean(m_Shape);
    best_fit::Tesselate_Shape(m_Shape,m_CadMesh,(float) 0.1); // Basistriangulierung des ganzen Shapes

    MeshCore::MeshTopoAlgorithm algo(m_CadMesh);
    algo.HarmonizeNormals();

	// flip all normals so that they are oriented in positive z-direction 
    MeshCore::MeshGeomFacet facet = m_CadMesh.GetFacet(0);
    if (facet.GetNormal().z < 0.0)
        algo.FlipNormals();

    int n = m_CadMesh.CountFacets();
    Base::Vector3f normal;

    MeshCore::MeshPointArray points = m_CadMesh.GetPoints();
    MeshCore::MeshFacetArray facets = m_CadMesh.GetFacets();

    for (int i=0; i<n; ++i)
    {
        MeshCore::MeshGeomFacet face = m_CadMesh.GetFacet(i);
        normal = face.GetNormal();

        if (normal.z < 0.0)
        {
            facets[i].FlipNormal();
        }
    }

    m_CadMesh.Assign(points, facets);
}

SpringbackCorrection::~SpringbackCorrection()
{
}
bool SpringbackCorrection::Load(const MeshCore::MeshKernel& aMesh)
{
	m_MeshVec.push_back(aMesh);
	//m_CadMesh = MeshRef;

	return true;
}

bool SpringbackCorrection::Load(const TopoDS_Shape& aShape)
{
	m_Shape = aShape;
	return true;
}
bool SpringbackCorrection::Load(const TopoDS_Shape& aShape, const MeshCore::MeshKernel& aMesh)
{
    m_Shape = aShape;
    m_Mesh  = aMesh;

    m_EdgeStruct.clear();
    EdgeMap.clear();
    MeshMap.clear();

    //Remove any existing Triangulation on the Shape
    BRepTools::Clean(m_Shape);
    best_fit::Tesselate_Shape(m_Shape,m_CadMesh,(float) 0.1); // Basistriangulierung des ganzen Shapes

    MeshCore::MeshTopoAlgorithm algo(m_CadMesh);
    algo.HarmonizeNormals();

    MeshCore::MeshGeomFacet facet = m_CadMesh.GetFacet(0);
    if (facet.GetNormal().z < 0.0)
        algo.FlipNormals();

    int n = m_CadMesh.CountFacets();
    Base::Vector3f normal;

    //MeshCore::MeshPointArray points = m_CadMesh.GetPoints();
    //MeshCore::MeshFacetArray facets = m_CadMesh.GetFacets();

    //for (int i=0; i<n; ++i)
    //{
    //    MeshCore::MeshGeomFacet face = m_CadMesh.GetFacet(i);
    //    normal = face.GetNormal();

    //    if (normal.z < 0.0)
    //    {
    //        facets[i].FlipNormal();
    //    }
    //}

    //m_CadMesh.Assign(points, facets);

    return true;
}

bool SpringbackCorrection::CalcCurv()
{
    Base::Builder3D logo;
    BRep_Builder VertexBuild;
    BRepExtrema_DistShapeShape pnt2edge;
    pnt2edge.SetDeflection(0.1);

    TopExp_Explorer aExpFace;
    TopExp_Explorer aExpEdge;
    TopoDS_Vertex V;

    MeshPnt aMeshStruct;
    MeshCore::MeshPointIterator pntIt(m_CadMesh);
    MeshCore::MeshKernel FaceMesh;
    MeshCore::MeshPointArray MeshPnts, MeshPntsCop, MeshPntsCad;
    MeshCore::MeshPointArray MeshPntsCopy;
    MeshCore::MeshFacetArray MeshFacets, MeshFacets2;
    MeshCore::MeshFacetIterator facetIt(m_CadMesh);

    std::pair<Base::Vector3f, MeshPnt> inp;
    std::vector<int> MeanVec;
    std::vector<FacePnt> FacePntVector;
    TopLoc_Location aloc;
    Base::Vector3f mP;
    gp_Pnt e_pnt, m_pnt;
    double dist, distSum, revSum;;
    int n;

    std::map<TopoDS_Edge, std::vector<double>, Edge_Less>::iterator edge_it;
    std::map<Base::Vector3f,MeshPnt,MeshPntLess >::iterator meshIt;
    std::vector<MeshCore::MeshPoint>::iterator pIt;

    m_CurvPos.resize(m_CadMesh.CountPoints());
    m_CurvNeg.resize(m_CadMesh.CountPoints());
    m_MeshStruct.resize(m_CadMesh.CountPoints());
    MeanVec.resize(m_CadMesh.CountPoints(), 0);

    // Fülle Map mit Punkten (Key) und deren, zur Basistriangulierung korrespondierenden, Indizes
    MeshPnts = m_CadMesh.GetPoints();
	MeshPntsCop = MeshPnts;
	MeshFacets2 = m_CadMesh.GetFacets();

    for (unsigned int i=0; i<MeshPnts.size(); ++i)
    {
        aMeshStruct.pnt = MeshPnts[i];        // stores point
        aMeshStruct.index = i;                // stores index
        aMeshStruct.maxCurv = 1e+3;
        aMeshStruct.minCurv = -1e+3;
        inp.first  = aMeshStruct.pnt;
        inp.second = aMeshStruct;
        MeshMap.insert(inp);
    }

    // explores all faces  ------------  Hauptschleife
    for (aExpFace.Init(m_Shape,TopAbs_FACE);aExpFace.More();aExpFace.Next())
    {
        TopoDS_Face aFace = TopoDS::Face(aExpFace.Current());
        TransferFaceTriangulationtoFreeCAD(aFace, FaceMesh);
        MeshPnts.clear();
        MeshPnts = FaceMesh.GetPoints();
        MeshPntsCopy = MeshPnts;
        n = MeshPnts.size();
        TopLoc_Location aLocation;
        // berechne normalen -> m_MeshStruct
        Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation);
        const TColgp_Array1OfPnt& aNodes = aTr->Nodes();
        // create array of node points in absolute coordinate system
        TColgp_Array1OfPnt aPoints(1, aNodes.Length());
        for ( Standard_Integer i = 1; i <= aNodes.Length(); i++)
            aPoints(i) = aNodes(i).Transformed(aLocation);

        const TColgp_Array1OfPnt2d& aUVNodes = aTr->UVNodes();


        BRepAdaptor_Surface aSurface(aFace);
        Base::Vector3f Pnt1, Pnt2;
        gp_Pnt2d par;
        gp_Pnt P;
        gp_Vec D1U, D1V;

        for (int i=1; i<n+1; ++i)
        {
            par = aUVNodes.Value(i);
            aSurface.D1(par.X(),par.Y(),P,D1U,D1V);
            P = aPoints(i);
            Pnt1.x = (float) P.X();
            Pnt1.y = (float) P.Y();
            Pnt1.z = (float) P.Z();
            meshIt = MeshMap.find(Pnt1);
            if (meshIt == MeshMap.end())
            {
                cout << "error";
                return false;
            }

            D1U.Cross(D1V);
            D1U.Normalize();
            if (aFace.Orientation() == TopAbs_FORWARD) D1U.Scale(-1.0);

            Pnt2.Set(float(Pnt1.x+D1U.X()),float(Pnt1.y+D1U.Y()),float(Pnt1.z+D1U.Z()));
            logo.addSingleArrow(Pnt1, Pnt2);

            m_MeshStruct[((*meshIt).second).index].normal.x = (float) D1U.X();
            m_MeshStruct[((*meshIt).second).index].normal.y = (float) D1U.Y();
            m_MeshStruct[((*meshIt).second).index].normal.z = (float) D1U.Z();

        }

        logo.saveToFile("c:/norm.iv");



        // get Inner Mesh Points
        int innerpoints = GetBoundary(FaceMesh, MeshPnts);



        FacePntVector.resize(innerpoints);  // stores inner-points and sourrounding edges-distances

        // explores the edges of the face ----------------------
        for (aExpEdge.Init(aFace,TopAbs_EDGE);aExpEdge.More();aExpEdge.Next())
        {
            TopoDS_Edge aEdge = TopoDS::Edge(aExpEdge.Current());

            edge_it = EdgeMap.find(aEdge);
            if (edge_it == EdgeMap.end())
            {
                cout << "error1";
                return false;
            }

            pnt2edge.LoadS1(aEdge);

            int counter = 0;

            for (pIt = MeshPnts.begin(); pIt != MeshPnts.end(); ++pIt)
            {
                //check if there is no boundary
                if (pIt->_ulProp == 0)
                {
                    m_pnt.SetCoord(pIt->x, pIt->y, pIt->z);
                    VertexBuild.MakeVertex(V,m_pnt,0.001);
                    pnt2edge.LoadS2(V);
                    pnt2edge.Perform();

                    if (pnt2edge.IsDone() == false)
                    {
                        throw Base::Exception("couldn't perform distance calculation pnt2edge \n");
                    }

                    dist = pnt2edge.Value();

                    FacePntVector[counter].pnt = *pIt;
                    FacePntVector[counter].distances.push_back(dist);
                    FacePntVector[counter].MinEdgeOff.push_back((*edge_it).second[0]);
                    FacePntVector[counter].MaxEdgeOff.push_back((*edge_it).second[1]);
                    ++counter;
                }

            }

            // Knoten auf der EDGE die EdgeOffset-Werte zuweisen

            // Edge -> Polygon -> Nodes
            Handle(Poly_PolygonOnTriangulation) polyg;
            Handle_Poly_Triangulation aTrLoc;
            BRep_Tool::PolygonOnTriangulation(aEdge,polyg,aTrLoc,aloc);

            TColStd_Array1OfInteger IndArr(1,polyg->NbNodes());
            IndArr = polyg->Nodes();

            const TColgp_Array1OfPnt& Nodes = aTrLoc->Nodes();
            TColgp_Array1OfPnt TrLocPnts(1, Nodes.Length());
            for ( Standard_Integer i = 1; i <= Nodes.Length(); i++)
                TrLocPnts(i) = Nodes(i).Transformed(aloc);

            for (int k=0; k<polyg->Nodes().Upper(); ++k)
            {
                e_pnt = TrLocPnts(IndArr.Value(k+1));

                mP.x = (float) e_pnt.X();
                mP.y = (float) e_pnt.Y();
                mP.z = (float) e_pnt.Z();

                meshIt = MeshMap.find(mP);
                if (meshIt == MeshMap.end())
                {
                    cout << "error2" << endl;
                    return false;
                }


                ++MeanVec[meshIt->second.index];

                // nehme stets den minimalen wert
                if (((*edge_it).second[0])>((*meshIt).second).minCurv)
                    ((*meshIt).second).minCurv = (*edge_it).second[0];

                if ((*edge_it).second[1]<((*meshIt).second).maxCurv)
                    ((*meshIt).second).maxCurv = (*edge_it).second[1];
            }
        }

        // Knoten INNERHALB eines Faces die Offset-Werte zuweisen
        for (unsigned int k=0; k<FacePntVector.size(); ++k)
        {
            meshIt = MeshMap.find(FacePntVector[k].pnt);

            if (meshIt == MeshMap.end())
            {
                cout << "error3";
                return false;
            }

            distSum = 0.0;
            for (unsigned int l=0; l<FacePntVector[k].distances.size(); ++l)
                distSum +=  FacePntVector[k].distances[l];

            revSum = 0.0;
            for (unsigned int l=0; l<FacePntVector[k].distances.size(); ++l)
            {
                revSum += distSum/FacePntVector[k].distances[l];

                if (((*meshIt).second).minCurv == -1e+3)
                    ((*meshIt).second).minCurv = 0.0;

                if (((*meshIt).second).maxCurv == 1e+3)
                    ((*meshIt).second).maxCurv = 0.0;

                ((*meshIt).second).minCurv += distSum*(FacePntVector[k].MinEdgeOff[l])/FacePntVector[k].distances[l];
                ((*meshIt).second).maxCurv += distSum*(FacePntVector[k].MaxEdgeOff[l])/FacePntVector[k].distances[l];

            }

            ((*meshIt).second).minCurv /= revSum;
            ((*meshIt).second).maxCurv /= revSum;

        }
        FacePntVector.clear();
    }



    Base::Builder3D log,log3d;
    Base::Vector3f pa,pb;
    char text[10];
    int w;

    // übergebe krümmungswerte an m_MeshStruct
    for (meshIt = MeshMap.begin(); meshIt != MeshMap.end(); ++meshIt)
    {
        w = meshIt->second.index;
        m_MeshStruct[w].pnt = (*meshIt).first;

        m_MeshStruct[w].minCurv = (((*meshIt).second).minCurv);
        m_MeshStruct[w].maxCurv = (((*meshIt).second).maxCurv);

        // Ausgabe
        if (m_MeshStruct[w].maxCurv<10000000000)
        {
            snprintf(text,10,"%f",m_MeshStruct[w].minCurv);
            //snprintf(text,10,"%i",w);
            log.addText(m_MeshStruct[w].pnt.x, m_MeshStruct[w].pnt.y, m_MeshStruct[w].pnt.z,text);
        }

        if (MeanVec[w] == 1)
            log3d.addSinglePoint(m_MeshStruct[w].pnt,4,0,0,0); // innere punkte - > schwarz
        else if (MeanVec[w] == 2)
            log3d.addSinglePoint(m_MeshStruct[w].pnt,4,1,1,1); // edge-punkte   - > weiß
        else
            log3d.addSinglePoint(m_MeshStruct[w].pnt,4,1,0,0); // eck-punkte    - > rot

        //m_MeshStruct[w].minCurv = (((*meshIt).second).minCurv)/MeanVec[w];
        //m_MeshStruct[w].maxCurv = (((*meshIt).second).maxCurv)/MeanVec[w];

        //if(m_MeshStruct[w].maxCurv < 100 || fabs(m_MeshStruct[w].minCurv) < 100)
        //{
        // if(m_MeshStruct[w].maxCurv > fabs(m_MeshStruct[w].minCurv))
        // {
        //  snprintf(text,10,"%f",m_MeshStruct[w].minCurv);
        //  //m_MeshStruct[w].normal.Scale(m_MeshStruct[w].minCurv,m_MeshStruct[w].minCurv,m_MeshStruct[w].minCurv);
        //  logo.addSingleArrow(m_MeshStruct[w].pnt, m_MeshStruct[w].pnt+m_MeshStruct[w].normal);
        // }
        // else
        // {
        //  //snprintf(text,4,"%f",m_MeshStruct[w].maxCurv);
        //  m_MeshStruct[w].normal.Scale(m_MeshStruct[w].maxCurv,m_MeshStruct[w].maxCurv,m_MeshStruct[w].maxCurv);
        //  logo.addSingleArrow(m_MeshStruct[w].pnt, m_MeshStruct[w].pnt+m_MeshStruct[w].normal);
        // }
        //}

        //if(m_MeshStruct[w].maxCurv < 100)
        //{
        // m_MeshStruct[w].normal.Scale(0.5*m_MeshStruct[w].maxCurv,0.5*m_MeshStruct[w].maxCurv,0.5*m_MeshStruct[w].maxCurv);
        // logo.addSingleArrow(m_MeshStruct[w].pnt, m_MeshStruct[w].pnt+m_MeshStruct[w].normal);
        //}*/

        //snprintf(text,10,"%f",m_MeshStruct[w].maxCurv);
        //snprintf(text,10,"%i",w);


        /*if(m_MeshStruct[w].maxCurv > fabs(m_MeshStruct[w].minCurv))
        {
         snprintf(text,10,"%f",m_MeshStruct[w].minCurv);
         
        }
        else
        {
         snprintf(text,10,"%f",m_MeshStruct[w].maxCurv);
        }*/



    }

    log.saveToFile("c:/printCurv.iv");
    log3d.saveToFile("c:/triPnts.iv");
    logo.saveToFile("c:/NormalsCurv.iv");

	MeshPntsCad = m_CadMesh.GetPoints();
	
	
	 for (unsigned int j=0; j<m_FixFaces.size(); ++j)
	 {
        TopoDS_Face aFace = TopoDS::Face(m_FixFaces[j]);
        TransferFaceTriangulationtoFreeCAD(aFace, FaceMesh);
		MeshPnts = FaceMesh.GetPoints();
		MeshFacets2 = m_CadMesh.GetFacets();
        MeshPntsCopy = MeshPnts;
        n = MeshPnts.size();
        TopLoc_Location aLocation;
        // berechne normalen -> m_MeshStruct
        Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation);
        const TColgp_Array1OfPnt& aNodes = aTr->Nodes();
        // create array of node points in absolute coordinate system
        TColgp_Array1OfPnt aPoints(1, aNodes.Length());
        for ( Standard_Integer i = 1; i <= aNodes.Length(); i++)
            aPoints(i) = aNodes(i).Transformed(aLocation);

        const TColgp_Array1OfPnt2d& aUVNodes = aTr->UVNodes();

        BRepAdaptor_Surface aSurface(aFace);
        Base::Vector3f Pnt1, Pnt2;
        gp_Pnt2d par;
        gp_Pnt P;
        gp_Vec D1U, D1V;
		std::vector<bool> trans_check(m_MeshStruct.size(), false);

        for (int i=1; i<n+1; ++i)
        {
            par = aUVNodes.Value(i);
            aSurface.D1(par.X(),par.Y(),P,D1U,D1V);
            P = aPoints(i);
            Pnt1.x = (float) P.X();
            Pnt1.y = (float) P.Y();
            Pnt1.z = (float) P.Z();
            meshIt = MeshMap.find(Pnt1);
            if (meshIt == MeshMap.end())
            {
                cout << "error";
                return false;
            }

            D1U.Cross(D1V);
            D1U.Normalize();
            if (aFace.Orientation() == TopAbs_FORWARD) D1U.Scale(-1.0);

			int g = ((*meshIt).second).index;

			D1U.Scale(0.1);
			if(trans_check[g] == false)
			{
				m_dist_vec[g].x = - D1U.X();
				m_dist_vec[g].y = - D1U.Y();
				m_dist_vec[g].z = - D1U.Z();

				MeshPntsCad[g].Set(MeshPntsCad[g].x - D1U.X(),
								   MeshPntsCad[g].y - D1U.Y(),
								   MeshPntsCad[g].z - D1U.Z());
				
				(m_MeshStruct[g].pnt).Set(MeshPntsCad[g].x - D1U.X(),
										  MeshPntsCad[g].y - D1U.Y(),
							    		  MeshPntsCad[g].z - D1U.Z());

				trans_check[g] = true;
			}
		}
	 }
	 m_CadMesh.Assign(MeshPntsCad, MeshFacets2);

     return true;
}


bool SpringbackCorrection::Init()
{
	m_EdgeStruct.clear();
    EdgeMap.clear();
    MeshMap.clear();
    //Remove any existing Triangulation on the Shape
    BRepTools::Clean(m_Shape);
    best_fit::Tesselate_Shape(m_Shape,m_CadMesh,(float) 0.1); // Basistriangulierung des ganzen Shapes

    MeshCore::MeshTopoAlgorithm algo(m_CadMesh);
    algo.HarmonizeNormals();

    MeshCore::MeshGeomFacet facet = m_CadMesh.GetFacet(0);
    if (facet.GetNormal().z < 0.0)
        algo.FlipNormals();

    int n = m_CadMesh.CountFacets();
    Base::Vector3f normal;

    MeshCore::MeshPointArray points = m_CadMesh.GetPoints();
    MeshCore::MeshFacetArray facets = m_CadMesh.GetFacets();

    for (int i=0; i<n; ++i)
    {
        MeshCore::MeshGeomFacet face = m_CadMesh.GetFacet(i);
        normal = face.GetNormal();

        if (normal.z < 0.0)
        {
            facets[i].FlipNormal();
        }
    }

    m_CadMesh.Assign(points, facets);

    double max = cMin;
    TopTools_IndexedDataMapOfShapeListOfShape anIndex;
    anIndex.Clear();
    TopExp aMap;
    aMap.MapShapesAndAncestors(m_Shape,TopAbs_EDGE,TopAbs_FACE,anIndex);
    TopExp_Explorer anExplorer, anExplorer2;
    TopoDS_Face aFace;
    EdgeStruct tempEdgeStruct;
    std::vector<EdgeStruct> EdgeVec;
    MeshCore::MeshKernel FaceMesh;
    std::vector<double> curvature(2);
    std::pair<TopoDS_Edge, std::vector<double> > aPair;

    float maxOffset, minOffset;

    for (anExplorer.Init(m_Shape,TopAbs_EDGE);anExplorer.More();anExplorer.Next())
    {
        tempEdgeStruct.aFace.clear();
        tempEdgeStruct.MaxOffset = 1e+10;
        tempEdgeStruct.MinOffset = -1e+10;
        tempEdgeStruct.anEdge = TopoDS::Edge(anExplorer.Current()); // store current edge

        const TopTools_ListOfShape& aFaceList = anIndex.FindFromKey(tempEdgeStruct.anEdge);
        TopTools_ListIteratorOfListOfShape aListIterator;

        for (aListIterator.Initialize(aFaceList);aListIterator.More(); aListIterator.Next())
        {
            // store corresponding faces
            aFace = TopoDS::Face(aListIterator.Value());
            tempEdgeStruct.aFace.push_back(aFace);
            TransferFaceTriangulationtoFreeCAD(aFace, FaceMesh);
            curvature = MeshCurvature(aFace, FaceMesh);

            if (aFace.Orientation() == TopAbs_REVERSED)
            {
                maxOffset = (float) -curvature[1];
                minOffset = (float) -curvature[0];
            }
            else
            {
                maxOffset = (float) curvature[0];
                minOffset = (float) curvature[1];
            }

            if (maxOffset < tempEdgeStruct.MaxOffset)
                tempEdgeStruct.MaxOffset = maxOffset;

            if (minOffset > tempEdgeStruct.MinOffset)
                tempEdgeStruct.MinOffset = minOffset;
        }


        if (tempEdgeStruct.MaxOffset > max)
            curvature[1] = tempEdgeStruct.MaxOffset;
        else
            curvature[1] = cMin;

        if (-tempEdgeStruct.MinOffset > max)
            curvature[0] = tempEdgeStruct.MinOffset;
        else
            curvature[0] = -cMin;

        aPair.first = tempEdgeStruct.anEdge;
        aPair.second = curvature;
        EdgeMap.insert(aPair);

    }
    return true;
}

bool SpringbackCorrection::Init_Setting(struct CuttingToolsSettings& set)
{
    m_set = set;
    return true;
}

bool SpringbackCorrection::SetFixEdges()
{
    TopExp_Explorer anExplorer;
    TopoDS_Edge anEdge;
    std::map<TopoDS_Edge, std::vector<double>, Edge_Less>::iterator edge_it;
    std::vector<double> pair(2,0.0);

    for (unsigned int i=0; i<m_FixFaces.size(); ++i)
    {
        for (anExplorer.Init(m_FixFaces[i],TopAbs_EDGE); anExplorer.More(); anExplorer.Next())
        {
            anEdge  = TopoDS::Edge(anExplorer.Current());
            edge_it = EdgeMap.find(anEdge);
            edge_it->second = pair;
        }
    }

    return true;
}

bool SpringbackCorrection::TransferFaceTriangulationtoFreeCAD(const TopoDS_Face& aFace, MeshCore::MeshKernel& FaceMesh)
{
    FaceMesh.Clear();
    MeshCore::MeshBuilder builder(FaceMesh);
    builder.Initialize(1000);
    Base::Vector3f Points[3];

    TopLoc_Location aLocation;
    // takes the triangulation of the face aFace:
    Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation);
    if (!aTr.IsNull()) // if this triangulation is not NULL
    {
        // takes the array of nodes for this triangulation:
        const TColgp_Array1OfPnt& aNodes = aTr->Nodes();
        // takes the array of triangles for this triangulation:
        const Poly_Array1OfTriangle& triangles = aTr->Triangles();
        // create array of node points in absolute coordinate system
        TColgp_Array1OfPnt aPoints(1, aNodes.Length());
        for ( Standard_Integer i = 1; i <= aNodes.Length(); i++)
            aPoints(i) = aNodes(i).Transformed(aLocation);
        // Takes the node points of each triangle of this triangulation.
        // takes a number of triangles:
        Standard_Integer nnn = aTr->NbTriangles();
        Standard_Integer nt,n1,n2,n3;
        for ( nt = 1 ; nt < nnn+1 ; nt++)
        {
            // takes the node indices of each triangle in n1,n2,n3:
            triangles(nt).Get(n1,n2,n3);
            // takes the node points:
            gp_Pnt aPnt1 = aPoints(n1);
            Points[0].Set(float(aPnt1.X()),float(aPnt1.Y()),float(aPnt1.Z()));
            gp_Pnt aPnt2 = aPoints(n2);
            Points[1].Set((float) aPnt2.X(),(float) aPnt2.Y(),(float) aPnt2.Z());
            gp_Pnt aPnt3 = aPoints(n3);
            Points[2].Set((float) aPnt3.X(),(float) aPnt3.Y(),(float) aPnt3.Z());
            // give the occ faces to the internal mesh structure of freecad
            MeshCore::MeshGeomFacet Face(Points[0],Points[1],Points[2]);
            builder.AddFacet(Face);
        }

    }
    // if the triangulation of only one face is not possible to get
    else
    {
        throw Base::Exception("Empty face triangulation\n");
    }

    // finish FreeCAD Mesh Builder and exit with new mesh
    builder.Finish();
    return true;

}

/*
MeshCore::MeshKernel SpringbackCorrection::BuildMesh(Handle_Poly_Triangulation aTri, std::vector<Base::Vector3f> TrPoints)
{
    MeshCore::MeshKernel FaceMesh;
    MeshCore::MeshBuilder builder(FaceMesh);
    builder.Initialize(1000);
    Base::Vector3f Points[3];

    const Poly_Array1OfTriangle& triangles = aTri->Triangles();
    Standard_Integer nnn = aTri->NbTriangles();
    Standard_Integer nt,n1,n2,n3;

    for ( nt = 1 ; nt < nnn+1 ; nt++)
    {
        // takes the node indices of each triangle in n1,n2,n3:
        triangles(nt).Get(n1,n2,n3);
        // takes the node points:
        Points[0] = TrPoints[n1];
        Points[1] = TrPoints[n2];
        Points[2] = TrPoints[n3];
        // give the occ faces to the internal mesh structure of freecad
        MeshCore::MeshGeomFacet Face(Points[0],Points[1],Points[2]);
        builder.AddFacet(Face);
    }

    // finish FreeCAD Mesh Builder and exit with new mesh
    builder.Finish();

    return FaceMesh;
}
*/

int SpringbackCorrection::GetBoundary(const MeshCore::MeshKernel &mesh, MeshCore::MeshPointArray &meshPnts)
{
    // get mesh-boundary
    // zweck: nur für die inneren punkte wird der curvature wert über die edge abstände berechnet
    std::list< std::vector <unsigned long> >  BoundariesIndex;
    std::list< std::vector <unsigned long> >::iterator bInd;


    MeshCore::MeshAlgorithm algo(mesh);
    algo.GetMeshBorders(BoundariesIndex);
    //Set all MeshPoints to Property 0
    for (unsigned int i=0;i<meshPnts.size();++i)
        meshPnts[i].SetProperty(0);

    //Set Boundary Points to 1
    int inner_points = 0;
    for (bInd = BoundariesIndex.begin(); bInd != BoundariesIndex.end(); ++bInd)
    {
        for (unsigned int i=0;i< bInd->size();++i)
        {
            meshPnts[(*bInd).at(i)].SetProperty(1);
        }

    }
    for (unsigned int i=0;i<meshPnts.size();++i)
    {
        if (meshPnts[i]._ulProp == 0)
            inner_points++;
    }

    return (inner_points);
}
/*
bool SpringbackCorrection::SmoothCurvature()
{
    MeshCore::MeshPointIterator v_it(m_Mesh);
    MeshCore::MeshRefPointToPoints vv_it(m_Mesh);
    std::set<MeshCore::MeshPointArray::_TConstIterator> PntNei;
    std::set<MeshCore::MeshPointArray::_TConstIterator>::iterator pnt_it;

    int n = m_MeshStruct.size();

    std::vector<double> SCMax(n);
    std::vector<double> SCMin(n);
    double maxCurv = 0.0, minCurv = 0.0;

    for (v_it.Begin(); v_it.More(); v_it.Next())
    {
        PntNei = vv_it[v_it.Position()];
        maxCurv += m_MeshStruct[v_it.Position()].maxCurv;
        minCurv += m_MeshStruct[v_it.Position()].minCurv;

        for (pnt_it = PntNei.begin(); pnt_it !=PntNei.end(); ++pnt_it)
        {
            maxCurv += m_MeshStruct[(*pnt_it)[0]._ulProp].maxCurv;
            minCurv += m_MeshStruct[(*pnt_it)[0]._ulProp].minCurv;
        }

        SCMax[v_it.Position()] = maxCurv/(PntNei.size()+1);
        SCMin[v_it.Position()] = minCurv/(PntNei.size()+1);

        maxCurv = 0.0;
        minCurv = 0.0;
    }

    for (int i=0; i<n; ++i)
    {
        m_MeshStruct[i].maxCurv = SCMax[i];
        m_MeshStruct[i].minCurv = SCMin[i];
    }

    return true;
}
*/

bool SpringbackCorrection::SmoothMesh(MeshCore::MeshKernel &Mesh, double d_max)
{
    Base::Builder3D log;
    MeshCore::MeshKernel localMesh, Meshtmp;
    MeshCore::MeshPoint mpnt, spnt;
    MeshCore::MeshPointArray locPointArray, PointArray = Mesh.GetPoints();
    MeshCore::MeshFacetArray locFacetArray, FacetArray = Mesh.GetFacets();

    MeshCore::MeshPointIterator v_it(Mesh);
    MeshCore::MeshRefPointToPoints vv_it(Mesh);
    std::set<unsigned long>::const_iterator pnt_it;
    MeshCore::MeshPointArray::_TConstIterator v_beg = Mesh.GetPoints().begin();

    Base::Vector3f N, L, coor;
    int n = m_MeshStruct.size();
    int g;

    for (v_it.Begin(); v_it.More(); v_it.Next())
    {

        g = v_it.Position();
        spnt.Set(0.0, 0.0, 0.0);
        locPointArray.push_back(*v_it);
        spnt += *v_it;
        const std::set<unsigned long>& PntNei = vv_it[(*v_it)._ulProp];

        if (PntNei.size() < 3)
            continue;

        for (pnt_it = PntNei.begin(); pnt_it !=PntNei.end(); ++pnt_it)
        {
            locPointArray.push_back(v_beg[*pnt_it]);
            spnt += v_beg[*pnt_it];
        }

        spnt.Scale((float) (1.0/(double(PntNei.size()) + 1.0)),(float) (1.0/(double(PntNei.size()) + 1.0)),(float) (1.0/(double(PntNei.size()) + 1.0)));

        localMesh.Assign(locPointArray, locFacetArray);


        // need at least one facet to perform the PCA
        MeshCore::MeshGeomFacet face;
        face._aclPoints[0] = locPointArray[0];
        face._aclPoints[1] = locPointArray[1];
        face._aclPoints[2] = locPointArray[2];
        localMesh.AddFacet(face);

        MeshCore::MeshEigensystem pca(localMesh);
        pca.Evaluate();
        Base::Matrix4D T1 = pca.Transform();

        N.x = (float) T1[0][0];
        N.y = (float) T1[0][1];
        N.z = (float) T1[0][2];
        L.Set(v_it->x - spnt.x, v_it->y - spnt.y, v_it->z - spnt.z);
        N.Normalize();


        if (N*L < 0.0)
            N.Scale(-1.0, -1.0, -1.0);

        if ((*v_it)._ulProp == 2286)
        {
            log.addSinglePoint(spnt,4,1,0,0);
            log.addSinglePoint(*v_it,4,0,0,0);
            for (unsigned int i=0; i<locPointArray.size(); ++i)
                log.addSinglePoint(locPointArray[i],4);

            for (int i=0; i<3; ++i)
            {
                coor.x = (float) T1[i][0];
                coor.y = (float) T1[i][1];
                coor.z = (float) T1[i][2];

                coor.Normalize();

                log.addSingleArrow(*v_it, *v_it + coor);
            }

            /*log.addSingleArrow(*v_it, *v_it - N);
            snprintf(text,10,"%i",(*v_it)._ulProp);
            log.addText(v_it->x, v_it->y, v_it->z,text);*/
        }

        double d = d_max;
        if (fabs(N*L)< d_max) d = fabs(N*L);
        N.Scale((float) d,(float) d,(float) d);

        PointArray[v_it.Position()].Set(v_it->x - N.x, v_it->y - N.y, v_it->z - N.z);
        locPointArray.clear();
        localMesh = Meshtmp;
    }

    Mesh.Assign(PointArray, FacetArray);
    log.saveToFile("c:/checkNormals.iv");

    return true;
}

bool SpringbackCorrection::SmoothMesh(MeshCore::MeshKernel &Mesh, std::vector<int> ind, double d_max)
{
    Base::Builder3D log;
    MeshCore::MeshKernel localMesh, Meshtmp;
    MeshCore::MeshPoint mpnt, spnt;
    MeshCore::MeshPointArray locPointArray, PointArray = Mesh.GetPoints();
    MeshCore::MeshFacetArray locFacetArray, FacetArray = Mesh.GetFacets();

    MeshCore::MeshPointIterator v_it(Mesh);
    MeshCore::MeshRefPointToPoints vv_it(Mesh);
    std::set<unsigned long>::const_iterator pnt_it;
    MeshCore::MeshPointArray::_TConstIterator v_beg = Mesh.GetPoints().begin();

    Base::Vector3f N, L, coor;

    int n = ind.size();

    for (int i=0; i<n; ++i)
    {
        v_it.Set(ind[i]);
        spnt.Set(0.0, 0.0, 0.0);
        locPointArray.push_back(*v_it);
        spnt += *v_it;
        const std::set<unsigned long>& PntNei = vv_it[(*v_it)._ulProp];

        if (PntNei.size() < 3)
            continue;

        for (pnt_it = PntNei.begin(); pnt_it !=PntNei.end(); ++pnt_it)
        {
            locPointArray.push_back(v_beg[*pnt_it]);
            spnt += v_beg[*pnt_it];
        }

        spnt.Scale((float) (1.0/(double(PntNei.size()) + 1.0)),(float) (1.0/(double(PntNei.size()) + 1.0)),(float) (1.0/(double(PntNei.size()) + 1.0)));

        localMesh.Assign(locPointArray, locFacetArray);


        // need at least one facet to perform the PCA
        MeshCore::MeshGeomFacet face;
        face._aclPoints[0] = locPointArray[0];
        face._aclPoints[1] = locPointArray[1];
        face._aclPoints[2] = locPointArray[2];
        localMesh.AddFacet(face);

        MeshCore::MeshEigensystem pca(localMesh);
        pca.Evaluate();
        Base::Matrix4D T1 = pca.Transform();

        N.x = (float) T1[0][0];
        N.y = (float) T1[0][1];
        N.z = (float) T1[0][2];
        L.Set(v_it->x - spnt.x, v_it->y - spnt.y, v_it->z - spnt.z);
        N.Normalize();


        if (N*L < 0.0)
            N.Scale(-1.0, -1.0, -1.0);

        if ((*v_it)._ulProp == 2286)
        {
            log.addSinglePoint(spnt,4,1,0,0);
            log.addSinglePoint(*v_it,4,0,0,0);
            for (unsigned int i=0; i<locPointArray.size(); ++i)
                log.addSinglePoint(locPointArray[i],4);

            for (int i=0; i<3; ++i)
            {
                coor.x = (float) T1[i][0];
                coor.y = (float) T1[i][1];
                coor.z = (float) T1[i][2];

                coor.Normalize();

                log.addSingleArrow(*v_it, *v_it + coor);
            }

            /*log.addSingleArrow(*v_it, *v_it - N);
            snprintf(text,10,"%i",(*v_it)._ulProp);
            log.addText(v_it->x, v_it->y, v_it->z,text);*/
        }

        double d = d_max;
        if (fabs(N*L)< d_max) d = fabs(N*L);
        N.Scale((float) d,(float) d,(float) d);

        PointArray[v_it.Position()].Set(v_it->x - N.x, v_it->y - N.y, v_it->z - N.z);
        locPointArray.clear();
        localMesh = Meshtmp;
    }

    Mesh.Assign(PointArray, FacetArray);
    log.saveToFile("c:/checkNormals.iv");

    return true;
}

/*
bool SpringbackCorrection::GetFaceAng(MeshCore::MeshKernel &mesh, int deg_tol)
{
    Base::Vector3f normal, base;
    double deg;
    int n = mesh.CountFacets();
    bool b = true;

    for (int i=0; i<n; ++i)
    {
        MeshCore::MeshGeomFacet face = mesh.GetFacet(i);
        face.CalcNormal();
        normal = face.GetNormal();
        normal.Normalize();
        base = normal;
        base.z = 0.0;
        base.Normalize();

        if (normal.z < 0.0)
            deg = 90.0 + acos(normal*base)*180.0/PI;
        else
            deg = 90.0 - acos(normal*base)*180.0/PI;

        if (deg > deg_tol)
            b = false;

        m_FaceAng.push_back(deg);
    }

    return b;
}
*/

std::vector<int> SpringbackCorrection::InitFaceCheck(MeshCore::MeshKernel &mesh, int degree)
{
    std::vector<int> faceInd;
    double tol = degree;
    double alpha;
    MeshCore::MeshFacetIterator fIt(mesh);
    MeshCore::MeshPointIterator mIt(mesh);
    MeshCore::MeshRefPointToFacets p2fIt(mesh);
    Base::Vector3f normal, base, gpnt;
    Base::Builder3D log;

    MeshCore::MeshPointArray mPnts   = mesh.GetPoints();
    MeshCore::MeshFacetArray mFacets = mesh.GetFacets();
    MeshCore::MeshFacetArray::_TConstIterator f_beg = mesh.GetFacets().begin();

    int n = mesh.CountFacets();


    for (int i=0; i<n; ++i)
    {
        MeshCore::MeshGeomFacet face = mesh.GetFacet(i);
        //face.CalcNormal();
        normal = face.GetNormal();
        normal.Normalize();
        base = normal;
        base.z = 0.0;
        base.Normalize();

        gpnt = face.GetGravityPoint();


        if (normal.z < 0.0)
        {
            alpha = 90.0 + acos(normal*base)*180.0/PI;
            //log.addSingleArrow(gpnt,gpnt+normal,6,1,0,0);
        }
        else
        {
            alpha = 90.0 - acos(normal*base)*180.0/PI;
            //log.addSingleArrow(gpnt,gpnt+normal);
        }

        if (alpha > tol)
        {
            // markiere kritisches face
            mFacets[i].SetProperty(0);

            for (int j=0; j<3; ++j)
            {
                const std::set<unsigned long>& faceSet = p2fIt[mFacets[i]._aulPoints[j]];

                for (std::set<unsigned long>::const_iterator it = faceSet.begin(); it != faceSet.end(); ++it)
                {
                    f_beg[*it].SetProperty(5);
                }
            }

            log.addSingleArrow(gpnt,gpnt+normal,4,1,0,0);
        }
        else
        {
            mFacets[i].SetProperty(1);
            faceInd.push_back(i);
        }
    }

    log.saveToFile("c:/normalschecker.iv");

    MeshCore::MeshFacetArray mFacets2 = mesh.GetFacets();

    for (unsigned int i=0; i<mFacets2.size(); ++i)
    {
        if (mFacets2[i]._ulProp == 5)
        {
            mFacets[i].SetProperty(0);
        }
    }

    mesh.Assign(mPnts, mFacets);

    log.saveToFile("c:/angles.iv");
    return faceInd;
}

std::vector<int> SpringbackCorrection::FaceCheck(MeshCore::MeshKernel &mesh, int degree)
{
    std::vector<int> faceInd;
    double tol = degree;
    double alpha;
    MeshCore::MeshFacetIterator fIt(mesh);
    MeshCore::MeshPointIterator mIt(mesh);
    Base::Vector3f normal, base, gpnt;
    Base::Builder3D log;


    MeshCore::MeshPointArray mPnts   = mesh.GetPoints();
    MeshCore::MeshFacetArray mFacets = mesh.GetFacets();

    int n = mesh.CountFacets();

    for (int i=0; i<n; ++i)
    {
        MeshCore::MeshGeomFacet face = mesh.GetFacet(i);
        face.CalcNormal();
        normal = face.GetNormal();
        normal.Normalize();
        base = normal;
        base.z = 0.0;
        base.Normalize();

        gpnt = face.GetGravityPoint();

        if (normal.z < 0.0)
        {
            alpha = 90.0 + acos(normal*base)*180.0/PI;
            log.addSingleArrow(gpnt,gpnt+normal,2,1,0,0);
        }
        else
            alpha = 90.0 - acos(normal*base)*180.0/PI;

        if (alpha > tol)
        {
            faceInd.push_back(i);
			cout << "i: " << i << ", angle: " << alpha << endl;
        }
    }

    log.saveToFile("c:/angles.iv");
    return faceInd;
}

/*
bool SpringbackCorrection::CorrectScale(double zLim)
{
    // VERSCHIEBUNGSVEKTOREN ...
    // berechnung der skalierungsfaktoren bzgl. der Cad-Normalen
    int n = m_CadMesh.CountPoints();
    double zLev;
    for (int i=0; i<n; ++i)
    {
        m_MeshStruct[i].normal.Normalize();
        zLev = m_MeshStruct[i].pnt.z + m_Offset[i]*m_MeshStruct[i].normal.z;

        if (zLev>zLim)
            m_Offset[i] = (zLim - m_MeshStruct[i].pnt.z)/m_MeshStruct[i].normal.z;
    }

    return true;
}
*/

bool SpringbackCorrection::Perform(int deg_Tol, bool out)
{
    unsigned int NumRef;
	std::vector<double> dist_vec;

    //GetFaceAng(m_CadMesh, deg_Tol+1);
    //cout << "Init" << endl;
    //Init();      // tesseliere shape -> Basistriangulierung CAD-Mesh
    // EdgeMap wird hier gefüllt

	Base::Vector3f nullvec(0.0,0.0,0.0);
	m_dist_vec.resize(m_CadMesh.CountPoints(), nullvec); // fülle mit Nullvektoren

    cout << "SetFixEdges" << endl;
    
	SetFixEdges();

	const MeshCore::MeshKernel RefMesh23 = m_CadMesh;

    cout << "CalcCurv" << endl;

    if (!CalcCurv())	
	   return false;
	
	// berechne Krümmungswerte über Edgekrümmungen
    // MeshMap wird hier gefüllt

    const MeshCore::MeshKernel RefMesh = m_CadMesh;  // übegebe CAD-Mesh vor der Verformung

    /*Base::Builder3D log;
    Base::Vector3f gpnt, normal;
    int numb = m_CadMesh.CountFacets();

    for (int i=0; i<numb; ++i)
       {
           MeshCore::MeshGeomFacet face = m_CadMesh.GetFacet(i);
           normal = face.GetNormal();


     if(normal.z < 0.0)
      log.saveToFile("c:/didid.iv");

     gpnt = face.GetGravityPoint();
     normal.Scale(10,10,10);
     log.addSingleArrow(gpnt,gpnt+normal);
    }

    log.saveToFile("c:/Facenormals.iv");*/

    // speichere normalen seperat
    m_normals.clear();
    m_normals.resize(m_MeshStruct.size());

    //Base::Builder3D logo;

    for (unsigned int i=0; i<m_normals.size(); ++i)
    {
        m_normals[i] = m_MeshStruct[i].normal;  // Normale am Punkt i der Basistriangulierung
        //logo.addSingleArrow(m_MeshStruct[i].pnt, m_MeshStruct[i].pnt + m_normals[i]);
    }

    //logo.saveToFile("c:/normals.iv");

    // übergebe Normalen und CAD-Mesh für Fehlerberechnng
    best_fit befi;
    befi.m_normals = m_normals;
    befi.m_CadMesh = m_CadMesh;

	m_error.resize(m_CadMesh.CountPoints(), 0.0);

	for(unsigned int i=0; i<m_MeshVec.size(); ++i)
	{
		befi.CompTotalError(m_MeshVec[i]);  // Fehlerberechnung
	}

    // VERSCHIEBUNGSVEKTOREN ...
    // berechnung der skalierungsfaktoren bzgl. der Cad-Normalen
    int n = m_CadMesh.CountPoints();
    for (int i=0; i<n; ++i)
    {
        m_MeshStruct[i].error = befi.m_error[i];

        if (m_MeshStruct[i].error < 0)
        {
            if ((m_MeshStruct[i].maxCurv - m_set.master_radius) < 0.0)
                m_Offset.push_back(0.0);
            else if (-m_MeshStruct[i].error > (m_MeshStruct[i].maxCurv - m_set.master_radius))
                m_Offset.push_back(m_MeshStruct[i].maxCurv - m_set.master_radius);
            else
                m_Offset.push_back(-m_MeshStruct[i].error);
        }
        else
        {
            if ((m_MeshStruct[i].minCurv + m_set.slave_radius) > 0.0)
                m_Offset.push_back(0.0);
            else if (m_MeshStruct[i].error > -(m_MeshStruct[i].minCurv + m_set.slave_radius))
                m_Offset.push_back(m_MeshStruct[i].minCurv + m_set.slave_radius);
            else
                m_Offset.push_back(-m_MeshStruct[i].error);
        }
    }

    //Base::BoundBox3f bbox = m_CadMesh.GetBoundBox();  // hole bounding-box
    //CorrectScale(bbox.MaxZ);                          // korrigiere verschiebungsvektoren...

	//m_set.correction_factor = -0.1;
    // skalierung der Cad-Normalen
    for (int i=0; i<n; ++i)
    {
        m_normals[i].Scale((float) (m_set.correction_factor*m_Offset[i]),
                           (float) (m_set.correction_factor*m_Offset[i]),
                           (float) (m_set.correction_factor*m_Offset[i]));
    }

	for(int i=0; i<m_normals.size(); ++i)
	{
		 m_dist_vec[i] = m_normals[i];
	}

	if(out==true) //hier werden die Outputvektoren für Catia geschrieben
	{
		MeshCore::MeshPointArray mpts = RefMesh23.GetPoints();

		Base::Builder3D loo;
		ofstream anOutputFile;
		anOutputFile.open("c:/catia_offset.txt");
		anOutputFile.precision(7);

		for(int i=0; i< mpts.size(); ++i)
		{
			loo.addSingleArrow(mpts[i], mpts[i] + m_dist_vec[i]);
			anOutputFile <<  mpts[i].x << " " << mpts[i].y << " " << mpts[i].z << " " << m_dist_vec[i].x << " " << m_dist_vec[i].y << " " << m_dist_vec[i].z << endl;
		}

		loo.saveToFile("c:/prpopo.iv");
	    anOutputFile.close();
		return true; //mehr braucne wir auch nicht....
	}



    std::vector<int> tmpVec;
    tmpVec = FaceCheck(m_CadMesh, deg_Tol+1);
	
    NumRef = (int) tmpVec.size();

    MeshCore::MeshPointArray pntAr = m_CadMesh.GetPoints();
    MeshCore::MeshFacetArray facAr = m_CadMesh.GetFacets();

    // Spiegelung
    Base::Builder3D log3d;
    for (int i=0; i<n; ++i)
    {
        log3d.addSingleArrow(pntAr[i], pntAr[i] + m_normals[i]);
        pntAr[i].Set(pntAr[i].x + m_normals[i].x, pntAr[i].y + m_normals[i].y, pntAr[i].z + m_normals[i].z);
    }

    log3d.saveToFile("c:/project2result.iv");

    m_CadMesh.Assign(pntAr, facAr);

    //std::vector<int> tmpVec;
    std::vector<Base::Vector3f> normalsRef = m_normals;
    int cc = 0;



    // ********************************** GLOBALE KORREKTUR ****************************************
    int cm = 49;
    InitFaceCheck(m_CadMesh, deg_Tol+1);  // kritische dreiecke -> _ulProp = 0
    MeshCore::MeshFacetArray facAr2 = m_CadMesh.GetFacets();

    while (true)
    {
        tmpVec = FaceCheck(m_CadMesh, deg_Tol+1);
        cout << "remaining: " << tmpVec.size() << endl;
        if (tmpVec.size() == NumRef || cm == 0)
        {
            cout << cm << "left" << endl;
            break;
        }

        --cm;
        MeshCore::MeshPointArray pntAr2 = RefMesh.GetPoints();

        for (unsigned int i=0; i<pntAr2.size(); ++i)
        {
            m_normals[i].Normalize();
            m_normals[i].Scale((cm*normalsRef[i].Length())/50,(cm*normalsRef[i].Length())/50, (cm*normalsRef[i].Length())/50);
            pntAr2[i].Set(pntAr2[i].x + m_normals[i].x, pntAr2[i].y + m_normals[i].y, pntAr2[i].z + m_normals[i].z);
        }

        m_CadMesh.Assign(pntAr2, facAr2);
    }

	for(int i=0;  i< m_normals.size(); ++i)
	{
		 m_dist_vec[i] += m_normals[i];
	}


	
    // *********************** REGION-GROWING **********************

    MeshCore::MeshFacetArray mFacets = m_CadMesh.GetFacets();
    MeshCore::MeshPointArray mPoints = m_CadMesh.GetPoints();
    int num = mFacets.size();

    for (int i=0; i<num; ++i) mFacets[i].ResetFlag(MeshCore::MeshFacet::VISIT);   // lösche alle VISIT-Flags

    m_RingCurrent = 0;
    std::vector<unsigned long> aRegion;
    std::vector< std::pair<unsigned long, double> > skals;
    std::vector< std::vector< std::pair<unsigned long, double> > > RegionSkals;

	MeshCore::MeshBuilder builder(m_Mesh_vis);
	builder.Initialize(10000);
	MeshCore::MeshBuilder builder2(m_Mesh_vis2);
	builder2.Initialize(10000);

    for (int i=0; i<num; ++i)
    {

        cout << i << " von " << num << endl;
        for (int m=0; m<num; ++m)
        {
            if (mFacets[m]._ulProp == 0)
			{
                mFacets[m].SetFlag(MeshCore::MeshFacet::VISIT);  // kritische faces kriegen ein visit-flag gesetzt
			}
        }

		if (mFacets[i]._ulProp == 0)
		{
				MeshCore::MeshGeomFacet Face(mPoints[mFacets[i]._aulPoints[0]],
								             mPoints[mFacets[i]._aulPoints[1]],
									         mPoints[mFacets[i]._aulPoints[2]]);
			
			    builder.AddFacet(Face);
		}
		else
		{
			    MeshCore::MeshGeomFacet Face2(mPoints[mFacets[i]._aulPoints[0]],
								              mPoints[mFacets[i]._aulPoints[1]],
									          mPoints[mFacets[i]._aulPoints[2]]);
			
			    builder2.AddFacet(Face2);
		}


        m_CadMesh.Assign(mPoints, mFacets);

        cout << "a" << endl;
        if (mFacets[i]._ulProp == 1 && !mFacets[i].IsFlag(MeshCore::MeshFacet::VISIT)) // falls unkritisches facet
            // welches noch nicht einer region zugewiesen wurde
        {

            cout << "b" << endl;
            m_RingVector.clear();
            m_RingVector.push_back(i);
            m_RegionVector.push_back(m_RingVector);
            m_RingVector.clear();

            m_RingCurrent = 0;

            m_CadMesh.VisitNeighbourFacets(*this,i);

            for (unsigned int j=0; j<m_RegionVector.size(); ++j)
            {
                cout << "c" << endl;
                for (unsigned int k=0; k<m_RegionVector[j].size(); ++k)
                {
                    aRegion.push_back(m_RegionVector[j][k]);

                }
            }

			/*Base::Vector3f pnt1(0,0,0);
			Base::Vector3f pnt2(1,0,0);
			Base::Vector3f pnt3(0,1,0);
			
			MeshCore::MeshGeomFacet Face(pnt1,pnt2,pnt3);
			builder.AddFacet(Face);*/

            m_Regions.push_back(aRegion);



            for (int l=0; l<num; ++l)            mFacets[l]._ucFlag = 0;

            cout << "d" << endl;

            for (unsigned int l=0; l<m_Regions.size(); ++l)
                for (unsigned int m=0; m<m_Regions[l].size(); ++m)
                    mFacets[m_Regions[l][m]].SetFlag(MeshCore::MeshFacet::VISIT);

    

            skals = RegionEvaluate(m_CadMesh, aRegion, normalsRef);
            RegionSkals.push_back(skals);
            skals.clear();

            m_RegionVector.clear();
            aRegion.clear();

            cout << "e" << endl;

        }
    }

	builder.Finish();
	builder2.Finish();

    cout << "fast" << endl;

    Base::Builder3D logg;
    double d;

    // stelle die regionen dar

    for (unsigned int i=0; i<RegionSkals.size(); ++i)
    {
        cout << i << endl;
        d = double(i)/double(RegionSkals.size()-1.0);
        cout << d << endl;
        for (unsigned int j=0; j<RegionSkals[i].size(); ++j)
        {

            logg.addSinglePoint((float) mPoints[RegionSkals[i][j].first].x,
                                (float) mPoints[RegionSkals[i][j].first].y,
                                (float) mPoints[RegionSkals[i][j].first].z,3,(float) d,(float) d,(float) d);


        }
    }

    logg.saveToFile("c:/regions.iv");





    /*
       // hole rand der regionen
       MeshCore::MeshRefPointToFacets p2fIt(tmpMesh);

       for(int i=0; i<m_Regions[0].size(); ++i)
       {
        for(int j=0; j<3; ++j)
        {
         std::set<MeshCore::MeshFacetArray::_TConstIterator>& faceSet = p2fIt[m_Regions[0][i]._aulPoints[j]];

                  for (std::set<MeshCore::MeshFacetArray::_TConstIterator>::const_iterator it = faceSet.begin(); it != faceSet.end(); ++it)
         {
          if((*it)[0]._ulProp == 0)
           m_RegionBounds.push_back((*it)[0]);
         }
        }
       }*/



    tmpVec = InitFaceCheck(m_CadMesh, deg_Tol+1);

    cout << " glob: " << tmpVec.size() << endl;

    // ********************************** LOKALE KORREKTUR ****************************************
    unsigned long ind;

    MeshCore::MeshPointArray tmpPnts = m_CadMesh.GetPoints();
    MeshCore::MeshFacetArray tmpFact = m_CadMesh.GetFacets();

    Base::Builder3D logic;
    int cm_ref = 50-cm;

    for (unsigned int i=0; i<RegionSkals.size(); ++i)
    {
        cm = cm_ref;

        while (true)
        {
            tmpVec = FaceCheck(m_CadMesh, deg_Tol+1);
            cout << "remaining: " << tmpVec.size() << endl;

            if (tmpVec.size() > NumRef || cm == 0)
            {
                tmpPnts = m_CadMesh.GetPoints();

                for (unsigned int k=0; k<tmpVec.size(); ++k)
                {
                    for (int l=0; l<3; ++l)
                    {
                        logic.addSinglePoint(tmpPnts[tmpFact[tmpVec[k]]._aulPoints[l]].x,
                                             tmpPnts[tmpFact[tmpVec[k]]._aulPoints[l]].y,
                                             tmpPnts[tmpFact[tmpVec[k]]._aulPoints[l]].z,5,0,0,1);
                    }
                }


                logic.saveToFile("c:/tired.iv");

                for (unsigned int j=0; j<RegionSkals[i].size(); ++j)
                {
                    ind = RegionSkals[i][j].first;
                    m_normals[ind].Normalize();
                    m_normals[ind].Scale(-normalsRef[ind].Length()/50,
                                         -normalsRef[ind].Length()/50,
                                         -normalsRef[ind].Length()/50);

                    tmpPnts[ind].Set(tmpPnts[ind].x + m_normals[ind].x,
                                     tmpPnts[ind].y + m_normals[ind].y,
                                     tmpPnts[ind].z + m_normals[ind].z);


					m_dist_vec[ind] += m_normals[ind];


                }

                m_CadMesh.Assign(tmpPnts, tmpFact);
                break;
            }

            tmpPnts = m_CadMesh.GetPoints();

            for (unsigned int j=0; j<RegionSkals[i].size(); ++j)
            {
                ind = RegionSkals[i][j].first;

                m_normals[ind].Normalize();
                m_normals[ind].Scale((normalsRef[ind].Length())/50,
                                     (normalsRef[ind].Length())/50,
                                     (normalsRef[ind].Length())/50);

                tmpPnts[ind].Set(tmpPnts[ind].x + m_normals[ind].x,
                                 tmpPnts[ind].y + m_normals[ind].y,
                                 tmpPnts[ind].z + m_normals[ind].z);

				m_dist_vec[ind] += m_normals[ind];
            }

            m_CadMesh.Assign(tmpPnts, tmpFact);
            --cm;
        }
    }

    //SmoothMesh(m_CadMesh, 50);
	//SmoothMesh(m_CadMesh, 50);
	/*SmoothMesh(m_CadMesh, 50);
	SmoothMesh(m_CadMesh, 50);
	SmoothMesh(m_CadMesh, 50);
	SmoothMesh(m_CadMesh, 50);
	SmoothMesh(m_CadMesh, 50);
	SmoothMesh(m_CadMesh, 50);*/

//	MeshCore::MeshPointArray mpts = RefMesh23.GetPoints();

	//Base::Builder3D loooo;
	//ofstream anOutputFile;
	//anOutputFile.open("c:/catia_offset.txt");
 //   anOutputFile.precision(7);

	//for(int i=0; i< mpts.size(); ++i)
	//{
	//	loooo.addSingleArrow(mpts[i], mpts[i] + m_dist_vec[i]);
	//	anOutputFile <<  mpts[i].x << " " << mpts[i].y << " " << mpts[i].z << " " << m_dist_vec[i].x << " " << m_dist_vec[i].y << " " << m_dist_vec[i].z << endl;
	//}

	//loooo.saveToFile("c:/prpopo.iv");
	//  anOutputFile.close();




	//anOutputFile << 
	



    return true;
}

std::vector< std::pair<unsigned long, double> > SpringbackCorrection::RegionEvaluate(const MeshCore::MeshKernel &mesh, std::vector<unsigned long> &RegionFacets, std::vector<Base::Vector3f> &normals)
{
    std::list< std::vector  <Base::Vector3f> > Borders;
    std::list< std::vector  <Base::Vector3f> >::iterator bIt;
    std::map <unsigned long, Base::Vector3f> RegionMap;
    std::map <unsigned long, Base::Vector3f>::iterator rIt;
    std::map <double, unsigned long> DistMap;
    std::map <double, unsigned long>::iterator dIt;
    std::pair<unsigned long, Base::Vector3f> Ind2Pnt;
    std::pair<double, unsigned long> Dist2Ind;

    std::vector< std::pair<double, unsigned long> >  dists;
    std::vector< std::pair< unsigned long, double> > skals;

    MeshCore::MeshAlgorithm algo(mesh);  // übergebe mesh
    algo.GetFacetBorders(RegionFacets, Borders); // speichert ränder der region in Borders

    MeshCore::MeshFacetArray facets = mesh.GetFacets();
    MeshCore::MeshPointArray points = mesh.GetPoints();

    // um doppelte indizes zu vermeiden push die punkte der region in eine map
    for (unsigned int i=0; i<RegionFacets.size(); ++i)
    {
        for (int j=0; j<3; ++j)
        {
            Ind2Pnt.first  = facets[RegionFacets[i]]._aulPoints[j];
            Ind2Pnt.second = points[Ind2Pnt.first];

            RegionMap.insert(Ind2Pnt);
        }
		
    }

    // berechne distanzen der regionenpunkte zu den rändern

    Base::Vector3f distVec;   // speichert abstandsvektor
    double distVal;     // speichert maximalen abstandswert zum rand

    for (rIt = RegionMap.begin(); rIt != RegionMap.end(); ++rIt)
    {
        distVal = 1e+3;
        for (bIt = Borders.begin(); bIt != Borders.end(); ++bIt)
        {
            for (unsigned int i=0; i< bIt->size(); ++i)
            {
                distVec =  (*rIt).second - (*bIt).at(i);

                if (distVec.Length() < distVal)
                    distVal = distVec.Length();
            }
        }

        Dist2Ind.first   = distVal;
        Dist2Ind.second  = (*rIt).first;

        dists.push_back(Dist2Ind);
        DistMap.insert(Dist2Ind);
    }

    dIt = DistMap.end();
    --dIt;
    double d_max = (*dIt).first;
    std::pair<unsigned long, double> pair;

    for (unsigned int i=0; i<dists.size(); ++i)
    {
        pair.first  = dists[i].second;

        if (dists[i].first != 0.0)
            pair.second = ( (cos( ((dists[i].first * PI) / d_max) - PI) + 1) / 2);  // 0.5 * [ cos( (dist * PI / dist_max) - PI ) + 1 ]
        else
            pair.second = 0.0;

        skals.push_back(pair);
        normals[pair.first].Scale((float) pair.second, (float) pair.second, (float) pair.second);
    }

    return skals;
}



bool SpringbackCorrection::FacetRegionGrowing(MeshCore::MeshKernel &mesh,
        std::vector<MeshCore::MeshFacet> &FacetRegion,
        MeshCore::MeshFacetArray &mFacets)
{
    MeshCore::MeshRefFacetToFacets ff_It(mesh);

    MeshCore::MeshFacet facet = FacetRegion.back();
    const std::set<unsigned long>& FacetNei = ff_It[facet._ulProp];
    MeshCore::MeshFacetArray::_TConstIterator f_beg = mesh.GetFacets().begin();

    std::set<unsigned long>::const_iterator f_it;
    for (f_it = FacetNei.begin(); f_it != FacetNei.end(); ++f_it)
    {
        if (f_beg[*f_it]._ucFlag == MeshCore::MeshFacet::VISIT)
        {
            FacetRegion.push_back(f_beg[*f_it]);
            mFacets[f_beg[*f_it]._ulProp].SetFlag(MeshCore::MeshFacet::INVALID); // markiere als schon zugewiesen
            FacetRegionGrowing(mesh, FacetRegion, mFacets);
        }
    }

    return true;
}

//
//bool SpringbackCorrection::Init()
//{
// Base::Builder3D log;
// Base::Vector3f  p1,p2;
// double curv;
// // Triangulate Shape (vorläufig)
// best_fit::Tesselate_Shape(m_Shape, m_Mesh, 1);
//
// MeshCurvature(m_Mesh);
//
// std::vector<Base::Vector3f> normals = best_fit::Comp_Normals(m_Mesh);
// MeshCore::MeshPointIterator p_it(m_Mesh);
// int i = 0;
//
// for(p_it.Begin(); p_it.More(); p_it.Next()){
//  normals[i].Scale(m_CurvMax[i], m_CurvMax[i], m_CurvMax[i]);
//  //p1.Set(PointArray[i].x,       PointArray[i].y,       PointArray[i].z);
//  p2.Set(p_it->x + normals[i].x,   p_it->y + normals[i].y,   p_it->z + normals[i].z);
//
//
//  if(m_CurvMax[i] < 100)
//  log.addSingleLine(*p_it, p2, 1 ,0, 0, 0 );
//
//  //cout << p_it->x << ", " << p_it->y << ", " << p_it->z << endl;
//  //cout <<normals[i].x << ", " << normals[i].y << ", " << normals[i].z << endl;
//  //cout << m_CurvMax[i] << endl;
//  ++i;
//
// }
//
// log.saveToFile("c:/servolation.iv");
//}

// return true;
bool SpringbackCorrection::GetCurvature(TopoDS_Face aFace)
{
    Base::Builder3D log;
    Handle_Geom_Surface geom_surface;
    geom_surface = BRep_Tool::Surface(aFace);
    gp_Pnt proPnt;
    double u_par,v_par,k1,k2;
    gp_Vec D1U,D1V,D2U,D2V,D2UV;
    Base::Vector3f p1,p2;

    MeshCore::MeshPointArray PointArray = m_Mesh.GetPoints();
    MeshCore::MeshFacetArray FacetArray = m_Mesh.GetFacets();

    MeshCore::MeshPointIterator p_it(m_Mesh);

    m_CurvMax.resize(PointArray.size());

    for (unsigned int i=0; i<PointArray.size(); ++i)
    {

        proPnt.SetX(PointArray[i].x);
        proPnt.SetY(PointArray[i].y);
        proPnt.SetZ(PointArray[i].z);

        GeomAPI_ProjectPointOnSurf aProjection(proPnt,geom_surface);
        aProjection.LowerDistanceParameters(u_par,v_par);

        // Berechne Krümmung
        geom_surface->D2(u_par,v_par,proPnt,D1U,D1V,D2U,D2V,D2UV);

        // erste & zweite Hauptkrümmung
        k1 = D1U.CrossMagnitude(D2U) / D1U.Magnitude();
        k2 = D1V.CrossMagnitude(D2V) / D1V.Magnitude();

        /*if(k1>k2) PointArray[i].SetProperty(1/k1);
        else      PointArray[i].SetProperty(1/k2);*/

        if (abs(k1)>abs(k2))
        {
            m_CurvMax[i] = 1/k1;
        }
        else
            if (k2!=0)
                m_CurvMax[i] = 1/k2;
            else
                m_CurvMax[i] = 100;


        D1U.Cross(D1V);
        D1U.Normalize();
        D1U.Scale(m_CurvMax[i]);

        p1.x = (float) (proPnt.X() + D1U.X());
        p1.y = (float) (proPnt.Y() + D1U.Y());
        p1.z = (float) (proPnt.Z() + D1U.Z());

        p2.x = (float) proPnt.X();
        p2.y = (float) proPnt.Y();
        p2.z = (float) proPnt.Z();

        log.addSingleLine(p2, p1, 1 ,0, 0, 0 );
    }


    MeshCore::MeshPointIterator v_it(m_Mesh);
    MeshCore::MeshRefPointToPoints vv_it(m_Mesh);
    MeshCore::MeshPointArray::_TConstIterator v_beg = m_Mesh.GetPoints().begin();
    std::set<unsigned long> PntNei;
    std::set<unsigned long> PntNei2;
    std::set<unsigned long> PntNei3;
    std::set<unsigned long> PntNei4;
    std::set<unsigned long>::iterator pnt_it1;
    std::set<unsigned long>::iterator pnt_it2;
    std::set<unsigned long>::iterator pnt_it3;
    std::set<unsigned long>::iterator pnt_it4;
    std::vector<unsigned long> nei;
    double curv;

    std::vector<double> CurvCop = m_CurvMax;

    for (v_it.Begin(); v_it.More(); v_it.Next())
    {
        PntNei = vv_it[v_it.Position()];
        curv = m_CurvMax[v_it.Position()];

        for (pnt_it1 = PntNei.begin(); pnt_it1 !=PntNei.end(); ++pnt_it1)
        {
            if (m_CurvMax[v_beg[*pnt_it1]._ulProp] < curv)
                curv = m_CurvMax[v_beg[*pnt_it1]._ulProp];

            PntNei2 = vv_it[v_beg[*pnt_it1]._ulProp];
            for (pnt_it2 = PntNei2.begin(); pnt_it2 !=PntNei2.end(); ++pnt_it2)
            {
                if (m_CurvMax[v_beg[*pnt_it2]._ulProp] < curv)
                    curv = m_CurvMax[v_beg[*pnt_it2]._ulProp];


                PntNei3 = vv_it[v_beg[*pnt_it2]._ulProp];
                for (pnt_it3 = PntNei3.begin(); pnt_it3 !=PntNei3.end(); ++pnt_it3)
                {
                    if (m_CurvMax[v_beg[*pnt_it3]._ulProp] < curv)
                        curv = m_CurvMax[v_beg[*pnt_it3]._ulProp];

                    PntNei4 = vv_it[v_beg[*pnt_it3]._ulProp];
                    for (pnt_it4 = PntNei4.begin(); pnt_it4 !=PntNei4.end(); ++pnt_it4)
                    {
                        if (m_CurvMax[v_beg[*pnt_it4]._ulProp] < curv)
                            curv = m_CurvMax[v_beg[*pnt_it4]._ulProp];
                    }
                }
            }
        }

        CurvCop[v_it.Position()] = curv;
    }

    m_CurvMax = CurvCop;


    return true;
}


// 1. Computes the curvature of the mesh at the verticies
// 2. Stores the minimum curvatures along the neighbours for all verticies in a vector
std::vector<double> SpringbackCorrection::MeshCurvature(const TopoDS_Face& aFace, const MeshCore::MeshKernel& mesh)
{

	TopLoc_Location aLocation;
    Handle_Poly_Triangulation aTr = BRep_Tool::Triangulation(aFace,aLocation);
	const TColgp_Array1OfPnt2d& aUVNodes = aTr->UVNodes();
	int n = aUVNodes.Length();
	BRepAdaptor_Surface aSurface(aFace);
    
    gp_Pnt2d par;
    gp_Pnt P;
    gp_Vec D1U, D1V, D2U, D2V, D2UV, nor, xvv, xuv, xuu;
	double H,K;   // Gaußsche- und mittlere Krümmung

	std::vector<double> aMaxCurve, aMinCurve;
	std::vector<double> curv(2);
    
	for (int i=0; i<n; ++i)
    {
        par = aUVNodes.Value(i+1);
		aSurface.D2(par.X(),par.Y(),P,D1U,D1V,D2U,D2V,D2UV);

		//berechne Hilfsnormale
		nor = D1U;
		nor.Cross(D1V);
		nor.Normalize();

		xvv = D2V;
		xuv = D2UV;
		xuu = D2U;

		xvv.Multiply(D1U*D1U);
		xuv.Multiply(2*(D1U*D1V));
		xuu.Multiply(D1V*D1V);

		H = ((xvv - xuv + xuu)*nor);
		H /= 2*((D1U*D1U)*(D1V*D1V) - (D1U*D1V)*(D1U*D1V));
		K = ((nor*D2U)*(nor*D2V) - (nor*D2UV)*(nor*D2UV))/((D1U*D1U)*(D1V*D1V) - (D1U*D1V)*(D1U*D1V));


		aMaxCurve.push_back(-(H - sqrt(H*H - K)));
		aMinCurve.push_back(-(H + sqrt(H*H - K)));

	}
		
		
		
	double maxCurv = 0.0;
	double avgCurv = 0.0;
	double tmp1 =  1e+10;
	double tmp2 = -1e+10;

	double mean_curvMax = 0.0, mean_curvMin = 0.0;
    int c1 = 0, c2 = 0;

	m_CurvPos.clear();
	m_CurvNeg.clear();
	m_CurvMax.clear();
	m_CurvPos.resize(mesh.CountPoints());
	m_CurvNeg.resize(mesh.CountPoints());
	m_CurvMax.resize(mesh.CountPoints());

	for ( unsigned long i=0; i<n; i++ )
	{
		if (aMaxCurve[i] > 0) m_CurvPos[i] = 1 / aMaxCurve[i];
		else                  m_CurvPos[i] = 1e+10;

		if (aMinCurve[i] < 0) m_CurvNeg[i] = 1 / aMinCurve[i];
		else                  m_CurvNeg[i] = -1e+10;

		if (m_CurvPos[i] < tmp1)
			tmp1 = m_CurvPos[i];

		if (m_CurvNeg[i] > tmp2)
			tmp2 = m_CurvNeg[i];

		if (aMaxCurve[i] > 0)
		{
			++c1;
			mean_curvMax += 1/aMaxCurve[i];
		}

		if (aMinCurve[i] < 0)
		{
			++c2;
			mean_curvMin += 1/aMinCurve[i];
		}
	}

	if (c1==0)
		mean_curvMax = 1e+3;
	else
		mean_curvMax /= mesh.CountPoints();

	if (c2==0)
		mean_curvMin = -1e+3;
	else
		mean_curvMin /= mesh.CountPoints();

	curv[0] = tmp1;
	curv[1] = tmp2;
	

	
	
	//Krümmung auf Netzbasis
	
	for(int i=0; i<n; ++i)
	{

		// get all points
	    
		//MeshCore::MeshKernel& rMesh = mesh;
		std::vector< Wm4::Vector3<float> > aPnts;
		std::vector<Base::Vector3f> aPnts_tmp;
		MeshCore::MeshPointIterator cPIt( mesh );
		for ( cPIt.Init(); cPIt.More(); cPIt.Next() )
		{
			Wm4::Vector3<float> cP( cPIt->x, cPIt->y, cPIt->z );
			Base::Vector3f cP_tmp( cPIt->x, cPIt->y, cPIt->z );
			aPnts.push_back( cP );
			aPnts_tmp.push_back(cP_tmp);
		}

		// get all point connections
		std::vector<int> anIdx;
		const std::vector<MeshCore::MeshFacet>& MeshFacetArray = mesh.GetFacets();
		for ( std::vector<MeshCore::MeshFacet>::const_iterator jt = MeshFacetArray.begin(); jt != MeshFacetArray.end(); ++jt )
		{
			for (int i=0; i<3; i++)
			{
				anIdx.push_back( (int)jt->_aulPoints[i] );
			}
		}

		// compute vertex based curvatures
		Wm4::MeshCurvature<float> meshCurv(mesh.CountPoints(), &(aPnts[0]), mesh.CountFacets(), &(anIdx[0]));

		// get curvature information now
		const Wm4::Vector3<float>* aMaxCurvDir = meshCurv.GetMaxDirections();
		const Wm4::Vector3<float>* aMinCurvDir = meshCurv.GetMinDirections();
		const float* aMaxCurv = meshCurv.GetMaxCurvatures();
		const float* aMinCurv = meshCurv.GetMinCurvatures();

		double maxCurv = 0.0;
		double avgCurv = 0.0;
		double tmp1 =  1e+10;
		double tmp2 = -1e+10;

		double mean_curvMax = 0.0, mean_curvMin = 0.0;
		int c1 = 0, c2 = 0;

		m_CurvPos.clear();
		m_CurvNeg.clear();
		m_CurvMax.clear();
		m_CurvPos.resize(mesh.CountPoints());
		m_CurvNeg.resize(mesh.CountPoints());
		m_CurvMax.resize(mesh.CountPoints());

		for ( unsigned long i=0; i<mesh.CountPoints(); i++ )
		{

			if (aMaxCurv[i] > 0) m_CurvPos[i] = 1 / aMaxCurv[i];
			else                 m_CurvPos[i] = 1e+10;

			if (aMinCurv[i] < 0) m_CurvNeg[i] = 1 / aMinCurv[i];
			else                 m_CurvNeg[i] = -1e+10;

			if (m_CurvPos[i] < tmp1)
				tmp1 = m_CurvPos[i];

			if (m_CurvNeg[i] > tmp2)
				tmp2 = m_CurvNeg[i];

			if (aMaxCurv[i] > 0)
			{
				++c1;
				mean_curvMax += 1/aMaxCurv[i];
			}

			if (aMinCurv[i] < 0)
			{
				++c2;
				mean_curvMin += 1/aMinCurv[i];
			}
		}

		if (c1==0)
			mean_curvMax = 1e+3;
		else
			mean_curvMax /= mesh.CountPoints();

		if (c2==0)
			mean_curvMin = -1e+3;
		else
			mean_curvMin /= mesh.CountPoints();

		curv[0] = tmp1;
		curv[1] = tmp2;
	}
	

    return curv;
}

/*
bool SpringbackCorrection::MirrorMesh(std::vector<double> error)
{
    // Flags: 0 - not yet checked
    //       1 - no correction applied, but neccessary
    //        2 - first correction applied and still neccessary
    //        3 - done successfully
    //        4 - done without success
    //        5 - boundary point

    int n = error.size();
    m_error = error;

    std::vector<int> InterPnts;
    std::vector<unsigned long> InterFace;
    std::vector<unsigned long> IFCopy;

    bool boo = true;

    std::vector<unsigned long> ind;
    std::vector<unsigned long> copy;

    MeshRef = m_Mesh;
    std::vector<Base::Vector3f> NormalsRef = m_normals;
    std::vector<Base::Vector3f> NormalOrig = m_normals;

    PointArray = MeshRef.GetPoints();
    MeshCore::MeshPointArray PntArray   = m_Mesh.GetPoints();
    MeshCore::MeshFacetArray FctArray   = m_Mesh.GetFacets();
    MeshCore::MeshFacetArray FacetArray = MeshRef.GetFacets();

    MeshCore::MeshFacetIterator f_it(MeshRef);
    MeshCore::MeshPointIterator v_it(MeshRef);
    MeshCore::MeshRefPointToPoints vv_it(MeshRef);
    MeshCore::MeshRefPointToFacets vf_it(MeshRef);

    std::set<MeshCore::MeshPointArray::_TConstIterator> PntNei;
    std::set<MeshCore::MeshFacetArray::_TConstIterator> FacetNei;

    // Iterates in facets in form of MeshGeomFacets
    std::set<MeshCore::MeshFacetArray::_TConstIterator>::iterator face_it;
    std::set<MeshCore::MeshPointArray::_TConstIterator>::iterator pnt_it;

    std::vector<Base::Vector3f> NeiLoc;
    std::vector<Base::Vector3f> NorLoc;
    std::vector<Base::Vector3f> TmpPntVec;
    std::vector<unsigned long>  TmpIndVec;
    std::vector<unsigned long>  nei;

    bool k=true;
    int count = 0;

    while (k==true)
    {
        // ------ Self-Intersection Check + Correction ------------------------------------------------------

        if (count ==2) break;
        count++;

        Base::Builder3D log3d;
        Base::Builder3D loga;
        Base::Vector3f Pnt, NeiPnt, NeiPntNext, NeiPntPrev, TmpPnt, TmpNor;

        std::vector<Base::Vector3f> Neis;
        double minScale, tmp;
        bool sign;

        ublas::matrix<double> A(3, 3);
        ublas::matrix<double> b(1, 3);

        ind.clear();
        for (unsigned int i=0; i<m_Mesh.CountPoints(); ++i)
            ind.push_back(i);


        // do correction for selected points ---------------------------------
        for (unsigned int j=0; j<ind.size(); ++j)
        {
            sign = (error[ind[j]] > 0);  // (+) -> true , (-) -> false

            MeshRef.Assign(PointArray, FacetArray);

            v_it.Set(ind[j]);

            Pnt      = *v_it;
            PntNei   = vv_it[ind[j]];
            FacetNei = vf_it[ind[j]];

            nei.clear();

            // falls boundary-point tue nichts bzw. gehe zum nächsten punkt
            if (FacetNei.size() != PntNei.size())
            {
                PointArray[ind[j]]._ucFlag = 5;
                m_CurvMax[ind[j]] = abs(error[ind[j]]);   // vorübergehend
                continue;
            }

            // ordne nachbarn
            ReorderNeighbourList(PntNei,FacetNei,nei,ind[j]);

            NeiLoc.clear();
            NorLoc.clear();
            NeiLoc.push_back(Pnt);
            NorLoc.push_back(NormalsRef[ind[j]]);

            for (unsigned int r=0; r<nei.size(); ++r)
            {
                v_it.Set(nei[r]);
                NeiLoc.push_back(*v_it);
                NorLoc.push_back(NormalsRef[nei[r]]);
            }


            if (count == 2)
            {
                if (sign ==true) minScale = -(1e+10);
                else      minScale =   1e+10;
                minScale = LocalCorrection(NeiLoc,NorLoc,sign,minScale);

                if ((abs(0.8*minScale) - abs(error[ind[j]])) > 0)
                {
                    PointArray[ind[j]]._ucFlag = 3;
                    m_CurvMax[ind[j]] = abs(minScale);
                    //cout << "t, ";
                    continue;
                }
                else
                {
                    PointArray[ind[j]]._ucFlag = 4;
                    m_CurvMax[ind[j]] = abs(minScale);
                    cout << "f, ";
                    continue;
                }
            }


            if (sign ==true) minScale = -(1e+10);
            else      minScale =   1e+10;

            minScale = LocalCorrection(NeiLoc,NorLoc,sign,minScale);

            if ((abs(0.8*minScale) - abs(error[ind[j]])) > 0)
            {
                PointArray[ind[j]]._ucFlag = 3;
                m_CurvMax[ind[j]] = abs(minScale);
                continue;
            }

            //---------------------------- 1. Korrektur -------------------------
            tmp = 0;
            std::vector<Base::Vector3f> ConvComb = FillConvex(NeiLoc,NorLoc,20);

            for (unsigned int l=0; l<ConvComb.size(); ++l)
            {
                if (sign ==true) minScale = -(1e+10);
                else      minScale =   1e+10;

                NeiLoc[0] = ConvComb[l];
                minScale = LocalCorrection(NeiLoc,NorLoc,sign,minScale);

                if (abs(minScale) > abs(tmp))
                {
                    tmp = minScale;
                    TmpPnt = NeiLoc[0];
                }
            }

            NeiLoc[0] = PointArray[ind[j]];
            cout << "new minScale: " << tmp << endl;

            if ((abs(0.8*tmp) - abs(error[ind[j]])) > 0)
            {
                PointArray[ind[j]].Set(TmpPnt.x, TmpPnt.y, TmpPnt.z);
                PointArray[ind[j]]._ucFlag = 3;
                m_CurvMax[ind[j]] = abs(tmp);
                continue;
            }
            else
            {
                PointArray[ind[j]]._ucFlag = 2;
                m_CurvMax[ind[j]] = abs(tmp);
            }

            //------------------------------- END -------------------------------

            // update
            for (unsigned int r=0; r<nei.size(); ++r)
            {
                v_it.Set(nei[r]);
                NeiLoc[r+1] = *v_it;
            }

            MeshRef.Assign(PointArray, FacetArray);

            //---------------------------- 2. Korrektur -------------------------
            tmp = GlobalCorrection(NeiLoc,NorLoc,sign,ind[j]);

            //MeshRef.Assign(PointArray, FacetArray);
            //m_Mesh = MeshRef;
            //return true;

            cout << "2: " << tmp << endl;

            if ((abs(0.8*tmp) - abs(error[ind[j]])) > 0)
            {
                PointArray[ind[j]].Set(NeiLoc[0].x, NeiLoc[0].y, NeiLoc[0].z);
                NormalsRef[ind[j]].Set(NorLoc[0].x, NorLoc[0].y, NorLoc[0].z);
                PointArray[ind[j]]._ucFlag = 3;
                m_CurvMax[ind[j]] = abs(tmp);
                continue;
            }
            else
            {
                if (m_CurvMax[ind[j]] < abs(tmp))
                {
                    m_CurvMax[ind[j]] = abs(tmp);
                    PointArray[ind[j]].Set(NeiLoc[0].x, NeiLoc[0].y, NeiLoc[0].z);
                    NormalsRef[ind[j]].Set(NorLoc[0].x, NorLoc[0].y, NorLoc[0].z);
                }
                // flag bleibt 2
            }

            //------------------------------- END -------------------------------

        } // end for

        cout << "Replace Mesh..." << endl;
        PntArray   = PointArray;
        m_normals  = NormalsRef;
        m_Mesh = MeshRef;

    } // end while


    double ver, mx=100;
    for (unsigned int i=0; i<error.size(); ++i)
    {
        ver = m_CurvMax[i] / abs(error[i]);
        if (ver < mx)
            mx = ver;
    }

    //cout << "skalierung: " << mx << endl;
    //for(int i=0; i<error.size(); ++i)
    //error[i] *= mx;



    // deform CAD-Mesh with regard to the scaled normals
    MeshCore::MeshPointIterator p_it(m_Mesh);
    Base::Builder3D log,log2;
    std::vector<int> IndexVec,NumVec, NumVecCopy;
    int c, lastNum, lastInd;

    // kritische punkte plus anzahl seiner kritischen nachbarn speichern
    //ind.clear();
    for (unsigned int j=0; j<ind.size(); ++j)
    {
        if (PointArray[ind[j]]._ucFlag == 3 || PointArray[ind[j]]._ucFlag == 5)
        {
            //ind.push_back(ind[j]);
            continue;
        }
        else
        {
            c=0;
            PntNei = vv_it[ind[j]];
            for (pnt_it = PntNei.begin(); pnt_it != PntNei.end(); ++pnt_it)
            {
                if (PointArray[(*pnt_it)->_ulProp]._ucFlag == 4)
                    c++;
            }

            IndexVec.push_back(ind[j]);
            NumVec.push_back(c);
        }
    }

    // normalenskalierung
    for (unsigned int j=0; j<ind.size(); ++j)
    {
        if ( ( abs(0.8*m_CurvMax[ind[j]]) - abs(error[ind[j]]) ) < 0)
        {
            if (error[ind[j]] < 0)
                m_normals[ind[j]].Scale((float) (0.8*m_CurvMax[ind[j]]),(float) (0.8*m_CurvMax[ind[j]]),(float) (0.8*m_CurvMax[ind[j]]));
            else
                m_normals[ind[j]].Scale((float) (-0.8*m_CurvMax[ind[j]]),(float) (-0.8*m_CurvMax[ind[j]]), (float) (-0.8*m_CurvMax[ind[j]]));
        }
        else
            m_normals[ind[j]].Scale((float) -error[ind[j]],(float)  -error[ind[j]],(float)  -error[ind[j]]);
    }


    for (unsigned int j=0; j<ind.size(); ++j)
    {
        log.addSingleLine(PointArray[ind[j]],PointArray[ind[j]] + m_normals[ind[j]],2,1,1,1);  // white arrows
        PntArray[ind[j]].Set(PntArray[ind[j]].x + m_normals[ind[j]].x,
                             PntArray[ind[j]].y + m_normals[ind[j]].y,
                             PntArray[ind[j]].z + m_normals[ind[j]].z);
    }

    m_Mesh.Assign(PntArray, FctArray);
    MeshRef = m_Mesh;
    log.saveToFile("c:/deformation.iv");


    // kritische punkte nach der anzahl seiner kritischen nachbarn sortieren
    NumVecCopy = NumVec;
    std::vector<int> SortNumVec(NumVec.size(), -1);
    std::vector<int> SortIndVec(NumVec.size(), -1);
    cout << NumVec.size() << endl;

    //cout << "vor dem sortieren: ";
    //for(int j=0; j<NumVec.size(); ++j)
    //{
    //cout << NumVec[j] << ", ";
    //}
    //cout << endl;

    for (unsigned int j=0; j<NumVecCopy.size(); ++j)
    {

        lastNum = NumVec.back();
        lastInd = IndexVec.back();

        NumVec.pop_back();
        IndexVec.pop_back();

        c=0;
        for (unsigned int i=0; i<NumVecCopy.size(); ++i)
        {
            if (NumVecCopy[i] < lastNum)
                ++c;
        }

        while (SortNumVec[c] == lastNum)
            ++c;

        SortNumVec[c] = lastNum;
        SortIndVec[c] = lastInd;
    }

    //cout << "danach: ";
    //for(int j=0; j<SortNumVec.size(); ++j)
    //{
    //cout << SortNumVec[j] << ", ";
    //}
    //cout << endl;

    NeiLoc.clear();
    NorLoc.clear();

    Base::Builder3D log1;

    MeshCore::MeshKernel mesh;
    MeshCore::MeshPoint mpnt;
    MeshCore::MeshPointArray mPointArray;
    MeshCore::MeshFacetArray mFacetArray;

    float w;

    for (unsigned int j=0; j<SortIndVec.size(); ++j)
    {
        Base::Vector3f bvec(0.0, 0.0, 0.0);
        NeiLoc.clear();
        NeiLoc.push_back(bvec);

        PntNei = vv_it[SortIndVec[j]];
        FacetNei = vf_it[SortIndVec[j]];
        nei.clear();

        // ordne nachbarn
        ReorderNeighbourList(PntNei,FacetNei,nei,SortIndVec[j]);

        mPointArray.clear();
        for (unsigned int i=0; i<nei.size(); ++i)
        {
            mpnt = PntArray[nei[i]];
            mPointArray.push_back(mpnt);
            //!!!!!!!!!!!!!!!!! NeiLoc.size() must be greater than 3!!!!!!!!!!!!!!!
            if (PntArray[nei[i]]._ucFlag != 4)
            {
                NeiLoc.push_back(PntArray[nei[i]]);
                log1.addSinglePoint(PntArray[nei[i]].x, PntArray[nei[i]].y, PntArray[nei[i]].z, 2,1,1,1);
                mPointArray.push_back(mpnt);
            }
            else
            {
                bvec += PntArray[nei[i]];
                log1.addSinglePoint(PntArray[nei[i]].x, PntArray[nei[i]].y, PntArray[nei[i]].z, 2,1,0,0);
            }
        }

        log1.saveToFile("c:/nachbarn.iv");

        mesh.Assign(mPointArray, mFacetArray);

        // need at least one facet to perform the PCA
        MeshCore::MeshGeomFacet face;
        mesh.AddFacet(face);

        // berechne hauptachsen
        MeshCore::MeshEigensystem pca(mesh);
        pca.Evaluate();
        Base::Matrix4D T1 = pca.Transform();
        std::vector<Base::Vector3f> v(3);

        v[0].x = (float) T1[0][0];
        v[0].y = (float) T1[0][1];
        v[0].z = (float) T1[0][2];
        v[1].x = (float) T1[1][0];
        v[1].y = (float) T1[1][1];
        v[1].z = (float) T1[1][2];
        v[2].x = (float) T1[2][0];
        v[2].y = (float) T1[2][1];
        v[2].z = (float) T1[2][2];

        v[0].Normalize();
        v[1].Normalize();
        v[2].Normalize();

        double deg,temp=0;
        int s;

        for (int i=0; i<3; ++i)
        {
            deg = v[i]*NormalOrig[SortIndVec[j]];
            if (abs(deg)>temp)
            {
                temp = abs(deg);
                s=i;
            }
        }

        if (v[s].z < 0.0)
            v[s] *= -1;

        for (unsigned int i=0; i<NeiLoc.size(); ++i)
            NorLoc.push_back(v[s]);

        // gewichtung (im verhältnis 1:2)
        w = float(1.0) /(float(NeiLoc.size()) + float(PntNei.size()) - float(1.0));
        bvec.Scale(w,w,w);

        for (unsigned int i=1; i<NeiLoc.size(); ++i)
        {
            bvec.x = bvec.x + 2*w*NeiLoc[i].x;
            bvec.y = bvec.y + 2*w*NeiLoc[i].y;
            bvec.z = bvec.z + 2*w*NeiLoc[i].z;
        }

        NeiLoc[0] = bvec;
        log1.addSinglePoint(NeiLoc[0],2,0,1,0);
        std::vector<Base::Vector3f> Convs = FillConvex(NeiLoc, NorLoc, 20);

        for (unsigned int i=0; i<Convs.size(); ++i)
            log1.addSinglePoint(Convs[i],2,0,0,0);

        log1.saveToFile("c:/nachbarn.iv");

        PntArray[SortIndVec[j]].Set(Convs[0].x, Convs[0].y, Convs[0].z);
        PntArray[SortIndVec[j]]._ucFlag = 3;

    }

    m_Mesh.Assign(PntArray, FctArray);

    return true;


    for (p_it.Begin(); p_it.More(); p_it.Next())
    {
        if (PointArray[p_it.Position()]._ucFlag == 3)
        {
            log.addSingleLine(*p_it,*p_it + m_normals[p_it.Position()],2,1,1,1);  // red arrows
            PntArray[p_it.Position()].Set(PntArray[p_it.Position()].x + m_normals[p_it.Position()].x,
                                          PntArray[p_it.Position()].y + m_normals[p_it.Position()].y,
                                          PntArray[p_it.Position()].z + m_normals[p_it.Position()].z);
        }

        if (PointArray[p_it.Position()]._ucFlag == 4)
        {
            log.addSingleLine(*p_it,*p_it + m_normals[p_it.Position()],2,1,0,0);  // red arrows
            PntArray[p_it.Position()].Set(PntArray[p_it.Position()].x + m_normals[p_it.Position()].x,
                                          PntArray[p_it.Position()].y + m_normals[p_it.Position()].y,
                                          PntArray[p_it.Position()].z + m_normals[p_it.Position()].z);
        }
    }

    m_Mesh.Assign(PntArray, FctArray);
    log.saveToFile("c:/deformation.iv");

    return true;
}
*/

/*
double SpringbackCorrection::LocalCorrection(std::vector<Base::Vector3f> Neib ,
        std::vector<Base::Vector3f> Normal, bool sign, double minScale)
{
    Base::Vector3f Pnt, NeiPnt, NeiPntNext, NeiPntPrev;

    ublas::matrix<double> A(3, 3);
    ublas::matrix<double> b(1, 3);

    // 2. Spalte bleibt unverändert
    A(0,2) = -Normal[0].x;
    A(1,2) = -Normal[0].y;
    A(2,2) = -Normal[0].z;

    // forward
    for (unsigned int k=1; k<Neib.size(); ++k)
    {
        NeiPnt = Neib[k];

        if ((k+1) == Neib.size())
        {
            NeiPntNext = Neib[1];
        }
        else
        {
            NeiPntNext = Neib[k+1];
        }

        A(0,2) = -Normal[0].x;
        A(0,0) = Normal[k].x;
        A(0,1) = (NeiPntNext.x - NeiPnt.x);
        A(1,2) = -Normal[0].y;
        A(1,0) = Normal[k].y;
        A(1,1) = (NeiPntNext.y - NeiPnt.y);
        A(2,2) = -Normal[0].z;
        A(2,0) = Normal[k].z;
        A(2,1) = (NeiPntNext.z - NeiPnt.z);

        b(0,0) = Neib[0].x - NeiPnt.x;
        b(0,1) = Neib[0].y - NeiPnt.y;
        b(0,2) = Neib[0].z - NeiPnt.z;

        //cout << "A-Matrix: " << endl;
        //cout << A(0,0) << ", " << A(0,1) << ", " << A(0,2) << endl;
        //cout << A(1,0) << ", " << A(1,1) << ", " << A(1,2) << endl;
        //cout << A(2,0) << ", " << A(2,1) << ", " << A(2,2) << endl;
        //cout << endl;

        //cout << "b-Vector: " << endl;
        //cout << b(0,0) << ", " << b(0,1) << ", " << b(0,2) << endl;
        //cout << endl;

        atlas::gesv(A,b);

        //cout << "solution: " << endl;
        //cout << b(0,0) << ", " << b(0,1) << ", " << b(0,2) << endl;
        //cout << endl;

        if ((b(0,2)<=0) && (sign == true) && (b(0,1)>=0) && (b(0,1)<=1))
        {
            if (minScale < b(0,2))
                minScale = b(0,2);
        }
        else if (b(0,2)>=0 && sign == false && (b(0,1)>=0) && (b(0,1)<=1))
        {
            if (minScale > b(0,2))
                minScale = b(0,2);
        }
    }

    // backward
    for (unsigned int k=1; k<Neib.size(); ++k)
    {
        NeiPnt = Neib[k];

        if (k == 1)
        {
            NeiPntPrev = Neib[Neib.size()-1];
        }
        else
        {
            NeiPntPrev = Neib[k-1];
        }

        A(0,2) = -Normal[0].x;
        A(0,0) = Normal[k].x;
        A(0,1) = (NeiPntPrev.x - NeiPnt.x);
        A(1,2) = -Normal[0].y;
        A(1,0) = Normal[k].y;
        A(1,1) = (NeiPntPrev.y - NeiPnt.y);
        A(2,2) = -Normal[0].z;
        A(2,0) = Normal[k].z;
        A(2,1) = (NeiPntPrev.z - NeiPnt.z);

        b(0,0) = Neib[0].x - NeiPnt.x;
        b(0,1) = Neib[0].y - NeiPnt.y;
        b(0,2) = Neib[0].z - NeiPnt.z;

        //cout << "A-Matrix: " << endl;
        //cout << A(0,0) << ", " << A(0,1) << ", " << A(0,2) << endl;
        //cout << A(1,0) << ", " << A(1,1) << ", " << A(1,2) << endl;
        //cout << A(2,0) << ", " << A(2,1) << ", " << A(2,2) << endl;
        //cout << endl;

        //cout << "b-Vector: " << endl;
        //cout << b(0,0) << ", " << b(0,1) << ", " << b(0,2) << endl;
        //cout << endl;

        atlas::gesv(A,b);

        //cout << "solution: " << endl;
        //cout << b(0,0) << ", " << b(0,1) << ", " << b(0,2) << endl;
        //cout << endl;

        if (b(0,2)<0 && sign == true && (b(0,1)>=0) && (b(0,1)<=1))
        {
            if (minScale < b(0,2))
                minScale = b(0,2);
        }
        else if (b(0,2)>0 && sign == false && (b(0,1)>=0) && (b(0,1)<=1))
        {
            if (minScale > b(0,2))
                minScale = b(0,2);
        }
    }

    return minScale;
}
*/

/*
std::vector<Base::Vector3f> SpringbackCorrection::FillConvex(std::vector<Base::Vector3f> Neib, std::vector<Base::Vector3f> Normals, int n)
{
    std::vector<Base::Vector3f> ConvComb;
    Base::Vector3f tmp;
    for (unsigned int i=1; i<Neib.size(); ++i)
    {
        for (int j=0; j<n; ++j)
        {
            //cout << "t, " ;
            tmp = Neib[i] - Neib[0];
            tmp.Scale(float(j)/float(n), float(j)/float(n), float(j)/float(n));
            if (InsideCheck(Neib[0] + tmp, Normals[0], Neib) == true)
                ConvComb.push_back(Neib[0] + tmp);
            else;
            //cout << "f, " ;
        }
    }
    cout << endl;
    return ConvComb;
}
*/

/*
bool SpringbackCorrection::InsideCheck(Base::Vector3f pnt, Base::Vector3f normal, std::vector<Base::Vector3f> Neib)
{
    Base::Vector3f Pnt, NeiPnt, NeiPntNext, Cross;

    ublas::matrix<double> A(3, 3);
    ublas::matrix<double> b(1, 3);

    bool b1 = true, b2;

    for (unsigned int k=1; k<Neib.size(); ++k)
    {
        NeiPnt = Neib[k];

        if ((k+1) == Neib.size())
        {
            NeiPntNext = Neib[1];
        }
        else
        {
            NeiPntNext = Neib[k+1];
        }

        Cross = normal%(NeiPntNext - NeiPnt);

        A(0,0) = normal.x;
        A(0,1) = (NeiPntNext.x - NeiPnt.x);
        A(0,2) = -Cross.x;
        A(1,0) = normal.y;
        A(1,1) = (NeiPntNext.y - NeiPnt.y);
        A(1,2) = -Cross.y;
        A(2,0) = normal.z;
        A(2,1) = (NeiPntNext.z - NeiPnt.z);
        A(2,2) = -Cross.z;

        b(0,0) = pnt.x - NeiPnt.x;
        b(0,1) = pnt.y - NeiPnt.y;
        b(0,2) = pnt.z - NeiPnt.z;

        atlas::gesv(A,b);

        if (b1==true)
        {
            if ( b(0,2) < 0)
            {
                b1 = false;
                b2 = true;
            }
            else if (b(0,2)>0)
            {
                b1 = false;
                b2 = false;
            }
        }

        if (b1==false)
        {
            if ((b2 == true)  && (b(0,2) > 0)) return false;
            if ((b2 == false) && (b(0,2) < 0)) return false;
        }
    }
    return true;
}
*/

/*
double SpringbackCorrection::GlobalCorrection(std::vector<Base::Vector3f> NeiLoc, std::vector<Base::Vector3f> NorLoc,
        bool sign, int ind)
{
    double minScale,mScRef,tmp = 0;
    Base::Vector3f TmpPnt, TmpNor;

    if (sign ==true) mScRef = -(1e+10);
    else      mScRef =   1e+10;

    minScale = mScRef;
    minScale = LocalCorrection(NeiLoc,NorLoc,sign,minScale);

    if ((abs(0.8*minScale) - abs(m_error[ind])) > 0)
    {
        PointArray[ind]._ucFlag = 3;
        m_CurvMax[ind] = abs(minScale);
        return minScale;
    }

    std::vector<Base::Vector3f> ConvComb = FillConvex(NeiLoc,NorLoc,20);

    // füge schwerpunkte der umgebenden faces hinzu
    std::set<MeshCore::MeshFacetArray::_TConstIterator> FacetNei;
    std::set<MeshCore::MeshFacetArray::_TConstIterator>::iterator face_it;
    MeshCore::MeshFacetIterator    f_it (MeshRef);
    MeshCore::MeshRefPointToFacets vf_it(MeshRef);

    FacetNei = vf_it[ind];

    for (face_it = FacetNei.begin(); face_it != FacetNei.end(); ++face_it)
    {
        TmpPnt.Set(0.0, 0.0, 0.0);
        TmpPnt += PointArray[(*face_it)->_aulPoints[0]];
        TmpPnt += PointArray[(*face_it)->_aulPoints[1]];
        TmpPnt += PointArray[(*face_it)->_aulPoints[2]];
        TmpPnt.Scale((float) (1.0/3.0),(float) (1.0/3.0),(float) (1.0/3.0));
        ConvComb.push_back(TmpPnt);
    }

    //Base::Builder3D logg;
    //for(int i=0; i<NeiLoc.size(); ++i)
    // logg.addSinglePoint(NeiLoc[i], 2,1,0,0);

    //for(int i=0; i<ConvComb.size(); ++i)
    // logg.addSinglePoint(ConvComb[i]);

    //logg.saveToFile("c:/convex.iv");

    for (unsigned int i=0; i<ConvComb.size(); ++i)
    {
        for (unsigned int j=1; j<NorLoc.size()-1; ++j)
        {

            minScale  = mScRef;
            NeiLoc[0] = ConvComb[i];
            NorLoc[0] = NorLoc[j];
            minScale  = LocalCorrection(NeiLoc,NorLoc,sign,minScale);


            if (minScale > tmp)
            {
                tmp = minScale;
                TmpPnt = NeiLoc[0];
                TmpNor = NorLoc[0];
            }
        }
    }

    NeiLoc[0] = TmpPnt;
    NorLoc[0] = TmpNor;

    if ((abs(0.8*tmp) - abs(m_error[ind])) > 0)
    {
        PointArray[ind]._ucFlag = 3;
        m_CurvMax[ind] = abs(tmp);
    }
    else
    {
        PointArray[ind]._ucFlag = 4;
        m_CurvMax[ind] = abs(tmp);
    }

    return tmp;
}
/*

/*! \brief Reorder the neighbour list

  This function will reorder the list in one-direction. Clockwise or counter clockwise is depending on the
  facet list and will not be checked by this function. (i.e the third vertex i.e vertex in first facet that
  is not the CurIndex or the first neighbour in pnt[Ok, I am also lost with this..., just debug and step to see what I mean...])
*/

/*
void SpringbackCorrection::ReorderNeighbourList(std::set<MeshCore::MeshPointArray::_TConstIterator> &pnt,
        std::set<MeshCore::MeshFacetArray::_TConstIterator> &face, std::vector<unsigned long> &nei, unsigned long CurInd)
{
    std::set<MeshCore::MeshPointArray::_TConstIterator>::iterator pnt_it;
    std::set<MeshCore::MeshFacetArray::_TConstIterator>::iterator face_it;
    std::vector<unsigned long>::iterator vec_it;
    std::vector<unsigned long>::iterator ulong_it;
    unsigned long PrevIndex;

    if (face.size() != pnt.size())  //this means boundary point
    {
        for (pnt_it = pnt.begin(); pnt_it != pnt.end(); ++pnt_it)
        {
            int c = 0;
            for (face_it = face.begin(); face_it != face.end(); ++face_it)
            {
                if ((*pnt_it)[0]._ulProp == (*face_it)[0]._aulPoints[0])
                    ++c;
                if ((*pnt_it)[0]._ulProp == (*face_it)[0]._aulPoints[1])
                    ++c;
                if ((*pnt_it)[0]._ulProp == (*face_it)[0]._aulPoints[2])
                    ++c;
            }

            if (c==1)
                break;
        }
    }
    else
        pnt_it = pnt.begin();



    face_it = face.begin();

    nei.push_back((*pnt_it)->_ulProp);  //push back first neighbour
    vec_it = nei.begin();
    PrevIndex = nei[0];  //Initialize PrevIndex
    for (unsigned int i = 1; i < pnt.size(); i++) //Start
    {
        while (true)
        {
            std::vector<unsigned long> facetpnt;
            facetpnt.push_back((*face_it)->_aulPoints[0]); //push back into a vector for easier iteration
            facetpnt.push_back((*face_it)->_aulPoints[1]);
            facetpnt.push_back((*face_it)->_aulPoints[2]);
            if ((ulong_it = find(facetpnt.begin(), facetpnt.end(), PrevIndex)) == facetpnt.end())  //if PrevIndex not found
            {
                //in current facet
                if (face_it != face.end())
                    ++face_it; //next face please
                else
                    break;

                continue;
            }
            else
            {
                for (unsigned int k = 0 ; k < 3; k++)
                {
                    //If current facetpnt[k] is not yet in nei_list AND it is not the CurIndex
                    if (((vec_it = find(nei.begin(), nei.end(), facetpnt[k])) == nei.end()) && facetpnt[k] != CurInd)
                    {
                        face.erase(face_it);   //erase this face
                        nei.push_back(facetpnt[k]);  //push back the index
                        PrevIndex = facetpnt[k];   //this index is now PrevIndex
                        face_it = face.begin(); //reassign the iterator
                        break;   //end this for-loop
                    }
                }
                break;  //end this while loop
            }
        }
    }
}
*/


bool SpringbackCorrection::Visit(const MeshCore::MeshFacet &rclFacet, const MeshCore::MeshFacet &rclFrom, unsigned long ulFInd, unsigned long ulLevel)
{
    if (ulLevel != m_RingCurrent)
    {
        ++m_RingCurrent;

        if (m_RingVector.size() == 0)
        {
            return false;
        }
        //else if(m_RingVector.size() < 2 && m_RingCurrent > 2)
        //{
        // m_RingVector.clear();
        // return false;
        //}
        else
        {
            m_RegionVector.push_back(m_RingVector);
            m_RingVector.clear();
        }
    }

    if (rclFacet._ulProp == 1 && rclFrom._ulProp == 1)
        m_RingVector.push_back(ulFInd);

    return true;
}
