// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

#include <BALL/STRUCTURE/solventExcludedSurface.h>
#include <BALL/STRUCTURE/triangle.h>
#include <BALL/STRUCTURE/triangleEdge.h>
#include <BALL/STRUCTURE/trianglePoint.h>
#include <BALL/STRUCTURE/triangulatedSES.h>
#include <BALL/STRUCTURE/triangulatedSurface.h>
#include <BALL/MATHS/analyticalGeometry.h>
#include <BALL/MATHS/angle.h>
#include <BALL/MATHS/circle3.h>
#include <BALL/MATHS/matrix44.h>
#include <BALL/MATHS/plane3.h>
#include <BALL/MATHS/quaternion.h>
#include <BALL/MATHS/sphere3.h>
#include <BALL/MATHS/vector3.h>
#include <BALL/MATHS/vector4.h>
#include <list>
#include <vector>


namespace BALL
{

    TriangulatedSES::TriangulatedSES()
        :	TriangulatedSurface(),
            ses_(NULL),
            density_(4.5)
    {
    }

    TriangulatedSES::TriangulatedSES
            (const TriangulatedSES& surface, bool deep)
        :	TriangulatedSurface(surface,deep),
            ses_(surface.ses_),
            density_(surface.density_)
    {
    }

    TriangulatedSES::TriangulatedSES(SolventExcludedSurface* ses, const double& density)
        :	TriangulatedSurface(),
            ses_(ses),
            density_(density)
    {
    }

    TriangulatedSES::~TriangulatedSES()
    {
    }

    void TriangulatedSES::set(const TriangulatedSES& surface, bool)
    {
        if (this != &surface)
        {
            TriangulatedSurface::set(surface);
            ses_ = surface.ses_;
            density_ = surface.density_;
        }
    }

    TriangulatedSES& TriangulatedSES::operator = (const TriangulatedSES& surface)
    {
        if (this != &surface)
        {
            TriangulatedSurface::operator = (surface);
            ses_ = surface.ses_;
            density_ = surface.density_;
        }
        return *this;
    }

    void TriangulatedSES::setDensity(const double& density)
    {
        density_ = density;
    }

    double TriangulatedSES::getDensity() const
    {
        return density_;
    }

    void TriangulatedSES::compute()
        throw(Exception::GeneralException,Exception::DivisionByZero)
    {
        SESTriangulator sest(this);
        sest.run();
    }


    SESTriangulator::SESTriangulator()
        :	tses_(0),
            point_(),
            edge_(),
            template_spheres_(),
            sqrt_density_(0.0)
    {
    }

    SESTriangulator::SESTriangulator(TriangulatedSES* tses)
        :	tses_(tses),
            point_(tses->ses_->number_of_vertices_),
            edge_(tses->ses_->number_of_edges_),
            template_spheres_(),
            sqrt_density_(sqrt(tses_->density_))
    {
    }

    SESTriangulator::~SESTriangulator()
    {
        std::list<TrianglePoint*>::iterator i;
        for (i = template_spheres_[0].begin(); i != template_spheres_[0].end(); i++)
        {
            delete *i;
        }
        for (i = template_spheres_[1].begin(); i != template_spheres_[1].end(); i++)
        {
            delete *i;
        }
        for (i = template_spheres_[2].begin(); i != template_spheres_[2].end(); i++)
        {
            delete *i;
        }
        for (i = template_spheres_[3].begin(); i != template_spheres_[3].end(); i++)
        {
            delete *i;
        }
    }

    void SESTriangulator::run()
        throw(Exception::GeneralException,Exception::DivisionByZero)
    {
        preProcessing();
        triangulateToricFaces();
        partitionSingularEdges();
        triangulateContactFaces();
        triangulateSphericFaces();
        //std::list<TrianglePoint*>::iterator p;
        //for (p = tses_->points_.begin(); p != tses_->points_.end(); p++)
        //{
        //	(*p)->normal_.normalize();
        //}
    }

    void SESTriangulator::preProcessing()
    {
        tses_->ses_->clean(tses_->density_);
        tses_->ses_->splitSphericFaces();
        for (Position i = 0;  i < tses_->ses_->number_of_vertices_; i++)
        {
            point_[i] = new TrianglePoint;
            point_[i]->point_ = tses_->ses_->vertices_[i]->point_;
            point_[i]->normal_ = tses_->ses_->vertices_[i]->normal_;
            tses_->points_.push_back(point_[i]);
            tses_->number_of_points_++;
        }
        buildTemplateSpheres();
    }


    void SESTriangulator::triangulateToricFaces()

    {
        double epsilon = Constants::EPSILON;
        Constants::EPSILON = 1e-4;
        double probe_radius(tses_->ses_->reduced_surface_->probe_radius_);
        for (Position i = 0; i < tses_->ses_->number_of_toric_faces_; i++)
        {
            triangulateToricFace(tses_->ses_->toric_faces_[i],probe_radius);
        }
        Constants::EPSILON = epsilon;
    }


    void SESTriangulator::partitionSingularEdges()
    {
        std::list<SESEdge*>::iterator e;
        for (e = tses_->ses_->singular_edges_.begin();
                 e != tses_->ses_->singular_edges_.end();
                 e++)
        {
            partitionSingularEdge(*e);
        }
    }


    void SESTriangulator::triangulateContactFaces()
    {
        SESFace* current_face;
        TSphere3<double> sphere;
        for (Position i = 0; i < tses_->ses_->number_of_contact_faces_; i++)
        {
            current_face = tses_->ses_->contact_faces_[i];
            sphere.set(tses_->ses_->reduced_surface_
                                                                ->atom_[current_face->rsvertex_->atom_]);
            triangulateContactFace(current_face,sphere);
        }
    }


    void SESTriangulator::triangulateSphericFaces()
    {
        SESFace* current_face;
        TSphere3<double> sphere;
        sphere.radius = tses_->ses_->reduced_surface_->probe_radius_;
        std::list<SESFace*> not_triangulated_faces;
        for (Position i = 0; i < tses_->ses_->number_of_spheric_faces_; i++)
        {
            current_face = tses_->ses_->spheric_faces_[i];
            sphere.p.set(current_face->rsface_->center_);
            if (!triangulateSphericFace(current_face,sphere))
            {
                not_triangulated_faces.push_back(current_face);
            }
        }
        Position end = not_triangulated_faces.size();
        Position counter = 0;
        while ((!not_triangulated_faces.empty()) && (counter < end))
        {
            current_face = not_triangulated_faces.front();
            not_triangulated_faces.pop_front();
            bool ok = false;
            std::list<SESEdge*>::iterator e
                    = current_face->edge_.begin();
            while (!ok && (e != current_face->edge_.end()))
            {
                if (edge_[(*e)->index_].front()->face_[0] != NULL)
                {
                    sphere.p.set(current_face->rsface_->center_);
                    SESEdge::Type type = (*e)->type_;
                    (*e)->type_ = SESEdge::TYPE_CONCAVE;
                    ok = triangulateSphericFace(current_face,sphere);
                    (*e)->type_ = type;
                }
                e++;
            }
            if (ok)
            {
                end--;
                counter = 0;
            }
            else
            {
                not_triangulated_faces.push_back(current_face);
                counter++;
            }
        }
    }


    void SESTriangulator::triangulateToricFace
            (SESFace*	face,
             const double&			probe_radius)
    {
        if (face->isFree())
        {
            triangulateFreeToricFace(face,probe_radius);
        }
        else
        {
            if (face->rsedge_->isSingular())
            {
                triangulateSingularToricFace(face,probe_radius);
            }
            else
            {
                triangulateNonSingularToricFace(face,probe_radius);
            }
        }
    }


