/// <summary>
        /// Compute edge intersections with bounding box.
        /// </summary>
        private void PostProcess(Rectangle box)
        {
            foreach (var edge in rays)
            {
                // The vertices of the infinite edge.
                var v1 = (Point)edge.origin;
                var v2 = (Point)edge.twin.origin;

                if (box.Contains(v1) || box.Contains(v2))
                {
                    // Move infinite vertex v2 onto the box boundary.
                    IntersectionHelper.BoxRayIntersection(box, v1, v2, ref v2);
                }
                else
                {
                    // There is actually no easy way to handle the second case. The two edges
                    // leaving v1, pointing towards the mesh, don't have to intersect the box
                    // (the could join with edges of other cells outside the box).

                    // A general intersection algorithm (DCEL <-> Rectangle) is needed, which
                    // computes intersections with all edges and discards objects outside the
                    // box.
                }
            }
        }
        public StandardVoronoi(Mesh mesh, Rectangle box, IVoronoiFactory factory, IPredicates predicates)
            : base(mesh, factory, predicates, true)
        {
            // We assume the box to be at least as large as the mesh.
            box.Expand(mesh.bounds);

            // We explicitly told the base constructor to call the Generate method, so
            // at this point the basic Voronoi diagram is already created.
            PostProcess(box);
        }
        /// <summary>
        /// Intersect segment with a bounding box.
        /// </summary>
        /// <param name="rect">The clip rectangle.</param>
        /// <param name="p0">Segment endpoint.</param>
        /// <param name="p1">Segment endpoint.</param>
        /// <param name="c0">The new location of p0.</param>
        /// <param name="c1">The new location of p1.</param>
        /// <returns>Returns true, if segment is clipped.</returns>
        /// <remarks>
        /// Based on Liang-Barsky function by Daniel White:
        /// http://www.skytopia.com/project/articles/compsci/clipping.html
        /// </remarks>
        public static bool LiangBarsky(Rectangle rect, Point p0, Point p1, ref Point c0, ref Point c1)
        {
            // Define the x/y clipping values for the border.
            double xmin = rect.Left;
            double xmax = rect.Right;
            double ymin = rect.Bottom;
            double ymax = rect.Top;

            // Define the start and end points of the line.
            double x0 = p0.X;
            double y0 = p0.Y;
            double x1 = p1.X;
            double y1 = p1.Y;

            double t0 = 0.0;
            double t1 = 1.0;

            double dx = x1 - x0;
            double dy = y1 - y0;

            double p = 0.0, q = 0.0, r;

            for (int edge = 0; edge < 4; edge++)
            {
                // Traverse through left, right, bottom, top edges.
                if (edge == 0) { p = -dx; q = -(xmin - x0); }
                if (edge == 1) { p = dx; q = (xmax - x0); }
                if (edge == 2) { p = -dy; q = -(ymin - y0); }
                if (edge == 3) { p = dy; q = (ymax - y0); }
                r = q / p;
                if (p == 0 && q < 0) return false; // Don't draw line at all. (parallel line outside)
                if (p < 0)
                {
                    if (r > t1) return false; // Don't draw line at all.
                    else if (r > t0) t0 = r; // Line is clipped!
                }
                else if (p > 0)
                {
                    if (r < t0) return false; // Don't draw line at all.
                    else if (r < t1) t1 = r; // Line is clipped!
                }
            }

            c0.X = x0 + t0 * dx;
            c0.Y = y0 + t0 * dy;
            c1.X = x0 + t1 * dx;
            c1.Y = y0 + t1 * dy;

            return true; // (clipped) line is drawn
        }
        public static Rectangle Bounds(this ITriangle triangle)
        {
            var bounds = new Rectangle();

            for (int i = 0; i < 3; i++)
            {
                bounds.Expand(triangle.GetVertex(i));
            }

            return bounds;
        }
