Get a unique result from Bresenham algorithm - c#

I want to rasterize a line using Bresenham's algorihm. My interpolated vertices shouldn't consist of diagonal steps. I did some search on StackOverflow and this topic seems to pretty much the thing I need.
The only problem I have with it is that I need to get the Same result if I changed the order of inputs, I mean if I swap the startPoint and endPoint of line I need to get the same set of interpolated vertices.
//the Method definition
List<Point> plotPoints(Point startPoint, Point endPoint);
//The thing I'm looking for
plotPoints(startPoint, endPoint)==plotPoints(endPoint, startPoint)
The code is almost same as The answer. However I did a bit customization for my purpose:
private float step=0.5;
public static List<Vector3> plotPoints(float x0, float y0, float x1, float y1) {
List<Vector3> plottedPoints = new List<Vector3>();
float dx = Mathf.Abs(x1 - x0), sx = x0 < x1 ? step : -step;
float dy = -Mathf.Abs(y1 - y0), sy = y0 < y1 ? step: -step;
float err = dx + dy, e2; /* error value e_xy */
for (; ; ) { /* loop */
if (x0 == x1 && y0 == y1) break;
plottedPoints.Add(new Vector3(x0,0, y0));
e2 = 2 * err;
if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
else if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
}
return plottedPoints;
}

As said in the comments, a trick is to normalize the input so that if you swap the endpoints, they will be swapped back automatically.
A possible way is by enforcing that the endpoints are lexicographically ordered (the smallest X first and in case of a tie, the smallest Y).

There is no such problem with the DDA algorithm, which can be formulated explicitly as
X = X0 + (k.DX) rnd D
Y = Y0 + (k.DY) rnd D
where D = max(|DX|, |DY|), rnd is a rounding operation and k goes from 0 to D.
If you swap the endpoints, the deltas change sign and you trade
Y0 + (k.DY) rnd D
for
Y1 + ((D-k).(-DY)) rnd D = Y1 - DY + (k.DY) rnd D = Y0 + (k.DY) rnd D.
This means that the algorithm is naturally "reversible".
For this to be true, the rnd operation must enjoy a translation invariance property, rnd(x+n) = rnd(x)+n, which corresponds to (k.DY) rnd D = floor((k.DY + S) / D) where S is some rounding offset (typically 0 or D>>1).

Related

X,Y line offset without self intersection

I am trying to correct this C# code which should create an offset line without self intersection. It calculates its offset from probed points(x,y coordinates) and an inputted offset distance. The Y offset component works but the X does not. Any help or insight would be infinitely appreciated.
Here is the section of code that executes this process.
private void OffsetData(double R)
{
double Increment = 0.01;
X2 = (double[])X.Clone(); // copy original
// apply a circle to every measured point and
// push neighbor points out beyond the circle
for (int i = 0; i < Npts; i++)
{
// offset forward
double k = i + Increment;
while (k < Npts - 1)
{
// determine how far away the neighbor is in Y
double dy = (k - i) * DeltaY;
// compute extent outward in X
double d = R * R - dy * dy;
if (d < 0) break; // beyond circel radius - no need to go further
double dx = Math.Sqrt(d);
//interpolate to find X[k] where K is a fraction
int ki = (int)k;
double Xk = X[ki] + (X[ki + 1] - X[ki]) * (k - ki);
// if x value is within circle push out
if (X2[i] < Xk + dx) X2[i] = Xk + dx;
k += Increment;
}
// offset backward
k = i - Increment;
while (k > 0)
{
// determine how far away the neighbor is in Y
double dy = (k - i) * DeltaY;
// compute extent outward in X
double d = R * R - dy * dy;
if (d < 0) break;
// beyond circle radius - no need to go further
double dx = Math.Sqrt(d);
//interpolate to find X[k] where K is a fraction
int ki = (int)k;
double Xk = X[ki] + (X[ki + 1] - X[ki]) * (k - ki);
// if x value is within circle push out
if (X2[i] < Xk + dx) X2[i] = Xk + dx;
k -= Increment;
}
}
}