    void SESTriangulator::triangulateNonSingularToricFace
            (SESFace*	face,
             const double&			probe_radius)
    {
        std::list<SESEdge*>::iterator e = face->edge_.begin();
        SESEdge* edge0 = *e;
        e++;
        SESEdge* edge1 = *e;
        e++;
        SESEdge* edge2 = *e;
        e++;
        SESEdge* edge3 = *e;
        std::list<SESVertex*>::iterator v = face->vertex_.begin();
        SESVertex* p0 = *v;
        v++;
        SESVertex* p1 = *v;

        // In how much segments the edge should be triangulated? This depends on the angle of the
        // corresponding RSEdge and the density.
        Size number_of_segments =
                (Size)Maths::round(face->rsedge_->angle_.value*edge3->circle_.radius*sqrt_density_);

        if (number_of_segments == 0)
        {
            number_of_segments++;
        }

        TAngle<double> psi(face->rsedge_->angle_.value/number_of_segments,true);

        // Get the normal vector of the rotation used to partition the SESEdges of the SESFace ...
        const TCircle3<double>& circle3 = edge3->circle_;
        const TCircle3<double>& circle1 = edge1->circle_;

        TVector3<double> normal = circle3.n;

        // ... and now partition the SESEdges ...
        vector< TVector3<double> > edge3_segments(number_of_segments+1);
        partitionOfCircle(circle3,edge3->vertex_[0]->point_,psi,number_of_segments,edge3_segments);

        edge3_segments[number_of_segments] = edge3->vertex_[1]->point_;

        if (edge3->vertex_[0] != p0)
        {
            TVector3<double> tmp;
            for (Position i = 0; i < (number_of_segments+1)/2; i++)
            {
                tmp = edge3_segments[i];
                edge3_segments[i] = edge3_segments[number_of_segments-i];
                edge3_segments[number_of_segments-i] = tmp;
            }
            normal.negate();
        }

        vector< TVector3<double> > edge1_segments(number_of_segments+1);
        partitionOfCircle(circle1,edge1->vertex_[0]->point_,psi,number_of_segments,edge1_segments);

        edge1_segments[number_of_segments] = edge1->vertex_[1]->point_;

        if (edge1->vertex_[0] != p1)
        {
            TVector3<double> tmp;
            for (Position i = 0; i < (number_of_segments+1)/2; i++)
            {
                tmp = edge1_segments[i];
                edge1_segments[i] = edge1_segments[number_of_segments-i];
                edge1_segments[number_of_segments-i] = tmp;
            }
        }
        TCircle3<double> center_circle(face->rsedge_->center_of_torus_,
                                                            normal,
                                                            face->rsedge_->radius_of_torus_);
        // ... and the "center_circle". This is the circle on which the centers oft the circle lie which
        // define the segments of the face.
        vector< TVector3<double> > centers(number_of_segments+1);
        partitionOfCircle(center_circle,edge0->circle_.p,psi,number_of_segments,centers);
        centers[number_of_segments] = edge2->circle_.p;

        // save an iterator to the last triangle
        //
        // workaround for MSVC from Andreas Moll: 22.07.06
        std::list<Triangle*>::iterator last_triangle = tses_->triangles_.end();
        bool at_start = false;
        if (tses_->number_of_triangles_ == 0)
        {
            at_start = true;
        }
        else
        {
            last_triangle--;
        }

        buildTriangles(edge0,edge1,edge2,edge3,centers,edge1_segments,edge3_segments, probe_radius);

        if (at_start)
        {
            last_triangle = tses_->triangles_.begin();
        }
        else
        {
            last_triangle++;
        }
        Triangle* test_triangle = *last_triangle;
        // swap the triangles if necessary
        TVector3<double> orth( (test_triangle->vertex_[1]->point_-test_triangle->vertex_[0]->point_) %
                                            (test_triangle->vertex_[2]->point_-test_triangle->vertex_[0]->point_));
        if (Maths::isGreater(orth*test_triangle->vertex_[0]->point_,orth*centers[0]))
        {
            std::list<Triangle*>::iterator t;
            for (t = last_triangle; t != tses_->triangles_.end(); t++)
            {
                TrianglePoint* temp = (*t)->vertex_[0];
                (*t)->vertex_[0] = (*t)->vertex_[1];
                (*t)->vertex_[1] = temp;
            }
        }
    }


    void SESTriangulator::triangulateFreeToricFace
            (SESFace*	face,
             const double&			probe_radius)
    {
        TVector3<double> normal(face->edge_.front()->circle_.n);
        TCircle3<double> circle1(face->edge_.front()->circle_);
        TCircle3<double> circle2(face->edge_.back()->circle_.p,
                                                normal,
                                                face->edge_.back()->circle_.radius);
        TCircle3<double> circle3(face->rsedge_->center_of_torus_,
                                                normal,
                                                face->rsedge_->radius_of_torus_);
        TVector3<double> orth(normal.y,-normal.x,0.0);
        if (orth == TVector3<double>::getZero())
        {
            orth.set(normal.z,0.0,-normal.x);
        }
        orth.normalize();
        TVector3<double> p1(circle1.p+(orth*circle1.radius));
        TVector3<double> p2(circle2.p+(orth*circle2.radius));
        TVector3<double> p3(circle3.p+(orth*circle3.radius));
        Size number_of_points
                = (Size)Maths::round(2*Constants::PI*circle1.radius*sqrt_density_);
        if (number_of_points == 0)
        {
            number_of_points++;
        }
        TAngle<double> phi(2*Constants::PI/number_of_points,true);
        std::vector< TVector3<double> > points1(number_of_points+1);
        std::vector< TVector3<double> > points2(number_of_points+1);
        std::vector< TVector3<double> > centers(number_of_points+1);
        partitionOfCircle(circle1,p1,phi,number_of_points,points1);
        partitionOfCircle(circle2,p2,phi,number_of_points,points2);
        partitionOfCircle(circle3,p3,phi,number_of_points,centers);
        points1.pop_back();
        points2.pop_back();
        centers.pop_back();
        SESEdge* dummy(NULL);
        buildTriangles(dummy,face->edge_.front(),dummy,face->edge_.back(),
                                     centers,points1,points2,probe_radius);
    }


    void SESTriangulator::triangulateSingularToricFace
            (SESFace*	face,
             const double&			probe_radius)

