/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2020 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#ifndef OSGEARTHUTIL_WINGED_EDGE_MESH_H
#define OSGEARTHUTIL_WINGED_EDGE_MESH_H 1

#include <osgEarth/Common>
#include <osgEarth/Math>
#include <osgEarth/Notify>
#include <algorithm>
#include <vector>
#include <deque>
#include <set>
#include <type_traits>
#include <iterator>
#include <osg/Vec3>
#include <osg/Geometry>
#include <osgEarth/rtree.h>

// Class for creating meshes and then editing them by cutting in new
// line segments.

namespace osgEarth { namespace Util
{
    struct OSGEARTH_EXPORT Empty
    {
    };
    template<typename Coord, typename V = Empty, typename E = Empty, typename F = Empty>
    class WingedEdgeMesh : public osg::Referenced
    {
    public:
        class Edge;
        class Face;

        //! Represents a single vertex in the topology graph
        struct Vertex : public V
        {
            Vertex(const Coord& pos)
                : position(pos)
            {
            }
            Coord position;
            // All Edge objects that has this vertex as the starting vertex (origVert)
            mutable std::vector<Edge*> edges;
        };

        bool isVertexInMesh(const Vertex* v)
        {
            return !v->edges.empty();
        }

        using VVec = std::vector<const Vertex*>;

        struct EdgeIntersection
        {
            EdgeIntersection()
                : edge(nullptr)
            {}
            EdgeIntersection(const Edge* edge, const Coord& position)
                : edge(edge), position(position)
            {}
            const Edge* edge;
            Coord position;
        };

        double distance2(const EdgeIntersection& ei, const Coord& point)
        {
            double x = ei.position.x() - point.x();
            double y = ei.position.y() - point.y();
            return x * x + y * y;
        }
        
        struct Face : public F
        {
            Face(Edge* e = nullptr)
                : edge(e)
            {
            }
            // An edge that is adjacent to this face
            Edge* edge;
            // Lots of hair for iterators over the edges and vertices
            // of a face.
            // XXX Is there any other kind of iterator than a
            // const_iterator for face edges?
            template<bool Const = false>
            class FaceIterator
            {
            public:
                using difference_type = int;
                using value_type = Edge*;
                using reference = typename std::conditional<Const, Edge* const &, Edge*&>::type;
                using pointer = typename std::conditional<Const, Edge* const *, Edge**>::type;
                using iterator_category = std::bidirectional_iterator_tag;
                pointer thisEdge;
                pointer originalEdge;
                bool atEnd;
                FaceIterator()
                    : thisEdge(nullptr), originalEdge(nullptr), atEnd(false)
                {}

                template<typename FaceType>
                FaceIterator(FaceType& face, bool atEnd)
                    :  originalEdge(&face.edge), atEnd(atEnd)
                {
                    if (atEnd)
                    {
                        thisEdge = nullptr;
                    }
                    else
                    {
                        thisEdge = originalEdge;
                    }
                }

                template<bool _Const = Const>
                typename std::enable_if<_Const, reference>::type
                operator*() const
                {
                    return *thisEdge;
                }

                template<bool _Const = Const>
                typename std::enable_if<!_Const, reference>::type
                operator*()
                {
                    return *thisEdge;
                }

                FaceIterator& operator++()
                {
                    if (atEnd)
                    {
                        return *this;
                    }
                    if ((*thisEdge)->nextEdge() == *originalEdge)
                    {
                        thisEdge = nullptr;
                        atEnd = true;
                    }
                    else
                    {
                        thisEdge = &(*thisEdge)->nextEdge();
                    }
                    return *this;
                }

                FaceIterator operator++(int)
                {
                    auto result = *this;
                    ++(*this);
                    return result;
                }

                FaceIterator& operator--()
                {
                    if (atEnd)
                    {
                        thisEdge = &(*originalEdge)->prevEdge();
                        atEnd = false;
                    }
                    else
                    {
                        thisEdge = &(*thisEdge)->prevEdge();
                    }
                    return *this;
                }

                FaceIterator operator--(int)
                {
                    auto result = *this;
                    --(*this);
                    return result;
                }

