Beispiel #1
0
        private void FinishLine(JCVEdge e)
        {
            if (!clipper.ClipEdge(e))
            {
                return;
            }

            // Make sure the graph edges are CCW
            int flip = TriIsCCW(e.Sites[0].center, e.Points[0], e.Points[1]) ? 0 : 1;

            for (int i = 0; i < 2; i++)
            {
                PointF[] tempPts  = new PointF[2];
                JCVSite  home     = e.Sites[i];
                JCVSite  neighbor = e.Sites[1 - i];
                tempPts[flip]     = e.Points[i];
                tempPts[1 - flip] = e.Points[1 - i];

                JCVGraphEdge ge = new JCVGraphEdge(e, home, neighbor, tempPts);
                home.edges.Add(ge);
            }
            //        // check that we didn't accidentally add a duplicate (rare), then remove it
            //        if(ge->next && ge->angle == ge->next->angle )
            //        {
            //            if(jcv_point_eq( &ge->pos[0], &ge->next->pos[0] ) && jcv_point_eq( &ge->pos[1], &ge->next->pos[1] ) )
            //            {
            //                ge->next = ge->next->next; // Throw it away, they're so few anyways
            //            }
            //      }
            //    }
        }
Beispiel #2
0
        private void SiteEvent(JCVSite site)
        {
            JCVHalfEdge left   = GetEdgeAboveX(site.center);
            JCVHalfEdge right  = left.right;
            JCVSite     bottom = (left.Edge is null) ? sites[0] : left.rSite;

            JCVEdge edge = new JCVEdge(bottom, site);

            edges.Add(edge);

            JCVHalfEdge he1 = new JCVHalfEdge(edge, false, left);
            JCVHalfEdge he2 = new JCVHalfEdge(edge, true, he1);

            lastInserted = right;

            PointF p;

            if (CheckCircleEvent(left, he1, out p))
            {
                priorityQueue.Remove(left);
                left.vertex = p;
                left.Y      = p.Y + PointDistance(site.center, p);
                priorityQueue.Add(left);
            }
            if (CheckCircleEvent(he2, right, out p))
            {
                he2.vertex = p;
                he2.Y      = p.Y + PointDistance(site.center, p);
                priorityQueue.Add(he2);
            }
        }
Beispiel #3
0
        public float A, B, C; // line equation: ax + by + c = 0

        public JCVEdge(JCVSite site, PointF[] points)
        {
            Points   = points;
            Sites    = new JCVSite[2];
            Next     = null;
            Sites[0] = site;
            Sites[1] = null;
        }
Beispiel #4
0
 public JCVGraphEdge(JCVEdge e, JCVSite home, JCVSite neighbor, PointF[] points)
 {
     Edge     = e;
     Home     = home;
     Neighbor = neighbor;
     Points   = points;
     Angle    = calcAngle(home);
 }
Beispiel #5
0
        //note to self: this is currently a black box. Figure out how it works at some point
        private bool RightOf(JCVHalfEdge he, PointF p)
        {
            JCVEdge edge    = he.Edge;
            JCVSite topsite = edge.Sites[1];

            bool rightOfSite = (p.X > topsite.X);

            if (rightOfSite ^ he.directionIsRight) //direction and rightOfSite don't match
            {
                return(rightOfSite);
            }

            float dxp, dyp, dxs, t1, t2, t3, yl;
            bool  above;

            if (edge.A == 1)
            {
                dyp = p.Y - topsite.Y;
                dxp = p.X - topsite.X;
                bool fast = false;
                if ((!rightOfSite & (edge.B < 0)) || (rightOfSite & (edge.B >= 0)))
                {
                    above = dyp >= edge.B * dxp;
                    fast  = above;
                }
                else
                {
                    above = (p.X + p.Y * edge.B) > edge.C;
                    if (edge.B < 0)
                    {
                        above = !above;
                    }
                    if (!above)
                    {
                        fast = true;
                    }
                }
                if (!fast)
                {
                    dxs   = topsite.X - edge.Sites[0].X;
                    above = edge.B * (dxp * dxp - dyp * dyp)
                            < dxs * dyp * (1 + 2 * dxp / dxs + edge.B * edge.B);
                    if (edge.B < 0)
                    {
                        above = !above;
                    }
                }
            }
            else // edge.b == 1
            {
                yl    = edge.C - edge.A * p.X;
                t1    = p.Y - yl;
                t2    = p.X - topsite.X;
                t3    = yl - topsite.Y;
                above = t1 * t1 > (t2 * t2 + t3 * t3);
            }
            return(he.directionIsRight ^ above);
        }