    {
        face->normalize(true);
        std::list<SESEdge*>::iterator e = face->edge_.begin();
        //std::vector<SESEdge*> edge(6);
        SESEdge* edge[6];
        edge[0] = *e;
        e++;
        edge[1] = *e;
        e++;
        edge[2] = *e;
        e++;
        edge[3] = *e;
        e++;
        edge[4] = *e;
        e++;
        edge[5] = *e;
        std::list<SESVertex*>::iterator v = face->vertex_.begin();
        //std::vector<SESVertex*> vertex(6);
        SESVertex* vertex[6];
        vertex[0] = *v;
        v++;
        vertex[1] = *v;
        v++;
        vertex[2] = *v;
        v++;
        vertex[3] = *v;
        v++;
        vertex[4] = *v;
        v++;
        vertex[5] = *v;
        Size number_of_segments
                = (Size)Maths::round(face->rsedge_->angle_.value*
                                                         edge[1]->circle_.radius*sqrt_density_);
        if (number_of_segments == 0)
        {
            number_of_segments++;
        }
        TAngle<double> psi(face->rsedge_->angle_.value/number_of_segments,true);
        Position offset = 0;
        std::list<Triangle*>::iterator last = tses_->triangles_.end();
        last--;
        for (Position counter = 0; counter < 2; counter++)
        {
            std::vector< TVector3<double> > edge_segments(number_of_segments+1);
            partitionOfCircle(edge[0+offset]->circle_,
                                                edge[0+offset]->vertex_[0]->point_,
                                                psi,
                                                number_of_segments,
                                                edge_segments);
            edge_segments[number_of_segments] = edge[0+offset]->vertex_[1]->point_;

            TVector3<double> axis(edge[0+offset]->circle_.n);
            if (edge[0+offset]->vertex_[0] != vertex[0+offset])
            {
                TVector3<double> tmp;
                for (Position i = 0; i < (number_of_segments+1)/2; i++)
                {
                    tmp = edge_segments[i];
                    edge_segments[i] = edge_segments[number_of_segments-i];
                    edge_segments[number_of_segments-i] = tmp;
                }
                axis.negate();
            }
            std::vector< TVector3<double> > point;
            for (Position i = 0; i < number_of_segments+1; i++)
            {
                point.push_back(vertex[1+offset]->point_);
            }
            TCircle3<double> center_circle(face->rsedge_->center_of_torus_,
                                                                axis,
                                                                face->rsedge_->radius_of_torus_);

            vector< TVector3<double> > centers(number_of_segments+1);
            partitionOfCircle(center_circle,edge[1+offset]->circle_.p,psi,
                                                number_of_segments,centers);
            centers[number_of_segments] = edge[2+offset]->circle_.p;

            SESEdge* dummy(NULL);
            buildTriangles(edge[1+offset],edge[0+offset],edge[2+offset],
                                         dummy,centers,edge_segments,point,probe_radius);
            offset += 3;
            Triangle* test_triangle;
            std::list<Triangle*>::iterator start;
            last++;
            test_triangle = *last;
            start = last;
            last = tses_->triangles_.end();
            last--;
            TVector3<double> orth( (test_triangle->vertex_[1]->point_-
                                                        test_triangle->vertex_[0]->point_) %
                                                (test_triangle->vertex_[2]->point_-
                                                        test_triangle->vertex_[0]->point_));
            if (Maths::isGreater(orth*(test_triangle->vertex_[0]->point_-centers[0]),
                                                     0.0))
            {
                std::list<Triangle*>::iterator t;
                TrianglePoint* temp;
                for (t = start; t != tses_->triangles_.end(); t++)
                {
                    temp = (*t)->vertex_[0];
                    (*t)->vertex_[0] = (*t)->vertex_[1];
                    (*t)->vertex_[1] = temp;
                }
            }
        }
    }


    void SESTriangulator::partitionSingularEdge(SESEdge* singular_edge)

    {
        if (singular_edge->vertex_[0] == NULL)
        {
            partitionFreeSingularEdge(singular_edge);
        }
        else
        {
            partitionNonFreeSingularEdge(singular_edge);
        }
    }


    void SESTriangulator::partitionFreeSingularEdge
            (SESEdge* singular_edge)

    {
        TAngle<double> phi;
        phi.value = 2*Constants::PI;
        Size number_of_segments
                = (Size)Maths::round(phi.value*
                                                         singular_edge->circle_.radius*
                                                         sqrt_density_);
        if (number_of_segments == 0)
        {
            number_of_segments++;
        }
        TAngle<double> psi(phi.value/number_of_segments,true);
        std::vector< TVector3<double> > points(number_of_segments+1);
        partitionOfCircle(singular_edge->circle_,
                                            TVector3<double>::getZero(),psi,
                                            number_of_segments,points,false);
        points.pop_back();
        TrianglePoint* p0;
        TrianglePoint* p1;
        TrianglePoint* p2;
        TriangleEdge* e;
        p1 = new TrianglePoint;
        p1->point_ = points[0];
        p1->normal_ = singular_edge->circle_.p-p1->point_;
        tses_->points_.push_back(p1);
        tses_->number_of_points_++;
        p0 = p1;
        for (Position k = 1; k < points.size(); k++)
        {
            p2 = new TrianglePoint;
            p2->point_ = points[k];
            p2->normal_ = singular_edge->circle_.p-p2->point_;
            tses_->points_.push_back(p2);
            tses_->number_of_points_++;
            e = new TriangleEdge;
            e->vertex_[0] = p1;
            e->vertex_[1] = p2;
            tses_->edges_.push_back(e);
            tses_->number_of_edges_++;
            edge_[singular_edge->index_].push_back(e);
            p1->edges_.insert(e);
            p2->edges_.insert(e);
            p1 = p2;
        }
        e = new TriangleEdge;
        e->vertex_[0] = p1;
        e->vertex_[1] = p0;
        tses_->edges_.push_back(e);
        tses_->number_of_edges_++;
        edge_[singular_edge->index_].push_back(e);
        p1->edges_.insert(e);
        p0->edges_.insert(e);
    }


    void SESTriangulator::partitionNonFreeSingularEdge
            (SESEdge* singular_edge)

    {
        TAngle<double> phi(getOrientedAngle(singular_edge->vertex_[0]->point_-
                                                                                    singular_edge->circle_.p,
                                                                                singular_edge->vertex_[1]->point_-
                                                                                    singular_edge->circle_.p,
                                                                                singular_edge->circle_.n));
        Size number_of_segments
                = (Size)Maths::round(phi.value*
                                                         singular_edge->circle_.radius*
                                                         sqrt_density_);
        if (number_of_segments == 0)
        {
            number_of_segments++;
        }
        TAngle<double> psi(phi.value/number_of_segments,true);
        std::vector< TVector3<double> > points(number_of_segments+1);
        partitionOfCircle(singular_edge->circle_,
                                            singular_edge->vertex_[0]->point_,psi,
                                            number_of_segments,points);
        points.pop_back();
        points.push_back(singular_edge->vertex_[1]->point_);
        TrianglePoint* p1;
        TrianglePoint* p2;
        TriangleEdge* e;
        p1 = point_[singular_edge->vertex_[0]->index_];
        p1->normal_ = singular_edge->circle_.p-p1->point_;
        for (Position k = 1; k < points.size()-1; k++)
        {
            p2 = new TrianglePoint;
            p2->point_ = points[k];
            p2->normal_ = singular_edge->circle_.p-p2->point_;
            tses_->points_.push_back(p2);
            tses_->number_of_points_++;
            e = new TriangleEdge;
            e->vertex_[0] = p1;
            e->vertex_[1] = p2;
            tses_->edges_.push_back(e);
            tses_->number_of_edges_++;
            edge_[singular_edge->index_].push_back(e);
            p1->edges_.insert(e);
            p2->edges_.insert(e);
            p1 = p2;
        }
        p2 = point_[singular_edge->vertex_[1]->index_];
        p2->normal_ = singular_edge->circle_.p-p2->point_;
        e = new TriangleEdge;
        e->vertex_[0] = p1;
        e->vertex_[1] = p2;
        tses_->edges_.push_back(e);
        tses_->number_of_edges_++;
        edge_[singular_edge->index_].push_back(e);
        p1->edges_.insert(e);
        p2->edges_.insert(e);
    }


