Exemplo n.º 1
0
    /// <summary>
    /// Check the upper and lower edges of the given region to see if
    /// they intersect.  If so, create the intersection and add it
    /// to the data structures.
    ///
    /// Returns TRUE if adding the new intersection resulted in a recursive
    /// call to AddRightEdges(); in this case all "dirty" regions have been
    /// checked for intersections, and possibly regUp has been deleted.
    /// </summary>
    private bool CheckForIntersect(ActiveRegion regUp)
    {
        ActiveRegion regLo = RegionBelow(regUp);

        MeshUtils.Edge   eUp   = regUp._eUp;
        MeshUtils.Edge   eLo   = regLo._eUp;
        MeshUtils.Vertex orgUp = eUp._Org;
        MeshUtils.Vertex orgLo = eLo._Org;
        MeshUtils.Vertex dstUp = eUp._Dst;
        MeshUtils.Vertex dstLo = eLo._Dst;

        Debug.Assert(!Geom.VertEq(dstLo, dstUp));
        Debug.Assert(Geom.EdgeSign(dstUp, _event, orgUp) <= 0.0f);
        Debug.Assert(Geom.EdgeSign(dstLo, _event, orgLo) >= 0.0f);
        Debug.Assert(orgUp != _event && orgLo != _event);
        Debug.Assert(!regUp._fixUpperEdge && !regLo._fixUpperEdge);

        if (orgUp == orgLo)
        {
            // right endpoints are the same
            return(false);
        }

        double tMinUp = Math.Min(orgUp._t, dstUp._t);
        double tMaxLo = Math.Max(orgLo._t, dstLo._t);

        if (tMinUp > tMaxLo)
        {
            // t ranges do not overlap
            return(false);
        }

        if (Geom.VertLeq(orgUp, orgLo))
        {
            if (Geom.EdgeSign(dstLo, orgUp, orgLo) > 0.0f)
            {
                return(false);
            }
        }
        else
        {
            if (Geom.EdgeSign(dstUp, orgLo, orgUp) < 0.0f)
            {
                return(false);
            }
        }

        // At this point the edges intersect, at least marginally

        MeshUtils.Vertex isect = _pool.Get <MeshUtils.Vertex>();
        Geom.EdgeIntersect(dstUp, orgUp, dstLo, orgLo, isect);
        // The following properties are guaranteed:
        Debug.Assert(Math.Min(orgUp._t, dstUp._t) <= isect._t);
        Debug.Assert(isect._t <= Math.Max(orgLo._t, dstLo._t));
        Debug.Assert(Math.Min(dstLo._s, dstUp._s) <= isect._s);
        Debug.Assert(isect._s <= Math.Max(orgLo._s, orgUp._s));

        if (Geom.VertLeq(isect, _event))
        {
            // The intersection point lies slightly to the left of the sweep line,
            // so move it until it's slightly to the right of the sweep line.
            // (If we had perfect numerical precision, this would never happen
            // in the first place). The easiest and safest thing to do is
            // replace the intersection by tess._event.
            isect._s = _event._s;
            isect._t = _event._t;
        }
        // Similarly, if the computed intersection lies to the right of the
        // rightmost origin (which should rarely happen), it can cause
        // unbelievable inefficiency on sufficiently degenerate inputs.
        // (If you have the test program, try running test54.d with the
        // "X zoom" option turned on).
        MeshUtils.Vertex orgMin = Geom.VertLeq(orgUp, orgLo) ? orgUp : orgLo;
        if (Geom.VertLeq(orgMin, isect))
        {
            isect._s = orgMin._s;
            isect._t = orgMin._t;
        }

        if (Geom.VertEq(isect, orgUp) || Geom.VertEq(isect, orgLo))
        {
            // Easy case -- intersection at one of the right endpoints
            CheckForRightSplice(regUp);
            _pool.Return(isect);
            return(false);
        }

        if (!Geom.VertEq(dstUp, _event) &&
            Geom.EdgeSign(dstUp, _event, isect) >= 0.0f ||
            !Geom.VertEq(dstLo, _event) &&
            Geom.EdgeSign(dstLo, _event, isect) <= 0.0f)
        {
            // Very unusual -- the new upper or lower edge would pass on the
            // wrong side of the sweep event, or through it. This can happen
            // due to very small numerical errors in the intersection calculation.
            if (dstLo == _event)
            {
                // Splice dstLo into eUp, and process the new region(s)
                _mesh.SplitEdge(_pool, eUp._Sym);
                Mesh.Splice(_pool, eLo._Sym, eUp);
                regUp = TopLeftRegion(regUp);
                eUp   = RegionBelow(regUp)._eUp;
                FinishLeftRegions(RegionBelow(regUp), regLo);
                AddRightEdges(regUp, eUp._Oprev, eUp, eUp, true);
                _pool.Return(isect);
                return(true);
            }
            if (dstUp == _event)
            {
                /* Splice dstUp into eLo, and process the new region(s) */
                _mesh.SplitEdge(_pool, eLo._Sym);
                Mesh.Splice(_pool, eUp._Lnext, eLo._Oprev);
                regLo = regUp;
                regUp = TopRightRegion(regUp);
                MeshUtils.Edge e = RegionBelow(regUp)._eUp._Rprev;
                regLo._eUp = eLo._Oprev;
                eLo        = FinishLeftRegions(regLo, null);
                AddRightEdges(regUp, eLo._Onext, eUp._Rprev, e, true);
                _pool.Return(isect);
                return(true);
            }
            // Special case: called from ConnectRightVertex. If either
            // edge passes on the wrong side of tess._event, split it
            // (and wait for ConnectRightVertex to splice it appropriately).
            if (Geom.EdgeSign(dstUp, _event, isect) >= 0.0f)
            {
                RegionAbove(regUp)._dirty = regUp._dirty = true;
                _mesh.SplitEdge(_pool, eUp._Sym);
                eUp._Org._s = _event._s;
                eUp._Org._t = _event._t;
            }
            if (Geom.EdgeSign(dstLo, _event, isect) <= 0.0f)
            {
                regUp._dirty = regLo._dirty = true;
                _mesh.SplitEdge(_pool, eLo._Sym);
                eLo._Org._s = _event._s;
                eLo._Org._t = _event._t;
            }
            // leave the rest for ConnectRightVertex
            _pool.Return(isect);
            return(false);
        }

        // General case -- split both edges, splice into new vertex.
        // When we do the splice operation, the order of the arguments is
        // arbitrary as far as correctness goes. However, when the operation
        // creates a new face, the work done is proportional to the size of
        // the new face.  We expect the faces in the processed part of
        // the mesh (ie. eUp._Lface) to be smaller than the faces in the
        // unprocessed original contours (which will be eLo._Oprev._Lface).
        _mesh.SplitEdge(_pool, eUp._Sym);
        _mesh.SplitEdge(_pool, eLo._Sym);
        Mesh.Splice(_pool, eLo._Oprev, eUp);
        eUp._Org._s = isect._s;
        eUp._Org._t = isect._t;
        _pool.Return(isect);
        isect = null;
        eUp._Org._pqHandle = _pq.Insert(eUp._Org);
        if (eUp._Org._pqHandle._handle == PQHandle.Invalid)
        {
            throw new InvalidOperationException("PQHandle should not be invalid");
        }
        GetIntersectData(eUp._Org, orgUp, dstUp, orgLo, dstLo);
        RegionAbove(regUp)._dirty = regUp._dirty = regLo._dirty = true;
        return(false);
    }