Example #5
0
        /// <inheritdoc />
        public Rectangle Bounds()
        {
            var bounds = new Rectangle();
            bounds.Expand(this.points.ToPoints());

            return bounds;
        }
Example #6
0
        private void UpdateMetrics(Rectangle bounds)
        {
            x_max = bounds.Right;
            x_min = bounds.Left;
            y_max = bounds.Top;
            y_min = bounds.Bottom;

            // Enlarge width 5% on each side
            double x_scale = x_max - x_min;
            x_max = x_max + 0.05 * x_scale;
            x_min = x_min - 0.05 * x_scale;
            x_scale = x_max - x_min;

            // Enlarge height 5% on each side
            double y_scale = y_max - y_min;
            y_max = y_max + 0.05 * y_scale;
            y_min = y_min - 0.05 * y_scale;
            y_scale = y_max - y_min;

            if (x_scale < y_scale)
            {
                int delta = (int)Math.Round((ps.Right - ps.X) * (y_scale - x_scale) / (2.0 * y_scale));

                ps.Expand(-delta, 0);
                clip.Expand(-delta, 0);
            }
            else
            {
                int delta = (int)Math.Round((ps.Bottom - ps.Y) * (x_scale - y_scale) / (2.0 * x_scale));

                ps.Expand(0, -delta);
                clip.Expand(0, -delta);
            }
        }
        protected List<Vertex> CreateRectangle(Rectangle rect, int nH, int nV, int boundary = 0)
        {
            var contour = new List<Vertex>(2 * nH + 2 * nV);

            // Horizontal and vertical step sizes.
            double stepH = rect.Width / nH;
            double stepV = rect.Height / nV;

            // Left box boundary points
            for (int i = 0; i < nV; i++)
            {
                contour.Add(new Vertex(rect.Left, rect.Bottom + i * stepV, 1));
            }

            // Top box boundary points
            for (int i = 0; i < nH; i++)
            {
                contour.Add(new Vertex(rect.Left + i * stepH, rect.Top, 1));
            }

            // Right box boundary points
            for (int i = 0; i < nV; i++)
            {
                contour.Add(new Vertex(rect.Right, rect.Top - i * stepV, 1));
            }

            // Bottom box boundary points
            for (int i = 0; i < nH; i++)
            {
                contour.Add(new Vertex(rect.Right - i * stepH, rect.Bottom, 1));
            }

            return contour;
        }
Example #8
0
        /// <summary>
        /// Read the vertices from memory.
        /// </summary>
        /// <param name="data">The input data.</param>
        internal void TransferNodes(IList<Vertex> points)
        {
            this.invertices = points.Count;
            this.mesh_dim = 2;
            this.bounds = new Rectangle();

            if (this.invertices < 3)
            {
                logger.Error("Input must have at least three input vertices.", "Mesh.TransferNodes()");
                throw new Exception("Input must have at least three input vertices.");
            }

            var v = points[0];

#if USE_ATTRIBS
            // Check attributes.
            this.nextras = v.attributes == null ? 0 : v.attributes.Length;
#endif

            // Simple heuristic to check if ids are already set.  We assume that if the
            // first two vertex ids are distinct, then all input vertices have pairwise
            // distinct ids.
            bool userId = (v.id != points[1].id);

            foreach (var p in points)
            {
                if (userId)
                {
                    p.hash = p.id;

                    // Make sure the hash counter gets updated.
                    hash_vtx = Math.Max(p.hash + 1, hash_vtx);
                }
                else
                {
                    p.hash = p.id = hash_vtx++;
                }

                this.vertices.Add(p.hash, p);
                this.bounds.Expand(p);
            }
        }
            public QuadNode(Rectangle box, TriangleQuadTree tree, bool init)
            {
                this.tree = tree;

                this.bounds = new Rectangle(box.Left, box.Bottom, box.Width, box.Height);
                this.pivot = new Point((box.Left + box.Right) / 2, (box.Bottom + box.Top) / 2);

                this.bitRegions = 0;

                this.regions = new QuadNode[4];
                this.triangles = new List<int>();

                if (init)
                {
                    int count = tree.triangles.Length;

                    // Allocate memory upfront
                    triangles.Capacity = count;

                    for (int i = 0; i < count; i++)
                    {
                        triangles.Add(i);
                    }
                }
            }