                bool operator==(const FaceIterator& it) const
                {
                    if (atEnd && it.atEnd)
                        return true;
                    else if (atEnd != it.atEnd)
                        return false;
                    else
                        return *thisEdge == *it.thisEdge;
                }

                bool operator!=(const FaceIterator& it) const
                {
                    return !(*this == it);
                }
            };

            FaceIterator<false> begin()
            {
                return FaceIterator<false>(*this, false);
            }

            FaceIterator<false> end()
            {
                return FaceIterator<false>(*this, true);
            }

            FaceIterator<true> begin() const
            {
                return FaceIterator<true>(*this, false);
            }

            FaceIterator<true> end() const
            {
                return FaceIterator<true>(*this, true);
            }

            template<bool Const = false>
            class FaceVertexIterator
            {
            public:
                using difference_type = int;
                using value_type = Vertex*;
                using reference = typename std::conditional<Const, const Vertex* const &, Vertex*&>::type;
                using pointer = typename std::conditional<Const, const Vertex* const *, Vertex**>::type;
                using iterator_category = std::bidirectional_iterator_tag;

                FaceIterator<Const> faceIterator;

                FaceVertexIterator(const FaceIterator<Const> faceIterator)
                    : faceIterator(faceIterator)
                {}

                template<bool _Const = Const>
                typename std::enable_if<_Const, reference>::type
                operator*() const
                {
                    return (*faceIterator)->origVert();
                }

                template<bool _Const = Const>
                typename std::enable_if<!_Const, reference>::type
                operator*()
                {
                    return (*faceIterator)->origVert();
                }

                FaceVertexIterator& operator++()
                {
                    ++faceIterator;
                    return *this;
                }

                FaceVertexIterator operator++(int)
                {
                    auto result = *this;
                    ++(*this);
                    return result;
                }

                FaceVertexIterator& operator--()
                {
                    --faceIterator;
                    return *this;
                }

                FaceVertexIterator operator--(int)
                {
                    auto result = *this;
                    --(*this);
                    return result;
                }

                bool operator==(const FaceVertexIterator& rhs) const
                {
                    return faceIterator == rhs.faceIterator;
                }

                bool operator!=(const FaceVertexIterator& rhs) const
                {
                    return faceIterator != rhs.faceIterator;
                }
            };

            class FacePositionIterator
            {
            public:
                using difference_type = int;
                using value_type = Coord;
                using reference = const Coord&;
                using pointer = const Coord*;
                using iterator_category = std::bidirectional_iterator_tag;

                FaceVertexIterator<true> fvIterator;

                FacePositionIterator(const FaceVertexIterator<true> fvIterator)
                    : fvIterator(fvIterator)
                {}

                const Coord& operator*() const
                {
                    return (*fvIterator)->position;
                }

                FacePositionIterator& operator++()
                {
                    ++fvIterator;
                    return *this;
                }

                FacePositionIterator operator++(int)
                {
                    auto result = *this;
                    ++(*this);
                    return result;
                }

                FacePositionIterator& operator--()
                {
                    --fvIterator;
                    return *this;
                }

                FacePositionIterator operator--(int)
                {
                    auto result = *this;
                    --(*this);
                    return result;
                }

                bool operator==(const FacePositionIterator& rhs) const
                {
                    return fvIterator == rhs.fvIterator;
                }

                bool operator!=(const FacePositionIterator& rhs) const
                {
                    return fvIterator != rhs.fvIterator;
                }
            };

        };

        struct FaceVerticesAdapter
        {
            const Face& face;
            FaceVerticesAdapter(const Face& face)
                : face(face)
            {}

            typename Face::template FaceVertexIterator<true> begin() const
            {
                return typename Face::template FaceVertexIterator<true>(face.begin());
            }

            typename Face::template FaceVertexIterator<true> end() const
            {
                return typename Face::template FaceVertexIterator<true>(face.end());
            }
        };

        struct FacePositionAdapter
        {
            const FaceVerticesAdapter fva;
            FacePositionAdapter(const Face& face)
                : fva(face)
            {}

            typename Face::FacePositionIterator begin() const
            {
                return typename Face::FacePositionIterator(fva.begin());
            }

            typename Face::FacePositionIterator end() const
            {
                return typename Face::FacePositionIterator(fva.end());
            }
        };