Is angle between 2 vectors reflex? (C#)

I need to be able to check whether the angle between three points (A, B and C) which make up part of a shape is reflex (> PI radians), as in the diagram below (sorry for poor paint skills!):
My points should always be anti-clockwise, and I always want to measure the angle on the inside of the shape.
I am currently doing this using the following code:
//triangle[] is an array of the three points I am testing, corresponding
// to [A, B, C] on the diagram above
//Vectors from B to A and C
PointF toA = PointFVectorTools.difference(triangle[0], triangle[1]);
PointF toC = PointFVectorTools.difference(triangle[2], triangle[1]);
double angle = Math.Atan2(toB.Y, toB.X) - Math.Atan2(toA.Y, toA.X);
//Put angle in range 0 to 2 PI
if (angle < 0) angle += 2 * Math.PI;
return angle > Math.PI;
This has worked in all the cases I have tried up until now, but with these co-ords it does not work:
(Where B=(2,3) )
The angle I get back is ~-0.5, whereas I would expect ~+0.5. Any ideas why this is wrong?
UPDATE
I've attempted to implement Nico's solution, and while I understand it in theory I'm getting a real headache trying to implement it. Here is the code so far:
//Vector A -> B
float dx = triangle[1].X - triangle[0].X;
float dy = triangle[1].Y - triangle[0].Y;
//Left normal = (y, -x)
PointF leftDir = new PointF(dy, -dx);
//Vector B -> C
dx = triangle[2].X - triangle[1].X;
dy = triangle[2].Y - triangle[1].Y;
//Dot product of B->C and Left normal
float dot = dx * leftDir.X + dy * leftDir.Y;
return dot < 0;
In the following, I assume that the x-axis points to the right and the y-axis points upwards. If this is not the case in your scenario, you might need to switch some signs.
If you have the line segment (x1, y1) - (x2, y2) and points are sorted counter-clockwise, you know that the shape is left of the line segment. The orthogonal direction vector that points to the line segment's left is:
leftDir = (y1 - y2, x2 - x1)
Together with the line segment, this direction defines a half space. If the following angle is convex, the third point must lie in this half space. If that's not the case, the angle is concave (which you apparently call reflex):
You can determine if the point lies in the same half space with the dot product:
isConcave = dot(p3 - p2, leftDir) < 0
In code:
float dx = x3 - x2;
float dy = y3 - y2;
float dot = dx * leftDir.x + dy * leftDir.y
return dot < 0;
I'm not sure how toB in your code is defined, and also I'm not familar with PointF.
Anyway you should use the cosine rule c^2 = a^2 + b^2 - 2ab cos(C) (where a,b,c are the lengths of the sides of the triangle, and C is the angle subtending c):
public bool IsReflex(... triangle)
{
var a = GetVectorLength(triangle[0].x, triangle[0].y, triangle[1].x, triangle[1].y);
var b = GetVectorLength(triangle[1].x, triangle[1].y, triangle[2].x, triangle[2].y);
var c = GetVectorLength(triangle[2].x, triangle[2].y, triangle[0].x, triangle[0].y);
var cosC = (c*c - a*a - b*b) / (2*a*b);
var C = Math.Acos(cosC); // this returns a value between 0 and pi
return Math.Abs(C) > (Math.PI/2);
}
private double GetVectorLength(double x0, double y0, double x1, double y1)
{
// using Pythagoras
var sideX = x0 - x1;
var sideY = y0 - y1;
return Math.Sqrt(sideX*sideX + sideY*sideY);
}

C# DirectX Circle Drawing not working correctly

I've been trying to recode a C++ DirectX code to C# that would help me with Drawing a perfect circle. Currently I have this code that i translated by myself:
private void Circle(int X, int Y, int radius, int numSides, Color color)
{
Vector2[] Line = new Vector2[128];
float Step = (float)(Math.PI * 2.0 / numSides);
int Count = 0;
for (float a = 0; a < Math.PI * 2.0; a += Step)
{
float X1 = (float)(radius * Math.Cos(a) + X);
float Y1 = (float)(radius * Math.Sin(a) + Y);
float X2 = (float)(radius * Math.Cos(a + Step) + X);
float Y2 = (float)(radius * Math.Sin(a + Step) + Y);
Line[Count].X = X1;
Line[Count].Y = Y1;
Line[Count + 1].X = X2;
Line[Count + 1].Y = Y2;
Count += 2;
}
line.Begin();
line.Draw(Line, color);
line.End();
}
The problem is that the circle is drawn but also a Line from a point in the circle to the left top corner, like this.
Don't iterate with a floating point variable. They might get imprecise during the iteration. In your case, the last step is probably very close behind the upper bound (instead of hitting it exactly). So it won't get calculated and left as the default (0, 0).
So use an integer iteration variable:
for (int i = 0; i < numSides; ++i)
{
float a = i * Step;
...
}
Then, you can also get rid of Count.
Furthermore, you should make your coordinate buffer dynamic:
Vector2[] Line = new Vector2[2 * numSides];

Find if point lies on line segment

I have line segment defined by these two points: A(x1,y1,z1) and B(x2,y2,z2). I have point p(x,y,z). How can I check if the point lies on the line segment?
Find the distance of point P from both the line end points A, B. If AB = AP + PB, then P lies on the line segment AB.
AB = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
AP = sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1));
PB = sqrt((x2-x)*(x2-x)+(y2-y)*(y2-y)+(z2-z)*(z2-z));
if(AB == AP + PB)
return true;
If the point is on the line then:
(x - x1) / (x2 - x1) = (y - y1) / (y2 - y1) = (z - z1) / (z2 - z1)
Calculate all three values, and if they are the same (to some degree of tolerance), your point is on the line.
To test if the point is in the segment, not just on the line, you can check that
x1 < x < x2, assuming x1 < x2, or
y1 < y < y2, assuming y1 < y2, or
z1 < z < z2, assuming z1 < z2
First take the cross product of AB and AP. If they are colinear, then it will be 0.
At this point, it could still be on the greater line extending past B or before A, so then I think you should be able to just check if pz is between az and bz.
This appears to be a duplicate, actually, and as one of the answers mentions, it is in Beautiful Code.
in case if someone looks for inline version:
public static bool PointOnLine2D (this Vector2 p, Vector2 a, Vector2 b, float t = 1E-03f)
{
// ensure points are collinear
var zero = (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y);
if (zero > t || zero < -t) return false;
// check if x-coordinates are not equal
if (a.x - b.x > t || b.x - a.x > t)
// ensure x is between a.x & b.x (use tolerance)
return a.x > b.x
? p.x + t > b.x && p.x - t < a.x
: p.x + t > a.x && p.x - t < b.x;
// ensure y is between a.y & b.y (use tolerance)
return a.y > b.y
? p.y + t > b.y && p.y - t < a.y
: p.y + t > a.y && p.y - t < b.y;
}
Your segment is best defined by parametric equation
for all points on your segment, following equation holds:
x = x1 + (x2 - x1) * p
y = y1 + (y2 - y1) * p
z = z1 + (z2 - z1) * p
Where p is a number in [0;1]
So, if there is a p such that your point coordinates satisfy those
3 equations, your point is on this line. And it p is between 0 and 1 -
it is also on line segment
Here's some C# code for the 2D case:
public static bool PointOnLineSegment(PointD pt1, PointD pt2, PointD pt, double epsilon = 0.001)
{
if (pt.X - Math.Max(pt1.X, pt2.X) > epsilon ||
Math.Min(pt1.X, pt2.X) - pt.X > epsilon ||
pt.Y - Math.Max(pt1.Y, pt2.Y) > epsilon ||
Math.Min(pt1.Y, pt2.Y) - pt.Y > epsilon)
return false;
if (Math.Abs(pt2.X - pt1.X) < epsilon)
return Math.Abs(pt1.X - pt.X) < epsilon || Math.Abs(pt2.X - pt.X) < epsilon;
if (Math.Abs(pt2.Y - pt1.Y) < epsilon)
return Math.Abs(pt1.Y - pt.Y) < epsilon || Math.Abs(pt2.Y - pt.Y) < epsilon;
double x = pt1.X + (pt.Y - pt1.Y) * (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
double y = pt1.Y + (pt.X - pt1.X) * (pt2.Y - pt1.Y) / (pt2.X - pt1.X);
return Math.Abs(pt.X - x) < epsilon || Math.Abs(pt.Y - y) < epsilon;
}
Or let the dotnet do the heavy lifting for you if using visual studio use a GraphicsPath
this will also allow you to add tolerances for if just clicked outside the line.
using (Drawing2D.GraphicsPath gp = new Drawing2D.GraphicsPath())
{
gp.AddLine(new Point(x1, y1), new Point(x2, y2));
// Make the line as wide as needed (make this larger to allow clicking slightly outside the line)
using (Pen objPen = new Pen(Color.Black, 6))
{
gp.Widen(objPen);
}
if (gp.IsVisible(Mouse.x, Mouse.y))
{
// The line was clicked
}
}
The cross product (B - A) × (p - A) should be much much shorter than B - A. Ideally, the cross product is zero, but that's unlikely on finite-precision floating-point hardware.
I use this to calculate the distance AB between points a and b.
static void Main(string[] args)
{
double AB = segment(0, 1, 0, 4);
Console.WriteLine("Length of segment AB: {0}",AB);
}
static double segment (int ax,int ay, int bx, int by)
{
Vector a = new Vector(ax,ay);
Vector b = new Vector(bx,by);
Vector c = (a & b);
return Math.Sqrt(c.X + c.Y);
}
struct Vector
{
public readonly float X;
public readonly float Y;
public Vector(float x, float y)
{
this.X = x;
this.Y = y;
}
public static Vector operator &(Vector a, Vector b)
{
return new Vector((b.X - a.X) * (b.X - a.X), (b.Y - a.Y) * (b.Y - a.Y));
}
}
based on Calculate a point along the line A-B at a given distance from A
Let V1 be the vector (B-A), and V2 = (p-A), normalize both V1 and V2.
If V1==(-V2) then the point p is on the line, but preceding A, & therefore not in the segment.
If V1==V2 the point p is on the line. Get the length of (p-A) and check if this is less-or-equal to length of (B-A), if so the point is on the segment, else it is past B.
This is my code which can run in WPF
public static class Math2DExtensions
{
public static bool CheckIsPointOnLineSegment(Point point, Line line, double epsilon = 0.1)
{
// Thank you #Rob Agar
// (x - x1) / (x2 - x1) = (y - y1) / (y2 - y1)
// x1 < x < x2, assuming x1 < x2
// y1 < y < y2, assuming y1 < y2
var minX = Math.Min(line.APoint.X, line.BPoint.X);
var maxX = Math.Max(line.APoint.X, line.BPoint.X);
var minY = Math.Min(line.APoint.Y, line.BPoint.Y);
var maxY = Math.Max(line.APoint.Y, line.BPoint.Y);
if (!(minX <= point.X) || !(point.X <= maxX) || !(minY <= point.Y) || !(point.Y <= maxY))
{
return false;
}
if (Math.Abs(line.APoint.X - line.BPoint.X) < epsilon)
{
return Math.Abs(line.APoint.X - point.X) < epsilon || Math.Abs(line.BPoint.X - point.X) < epsilon;
}
if (Math.Abs(line.APoint.Y - line.BPoint.Y) < epsilon)
{
return Math.Abs(line.APoint.Y - point.Y) < epsilon || Math.Abs(line.BPoint.Y - point.Y) < epsilon;
}
if (Math.Abs((point.X - line.APoint.X) / (line.BPoint.X - line.APoint.X) - (point.Y - line.APoint.Y) / (line.BPoint.Y - line.APoint.Y)) < epsilon)
{
return true;
}
else
{
return false;
}
}
}
public record Line
{
public Point APoint { get; init; }
public Point BPoint { get; init; }
}
My code is in github
Thank you #Rob Agar and #MetaMapper
You could check if the point lies between the two planes defined by point1 and point2 and the line direction:
/// Returns the closest point from #a point to this line on this line.
vector3 <Type>
line3d <Type>::closest_point (const vector3 <Type> & point) const
{
return this -> point () + direction () * dot (point - this -> point (), direction ());
}
/// Returns true if #a point lies between point1 and point2.
template <class Type>
bool
line_segment3 <Type>::is_between (const vector3 <Type> & point) const
{
const auto closest = line () .closest_point (point);
return abs ((closest - point0 ()) + (closest - point1 ())) <= abs (point0 () - point1 ());
}

Line rasterisation: Cover all pixels, regardless of line gradient?

Basically, I want to use a line algo to determine which cells to check for collisions for my raycaster.
Bresenham isn't great for this as it uses a unified-thickness approach, meaning that it ignores cells that aren't at least half-covering the line. Not great at all, because it means that some segments of my line aren't being checked for intersections with the cells, leading to errors.
I can't seem to find any "thick-line" algorithms, can anyone help me find one?
Green: What I would like.
Red: What I currently have and don't want.
I had exactly the same problem as you and found an very simple solution. Usually, Bresenham has two consecutive if's to determine whether it should increase the coordinate for the two dimensions:
public void drawLine(int x0, int y0, int x1, int y1, char ch) {
int dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2; // error value e_xy
for (;;) {
put(x0, y0, ch);
if (x0 == x1 && y0 == y1) break;
e2 = 2 * err;
// horizontal step?
if (e2 > dy) {
err += dy;
x0 += sx;
}
// vertical step?
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
Now all you have to do is to insert an else before the second if:
public void drawLineNoDiagonalSteps(int x0, int y0, int x1, int y1, char ch) {
int dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2;
for (;;) {
put(x0, y0, ch);
if (x0 == x1 && y0 == y1) break;
e2 = 2 * err;
// EITHER horizontal OR vertical step (but not both!)
if (e2 > dy) {
err += dy;
x0 += sx;
} else if (e2 < dx) { // <--- this "else" makes the difference
err += dx;
y0 += sy;
}
}
}
Now the algorithm doesn't change both coordinates at once anymore.
I haven't thoroughly tested this but it seems to work pretty well.
This thread old, but I thought it'd be worth putting this on the Internet:
// This prints the pixels from (x, y), increasing by dx and dy.
// Based on the DDA algorithm (uses floating point calculations).
void pixelsAfter(int x, int y, int dx, int dy)
{
// Do not count pixels |dx|==|dy| diagonals twice:
int steps = Math.abs(dx) == Math.abs(dy)
? Math.abs(dx) : Math.abs(dx) + Math.abs(dy);
double xPos = x;
double yPos = y;
double incX = (dx + 0.0d) / steps;
double incY = (dy + 0.0d) / steps;
System.out.println(String.format("The pixels after (%d,%d) are:", x, y));
for(int k = 0; k < steps; k++)
{
xPos += incX;
yPos += incY;
System.out.println(String.format("A pixel (%d) after is (%d, %d)",
k + 1, (int)Math.floor(xPos), (int)Math.floor(yPos)));
}
}
Without loss of generality, assume x2 >= x1, then
int x = floor(x1);
int y = floor(y1);
double slope = (x2 - x1) / (y2 - y1);
if (y2 >= y1) {
while (y < y2) {
int r = floor(slope * (y - y1) + x1);
do {
usepixel(x, y);
++x;
} while (x < r);
usepixel(x, y);
++y;
}
}
else {
while (y > y2) {
int r = floor(slope * (y - y1) + x1);
do {
usepixel(x, y);
++x;
} while (x < r);
usepixel(x, y);
--y;
}
}
The floor calls can probably be written just as a cast-to-integer.
There is an interesting article available in GPU Gems, maybe it can help you: Chapter 22. Fast Prefiltered Lines
What about Bresenham with an additional constraint that no diagonal moves are allowed: Generate the points with the traditional algorithm, then as a post-processing step insert extra steps needed to make only orthogonal movements.
You could find all the intersections your ray has with the horizontal grid lines, and then mark all the cells on a row that either have an intersection point on one side, or are between the two cells with the intersections on the row.
Finding the intersections can be done by starting from the origin, advancing the point to the first intersection (and marking the cells in the process), finding out the vector that takes you from an intersection to the next (both these operations are basic similar triangles (or trig)) and then advancing column by column until you've gone far enough. Advancing column by column involves one vector addition per column, and a small loop to fill in the cells between the ones with intersections. Replace "mark" with "process" if you're processing the cells on the fly - this algorithm is guaranteed to mark each cell only once.
The same could be done with the vertical lines, but grids are generally stored in horizontal slices so I chose that. If you're using trig, you'll need to handle straight horizontal lines with a special case.
By the way, as far as I know, this is how old grid-based raycaster "3D" games (like Wolfenstein 3D) were done. I first read about this algorithm from this book, eons ago.

Categories