Example #10
0
 /// <summary>
 /// Expand rectangle to include given rectangle.
 /// </summary>
 /// <param name="x">X coordinate.</param>
 /// <param name="y">Y coordinate.</param>
 public void Expand(Rectangle other)
 {
     xmin = Math.Min(xmin, other.xmin);
     ymin = Math.Min(ymin, other.ymin);
     xmax = Math.Max(xmax, other.xmax);
     ymax = Math.Max(ymax, other.ymax);
 }
Example #11
0
        private static Point FindPointInPolygon(List<Vertex> contour, int limit, double eps)
        {
            var bounds = new Rectangle();
            bounds.Expand(contour.ToPoints());

            int length = contour.Count;

            var test = new Point();

            Point a, b, c; // Current corner points.

            double bx, by;
            double dx, dy;
            double h;

            var predicates = new RobustPredicates();

            a = contour[0];
            b = contour[1];

            for (int i = 0; i < length; i++)
            {
                c = contour[(i + 2) % length];

                // Corner point.
                bx = b.x;
                by = b.y;

                // NOTE: if we knew the contour points were in counterclockwise order, we
                // could skip concave corners and search only in one direction.

                h = predicates.CounterClockwise(a, b, c);

                if (Math.Abs(h) < eps)
                {
                    // Points are nearly co-linear. Use perpendicular direction.
                    dx = (c.y - a.y) / 2;
                    dy = (a.x - c.x) / 2;
                }
                else
                {
                    // Direction [midpoint(a-c) -> corner point]
                    dx = (a.x + c.x) / 2 - bx;
                    dy = (a.y + c.y) / 2 - by;
                }

                // Move around the contour.
                a = b;
                b = c;

                h = 1.0;

                for (int j = 0; j < limit; j++)
                {
                    // Search in direction.
                    test.x = bx + dx * h;
                    test.y = by + dy * h;

                    if (bounds.Contains(test) && IsPointInPolygon(test, contour))
                    {
                        return test;
                    }

                    // Search in opposite direction (see NOTE above).
                    test.x = bx - dx * h;
                    test.y = by - dy * h;

                    if (bounds.Contains(test) && IsPointInPolygon(test, contour))
                    {
                        return test;
                    }

                    h = h / 2;
                }
            }

            throw new Exception();
        }
        /// <summary>
        /// Intersect a ray with a bounding box.
        /// </summary>
        /// <param name="rect">The clip rectangle.</param>
        /// <param name="p0">The ray startpoint (inside the box).</param>
        /// <param name="p1">Any point in ray direction (NOT the direction vector).</param>
        /// <param name="c1">The intersection point.</param>
        /// <returns>Returns false, if startpoint is outside the box.</returns>
        public static bool BoxRayIntersection(Rectangle rect, Point p0, Point p1, ref Point c1)
        {
            double x = p0.X;
            double y = p0.Y;

            double dx = p1.x - x;
            double dy = p1.y - y;

            double t1, x1, y1, t2, x2, y2;

            // Bounding box
            double xmin = rect.Left;
            double xmax = rect.Right;
            double ymin = rect.Bottom;
            double ymax = rect.Top;

            // Check if point is inside the bounds
            if (x < xmin || x > xmax || y < ymin || y > ymax)
            {
                return false;
            }

            // Calculate the cut through the vertical boundaries
            if (dx < 0)
            {
                // Line going to the left: intersect with x = minX
                t1 = (xmin - x) / dx;
                x1 = xmin;
                y1 = y + t1 * dy;
            }
            else if (dx > 0)
            {
                // Line going to the right: intersect with x = maxX
                t1 = (xmax - x) / dx;
                x1 = xmax;
                y1 = y + t1 * dy;
            }
            else
            {
                // Line going straight up or down: no intersection possible
                t1 = double.MaxValue;
                x1 = y1 = 0;
            }

            // Calculate the cut through upper and lower boundaries
            if (dy < 0)
            {
                // Line going downwards: intersect with y = minY
                t2 = (ymin - y) / dy;
                x2 = x + t2 * dx;
                y2 = ymin;
            }
            else if (dy > 0)
            {
                // Line going upwards: intersect with y = maxY
                t2 = (ymax - y) / dy;
                x2 = x + t2 * dx;
                y2 = ymax;
            }
            else
            {
                // Horizontal line: no intersection possible
                t2 = double.MaxValue;
                x2 = y2 = 0;
            }

            if (t1 < t2)
            {
                c1.x = x1;
                c1.y = y1;
            }
            else
            {
                c1.x = x2;
                c1.y = y2;
            }

            return true;
        }