        // Yet another iterator! Faces around a vertex. The iterator
        // might reference a nullptr if the corresponding edge has no
        // face, so that must be checked by the user.
        class VertexFaceIterator
        {
        public:
            using difference_type = int;
            using value_type = const Face *;
            using reference = const Face*&;
            using pointer = const Face**;
            using iterator_category = std::bidirectional_iterator_tag;
            using NestedIterator = typename std::vector<Edge*>::const_iterator;

            NestedIterator eIterator;

            VertexFaceIterator(const NestedIterator eIterator)
                : eIterator(eIterator)
            {

            }

            const Face* operator*() const
            {
                return (*eIterator)->f;
            }

            VertexFaceIterator& operator++()
            {
                ++eIterator;
                return *this;
            }

            VertexFaceIterator operator++(int)
            {
                auto result = *this;
                ++(*this);
                return result;
            }

            VertexFaceIterator& operator--()
            {
                --eIterator;
                return *this;
            }

            VertexFaceIterator operator--(int)
            {
                auto result = *this;
                --(*this);
                return result;
            }

            bool operator==(const VertexFaceIterator& rhs) const
            {
                return eIterator == rhs.eIterator;
            }

            bool operator!=(const VertexFaceIterator& rhs) const
            {
                return eIterator != rhs.eIterator;
            }
        };

        struct VertexFaceAdapter
        {
            const Vertex* vertex;

            VertexFaceAdapter(const Vertex* vertex)
                : vertex(vertex)
            {}

            typename Face::VertexFaceIterator begin() const
            {
                return typename Face::VertexFaceIterator(vertex->edges.begin());
            }

            typename Face::VertexFaceIterator end() const
            {
                return typename Face::VertexFaceIterator(vertex->edges.end());
            }
        };

        // Number of face edges and vertices
        int getFaceSize(const Face* f)
        {
            if (!f->edge)
                return 0;
            return std::distance(f->begin(), f->end());
        }

        VVec getFaceVertices(const Face* f)
        {
            VVec result;
            if (!f->edge)
            {
                return result;
            }
            for (auto& e : *f)
            {
                result.push_back(e->origVert());
            }
            return result;
        }

        struct VertexCmp
        {
            bool operator()(const Coord& lhs, const Coord& rhs) const
            {
                if (lhs.x() < rhs.x())
                    return true;
                else if (lhs.x() > rhs.x())
                    return false;
                else
                    return lhs.y() < rhs.y();
            }

            bool operator()(const Vertex& lhs, const Vertex& rhs) const
            {
                return (*this)(lhs.position, rhs.position);
            }

            bool operator()(const Vertex& lhs, const Coord& rhs) const
            {
                return (*this)(lhs.position, rhs);
            }

            bool operator()(const Coord& lhs, const Vertex& rhs) const
            {
                return (*this)(lhs, rhs.position);
            }
        };

        typedef std::map<Coord, Vertex> VertexMap;
        const Vertex* getVertex(const Coord& position)
        {
            auto result = vertices.emplace(std::make_pair(position, position));
            return &result.first->second;
        }

        const Vertex* lookupVertex(const Coord& position)
        {
            auto vItr = vertices.find(position);
            if (vItr == vertices.end())
            {
                return nullptr;
            }
            else
            {
                return &vItr->second;
            }
        }

        // Half Edges surround faces in counter-clockwise order
        // The vertices are in order for the left face
        struct Edge : public E
        {
            Edge(const Vertex* vOrig, const Vertex* vDest)
                : mate(nullptr), f(nullptr)
            {
                v[0] = vOrig;
                v[1] = vDest;
                e[0] = nullptr;
                e[1] = nullptr;
            }
            const Vertex* v[2];
            // left face
            Face* f;
            // edges - prev, next edge on left face
            Edge* e[2];
            const Vertex*& origVert()
            {
                return v[0];
            }
            const Vertex* origVert() const
            {
                return v[0];
            }
            const Vertex*& destVert()
            {
                return v[1];
            }
            const Vertex* destVert() const
            {
                return v[1];
            }
            Edge*& prevEdge()
            {
                return e[0];
            }
            Edge* prevEdge() const
            {
                return e[0];
            }
            Edge*& nextEdge()
            {
                return e[1];
            }
            Edge* nextEdge() const
            {
                return e[1];
            }
            // The half edge running in the other direction
            Edge* mate;
        };