    void SESTriangulator::triangulateContactFace(SESFace*	face, const TSphere3<double>&	sphere)
    {
        Position number_of_edges = face->edge_.size();
        if (number_of_edges > 0)
        {
            // the face does not come from a free vertex
            if ((number_of_edges == 2) &&
                    (edge_[face->edge_.front()->index_].size() == 1) &&
                    (edge_[face->edge_.back()->index_].size() == 1)			)
            {
                return;
            }
            if ((number_of_edges == 3) &&
                    (edge_[face->edge_.front()->index_].size() == 1) &&
                    (edge_[(*(face->edge_.begin())++)->index_].size() == 1) &&
                    (edge_[face->edge_.back()->index_].size() == 1)			)
            {
                Triangle* triangle = new Triangle;
                HashSet<TrianglePoint*> points;
                points.insert(point_[face->edge_.front()->vertex_[0]->index_]);
                points.insert(point_[face->edge_.front()->vertex_[1]->index_]);
                points.insert(point_[face->edge_.back()->vertex_[0]->index_]);
                points.insert(point_[face->edge_.back()->vertex_[1]->index_]);
                HashSet<TrianglePoint*>::Iterator p = points.begin();
                for (Position i = 0; i < 3; i++)
                {
                    triangle->vertex_[i] = *p;
                    p++;
                }
                TVector3<double> normal((triangle->vertex_[0]->point_- triangle->vertex_[1]->point_	) %
                                        (triangle->vertex_[0]->point_- triangle->vertex_[2]->point_	)	 );
                if (Maths::isGreater(normal*(sphere.p-triangle->vertex_[1]->point_), 0.0))
                {
                    TrianglePoint* tmp = triangle->vertex_[0];
                    triangle->vertex_[0] = triangle->vertex_[1];
                    triangle->vertex_[1] = tmp;
                }
                tses_->triangles_.push_back(triangle);
                tses_->number_of_triangles_++;
                return;
            }

            // get a template sphere for the face to triangulate
            HashMap<Size, std::list<TrianglePoint*> >::ConstIterator s
                    = template_spheres_.find(numberOfRefinements(tses_->density_,	sphere.radius));

            std::list<TrianglePoint*>::const_iterator p;
            TrianglePoint* point;
            TriangulatedSES part;
            for (p = s->second.begin(); p != s->second.end(); p++)
            {
                point = new TrianglePoint;
                point->point_ = (*p)->point_;
                point->normal_ = (*p)->normal_;
                part.points_.push_back(point);
                part.number_of_points_++;
            }
            part.blowUp(sphere.radius);

            // cut the face with all its edges
            TPlane3<double> plane;
            std::list<SESEdge*>::iterator edge;
            for (edge = face->edge_.begin(); edge != face->edge_.end(); edge++)
            {
                plane.p = (*edge)->circle_.p-sphere.p;
                plane.n = (*edge)->circle_.n;
                part.cut(plane, 0.05);
            }
            part.shift(sphere.p);
            buildSphericTriangles(face, part, sphere);
            part.deleteIsolatedPoints();
            tses_->join(part);
        }
        else
        {
            // the face comes from a free vertex
            TriangulatedSphere part;
            part.icosaeder();
            part.refine(numberOfRefinements(tses_->density_,sphere.radius));
            part.blowUp(sphere.radius);
            part.shift(sphere.p);
            tses_->join(part);
        }
    }

    bool SESTriangulator::triangulateSphericFace(SESFace* face, const TSphere3<double>& sphere)
    {
        TriangulatedSES part;
        bool ok = buildSphericTriangles(face,part,sphere,false);
        if (ok)
        {
            tses_->join(part);
            return true;
        }
        else
        {
            return false;
        }
    }


    bool SESTriangulator::buildSphericTriangles(SESFace* face, TriangulatedSES&	part,
                                                const TSphere3<double>& sphere, bool convex)
    {
        HashSet<TrianglePoint*> points;
        std::list<TrianglePoint*>::iterator p;
        for (p = part.points_.begin(); p != part.points_.end(); p++)
        {
            points.insert(*p);
        }
        std::list<TriangleEdge*>::const_iterator c;
        std::list<SESEdge*>::const_iterator e;
        for (e = face->edge_.begin(); e != face->edge_.end(); e++)
        {
            for (c = edge_[(*e)->index_].begin();
                     c != edge_[(*e)->index_].end(); c++)
            {
                points.insert((*c)->vertex_[0]);
                points.insert((*c)->vertex_[1]);
            }
        }
        std::list<TriangleEdge*> border;
        if (!buildFirstTriangle(face,part,border,sphere,points,convex))
        {
            return false;
        }
        while (!border.empty())
        {
            TriangleEdge* edge = border.front();
            border.pop_front();
            Triangle* start_triangle = edge->face_[0];
            TrianglePoint* third_point
                    = start_triangle->third(edge->vertex_[0],edge->vertex_[1]);
            TVector3<double> normal((third_point->point_-edge->vertex_[0]->point_) %
                                                 (third_point->point_-edge->vertex_[1]->point_)	);
            double test_value = normal*third_point->point_;
            Index p0 = start_triangle->getRelativeIndex(edge->vertex_[0]);
            Index p1 = start_triangle->getRelativeIndex(edge->vertex_[1]);
            Index diff = p1-p0;
            if ((convex && ((diff == -1) || (diff == 2))) ||
                    (!convex && ((diff == 1) || (diff == -2)))	)
            {
                TrianglePoint* tmp = edge->vertex_[0];
                edge->vertex_[0] = edge->vertex_[1];
                edge->vertex_[1] = tmp;
            }

            HashSet<TrianglePoint*>::Iterator next = points.begin();
            for (; +next; ++next)
            {
                TrianglePoint* tpoint = *next;
                if (tpoint != edge->vertex_[0] &&
                        tpoint != edge->vertex_[1] &&
                        tpoint != third_point)
                {
                    break;
                }
            }

            if (!+next) continue;

            std::list<TrianglePoint*> third;
            third.push_back(*next);
            normal.set(((*next)->point_-edge->vertex_[1]->point_) %
                                 ((*next)->point_-edge->vertex_[0]->point_)	);
            test_value = normal*edge->vertex_[0]->point_;
            next++;
            while (+next)
            {
                if ((*next != edge->vertex_[0]) && (*next != edge->vertex_[1]) &&
                        (*next != third_point))
                {
                    double this_value = normal*(*next)->point_;
                    if (Maths::isGreater(this_value,test_value))
                    {
                        third.clear();
                        third.push_back(*next);
                        normal.set(((*next)->point_-edge->vertex_[1]->point_) %
                                             ((*next)->point_-edge->vertex_[0]->point_)	);
                        test_value = normal*edge->vertex_[0]->point_;
                    }
                    else
                    {
                        if (Maths::isEqual(this_value,test_value))
                        {
                            third.push_back(*next);
                        }
                    }
                }
                next++;
            }
            switch (third.size())
            {
                case 0 :	break;
                case 1 :	buildUnambiguousTriangle(edge,third.front(),border,
                                                                                     sphere,part,convex);
                                    break;
                default :	buildAmbiguousTriangles(edge,third,border,
                                                                                    sphere,part,convex);
                                    break;
            }
        }
        return true;
    }