Example #13
0
        public static TriangleNet.Geometry.Point FindPointInPolygon(SectionContour contour, List <SectionContour> otherContours,
                                                                    int limit, double eps = 2e-5)
        {
            List <Vertex> poly   = contour.Points.Select(p => new Vertex(p.X, p.Y)).ToList();
            var           bounds = new TriangleNet.Geometry.Rectangle();

            bounds.Expand(poly);

            int length = poly.Count;

            var test = new TriangleNet.Geometry.Point();

            TriangleNet.Geometry.Point a, b, c; // Current corner points.

            double bx, by;
            double dx, dy;
            double h;

            var predicates = new RobustPredicates();

            a = poly[0];
            b = poly[1];

            for (int i = 0; i < length; i++)
            {
                c = poly[(i + 2) % length];

                // Corner point.
                bx = b.X;
                by = b.Y;

                // NOTE: if we knew the contour points were in counterclockwise order, we
                // could skip concave corners and search only in one direction.

                h = predicates.CounterClockwise(a, b, c);

                if (Math.Abs(h) < eps)
                {
                    // Points are nearly co-linear. Use perpendicular direction.
                    dx = (c.Y - a.Y) / 2;
                    dy = (a.X - c.X) / 2;
                }
                else
                {
                    // Direction [midpoint(a-c) -> corner point]
                    dx = (a.X + c.X) / 2 - bx;
                    dy = (a.Y + c.Y) / 2 - by;
                }

                // Move around the contour.
                a = b;
                b = c;

                h = 1.0;

                for (int j = 0; j < limit; j++)
                {
                    // Search in direction.
                    test.X = bx + dx * h;
                    test.Y = by + dy * h;

                    if (bounds.Contains(test) && IsPointInPolygon(test, contour, otherContours))
                    {
                        return(test);
                    }

                    // Search in opposite direction (see NOTE above).
                    test.X = bx - dx * h;
                    test.Y = by - dy * h;

                    if (bounds.Contains(test) && IsPointInPolygon(test, contour, otherContours))
                    {
                        return(test);
                    }

                    h = h / 2;
                }
            }

            throw new Exception();
        }
Example #14
0
        private static Point FindPointInPolygon(List<Vertex> contour)
        {
            var bounds = new Rectangle();
            bounds.Expand(contour);

            int length = contour.Count;
            int limit = 8;

            var test = new Point();

            Point a, b; // Current edge.
            double cx, cy; // Center of current edge.
            double dx, dy; // Direction perpendicular to edge.

            for (int i = 0; i < length; i++)
            {
                a = contour[i];
                b = contour[(i + 1) % length];

                cx = (a.x + b.x) / 2;
                cy = (a.y + b.y) / 2;

                dx = (b.y - a.y) / 1.374;
                dy = (a.x - b.x) / 1.374;

                for (int j = 1; j <= limit; j++)
                {
                    // Search to the right of the segment.
                    test.x = cx + dx / j;
                    test.y = cy + dy / j;

                    if (bounds.Contains(test) && IsPointInPolygon(test, contour))
                    {
                        return test;
                    }

                    // Search on the other side of the segment.
                    test.x = cx - dx / j;
                    test.y = cy - dy / j;

                    if (bounds.Contains(test) && IsPointInPolygon(test, contour))
                    {
                        return test;
                    }
                }
            }

            throw new Exception();
        }