        Edge* newEdge(const Vertex* vOrig, const Vertex* vDest)
        {
            edges.emplace_back(vOrig, vDest);
            return &edges.back();
        }

        Face* newFace(Edge* edge = nullptr)
        {
            faces.emplace_back(edge);
            return &faces.back();
        }

        ~WingedEdgeMesh()
        {
        }
        VertexMap vertices;
        std::deque<Edge> edges;
        std::deque<Face> faces;
        RTree<Face *, double, 2> faceIndex;

        // Create a Face from a list of Vertex*
        template<typename VItr>
        Face* addFace(VItr begin, VItr end)
        {
            Face* f = newFace();
            Edge *firstEdge = nullptr, *prevEdge = nullptr;
            VItr first = begin;
            // Set v0Itr to last vertex in new face
            VItr v0Itr = end - 1, v1Itr = first;
            for (; v1Itr != end; v0Itr = v1Itr++)
            {
                Edge* e = newEdge(*v0Itr, *v1Itr);
                if (!f->edge)
                {
                    f->edge = e;
                }
                e->f = f;
                // Search for the matching half-edge. It's origin will be
                // this edge's destination.
                auto mateEdgeItr = std::find_if((*v1Itr)->edges.begin(), (*v1Itr)->edges.end(),
                                                [v0Itr](const Edge* vertEdge)
                                                {
                                                    return *v0Itr == vertEdge->destVert();
                                                });
                if (mateEdgeItr != (*v1Itr)->edges.end())
                {
                    e->mate = *mateEdgeItr;
                    (*mateEdgeItr)->mate = e;
                }
                if (!firstEdge)
                {
                    firstEdge = e;
                }
                if (prevEdge)
                {
                    e->prevEdge() = prevEdge;
                    prevEdge->nextEdge() = e;
                }
                if (v1Itr + 1 == end)
                {
                    e->nextEdge() = firstEdge;
                    firstEdge->prevEdge() = e;
                }
                prevEdge = e;
                (*v0Itr)->edges.push_back(e);
            }
            FacePositionAdapter adapter(*f);
            osg::BoundingBoxd bbox = polygonBBox2d(adapter.begin(), adapter.end());
            double minv[2] = {bbox.xMin(), bbox.yMin()};
            double maxv[2] = {bbox.xMax(), bbox.yMax()};
            faceIndex.Insert(minv, maxv, f);
            return f;
        }

        bool removeEdge(Edge* e)
        {
            auto origVert = e->origVert();
            auto edgeInVerts = std::find(origVert->edges.begin(), origVert->edges.end(), e);
            if (edgeInVerts != origVert->edges.end())
            {
                origVert->edges.erase(edgeInVerts);
            }
            if (e->mate)
            {
                e->mate->mate = nullptr;
            }
            if (auto prev = e->prevEdge())
            {
                prev->nextEdge() = nullptr;
            }
            if (auto next = e->nextEdge())
            {
                next->prevEdge() = nullptr;
            }
            e->mate = nullptr;
            e->origVert() = nullptr;
            e->destVert() = nullptr;
            e->prevEdge() = nullptr;
            e->nextEdge() = nullptr;
            e->f = nullptr;

            return true;
        }

        bool removeFace(Face* f)
        {
            FacePositionAdapter adapter(*f);
            osg::BoundingBoxd bbox = polygonBBox2d(adapter.begin(), adapter.end());
            double minv[2] = {bbox.xMin(), bbox.yMin()};
            double maxv[2] = {bbox.xMax(), bbox.yMax()};
            faceIndex.Remove(minv, maxv, f);
            Edge* firstEdge = f->edge;
            // Slightly tortured logic because the edge's members are
            // all set to nullptr when it is removed.
            Edge *edge = firstEdge, *nextEdge = nullptr;
            do 
            {
                nextEdge = edge->nextEdge();
                removeEdge(edge);
                edge = nextEdge;
            }
            while (edge); // or nextEdge != nullptr?
            f->edge = nullptr;
            return true;
        }