Beispiel #6
0
        private void CircleEvent()
        {
            JCVHalfEdge left = priorityQueue.First();

            priorityQueue.Remove(left);

            JCVHalfEdge leftleft   = left.left;
            JCVHalfEdge right      = left.right;
            JCVHalfEdge rightright = right.right;
            JCVSite     bottom     = left.lSite;
            JCVSite     top        = right.rSite;

            PointF vertex = left.vertex;

            EndPoints(left.Edge, vertex, left.directionIsRight);
            EndPoints(right.Edge, vertex, right.directionIsRight);

            lastInserted = rightright;

            priorityQueue.Remove(right);
            left.Unlink();
            right.Unlink();

            bool dirIsRight = false;

            if (bottom.Y > top.Y)
            {
                JCVSite temp = bottom;
                bottom     = top;
                top        = temp;
                dirIsRight = true;
            }

            JCVEdge edge = new JCVEdge(bottom, top);

            edges.Add(edge);

            JCVHalfEdge he = new JCVHalfEdge(edge, dirIsRight, leftleft);

            EndPoints(edge, vertex, !dirIsRight);

            PointF p;

            if (CheckCircleEvent(leftleft, he, out p))
            {
                priorityQueue.Remove(leftleft);
                leftleft.vertex = p;
                leftleft.Y      = p.Y + PointDistance(bottom.center, p);
                priorityQueue.Add(leftleft);
            }
            if (CheckCircleEvent(he, rightright, out p))
            {
                he.vertex = p;
                he.Y      = p.Y + PointDistance(bottom.center, p);
                priorityQueue.Add(he);
            }
        }
Beispiel #7
0
        private float calcAngle(JCVSite site)
        {
            // We take the average of the two points, since we can better distinguish between very small edges
            float x     = (Points[0].X + Points[1].X) / 2;
            float y     = (Points[0].Y + Points[1].Y) / 2;
            float diffy = y - site.Y;
            float angle = (float)Math.Atan2(diffy, x - site.X);

            if (diffy < 0)
            {
                angle = (float)(angle + 2 * Math.PI);
            }
            return(angle);
        }
Beispiel #8
0
        public JCVEdge(JCVSite site1, JCVSite site2)
        {
            Points      = new PointF[2];
            Sites       = new JCVSite[2];
            Next        = null;
            Sites[0]    = site1;
            Sites[1]    = site2;
            Points[0].X = JCV_INVALID_VALUE;
            Points[0].Y = JCV_INVALID_VALUE;
            Points[1].X = JCV_INVALID_VALUE;
            Points[1].Y = JCV_INVALID_VALUE;

            // Create line equation between S1 and S2:
            // float a = -1 * (site2.Y - site1.Y);
            // float b = site2.X - site1.X;
            // //float c = -1 * (site2.X - site1.X) * site1.Y + (site2.Y - site1.Y) * site1.X;
            //
            // // create perpendicular line
            // float pa = b;
            // float pb = -a;
            // //float pc = pa * site1.X + pb * site1.Y;
            //
            // // Move to the mid point
            // float mx = site1.X + dx * float(0.5);
            // float my = site1.Y + dy * float(0.5);
            // float pc = ( pa * mx + pb * my );

            float dx           = site2.X - site1.X;
            float dy           = site2.Y - site1.Y;
            bool  dx_is_larger = (dx * dx) > (dy * dy); // instead of fabs

            // Simplify it, using dx and dy
            C = dx * (site1.X + dx * 0.5f) + dy * (site1.Y + dy * 0.5f);

            if (dx_is_larger)
            {
                A  = (float)1;
                B  = dy / dx;
                C /= dx;
            }
            else
            {
                A  = dx / dy;
                B  = (float)1;
                C /= dy;
            }
        }