    bool SESTriangulator::buildFirstTriangle
            (SESFace*												face,
             TriangulatedSES&								part,
             std::list<TriangleEdge*>&			border,
             const TSphere3<double>&									sphere,
             const HashSet<TrianglePoint*>&	points,
                bool															convex)
    {
        SESEdge* first_sesedge = firstSESEdge(face->edge_);
        if (first_sesedge == NULL)
        {
            return false;
        }
        TriangleEdge* edge = edge_[first_sesedge->index_].front();
        HashSet<TrianglePoint*> same_edge;
        std::list<TriangleEdge*>::const_iterator e;
        for (e = edge_[first_sesedge->index_].begin();
                 e != edge_[first_sesedge->index_].end(); e++)
        {
            same_edge.insert((*e)->vertex_[0]);
            same_edge.insert((*e)->vertex_[1]);
        }
        // orientiere die edge so, wie sie im existierenden Dreieck NICHT
        // orientiert ist (so soll sie im neuen Dreieck orientiert sein)
        TVector3<double> edge_vector(edge->vertex_[0]->point_-edge->vertex_[1]->point_);
        Triangle* triangle = edge->face_[0];
        Index p0 = triangle->getRelativeIndex(edge->vertex_[0]);
        Index p1 = triangle->getRelativeIndex(edge->vertex_[1]);
        Index diff = p1-p0;
        if ((diff == 1) || (diff == -2))
        {
            TrianglePoint* tmp = edge->vertex_[0];
            edge->vertex_[0] = edge->vertex_[1];
            edge->vertex_[1] = tmp;
            edge_vector = -edge_vector;
        }
        HashSet<TrianglePoint*>::ConstIterator next = points.begin();
        HashSet<TrianglePoint*>::ConstIterator test;
        std::list<TrianglePoint*> third;
        TVector3<double> normal;
        while (next != points.end())
        {
            if (!same_edge.has(*next))
            {
                normal.set(edge_vector % (edge->vertex_[0]->point_-(*next)->point_));
                double test_value = normal*edge->vertex_[0]->point_;
                bool is_convex = true;
                test = points.begin();
                while (test != points.end())
                {
                    if ((*test != *next) &&
                            (*test != edge->vertex_[0]) &&
                            (*test != edge->vertex_[1]))
                    {
                        double this_value = normal*(*test)->point_;
                        if ((Maths::isGreater(this_value,test_value) && convex) ||
                                (Maths::isLess(this_value,test_value) && !convex))
                        {
                            is_convex = false;
                        }
                    }
                    test++;
                }
                if (is_convex)
                {
                    third.push_back(*next);
                }
            }
            next++;
        }
        std::list<TrianglePoint*> real_third;
        if (third.size() == 1)
        {
            real_third.push_back(third.front());
        }
        else
        {
            // normal vector of the old triangle (shows out of the molecule)
            normal.set((triangle->vertex_[0]->point_-triangle->vertex_[1]->point_) %
                                 (triangle->vertex_[0]->point_-triangle->vertex_[2]->point_)	);
            TAngle<double> min(3*Constants::PI,true);
            std::list<TrianglePoint*>::iterator p = third.begin();
            TVector3<double> new_normal;
            TAngle<double> angle;
            while (p != third.end())
            {
                new_normal.set(edge_vector % (edge->vertex_[0]->point_-(*p)->point_));
                angle = getOrientedAngle(normal,new_normal,edge_vector);
                if (angle <= min)
                {
                    if (angle < min)
                    {
                        real_third.clear();
                        min = angle;
                    }
                    real_third.push_back(*p);
                }
                p++;
            }
        }
        switch (real_third.size())
        {
            case 0 :	break;
            case 1 :	buildUnambiguousTriangle(edge,real_third.front(),border,
                                                                                 sphere,part,convex);
                                break;
            default :	buildAmbiguousTriangles(edge,real_third,border,
                                                                                sphere,part,convex);
                                break;
        }
        return true;
    }


    SESEdge* SESTriangulator::firstSESEdge
            (const std::list<SESEdge*>& sesedge)

    {
        bool found = false;
        std::list<SESEdge*>::const_iterator e = sesedge.begin();
        while (e != sesedge.end())
        {
            found = false;
            while ((found == false) && (e != sesedge.end()))
            {
                if ((*e)->type_ == SESEdge::TYPE_SINGULAR)
                {
                    e++;
                }
                else
                {
                    found = true;
                }
            }
            if (found)
            {
                if (edge_[(*e)->index_].size() == 1)
                {
                    TriangleEdge* edge = edge_[(*e)->index_].front();
                    TVector3<double> diff(edge->vertex_[0]->point_-edge->vertex_[1]->point_);
                    if (diff*diff < 0.01)
                    {
                        e++;
                    }
                    else
                    {
                        return *e;
                    }
                }
                else
                {
                    return *e;
                }
            }
        }
        return NULL;
    }


    void SESTriangulator::buildUnambiguousTriangle
            (TriangleEdge*						 edge,
             TrianglePoint*						 point,
             std::list<TriangleEdge*>& border,
             const TSphere3<double>&						 sphere,
             TriangulatedSES&					 part,
                bool													convex
            )

    {
        TriangleEdge* edge1;
        TriangleEdge* edge2;
        Triangle* triangle;
        bool old1, old2;
        createTriangleAndEdges(edge,point,sphere,
                                                     edge1,old1,edge2,old2,triangle,convex);
        if (old1 == true)
        {
            if (edge1->face_[0] == NULL)
            {
                edge1->face_[0] = triangle;
            }
            else
            {
                edge1->face_[1] = triangle;
            }
            border.remove(edge1);
        }
        else
        {
            edge1->vertex_[0]->edges_.insert(edge1);
            edge1->vertex_[1]->edges_.insert(edge1);
            edge1->face_[0] = triangle;
            part.edges_.push_back(edge1);
            part.number_of_edges_++;
            border.push_back(edge1);
        }
        if (old2 == true)
        {
            if (edge2->face_[0] == NULL)
            {
                edge2->face_[0] = triangle;
            }
            else
            {
                edge2->face_[1] = triangle;
            }
            border.remove(edge2);
        }
        else
        {
            edge2->vertex_[0]->edges_.insert(edge2);
            edge2->vertex_[1]->edges_.insert(edge2);
            edge2->face_[0] = triangle;
            part.edges_.push_back(edge2);
            part.number_of_edges_++;
            border.push_back(edge2);
        }
        edge->face_[1] = triangle;
        triangle->vertex_[0]->faces_.insert(triangle);
        triangle->vertex_[1]->faces_.insert(triangle);
        triangle->vertex_[2]->faces_.insert(triangle);
        part.triangles_.push_back(triangle);
        part.number_of_triangles_++;
    }


    void SESTriangulator::buildAmbiguousTriangles
            (TriangleEdge*						 edge,
             std::list<TrianglePoint*> points,
             std::list<TriangleEdge*>& border,
             const TSphere3<double>&						 sphere,
             TriangulatedSES&					 part,
                bool												 convex
            )