        // Create new faces using a new vertex in the face
        void subdivideFace(Face* f, const Vertex* v)
        {
            auto faceVerts = getFaceVertices(f);
            removeFace(f);
            // Add back the triangles created by the subdivision.
            for (auto v0Itr = faceVerts.begin(); v0Itr != faceVerts.end(); ++v0Itr)
            {
                auto v1Itr = v0Itr + 1;
                if (v1Itr == faceVerts.end())
                {
                    v1Itr = faceVerts.begin();
                }
                const Vertex* varray[] = {v, *v0Itr, *v1Itr};
                addFace(&varray[0], &varray[3]);
            }
        }

        // Split an edge at vertex newVert, connecting it to another vertex
        // on the same face as the edge to create two faces. Operates only on lists of
        // vertices, producing the vertices of the two new faces.
        //
        // XXX Handle the case where newVert is part of the split edge
        // i.e., equal to origVert or destVert. (?)

        template<typename VertIterator>
        void splitOneFace(const VertIterator& vertsBegin, const VertIterator& vertsEnd,
                          const Vertex* origVert, const Vertex* destVert, const Vertex* newVert,
                          VVec& out0, VVec& out1)
        {
            auto ovItr = std::find(vertsBegin, vertsEnd, origVert);
            // First poly (triangle)
            if (ovItr == vertsBegin)
            {
                out0.push_back((*std::prev(vertsEnd)));
            }
            else
            {
                out0.push_back(*std::prev(ovItr));
            }
            out0.push_back(origVert);
            out0.push_back(newVert);
            // Second poly
            out1.push_back(newVert);
            // Now all the way back to origVert, perhaps going around the
            // Horn
            auto out1VertItr = std::next(ovItr); // points at destVert or faceVerts.end()
            if (out1VertItr != vertsEnd)
            {
                out1.push_back(*out1VertItr++);
            }
            
            for (; out1VertItr != vertsEnd && out1VertItr != ovItr; ++out1VertItr)
            {
                out1.push_back(*out1VertItr);
            }
            if (out1VertItr == vertsEnd)
            {
                for (out1VertItr = vertsBegin; out1VertItr != ovItr; ++ out1VertItr)
                {
                    out1.push_back(*out1VertItr);
                }
            }
            // Now out1VertItr should point at origVert
        }
    
        void splitEdge(Edge* e, const Vertex* v)
        {
            const Vertex* origVert = e->origVert();
            const Vertex* destVert = e->destVert();
            // Vertices for new faces
            VVec newFaces[4];
            Face *oldFace = e->f, *oldOtherFace = nullptr;
            FaceVerticesAdapter faceVerts(*oldFace);
            splitOneFace(faceVerts.begin(), faceVerts.end(), origVert, destVert, v, newFaces[0], newFaces[1]);
            if (e->mate)
            {
                oldOtherFace = e->mate->f;
                FaceVerticesAdapter otherFaceVerts(*oldOtherFace);
                splitOneFace(otherFaceVerts.begin(), otherFaceVerts.end(),
                             destVert, origVert, v, newFaces[2], newFaces[3]);
            }
            removeFace(oldFace);
            if (oldOtherFace)
            {
                removeFace(oldOtherFace);
            }
            for (int i = 0; i < 4; ++i)
            {
                if (!newFaces[i].empty())
                {
                    addFace(newFaces[i].begin(), newFaces[i].end());
                }
            }
        }

        void addGeometry(const osg::Geometry* geom)
        {
            const osg::Geometry::PrimitiveSetList& primSets = geom->getPrimitiveSetList();
            osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());
            for (auto primSet : primSets)
            {
                osg::DrawElementsUShort* de = dynamic_cast<osg::DrawElementsUShort*>(primSet.get());
                if (de && de->getMode() == osg::PrimitiveSet::TRIANGLES)
                {
                    for (int i = 0; i < de->getNumIndices(); i += 3)
                    {
                        Coord coords[3];
                        const Vertex* vtx[3];
                        for (int j = 0; j <  3; ++j)
                        {
                            coords[j] = (*verts)[de->index(i + j)];
                            vtx[j] = getVertex(coords[j]);
                        }
                        addFace(&vtx[0], &vtx[3]);
                    }
                }
            }
        }
        