Example #15
0
 /// <summary>
 /// Check if given rectangle is inside bounding box.
 /// </summary>
 /// <param name="other">Rectangle to check.</param>
 /// <returns>Return true, if bounding box contains given rectangle.</returns>
 public bool Contains(Rectangle other)
 {
     return (xmin <= other.Left && other.Right <= xmax
         && ymin <= other.Bottom && other.Top <= ymax);
 }
 public QuadNode(Rectangle box, TriangleQuadTree tree)
     : this(box, tree, false)
 {
 }
Example #17
0
 /// <summary>
 /// Check if given rectangle intersects bounding box.
 /// </summary>
 /// <param name="other">Rectangle to check.</param>
 /// <returns>Return true, if given rectangle intersects bounding box.</returns>
 public bool Intersects(Rectangle other)
 {
     return (other.Left < xmax && xmin < other.Right
         && other.Bottom < ymax && ymin < other.Top);
 }
            public void CreateSubRegion(int currentDepth)
            {
                // The four sub regions of the quad tree
                //   +--------------+
                //   | nw 2 | ne 3  |
                //   |------+pivot--|
                //   | sw 0 | se 1  |
                //   +--------------+
                Rectangle box;

                var width = bounds.Right - pivot.x;
                var height = bounds.Top - pivot.y;

                // 1. region south west
                box = new Rectangle(bounds.Left, bounds.Bottom, width, height);
                regions[0] = new QuadNode(box, tree);

                // 2. region south east
                box = new Rectangle(pivot.x, bounds.Bottom, width, height);
                regions[1] = new QuadNode(box, tree);

                // 3. region north west
                box = new Rectangle(bounds.Left, pivot.y, width, height);
                regions[2] = new QuadNode(box, tree);

                // 4. region north east
                box = new Rectangle(pivot.x, pivot.y, width, height);
                regions[3] = new QuadNode(box, tree);

                Point[] triangle = new Point[3];

                // Find region for every triangle vertex
                foreach (var index in triangles)
                {
                    ITriangle tri = tree.triangles[index];

                    triangle[0] = tri.GetVertex(0);
                    triangle[1] = tri.GetVertex(1);
                    triangle[2] = tri.GetVertex(2);

                    AddTriangleToRegion(triangle, index);
                }

                for (int i = 0; i < 4; i++)
                {
                    if (regions[i].triangles.Count > tree.sizeBound && currentDepth < tree.maxDepth)
                    {
                        regions[i].CreateSubRegion(currentDepth + 1);
                    }
                }
            }
Example #19
0
 public Rectangle(Rectangle other)
     : this(other.Left, other.Bottom, other.Right, other.Top)
 {
 }
 protected List<Vertex> CreateRectangle(Rectangle rect, int n, int boundary = 0)
 {
     return CreateRectangle(rect, n, n, boundary);
 }