    {
        std::list<TrianglePoint*>::iterator p;
        points.push_back(edge->vertex_[0]);
        points.push_back(edge->vertex_[1]);
        std::list<TriangleEdge*> planar_edges;
        planar_edges.push_back(edge);
        TriangleEdge* edge0;
        TriangleEdge* edge1;
        TriangleEdge* edge2;
        Triangle* triangle;
        bool old1, old2;
        while (!planar_edges.empty())
        {
            edge0 = planar_edges.front();
            planar_edges.pop_front();
            p = points.begin();
            bool built = false;
            while ((p != points.end()) && (built == false))
            {
                if ((*p == edge0->vertex_[0]) || (*p == edge0->vertex_[1]))
                {
                    p++;
                }
                else
                {
                    createTriangleAndEdges(edge0,*p,sphere,edge1,old1,edge2,old2,triangle,convex);
                    if (edge0 == edge)
                    {
                        // the first triangle has not to be tested
                        built = true;
                    }
                    else
                    {
                        Triangle* old_triangle = edge0->face_[0];
                        Index i1 = old_triangle->getRelativeIndex(edge0->vertex_[0]);
                        Index i2 = old_triangle->getRelativeIndex(edge0->vertex_[1]);
                        bool back = false;
                        if ((i1-i2 == 1) || (i1-i2 == -2))
                        {
                            back = true;
                        }
                        i1 = triangle->getRelativeIndex(edge0->vertex_[0]);
                        i2 = triangle->getRelativeIndex(edge0->vertex_[1]);
                        if (back)
                        {
                            if ((i1-i2 == -1) || (i1-i2 == 2))
                            {
                                built = true;
                            }
                        }
                        else
                        {
                            if ((i1-i2 == 1) || (i1-i2 == -2))
                            {
                                built = true;
                            }
                        }
                    }
                    if (built)
                    {
                        edge0->face_[1] = triangle;
                        triangle->vertex_[0]->faces_.insert(triangle);
                        triangle->vertex_[1]->faces_.insert(triangle);
                        triangle->vertex_[2]->faces_.insert(triangle);
                        if (old1 == true)
                        {
                            if (edge1->face_[0] == NULL)
                            {
                                edge1->face_[0] = triangle;
                            }
                            else
                            {
                                edge1->face_[1] = triangle;
                            }
                            border.remove(edge1);
                            planar_edges.remove(edge1);
                        }
                        else
                        {
                            edge1->face_[0] = triangle;
                            border.push_back(edge1);
                            planar_edges.push_back(edge1);
                            edge1->vertex_[0]->edges_.insert(edge1);
                            edge1->vertex_[1]->edges_.insert(edge1);
                            part.edges_.push_back(edge1);
                            part.number_of_edges_++;
                        }
                        if (old2 == true)
                        {
                            if (edge2->face_[0] == NULL)
                            {
                                edge2->face_[0] = triangle;
                            }
                            else
                            {
                                edge2->face_[1] = triangle;
                            }
                            border.remove(edge2);
                            planar_edges.remove(edge2);
                        }
                        else
                        {
                            edge2->face_[0] = triangle;
                            border.push_back(edge2);
                            planar_edges.push_back(edge2);
                            edge2->vertex_[0]->edges_.insert(edge2);
                            edge2->vertex_[1]->edges_.insert(edge2);
                            part.edges_.push_back(edge2);
                            part.number_of_edges_++;
                        }
                        border.remove(edge0);
                        part.triangles_.push_back(triangle);
                        part.number_of_triangles_++;
                    }
                    else
                    {
                        p++;
                        delete triangle;
                        if (old1 == false)
                        {
                            delete edge1;
                        }
                        if (old2 == false)
                        {
                            delete edge2;
                        }
                    }
                }
            }
        }
    }


    void SESTriangulator::createTriangleAndEdges
            (TriangleEdge*	edge,
             TrianglePoint* point,
             const TSphere3<double>& sphere,
             TriangleEdge*& edge1,
             bool&							old1,
             TriangleEdge*& edge2,
             bool&							old2,
             Triangle*&			triangle,
             bool								convex
            )

    {
        // build two new edges
        edge1	= new TriangleEdge;
        edge1->vertex_[0] = edge->vertex_[0];
        edge1->vertex_[1] = point;
        edge2 = new TriangleEdge;
        edge2->vertex_[0] = point;
        edge2->vertex_[1] = edge->vertex_[1];
        // do the edges exist ?
        TriangleEdge* test = edge->vertex_[0]->has(edge1);
        if (test != NULL)
        {
            delete edge1;
            edge1 = test;
            old1 = true;
        }
        else
        {
            old1 = false;
        }
        test = edge->vertex_[1]->has(edge2);
        if (test != NULL)
        {
            delete edge2;
            edge2 = test;
            old2 = true;
        }
        else
        {
            old2 = false;
        }
        // build the new triangle
        triangle = new Triangle;
        triangle->vertex_[0] = edge->vertex_[1];
        triangle->vertex_[1] = edge->vertex_[0];
        triangle->vertex_[2] = point;
        triangle->edge_[0] = edge;
        triangle->edge_[1] = edge1;
        triangle->edge_[2] = edge2;
        // swap triangle if necessary
        TVector3<double> test_vector((triangle->vertex_[1]->point_-
                                                                triangle->vertex_[0]->point_)%
                                                        (triangle->vertex_[2]->point_-
                                                                triangle->vertex_[0]->point_)	);
        double test_value = test_vector*(sphere.p-triangle->vertex_[0]->point_);
        if ((Maths::isGreater(test_value,0) && convex) ||
                (Maths::isLess(test_value,0) && !convex)			)
        {
            TrianglePoint* temp = triangle->vertex_[0];
            triangle->vertex_[0] = triangle->vertex_[1];
            triangle->vertex_[1] = temp;
        }
    }


    void SESTriangulator::partitionOfCircle(const TCircle3<double>&	circle, const TVector3<double>&	p0, const TAngle<double>&	phi,
                                            Size number_of_segments, vector< TVector3<double> >& partition, bool on_surface)
    {
        TVector4<double> p;
        if (on_surface)
        {
            TVector3<double> p_(p0-circle.p);
            p.set(p_.x, p_.y, p_.z, 0.0);
        }
        else
        {
            p.set(circle.n.y,-circle.n.x,0.0,0.0);
            if (p == TVector4<double>::getZero())
            {
                p.set(circle.n.z,0.0,-circle.n.x,0.0);
            }
            p.normalize();
            p *= circle.radius;
        }

        TQuaternion<double> rotate(circle.n, phi);
        TMatrix4x4<double>  rotation;
        rotate.getRotationMatrix(rotation);

        partition[0] = TVector3<double>(p.x,p.y,p.z)+circle.p;
        for (Size i = 0; i < number_of_segments; i++)
        {
            p = rotation*p;
            partition[i+1] = TVector3<double>(p.x,p.y,p.z)+circle.p;
        }
    }


    Size SESTriangulator::numberOfRefinements(const double& density, const double& radius)
    {
        double test0 = (4.0*density*Constants::PI*radius*radius-12.0)/30.0;
        Size n = 0;
        if (Maths::isGreaterOrEqual(test0,0.0))
        {
            double test1 = 1;
            double test2 = 1;
            while (Maths::isLess(test2,test0))
            {
                test1 = test2;
                test2 *= 4;
                n++;
            }
            if (Maths::isLess(test2-test0,test0-test1))
            {
                n++;
            }
        }
        if (n > 3)
        {
            n = 3;
        }
        return n;
    }


    void SESTriangulator::buildTemplateSpheres()

    {
        TriangulatedSphere::ConstPointIterator p;
        TrianglePoint* point;
        TriangulatedSphere sphere;
        sphere.icosaeder(true);
        for (p = sphere.beginPoint(); p != sphere.endPoint(); p++)
        {
            point = new TrianglePoint(**p);
            template_spheres_[0].push_back(point);
        }
        sphere.refine(1,true);
        for (p = sphere.beginPoint(); p != sphere.endPoint(); p++)
        {
            point = new TrianglePoint(**p);
            template_spheres_[1].push_back(point);
        }
        sphere.refine(1,true);
        for (p = sphere.beginPoint(); p != sphere.endPoint(); p++)
        {
            point = new TrianglePoint(**p);
            template_spheres_[2].push_back(point);
        }
        sphere.refine(1,true);
        for (p = sphere.beginPoint(); p != sphere.endPoint(); p++)
        {
            point = new TrianglePoint(**p);
            template_spheres_[3].push_back(point);
        }
    }