        bool isPointInFace(const Face* f, const Coord& pt)
        {
            FacePositionAdapter fpa(*f);
            return pointInPoly2d(pt, fpa.begin(), fpa.end());
        }

        Face* getFaceContainingPoint(const Coord& pt)
        {
            std::vector<Face*> hits;
            double minv[2] = {pt.x(), pt.y()};
            double maxv[2] = {pt.x(), pt.y()};
            faceIndex.Search(minv, maxv, &hits, 99);
            for (Face* face : hits)
            {
                if (face->edge && isPointInFace(face, pt))
                {
                    return face;
                }
            }
            return nullptr;
        }

        bool vertsShareEdge(const Vertex* v0, const Vertex* v1)
        {
            for (auto edge : v0->edges)
            {
                if (edge->destVert() == v1)
                    return true;
            }
            for (auto edge : v1->edges)
            {
                if (edge->destVert() == v0)
                    return true;
            }
            return false;
        }


        EdgeIntersection intersectFaceSegment(Face* face, const Vertex* a, const Vertex* b)
        {
            const Segment2d seg(a->position, b->position);
            for (const Edge* edge : *face)
            {
                if (!(a == edge->origVert() || a == edge->destVert()
                      || b == edge->origVert() || b == edge->destVert()))
                {
                    Coord intersection;
                    Segment2d edgeSeg(edge->origVert()->position, edge->destVert()->position);
                    if (edgeSeg.intersect(seg, intersection))
                    {
                        return EdgeIntersection(edge, intersection);
                    }
                }
            }
            return EdgeIntersection();
        }

        // Make sure that a segment's endpoints are connected vertices
        // in the mesh. This can make new faces. It also deals with the
        // case of the endpoints not being within the bounds of the
        // mesh; in that case points are created on the boundaries of
        // the mesh and a new segment that does lie in the mash
        // is returned.
        //
        // returns false if it is not possible to create endpoints
        // within the mesh.
        bool insureSegmentInMesh(const Segment2d& segment, Segment2d& newSegment)
        {
            newSegment = segment;
            // 1) End points must lie on mesh vertices. If they don't,
            // add those vertices.
            const Vertex* a = getVertex(segment._a);
            const Vertex* b = getVertex(segment._b);
            Face *aFace = nullptr, *bFace = nullptr;
            if (!isVertexInMesh(a))
            {
                aFace = getFaceContainingPoint(a->position);
                if (aFace)
                {
                    subdivideFace(aFace, a);
                }
            }
            if (!isVertexInMesh(b))
            {
                bFace = getFaceContainingPoint(b->position);
                if (bFace)
                {
                    subdivideFace(bFace, b);
                }
            }
            // Test if the vertices were already in the mesh, or are
            // now due to a subdivided face
            if (isVertexInMesh(a) && isVertexInMesh(b))
            {
                return true;
            }
            // One or both endpoints are not contained in the mesh,
            // which means that the segment crosses one or two edges
            // of the mesh. Find and split the edges to create
            // vertices in the mesh.
            EdgeIntersection aEdgeInter, bEdgeInter;
            if (!isVertexInMesh(a))
            {
                Ray2d aRay(segment._a, segment._b - segment._a);
                aEdgeInter = getBorderEdge(aRay);
            }
            if (!isVertexInMesh(b))
            {
                Ray2d bRay(segment._b, segment._a - segment._b);
                bEdgeInter = getBorderEdge(bRay);
            }
            if (!((isVertexInMesh(a) || aEdgeInter.edge)
                  && (isVertexInMesh(b) || bEdgeInter.edge)))
                return false;
            bool haveAInter = false;
            if (aEdgeInter.edge)
            {
                haveAInter = true;
                const Vertex* edgeVert = getVertex(aEdgeInter.position);
                if (!isVertexInMesh(edgeVert))
                {
                    splitEdge(const_cast<Edge*>(aEdgeInter.edge), edgeVert);
                }
                newSegment._a = aEdgeInter.position;
            }
            if (bEdgeInter.edge)
            {
                // If we needed to split an edge to find a point in
                // the mesh for the "a" vertex, then that operation
                // could destroy the edge that we found for the "b"
                // vertex. This could happen, for example, at the
                // corner of the mesh if those edges are in a shared
                // triangle.
                if (!bEdgeInter.edge->f)
                {
                    if (haveAInter)
                    {
                        Ray2d bRay(segment._b, segment._a - segment._b);
                        bEdgeInter = getBorderEdge(bRay);
                    }
                    else
                    {
                        OE_NOTICE << "invalid edge\n";
                        return false;
                    }
                }
                const Vertex* edgeVert = getVertex(bEdgeInter.position);
                if (!isVertexInMesh(edgeVert))
                {
                    splitEdge(const_cast<Edge*>(bEdgeInter.edge), edgeVert);
                }
                newSegment._b = bEdgeInter.position;
            }
            return true;
        }