Beispiel #9
0
        // They're sorted CCW, so if the current->pos[1] != next->pos[0], then we have a gap
        public override bool FillGaps(JCVSite site, JCVDiagram diagram)
        {
            if (site.edges.Count == 0) //no edges, must be single cell graph
            {
                if (diagram.sites.Count != 0)
                {
                    throw new Exception("Invalid graph: edgeless site in graph");
                }

                PointF[] points = new PointF[2];
                points[0] = new PointF(boundingBox.Left, boundingBox.Top);
                points[1] = new PointF(boundingBox.Right, boundingBox.Top);

                JCVEdge edge = new JCVEdge(site, points);
                diagram.edges.Add(edge);
                JCVGraphEdge gap = new JCVGraphEdge(edge, site, null, points);
                site.edges.Add(gap);
            }

            if (site.edges.Count == 1) // one edge, assume corner gap
            {
                JCVGraphEdge current = site.edges[0];

                PointF[] points = new PointF[2];
                points[0] = current.Points[1];
                if (current.Points[1].X < boundingBox.Right && current.Points[1].Y == boundingBox.Top)
                {
                    points[1] = new PointF(boundingBox.Right, boundingBox.Top);
                }
                else if (current.Points[1].X > boundingBox.Left && current.Points[1].Y == boundingBox.Bottom)
                {
                    points[1] = new PointF(boundingBox.Left, boundingBox.Bottom);
                }
                else if (current.Points[1].Y > boundingBox.Top && current.Points[1].X == boundingBox.Left)
                {
                    points[1] = new PointF(boundingBox.Left, boundingBox.Top);
                }
                else if (current.Points[1].Y < boundingBox.Bottom && current.Points[1].X == boundingBox.Right)
                {
                    points[1] = new PointF(boundingBox.Right, boundingBox.Bottom);
                }

                JCVEdge edge = new JCVEdge(site, points);
                diagram.edges.Add(edge);
                JCVGraphEdge gap = new JCVGraphEdge(edge, site, null, points);
                site.edges.Add(gap);
            }

            int eIndex = 0;

            while (eIndex < site.edges.Count)
            {
                JCVGraphEdge current = site.edges[eIndex];
                JCVGraphEdge next    = site.edges[(eIndex + 1) % site.edges.Count];
                if (PointIsOnEdge(current.Points[1]) && current.Points[1] != next.Points[0])
                {
                    //border gap
                    if (current.Points[1].X == next.Points[0].X || current.Points[1].Y == next.Points[0].Y)
                    {
                        PointF[] points = { current.Points[1], next.Points[0] };
                        JCVEdge  edge   = new JCVEdge(site, points);
                        diagram.edges.Add(edge);
                        JCVGraphEdge gap = new JCVGraphEdge(edge, site, null, points);

                        // note: performance of repeated insertions may justify switching to linked list or SortedSet structure
                        // for processing phase; List currently used due to ease of use, and fact that it will be as fast or
                        // faster than other structures when the diagram is later used (post generation)
                        site.edges.Insert(eIndex + 1, gap);
                    }
                    else if (PointIsOnEdge(current.Points[1]) && PointIsOnEdge(next.Points[0]))
                    {
                        PointF[] points = new PointF[2];
                        points[0] = current.Points[1];
                        if (current.Points[1].X < boundingBox.Right && current.Points[1].Y == boundingBox.Top)
                        {
                            points[1] = new PointF(boundingBox.Right, boundingBox.Top);
                        }
                        else if (current.Points[1].X > boundingBox.Left && current.Points[1].Y == boundingBox.Bottom)
                        {
                            points[1] = new PointF(boundingBox.Left, boundingBox.Bottom);
                        }
                        else if (current.Points[1].Y > boundingBox.Top && current.Points[1].X == boundingBox.Left)
                        {
                            points[1] = new PointF(boundingBox.Left, boundingBox.Top);
                        }
                        else if (current.Points[1].Y < boundingBox.Bottom && current.Points[1].X == boundingBox.Right)
                        {
                            points[1] = new PointF(boundingBox.Right, boundingBox.Bottom);
                        }

                        JCVEdge edge = new JCVEdge(site, points);
                        diagram.edges.Add(edge);
                        JCVGraphEdge gap = new JCVGraphEdge(edge, site, null, points);
                        site.edges.Insert(eIndex + 1, gap);
                    }
                    else
                    {
                        //something went wrong; abort instead of looping indefinitely
                        throw new Exception("Invalid Gap state, site location " + site.center.ToString());
                    }
                }
                eIndex++;
            }

            //    current = current->next;
            //    if (current)
            //    {
            //        next = current->next;
            //        if (!next)
            //            next = site->edges;
            //    }
            //}

            ////*********** moved down from top ****************
            //jcv_graphedge* current = site->edges;
            //if (!current)
            //{
            //    // No edges, then it should be a single cell
            //    assert(allocator->numsites == 1);

            //    jcv_graphedge* gap = jcv_alloc_graphedge(allocator);
            //    gap->neighbor = 0;
            //    gap->pos[0] = clipper->min;
            //    gap->pos[1].x = clipper->max.x;
            //    gap->pos[1].y = clipper->min.y;
            //    gap->angle = jcv_calc_sort_metric(site, gap);
            //    gap->next = 0;
            //    gap->edge = jcv_create_gap_edge(allocator, site, gap);

            //    current = gap;
            //    site->edges = gap;
            //}

            //jcv_graphedge* next = current->next;
            //if (!next)
            //{
            //    // Only one edge, then we assume it's a corner gap
            //    jcv_graphedge* gap = jcv_alloc_graphedge(allocator);
            //    jcv_create_corner_edge(allocator, site, current, gap);
            //    gap->edge = jcv_create_gap_edge(allocator, site, gap);

            //    gap->next = current->next;
            //    current->next = gap;
            //    current = gap;
            //    next = site->edges;
            //}
            return(false);
        }
Beispiel #10
0
 public abstract bool FillGaps(JCVSite site, JCVDiagram diagram);