I'm currently trying to get the clipped cells from a Polygon-Voronoi-Intersection.
Here is what I've got so far:
I have a polygon and computed some points in it to calculate a voronoi diagram and the red lines on the figure below are the voronoi edges.
Then I used an algorithm to get the corner points from every cell and now I need to get the corners in the right direction (clockwise) to generate the cell polygon.
Found Corners for one cell
First I was using this method:
private List<Vector> sortClockwise(List<Vector> points)
{
points = points.OrderBy(x => Math.Atan2(x.X, x.Y)).ToList();
return points;
}
but in some special concave polygons this doesn't work and the right order gets mixed up.
Does anyone have a suggetion or hint how this could be done the most simplest way? Consider that the polygon points are in the right order already and the voronoi corners are mixed up and need to get sorted to the polygon points.
My idea:
Find first polygon point in cell corners
go along polygon direction and look if point of voronoi vertices is on that line.
if yes: get endpoint of found voronoi edge and look for shared voronoi edges.
if shared edges found, always take the most right one
do until you reach fist point
Is that the only way I could do that?
EDIT - UPDATE
Okay I have some sort of half answer now.
As I said, I have all the vertices which belong to one of the voronoi's cells but the order is still messed up so I thought I could sort them by angle from the centroid like so:
private List<Vector> sortClockwiseBySentroid(List<Vector> points, Vector center)
{
points = points.OrderBy(x => Math.Atan2(x.X - center.X, x.Y - center.Y)).ToList();
return points;
}
But this doesn't always work. Here are the examples when its working and when not. The problem is that on concave edges the angle from the centorid to the corner is sometimes smaller than the one I really need. Any suggestion on how to fix this?
Here its working
Here its not working...
This is how is sort the list of vertices in clockwise order for a cell in my Voronoi generation. Assuming you know which vertices you need to sort this code should do the job.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class ConvexHull
{
private List<Vector2> vertices;
public ConvexHull()
{
vertices = new List<Vector2>();
}
public ConvexHull(Vector2[] vertices)
{
this.vertices = new List<Vector2>(vertices);
}
public void AddVertices(Vector2[] vertices)
{
this.vertices.AddRange(new List<Vector2>(vertices));
}
public Vector2[] Generate()
{
if (vertices.Count > 1)
{
int k = 0;
Vector2[] hull = new Vector2[2 * vertices.Count];
// Make the list distinct and sorted
vertices = vertices.Distinct().OrderBy(v => v.x).ToList();
//vertices.Sort();
//Array.Sort(vertices);
// Build lower hull
for (int i = 0; i < vertices.Count; ++i)
{
while (k >= 2 && Cross(hull[k - 2], hull[k - 1], vertices[i]) <= 0)
k--;
hull[k++] = vertices[i];
}
// Build upper hull
for (int i = vertices.Count - 2, t = k + 1; i >= 0; i--)
{
while (k >= t && Cross(hull[k - 2], hull[k - 1], vertices[i]) <= 0)
k--;
hull[k++] = vertices[i];
}
if (k > 1)
{
hull = hull.Take(k - 1).ToArray();
}
return hull;
}
if (vertices.Count <= 1)
{
return vertices.ToArray();
}
return null;
}
private float Cross(Vector2 p1, Vector2 p2, Vector2 p3)
{
return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
}
}
Related
I am creating a program to generate a path for a CNC machine laser/plasma cutting. In it, the user should be able to cut shapes in the base element and be able to acquire the points and vectors of those cuts. I added the possibility to draw arrows (points and vectors) on selected walls according to which the tool should travel. This is based on obtaining the normal vector of the selected wall, which is used to determine the angle of cut.
Unfortunately, I do not know how to get the same effect on walls with a variable normal vector. An example of such an edge is the inclined cylinder. When I apply arrows to such an edge they all have the same vector.
Code sample:
public List<Mesh> DrawArrowsOnSelectedFace(Entity entity)
{
List<Mesh> arrowList = new List<Mesh>();
Brep ent = (Brep)entity;
for (int i = 0; i < ent.Faces.Length; i++)
{
if (ent.GetFaceSelection(i))
{
Surface[] sf = ent.Faces[i].ConvertToSurface(ent);
foreach (Surface surf in sf)
{
ICurve[] extractedEdges = surf.ExtractEdges();
Vector3D rotation = CalculatePerpenticularToNormalVector(surf);
foreach (ICurve curve in extractedEdges)
{
Point3D[] segmented = curve.GetPointsByLengthPerSegment(5);
for (int j = 1; j <= segmented.Length - 1; j++)
{
Point3D point1 = segmented[j - 1];
Mesh arrow = CreateArrow(point1, rotation);
arrowList.Add(arrow);
}
}
}
}
}
return arrowList;
}
private Vector3D CalculatePerpenticularToNormalVector(Surface surface)
{
Point3D point3D1 = new Point3D(surface.ControlPoints[0, 0].X, surface.ControlPoints[0, 0].Y, surface.ControlPoints[0, 0].Z);
Point3D point3D2 = new Point3D(surface.ControlPoints[0, 1].X, surface.ControlPoints[0, 1].Y, surface.ControlPoints[0, 1].Z);
Point3D point3D3 = new Point3D(surface.ControlPoints[1, 0].X, surface.ControlPoints[1, 0].Y, surface.ControlPoints[1, 0].Z);
Plane plane = new Plane(point3D1, point3D2, point3D3);
Vector3D equation = new Vector3D(plane.Equation.X, plane.Equation.Y, plane.Equation.Z);
Vector3D vectorZ = new Vector3D();
vectorZ.PerpendicularTo(Vector3D.AxisMinusY);
Vector3D result = CalculateRotation(vectorZ, equation);
result.Normalize();
return result;
}
private Mesh CreateArrow(Point3D point3D, Vector3D rotation)
{
if (point3D.Z >= -0.5)
{
return Mesh.CreateArrow(point3D, rotation, 0.3, 5, 0.35, 2, 36, Mesh.natureType.Smooth, Mesh.edgeStyleType.Sharp);
}
else return null;
}
private Vector3D CalculateRotation(Vector3D vector, Vector3D equation)
{
return vector - Vector3D.Dot(vector, equation) * equation;
}
What type should I best use for Boolean operations?
I also have a part of the code prepared where the arrows are drawn based on the common part of the basic element and the cut shape. Both of these shapes are BREPs. Unfortunately, this uses a lot of memory and takes some time.
You can convert the yellow face to a Surface using Brep.Faces[i].ConvertToSurface() and generating U or V isocurves of the resulting surface at equally spaced parameters using Surface.IsocurveU(t) or Surface.IsocurveU(t).
I'm learning about Bezier curves and would like to parameterize the equations for distance using an estimation method. So far, my code seems to work for single points (EG Bezier(start=0, mid=1, end=5, nPoints=6) yields [0 1 2 3 4 5]). However, when I attempt to apply this to multi-dimensional curves, my results are not as expected.
C# code (executed in Unity for visualization). The function (should) get a point on the curve (defined by the points pts) at a length l% of the length.
Vector3 BezierL(Vector3[] pts, float l)
{
int i;
float[] tVals = new float[n];
Vector3[] points = new Vector3[n];
float[] cumDist = new float[n];
for (i = 1; i < n; i++)
{
tVals[i] = i / (float)(n - 1);
points[i] = Bezier(pts, tVals[i]);
cumDist[i] = cumDist[i - 1] +
(points[i] - points[i - 1]).magnitude;
}
// Interpolate to estimate t
float targetLen = l * cumDist[n - 1];
int ind = Array.BinarySearch(cumDist, targetLen);
if (ind < 0)
ind = ~ind;
float t = Mathf.Lerp(tVals[ind - 1], tVals[ind],
(targetLen - cumDist[ind - 1]) / (cumDist[ind] - cumDist[ind - 1]));
return Bezier(pts, t);
}
where Bezier(Vector3[] pts, t) gets a point on the curve defined by pts at time t. For whatever reason, this partially works in that all points are equally spaced, but some points are stacked at the initial point rather than being distributed along the curve.
This was my reference for developing this algorithm, so I'm unsure if my implementation is incorrect, or if it only applies to lower-dimensional curves.
Thanks in advance!
Oof how embarrassing, I just forgot to compute the 0th point!
I am having trouble trying to write a method (in c#) that returns all of the integer lattice pairs within a circle of a given radius at a specific offset. I found this article https://en.wikipedia.org/wiki/Gauss_circle_problem but unfortunately it seems more interested in calculating the number of lattice pairs rather than identifying each individual lattice pair.
I am also having issues understanding some of the math terminology/symbols as my math is sadly somewhat lacking, so code examples or detailed explanations would be super helpful if possible.
my plan so far is to just check each integer value combination from the radius to negative radius and then simply check the distance to the origin, before applying the offset to the vectors that are within range.
Am i on the right track with this, or is there a more optimized way to achieve this?
example stub:
public class CircleTest ()
{
public List<Vector2>GetContainedIntegerVectors(float radius, Vector2 centerPosition)
{
//math goes here
}
}
Simple Vector2 class
public class Vector2 ()
{
public float x {get; set;}
public float y {get; set;}
}
Thanks!
For my understanding you are on the right track, but there are some optimizations possible:
use the System.Windows.Vector class from C# instead of your own
you only have to calculate the points of a quarter of the circle, eg for x>0 and y>=0 and mirror the rest (plus include centerpoint).
here a possible implementation:
List<Vector> tmpList = new List<Vector();
List<Vector> list = new List<Vector();
double rSquared=r*r; // using sqared reduces execution time (no square root needed)
for(int x=1; x<=r; x++)
for(int y=0; y<=r; y++) {
Vector v = new Vector(x,y);
if(v.LengthSquared<=rSquared)
tmpList.Add(v);
else
break;
}
list.Add(centerVector);
foreach(Vector v in tmpList) {
Vector vMirr = new Vector(v.X, -1*v.Y);
list.Add(Vector.Add(centerVector, v));
list.Add(Vector.Add(centerVector, v.Negate()));
list.Add(Vector.Add(centerVector, vMirr));
list.Add(Vector.Add(centerVector, vMirr.Negate));
}
public List<Vector2>GetContainedVectors(int radius, Vector2 offset)
{
List<Vector2> returnValues = new List<Vector2>();
for (int x = radius; x > -radius; x--)
{
for (int y = radius; y > -radius; y--)
{
if(Vector2.Distance(new Vector2(x,y), Vector2.zero) <= radius)
{
returnValues.Add(new Vector2(x + offset.x, y + offset.y));
}
}
}
return returnValues;
}
I have 2 polygons, one is always convex, the other can be convex or concave. Vertices on these polygons are sorted anti-clockwise.
for(int i = 0; i < sorted.Count; i++)
{
Vector2 start1 = sorted[i];
Vector2 end1 = sorted[(i + 1) % sorted.Count];
for(int j = 0; j < otherPolygon.Count; j++)
{
Vector2 start2 = otherPolygon[j];
Vector2 end2 = otherPolygon[(j + 1) % otherPolygon.Count];
Vector2 intersection = Intersection(start1, end1, start2, end2);
if (!float.IsPositiveInfinity(intersection.x))
{
intersections.Add(intersection);
}
}
}
Using this loop I can find the intersection points of the edges. The issue is that depending on where the convex polygon is, the order in which i find the intersection points changes. Is there a way to guarantee that the intersection points are always found in the same order?
EDIT:
Example case -
2 Polygons A(sorted array in the code) and B(otherPolygon array in the code). A is static and can be concave. B is moving around and is always convex.
If B is on the right from the A and intersecting, then the intersection points are found clockwise order. If B is on the left the the intersections points are found in the anti-clockwise order.
I have a list of Point types in C#. I want to run Dijkstra's algorithm on this list of points where the first entry in the list is the starting location.
Is there a way of doing this using an existing library?
If such library doesn't exist, is there a way of calculating the distance between two points with x and y coordinates. For example, calculate the distance between point A (x coordinate =2, y coordinate = 4) and point B ((x coordinate =9, y coordinate = 7).
I have used the ZedGraph library to build the graph.
I think you misunderstood, what the Dijkstra algorithm stands for.
For a given source vertex (node) in the graph, the algorithm finds the path with lowest cost (i.e. the shortest path) between that vertex and every other vertex.
What you need (i think) the lowest distance between two points based on their coordinates.
And the distance between two points can be counted using basic math:
Point p = new Point(4, 5);
Point r = new Point(10, 2);
double distance = Math.Sqrt(Math.Pow(p.X - r.X, 2) + Math.Pow(p.Y - r.Y, 2));
using this knowledge the problem could be solved with two functions like this:
Returns the distance between p and r:
static double distance(Point p, Point r)
{
return Math.Sqrt(Math.Pow(p.X - r.X, 2) + Math.Pow(p.Y - r.Y, 2));
}
Returns the index of the closest point to the fromIndex th element of the points list:
static int closestPoint(List<Point> points, int fromIndex)
{
Point start = points[fromIndex];
int resultIndex = 0;
for (int i = 1; i < points.Count; i++)
{
if (fromIndex == i)
continue;
Point current = points[i];
if (distance(start, current) < distance(start, points[resultIndex]))
resultIndex = i;
}
return resultIndex;
}
I'm really sorry, if i misunderstood you!