    void SESTriangulator::buildTriangles
         (SESEdge*											edge0,
            SESEdge*											edge1,
            SESEdge*											edge2,
            SESEdge*											edge3,
            const std::vector< TVector3<double> >&	centers,
            const std::vector< TVector3<double> >&	edge1_points,
            const std::vector< TVector3<double> >&	edge3_points,
            const double&													probe_radius)

    {
        TAngle<double> pi(Constants::PI,true);
        TAngle<double> psi;
        // How much triangles should be built in each segment of the face?
        // Attention: number_of_triangles is the half of the number of triangles
        // for each segment.
        GetAngle(edge1_points[0]-centers[0],edge3_points[0]-centers[0],psi);
        Size number_of_triangles
                = (Size)Maths::round(psi.value*probe_radius*sqrt_density_);
        if (number_of_triangles == 0)
        {
            number_of_triangles++;
        }
        TAngle<double> phi(psi/number_of_triangles,true);
        Size number_of_segments = centers.size()-1;
        // How much TrianglePoints lie on the face?
        // Remark: edge3 == NULL iff the face is singular
        Size number_of_points
                = ((edge3 != NULL) ? (number_of_segments+1)*(number_of_triangles+1)
                                                     : (number_of_segments+1)* number_of_triangles + 1);
        std::vector<TrianglePoint*> points(number_of_points);
        if (edge3 == NULL)
        {
            // singular face
            // get the index of the SESVertex on the top of the face
            // (remember: singular faces are two triangles)
            Index index;
            if (edge0->vertex_[0]->point_ == edge3_points[0])
            {
                index = edge0->vertex_[0]->index_;
            }
            else
            {
                index = edge0->vertex_[1]->index_;
            }
            TrianglePoint* top = point_[index];
            top->normal_ = centers[number_of_segments]-top->point_;
            points[(number_of_segments+1)*number_of_triangles] = top;
        }
        Position end
                = ((edge3 != NULL) ? number_of_triangles+1 : number_of_triangles);
        for (Position i = 0; i <= number_of_segments; i++)
        {
            TCircle3<double> circle(centers[i],
                                                 (edge1_points[i]-centers[i])%
                                                 (edge3_points[i]-centers[i]),
                                                 probe_radius);
            std::vector< TVector3<double> > line(number_of_triangles+1);
            partitionOfCircle(circle,edge1_points[i],phi,number_of_triangles,line);

            for (Position j = 0; j < end; j++)
            {
                // get the index of the point if it just exists (point on the corner)
                Index index = -1;
                if (edge0 != NULL)
                {
                    // not free face
                    if ((i == 0) && (j == 0))
                    {
                        double dist1 = line[0].getSquareDistance(edge0->vertex_[0]->point_);
                        double dist2 = line[0].getSquareDistance(edge0->vertex_[1]->point_);
                        index = ((dist1 < dist2) ? edge0->vertex_[0]->index_
                                                                         : edge0->vertex_[1]->index_);
                    }
                    if ((i == 0) && (j == number_of_triangles) && (edge3 != NULL))
                    {
                        double dist1 = line[number_of_triangles].getSquareDistance(edge0->vertex_[0]->point_);
                        double dist2 = line[number_of_triangles].getSquareDistance(edge0->vertex_[1]->point_);
                        index = ((dist1 < dist2) ? edge0->vertex_[0]->index_
                                                                         : edge0->vertex_[1]->index_);
                    }
                    if ((i == number_of_segments) && (j == 0))
                    {
                        double dist1 = line[0].getSquareDistance(edge2->vertex_[0]->point_);
                        double dist2 = line[0].getSquareDistance(edge2->vertex_[1]->point_);
                        index = ((dist1 < dist2) ? edge2->vertex_[0]->index_
                                                                         : edge2->vertex_[1]->index_);
                    }
                    if ((i == number_of_segments) && (j == number_of_triangles) && (edge3 != NULL))
                    {
                        double dist1 = line[number_of_triangles].getSquareDistance(edge2->vertex_[0]->point_);
                        double dist2 = line[number_of_triangles].getSquareDistance(edge2->vertex_[1]->point_);
                        index = ((dist1 < dist2) ? edge2->vertex_[0]->index_
                                                                         : edge2->vertex_[1]->index_);
                    }
                }
                TrianglePoint* point;
                if (index == -1)
                {
                    // create a new point if it not exists yet
                    point = new TrianglePoint;
                    tses_->points_.push_back(point);
                    tses_->number_of_points_++;
                    point->point_ = line[j];
                    point->normal_ = centers[i]-line[j];
                }
                else
                {
                    point = point_[index];
                }
                points[i*end+j] = point;
            }
        }
        // number of edges to create
        Size edge_number = ((edge3 != NULL) ? 3*number_of_segments*number_of_triangles +
                                                                                    number_of_segments+number_of_triangles
                                                                                : 3*number_of_segments*number_of_triangles-
                                                                                    2*number_of_segments+number_of_triangles-1	 );
        std::vector<TriangleEdge*> edges(edge_number);
        // build the vertical edges
        Position offset;
        Position offset2;
        TriangleEdge* new_edge;
        for (Position j = 0; j <= number_of_segments; j++)
        {
            offset = j*end;
            for (Position i = 0; i < end-1; i++)
            {
                offset2 = offset+i;
                new_edge = new TriangleEdge;
                tses_->edges_.push_back(new_edge);
                tses_->number_of_edges_++;
                new_edge->vertex_[0] = points[offset2];
                new_edge->vertex_[0]->edges_.insert(new_edge);
                new_edge->vertex_[1] = points[offset2+1];
                new_edge->vertex_[1]->edges_.insert(new_edge);
                if ((j == 0) && (edge0 != 0))
                {
                    edge_[edge0->index_].push_back(new_edge);
                }
                else
                {
                    if ((j == number_of_segments) && (edge0 != 0))
                    {
                        edge_[edge2->index_].push_back(new_edge);
                    }
                }
                edges[offset2-j] = new_edge;
            }
        }
        // build the horizontal edges
        Position add1 = (end-1)*(number_of_segments+1);
        for (Position j = 0; j < number_of_segments; j++)
        {
            offset = j*end;
            for (Position i = 0; i < end; i++)
            {
                offset2 = offset+i;
                new_edge = new TriangleEdge;
                tses_->edges_.push_back(new_edge);
                tses_->number_of_edges_++;
                new_edge->vertex_[0] = points[offset2];
                new_edge->vertex_[0]->edges_.insert(new_edge);
                new_edge->vertex_[1] = points[offset2+end];
                new_edge->vertex_[1]->edges_.insert(new_edge);
                if ((i == 0) && (edge1 != 0))
                {
                    edge_[edge1->index_].push_back(new_edge);
                }
                else
                {
                    if ((i == end-1) && (edge3 != 0))
                    {
                        edge_[edge3->index_].push_back(new_edge);
                    }
                }
                edges[offset2+add1] = new_edge;
            }
        }
        // buid the diagonal edges
        Position add2 = add1+end*number_of_segments;
        for (Position j = 0; j < number_of_segments; j++)
        {
            offset = j*end-j;
            for (Position i = 0; i < end-1; i++)
            {
                offset2 = offset+i;
                new_edge = new TriangleEdge;
                tses_->edges_.push_back(new_edge);
                tses_->number_of_edges_++;
                new_edge->vertex_[0] = points[offset2+j];
                new_edge->vertex_[0]->edges_.insert(new_edge);
                new_edge->vertex_[1] = points[offset2+j+end+1];
                new_edge->vertex_[1]->edges_.insert(new_edge);
                edges[offset2+add2] = new_edge;
            }
        }
        // number of triangles to build
        Size triangle_number = 2*number_of_segments*(end-1);
        std::vector<Triangle*> triangles(triangle_number);
        // build the triangles
        for (Position i = 0; i < end-1; i++)
        {
            for (Position j = 0; j < number_of_segments; j++)
            {
                offset2 = j*end+i;
                Triangle* t1 = new Triangle;
                    tses_->triangles_.push_back(t1);
                    tses_->number_of_triangles_++;
                    t1->vertex_[0] = points[offset2];
                    t1->vertex_[1] = points[offset2+1];
                    t1->vertex_[2] = points[offset2+1+end];
                    t1->edge_[0] = edges[offset2-j];
                    t1->edge_[1] = edges[offset2+add1+1];
                    t1->edge_[2] = edges[offset2-j+add2];
                    t1->vertex_[0]->faces_.insert(t1);
                    t1->vertex_[1]->faces_.insert(t1);
                    t1->vertex_[2]->faces_.insert(t1);
                    t1->edge_[0]->face_[0] = t1;
                    t1->edge_[1]->face_[0] = t1;
                    t1->edge_[2]->face_[0] = t1;
                    triangles[2*(number_of_segments*i+j)] = t1;
                Triangle* t2 = new Triangle;
                    tses_->triangles_.push_back(t2);
                    tses_->number_of_triangles_++;
                    t2->vertex_[0] = points[offset2];
                    t2->vertex_[1] = points[offset2+1+end];
                    t2->vertex_[2] = points[offset2+end];
                    t2->edge_[0] = edges[offset2-j+end-1];
                    t2->edge_[1] = edges[offset2+add1];
                    t2->edge_[2] = edges[offset2-j+add2];
                    t2->vertex_[0]->faces_.insert(t2);
                    t2->vertex_[1]->faces_.insert(t2);
                    t2->vertex_[2]->faces_.insert(t2);
                    t2->edge_[0]->face_[0] = t2;
                    t2->edge_[1]->face_[0] = t2;
                    t2->edge_[2]->face_[0] = t2;
                    triangles[2*(number_of_segments*i+j)+1] = t2;
            }
        }
        // close free faces
        if (edge0 == NULL)
        {
            offset = number_of_segments*end;
            TriangleEdge* edge = new TriangleEdge;
                tses_->edges_.push_back(edge);
                tses_->number_of_edges_++;
                edge->vertex_[0] = points[offset];
                edge->vertex_[1] = points[0];
                points[offset]->edges_.insert(edge);
                points[0]->edges_.insert(edge);
                edge_[edge1->index_].push_back(edge);
            for (Position i = 0; i < number_of_triangles; i++)
            {
                offset2 = offset+i;
                Triangle* t1 = new Triangle;
                    tses_->triangles_.push_back(t1);
                    tses_->number_of_triangles_++;
                    t1->vertex_[0] = points[offset2];
                    t1->vertex_[1] = points[i+1];
                    t1->vertex_[2] = points[i];
                    t1->edge_[0] = edge;
                    edge = new TriangleEdge;
                        tses_->edges_.push_back(edge);
                        tses_->number_of_edges_++;
                        edge->vertex_[0] = points[offset2];
                        edge->vertex_[1] = points[i+1];
                        points[offset2]->edges_.insert(edge);
                        points[i+1]->edges_.insert(edge);
                    t1->edge_[1] = edge;
                    t1->edge_[2] = edges[i];
                    t1->vertex_[0]->faces_.insert(t1);
                    t1->vertex_[1]->faces_.insert(t1);
                    t1->vertex_[2]->faces_.insert(t1);
                    t1->edge_[0]->face_[0] = t1;
                    t1->edge_[1]->face_[0] = t1;
                    t1->edge_[2]->face_[0] = t1;
                    triangles.push_back(t1);
                Triangle* t2 = new Triangle;
                    tses_->triangles_.push_back(t2);
                    tses_->number_of_triangles_++;
                    t2->vertex_[0] = points[offset2];
                    t2->vertex_[1] = points[offset2+1];
                    t2->vertex_[2] = points[i+1];
                    t2->edge_[0] = edge;
                    t2->edge_[1] = edges[offset2-number_of_segments];
                    edge = new TriangleEdge;
                        tses_->edges_.push_back(edge);
                        tses_->number_of_edges_++;
                        edge->vertex_[0] = points[offset2+1];
                        edge->vertex_[1] = points[i+1];
                        points[offset2+1]->edges_.insert(edge);
                        points[i+1]->edges_.insert(edge);
                    t2->edge_[2] = edge;
                    t2->vertex_[0]->faces_.insert(t2);
                    t2->vertex_[1]->faces_.insert(t2);
                    t2->vertex_[2]->faces_.insert(t2);
                    t2->edge_[0]->face_[0] = t2;
                    t2->edge_[1]->face_[0] = t2;
                    t2->edge_[2]->face_[0] = t2;
                    triangles.push_back(t2);
            }
            edge_[edge3->index_].push_back(edge);
        }
        // get the top of a singular face
        if (edge3 == NULL)
        {
            Position last = (number_of_segments+1)*number_of_triangles;
            offset = (end-1)*(number_of_segments+2);
            TriangleEdge* edge = new TriangleEdge;
                tses_->edges_.push_back(edge);
                tses_->number_of_edges_++;
                edge->vertex_[0] = points[number_of_triangles-1];
                edge->vertex_[1] = points[last];
                edge->vertex_[0]->edges_.insert(edge);
                edge->vertex_[1]->edges_.insert(edge);
                edge_[edge0->index_].push_back(edge);
            for (Position i = 0; i < number_of_segments; i++)
            {
                Triangle* t = new Triangle;
                    tses_->triangles_.push_back(t);
                    tses_->number_of_triangles_++;
                    t->vertex_[0] = points[number_of_triangles*(i+1)-1];
                    t->vertex_[1] = points[last];
                    t->vertex_[2] = points[number_of_triangles*(i+2)-1];
                    t->edge_[0] = edge;
                    t->edge_[1] = edges[offset+i*end];
                    edge = new TriangleEdge;
                        tses_->edges_.push_back(edge);
                        tses_->number_of_edges_++;
                        edge->vertex_[0] = points[number_of_triangles*(i+2)-1];
                        edge->vertex_[1] = points[last];
                        edge->vertex_[0]->edges_.insert(edge);
                        edge->vertex_[1]->edges_.insert(edge);
                        if (i == number_of_segments-1)
                        {
                            edge_[edge2->index_].push_back(edge);
                        }
                    t->edge_[2] = edge;
                    t->vertex_[0]->faces_.insert(t);
                    t->vertex_[1]->faces_.insert(t);
                    t->vertex_[2]->faces_.insert(t);
                    t->edge_[0]->face_[0] = t;
                    t->edge_[1]->face_[0] = t;
                    t->edge_[2]->face_[0] = t;
                    triangles.push_back(t);
            }
        }
    }


}	// namespace BALL
