#include <iostream>

#include "OpenCascadeAll.h"

#include <BRepLProp_CurveTool.hxx>
#include <BRepLProp_CLProps.hxx>

#include <HLRBRep.hxx>
#include <HLRBRep_Algo.hxx>
#include <HLRBRep_HLRToShape.hxx>
#include <HLRAlgo_Projector.hxx>

#include <BRepMesh_IncrementalMesh.hxx>
#include <HLRBRep_PolyAlgo.hxx>
#include <HLRBRep_PolyHLRToShape.hxx>

void dumpShape(const TopoDS_Shape& s);

int main()
{
    std::cout << "PolyAlgo Start" << std::endl;
    gp_Pnt org(0,0,0);
    gp_Pnt ext(50,50,50);
    gp_Pnt centroid(25,25,25);
    gp_Dir z(0,0,1);
//    gp_Ax2 viewAxis(org , z);
    gp_Ax2 viewAxis(centroid , z);

    BRepPrimAPI_MakeBox mkBox(org,ext);
    TopoDS_Solid mySolid = mkBox.Solid();

    //use exact algorithm to project box
    Handle(HLRBRep_Algo) brep_hlr = NULL;
    brep_hlr = new HLRBRep_Algo();
    brep_hlr->Add(mySolid);
    HLRAlgo_Projector projector( viewAxis );
    brep_hlr->Projector(projector);

    brep_hlr->Update();
    brep_hlr->Hide();

    HLRBRep_HLRToShape hlrToShape(brep_hlr);
    TopoDS_Shape visHard    = hlrToShape.VCompound();

    std::cout << "exactAlgo Result:" << std::endl;
    dumpShape(visHard);
    std::cout << std::endl;

    //use polygon algorithm to project box
    BRepMesh_IncrementalMesh(mySolid, 0.10); //Poly Algo requires a mesh!
    Handle(HLRBRep_PolyAlgo) brep_hlrPoly = new HLRBRep_PolyAlgo();
    brep_hlrPoly->Load(mySolid);
    brep_hlrPoly->Projector(projector);
    brep_hlrPoly->Update();

    HLRBRep_PolyHLRToShape polyhlrToShape;
    polyhlrToShape.Update(brep_hlrPoly);
    visHard = polyhlrToShape.VCompound();

    std::cout << "polyAlgo Result:" << std::endl;
    dumpShape(visHard);

    std::cout << "PolyAlgo End" << std::endl;
    return 0;
}

void dumpShape(const TopoDS_Shape& s)
{
    TopExp_Explorer expl(s, TopAbs_EDGE);
    int i;
    for (i = 1 ; expl.More(); expl.Next(),i++) {
        const TopoDS_Edge& e = TopoDS::Edge(expl.Current());
        BRepAdaptor_Curve adapt(e);
        double start = BRepLProp_CurveTool::FirstParameter(adapt);
        double end = BRepLProp_CurveTool::LastParameter(adapt);
        BRepLProp_CLProps propStart(adapt,start,0,Precision::Confusion());
        const gp_Pnt& vStart = propStart.Value();
        BRepLProp_CLProps propEnd(adapt,end,0,Precision::Confusion());
        const gp_Pnt& vEnd = propEnd.Value();
        std::cout << "edge: " << i << " start: (" << vStart.X() << "," << vStart.Y() << "," << vStart.Z() << ") end: (" <<
                  vEnd.X() << "," << vEnd.Y() << "," << vEnd.Z() << ")" << std::endl;
    }
}