        // Get Border edge leaving vertex, if any. Note that there can
        // be only one!
        const Edge* getVertexBorderEdge(const Vertex* v)
        {
            auto eitr = std::find_if(v->edges.begin(), v->edges.end(),
                                     [](const Edge* edge)
                                     {
                                         return !edge->mate;
                                     });
            if (eitr != v->edges.end())
            {
                return *eitr;
            }
            else
            {
                return nullptr;
            }
        }

        // Work around the edge of the mesh, testing for edges that
        // intersect the ray
        EdgeIntersection getBorderEdge(Ray2d& ray)
        {
            // Hope that there aren't more than two!
            std::vector<EdgeIntersection> results;
            // Find the  "bottom left" vertex that has edges. This
            // should be on a corner, or at least a border.
            const Edge* firstEdge = nullptr;
            for (auto vitr = vertices.begin(); vitr != vertices.end(); ++vitr)
            {

                if ((firstEdge = getVertexBorderEdge(&vitr->second)))
                {
                    break;
                }
            }
            if (!firstEdge)
            {
                // throw?
                return EdgeIntersection();
            }
            const Edge* e = firstEdge;
            do
            {
                {
                    Segment2d seg = fromEdge(e);
                    Coord intersect;
                    if (seg.intersect(ray, intersect))
                    {
                        if (e->f)
                        {
                            results.emplace_back(e, intersect);
                        }
                        else
                        {
                            OE_NOTICE << "invalid edge!\n";
                        }
                    }
                }
                e = getVertexBorderEdge(e->destVert());
            }
            while (e && e != firstEdge);
            if (results.empty())
            {
                return EdgeIntersection();
            }
            // return the intersection closed to the ray origin
            auto itr = std::min_element(results.begin(), results.end(),
                                        [&ray,this](const EdgeIntersection& lhs, const EdgeIntersection& rhs)
                                        {
                                            return distance2(lhs, ray._a) < distance2(rhs, ray._a);
                                        });
            return *itr;
        }

        bool cutSegment(const Segment2d& segment)
        {
            Segment2d realSegment;
            // 1) End points must lie on mesh vertices. If they don't,
            // add those vertices.
            if (!insureSegmentInMesh(segment, realSegment))
            {
                return false;
            }
            const Vertex* a = getVertex(realSegment._a);
            const Vertex* b = getVertex(realSegment._b);
            const Vertex* current = a;
            // Proceed through the mesh along the mesh, attempting to
            // create an edge from our current vertex to the segment
            // end point.
            while (!(current == b || vertsShareEdge(current, b)))
            {
                // Look in adjacent faces for an edge that intersects
                // the segment
                EdgeIntersection edgeIntersection;
                for (auto edge : current->edges)
                {
                    Face* face = edge->f;
                    edgeIntersection = intersectFaceSegment(face, current, b) ;
                    if (edgeIntersection.edge)
                    {
                        break;
                    }
                }
                if (!edgeIntersection.edge)
                {
                    // Urk, couldn't find an edge
                    return false;
                }
                current = getVertex(edgeIntersection.position);
                splitEdge(const_cast<Edge*>(edgeIntersection.edge), current);
            }
            return true;
        }

        Segment2d fromEdge(const Edge* edge)
        {
            return Segment2d(edge->origVert()->position, edge->destVert()->position);
        }
    };
    
    
    }}
#endif