Example #21
0
        /// <summary>
        /// Gets the Voronoi diagram as raw output data.
        /// </summary>
        /// <param name="mesh"></param>
        /// <returns></returns>
        /// <remarks>
        /// The Voronoi diagram is the geometric dual of the Delaunay triangulation.
        /// Hence, the Voronoi vertices are listed by traversing the Delaunay
        /// triangles, and the Voronoi edges are listed by traversing the Delaunay
        /// edges.
        ///</remarks>
        private void Generate()
        {
            mesh.Renumber();
            mesh.MakeVertexMap();

            // Allocate space for voronoi diagram
            this.points = new Point[mesh.triangles.Count + mesh.hullsize];
            this.regions = new Dictionary<int, VoronoiRegion>(mesh.vertices.Count);

            rayPoints = new Dictionary<int, Point>();
            rayIndex = 0;

            bounds = new Rectangle();

            // Compute triangles circumcenters and setup bounding box
            ComputeCircumCenters();

            // Add all Voronoi regions to the map.
            foreach (var vertex in mesh.vertices.Values)
            {
                regions.Add(vertex.id, new VoronoiRegion(vertex));
            }

            // Loop over the mesh vertices (Voronoi generators).
            foreach (var region in regions.Values)
            {
                //if (item.Boundary == 0)
                {
                    ConstructCell(region);
                }
            }
        }
        /// <summary>
        /// Generates a structured mesh.
        /// </summary>
        /// <param name="bounds">Bounds of the mesh.</param>
        /// <param name="nx">Number of segments in x direction.</param>
        /// <param name="ny">Number of segments in y direction.</param>
        /// <returns>Mesh</returns>
        public static IMesh StructuredMesh(Rectangle bounds, int nx, int ny)
        {
            var polygon = new Polygon((nx + 1) * (ny + 1));

            double x, y, dx, dy, left, bottom;

            dx = bounds.Width / nx;
            dy = bounds.Height / ny;

            left = bounds.Left;
            bottom = bounds.Bottom;

            int i, j, k, l, n = 0;

            // Add vertices.
            var points = new Vertex[(nx + 1) * (ny + 1)];

            for (i = 0; i <= nx; i++)
            {
                x = left + i * dx;

                for (j = 0; j <= ny; j++)
                {
                    y = bottom + j * dy;

                    points[n++] = new Vertex(x, y);
                }
            }

            polygon.Points.AddRange(points);

            n = 0;

            // Set vertex hash and id.
            foreach (var v in points)
            {
                v.hash = v.id = n++;
            }

            // Add boundary segments.
            var segments = polygon.Segments;

            segments.Capacity = 2 * (nx + ny);

            Vertex a, b;

            for (j = 0; j < ny; j++)
            {
                // Left
                a = points[j];
                b = points[j + 1];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;

                // Right
                a = points[nx * (ny + 1) + j];
                b = points[nx * (ny + 1) + (j + 1)];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;
            }

            for (i = 0; i < nx; i++)
            {
                // Bottom
                a = points[(ny + 1) * i];
                b = points[(ny + 1) * (i + 1)];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;

                // Top
                a = points[ny + (ny + 1) * i];
                b = points[ny + (ny + 1) * (i + 1)];

                segments.Add(new Segment(a, b, 1));

                a.Label = b.Label = 1;
            }

            // Add triangles.
            var triangles = new InputTriangle[2 * nx * ny];

            n = 0;

            for (i = 0; i < nx; i++)
            {
                for (j = 0; j < ny; j++)
                {
                    k = j + (ny + 1) * i;
                    l = j + (ny + 1) * (i + 1);

                    // Create 2 triangles in rectangle [k, l, l + 1, k + 1].

                    if ((i + j) % 2 == 0)
                    {
                        // Diagonal from bottom left to top right.
                        triangles[n++] = new InputTriangle(k, l, l + 1);
                        triangles[n++] = new InputTriangle(k, l + 1, k + 1);
                    }
                    else
                    {
                        // Diagonal from top left to bottom right.
                        triangles[n++] = new InputTriangle(k, l, k + 1);
                        triangles[n++] = new InputTriangle(l, l + 1, k + 1);
                    }
                }
            }

            return Converter.ToMesh(polygon, triangles);
        }
 public StandardVoronoi(Mesh mesh, Rectangle box)
     : this(mesh, box, new DefaultVoronoiFactory(), RobustPredicates.Default)
 {
 }