Circle problems in c# - c#

I need help with this portion
side note: I have two circles.
I need to create 5 methods to find if a circle:
Intersect (Circle c),
tangentOut (Circle c),
tangentIn (Circle),
disjoint (Circle ),
and contained (Circle ),
(Basically, I need to decide if another circle c intersects this circle, is tangent to this circle from outside, is inside this circle but intersects at a point, is outside of this circle without any touch, or is totally inside this circle.)
To find if it intersects the other circle I made this code:
public bool intersect(Circle c)
{
Point p = new Point(), myCenter = new Point();
p.setPoint(c.x, c.y);
myCenter.setPoint(x, y);
return myCenter.dist(p) < radius + c.radius;
}
but when I make the two circle (0,0,1) and (0,0,5). It shows that the circle intersect. Shouldn't it show that it does not intersect?
I also need help on the other methods as well.
Thanks in advance!
Here is my code:
public static void Main(string[] args)
{
Circle c1 = new Circle(0, 0, 1), c2 = new Circle(1, 0, 1);
Point p1 = new Point();
p1.setPoint(0, 1);
p1.print();
Console.Write(", ");
c1.print();
Console.WriteLine();
if (c1.onCircle(p1))
{
// Console.Write(" Point ");
p1.print();
Console.Write (" on ");
c1.print();
Console.WriteLine();
}
else
Console.WriteLine("Point NOT on circle");
if (c1.intersect(c2))
{
// Console.WriteLine("Two circles intersect");
c1.print();
Console.Write(" intersects ");
c2.print();
Console.WriteLine();
}
else
Console.WriteLine("Two circles do NOT intersect");
}
My Class:
class Circle : Point
{
private double radius;
public Circle(double xV, double yV, double r)
{
this.x = xV;
this.y = yV;
this.radius = r;
}
public void setRadius(double r)
{
radius = r > 0 ? radius : 0;
}
public bool onCircle(Point p)
{
return dist(p) == radius;
}
public bool intersect (Circle c)
{
Point p = new Point (), myCenter = new Point();
p.setPoint (c.x, c.y);
myCenter.setPoint (x, y);
return myCenter.dist(p) < radius + c.radius;
}
public void print()
{
Console.Write("Circle: ({0}, {1}, {2})", x, y, radius);
}
}
Class for point:
public class Point
{
protected double x; // x coordiate of Point
protected double y; // y coordinate of Point
public void setPoint (double xCoor, double yCoor) {
x = xCoor;
y = yCoor;
}
public double dist(Point p) // compute the distance of point p to the current point
{
double distance;
distance = Math.Sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
return distance;
}
public void print()
{
Console.Write("Point: ({0}, {1})", x, y);
}
}

Your coding style looks iffy - I'll just help you on the math.
Take two circles, A (center c1, radius r1) and B (center c2, radius r2). Let d = c1.dist(c2).
tangentOut: condition is that d = r1 + r2
tangentIn: d = abs(r2 - r1)
disjoint: d > r1 + r2
contained: d < abs(r2 - r1)
Also, taking into account numerical precision, change any equalities to delta-epsilon comparisons. E.g. a = b becomes abs(a - b) < e where e is some maximum threshold.

You should reexamine your logic for intersection. What you have now is a method that only works for circles that do not intersect when one does not fully enclose the other. The situation you choose to test, concentric circles, shows this as the distance between the centers is 0 and that is in fact less than the sum of the radiuses. Another situation that would probably not be caught is that of a single degenerate intersection point.
I would suggest reading the Wolfram Alpha article on Circle-Circle Intersection to come up with a better test method.

Your intersect method looks like it should produce an accurate result, but since Circle derives from Point it could be greatly simplified:
public bool intersect(Circle c)
{
return dist(c) < radius + c.radius;
}
All of the other operations are similar:
public bool tangentOut(Circle c)
{
return dist(c) == radius + c.radius;
}
public bool tangentIn(Circle c)
{
return dist(c) == Math.Abs(c.radius - radius);
}
public bool disjoint(Circle c)
{
return dist(c) > radius + c.radius;
}
public bool contains(Circle c)
{
return dist(c) <= radius - c.radius
}
Ramblings on Epsilon values follows...
The comparison in the tangentIn and tangentOut requires a slight change to account for accuracy problems. It's tempting to use a static epsilon figure (as in your comment exchange with willywonka) is asking for trouble when working with larger values. Instead you can scale the epsilon based on the numbers being compared.
The base for epsilon is the difference between 1 and the next possible number, by setting the lowest bit in the binary representation of the value. According to the Wikipedia entry for double-precision floating-point format (which I confirmed by testing it), that's approximately 2E-16. Which is fine for numbers between 0 and 2-E but doesn't work when you get outside that range. Similarly using larger values will give you larger range, but will at some point stop working.
So instead of using a static figure, scale the maximum value down by a useful amount - say one part in 10^9 - and use that as your epsilon. An example extension method:
public static class Extensions
{
public static bool EpsilonEqual(this double l, double r, double eScale = 1e+9)
{
double d = Math.Abs(l - r);
double e = Math.Abs(Math.Max(l, r)) / 1e+9;
return d <= e;
}
}
Adjust the scale factor to suit your accuracy requirements. Then you can do this:
public bool tangentOut(Circle c)
{
return dist(c).EpsilonEquals(radius + c.radius);
}
public bool tangentIn(Circle c)
{
return dist(c).EpsilonEquals(Math.Abs(c.radius - radius));
}

Related

Checking if a point is on a line segment, works except in some cases (rounding error?)

For the issue below, is it a matter of I'm so close to zero but comparing zero with a tolerance won't work? The more precise the numbers, the more my check for an arc's point on a line fails and the less precise the more it works. The CAD drawing does have an arc that has a point on a line segment and that is where I get my input co-ordinates from for this test.
class Line
{
public Point Point1 {get;set;}
public Point Point2 {get;set;}
public Line(double x1, double y1, double x2, double y2)
{
Point1 = new Point(x1,y1); Point2 = new Point(x2,y2);
}
}
class Point
{
public double X {get;set;}
public double Y {get;set;}
public Point (double x, double y)
{
X = x; Y = y;
}
}
//4 decimal place numbers, works
Point arcEnd = new Point(3.8421, 16.9538); // these numbers don't
//3.84212141717697,
//16.9538136440052
Point arcStart = new Point(4.0921, 17.2038);
//test an arc point on/off the line
Line line = new Line(3.9336, 16.9538, 3.7171, 16.9538);
//these numbers don't 3.93362776812308, 16.9538136440053,
//3.71712141717697, 16.9538136440054
bool on_line = Sign(line.Point1, line.Point2, arcEnd) //true
//more precise numbers, from CAD / dxf drawing for line and arc, arc end
//point touches somewhere on the line (included in comments above, fail)
//so on_line = true for the above inputs and the Sign function gives zero,
//but when using the commented precise numbers sign gives back 1 and the
//value computed in sign is 3.0639866299190109E-14.
public static bool Sign(Point Point1, Point Point2, Point point)
{
double value = (Point2.X - Point1.X) * (p.Y - Point1.Y) - (Point2.Y - Point1.Y) * (p.X - Point1.X);
return Equals(Math.Sign(value), 0);
}
public static bool Equals(double d1, double d2, double tolerance=0.000001)
{
double a = Math.Abs(d1 - d2);
double b = Math.Abs(d1 * tolerance);
if (a <= b)
{
return true;
}
return false;
}
Reviewed formulas and stack overflow, the algorithm works a majority of the time but found cases it fails and I traced it to the included example and identified my check is giving back Sign = 1 not Sign = 0 for the above inputs and more precision.
You made two mistakes. First, you used Sign function in "Return Equals(Math.Sign(value), 0);", which will give you the value of 1 for any positive number and value of -1 for any negative number. This will destroy your attempt to use tolerance. Second, you tried to compare the difference with a ratio of the first number "b = Math.Abs(d1 * tolerance)", which will always return False. I recommend you compare it with tolerance itself, like this.
public static bool Sign(Point Point1, Point Point2, Point point)
{
double value = (Point2.X - Point1.X) * (point.Y - Point1.Y) - (Point2.Y - Point1.Y) * (point.X - Point1.X);
return Equals(value, 0);
}
public static bool Equals(double d1, double d2, double tolerance = 0.000001)
{
double a = Math.Abs(d1 - d2);
if (a <= tolerance)
return true;
return false;
}

Considering only 3D points, wouldn't this naive approach to the "smallest enclosing ball" be good enough?

Lets use C# in our example.
public class Sphere
{
public Point Center { get; set; }
public float Radius { get; set; }
public Sphere(IEnumerable<Point> points)
{
Point first = points.First();
Point vecMaxZ = first;
Point vecMinZ = first;
Point vecMaxY = first;
Point vecMinY = first;
Point vecMinX = first;
Point vecMaxX = first;
foreach (Point current in points)
{
if (current.X < vecMinX.X)
{
vecMinX = current;
}
if (current.X > vecMaxX.X)
{
vecMaxX = current;
}
if (current.Y < vecMinY.Y)
{
vecMinY = current;
}
if (current.Y > vecMaxY.Y)
{
vecMaxY = current;
}
if (current.Z < vecMinZ.Z)
{
vecMinZ = current;
}
if (current.Z > vecMaxZ.Z)
{
vecMaxZ = current;
}
}
//the lines bellow assure at least 2 points sit on the surface of the sphere.
//I'm pretty sure the algorithm is solid so far, unless I messed up the if/elses.
//I've been over this, looking at the variables and the if/elses and they all
//seem correct, but our own errors are the hardest to spot,
//so maybe there's something wrong here.
float diameterCandidateX = vecMinX.Distance(vecMaxX);
float diameterCandidateY = vecMinY.Distance(vecMaxY);
float diameterCandidateZ = vecMinZ.Distance(vecMaxZ);
Point c;
float r;
if (diameterCandidateX > diameterCandidateY)
{
if (diameterCandidateX > diameterCandidateZ)
{
c = vecMinX.Midpoint(vecMaxX);
r = diameterCandidateX / 2f;
}
else
{
c = vecMinZ.Midpoint(vecMaxZ);
r = diameterCandidateZ / 2f;
}
}
else if (diameterCandidateY > diameterCandidateZ)
{
c = vecMinY.Midpoint(vecMaxY);
r = diameterCandidateY / 2f;
}
else
{
c = vecMinZ.Midpoint(vecMaxZ);
r = diameterCandidateZ / 2f;
}
//the lines bellow look for points outside the sphere, and if one is found, then:
//1 let dist be the distance from the stray point to the current center
//2 let diff be the equal to dist - radius
//3 radius will then the increased by half of diff.
//4 a vector with the same direction as the stray point but with magnitude equal to diff is found
//5 the current center is moved by half the vector found in the step above.
//
//the stray point will now be included
//and, I would expect, the relationship between the center and other points will be mantained:
//if distance from p to center = r / k,
//then new distance from p to center' = r' / k,
//where k doesn't change from one equation to the other.
//this is where I'm wrong. I cannot figure out how to mantain this relationship.
//clearly, I'm moving the center by the wrong amount, and increasing the radius wrongly too.
//I've been over this problem for so much time, I cannot think outside the box.
//my whole world is the box. The box and I are one.
//maybe someone from outside my world (the box) could tell me where my math is wrong, please.
foreach (Point current in points)
{
float dist = current.Distance(c);
if (dist > r)
{
float diff = dist - r;
r += diff / 2f;
float scaleFactor = diff / current.Length();
Point adjust = current * scaleFactor;
c += adjust / 2f;
}
}
Center = c;
Radius = r;
}
public bool Contains(Point point) => Center.Distance(point) <= Radius;
public override string ToString() => $"Center: {Center}; Radius: {Radius}";
}
public class Point
{
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
public Point(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
public float LengthSquared() => X * X + Y * Y + Z * Z;
public float Length() => (float) Math.Sqrt(X * X + Y * Y + Z * Z);
public float Distance(Point another)
{
return (float) Math.Sqrt(
(X - another.X) * (X - another.X)
+ (Y - another.Y) * (Y - another.Y)
+ (Z - another.Z) * (Z - another.Z));
}
public float DistanceSquared(Point another)
{
return (X - another.X) * (X - another.X)
+ (Y - another.Y) * (Y - another.Y)
+ (Z - another.Z) * (Z - another.Z);
}
public Point Perpendicular()
{
return new Point(-Y, X, Z);
}
public Point Midpoint(Point another)
{
return new Point(
(X + another.X) / 2f,
(Y + another.Y) / 2f,
(Z + another.Z) / 2f);
}
public override string ToString() => $"({X}, {Y}, {Z})";
public static Point operator +(Point p1, Point p2)
{
return new Point(p1.X + p2.X, p1.Y + p2.Y, p1.Z + p2.Z);
}
public static Point operator *(Point p1, float v)
{
return new Point(p1.X * v, p1.Y * v, p1.Z * v);
}
public static Point operator /(Point p1, float v)
{
return new Point(p1.X / v, p1.Y / v, p1.Z / v);
}
}
//Note: this class is here so I can be able to solve the problems suggested by
//Eric Lippert.
public class Line
{
private float coefficient;
private float constant;
public Line(Point p1, Point p2)
{
float deltaY = p2.Y - p1.Y;
float deltaX = p2.X - p1.X;
coefficient = deltaY / deltaX;
constant = coefficient * -p1.X + p1.Y;
}
public Point FromX(float x)
{
return new Point(x, x * coefficient + constant, 0);
}
public Point FromY(float y)
{
return new Point((y - constant) / coefficient, y, 0);
}
public Point Intersection(Line another)
{
float x = (another.constant - constant) / (coefficient - another.coefficient);
float y = FromX(x).Y;
return new Point(x, y, 0);
}
}
Can I safely assume this will run at least just as fast as the fancy algorithms out there that usually consider, for robustness sake, the possibility of the Points having any number of dimensions, from 2 to anything, like 1000 or 10,000 dimensions.
I only need it for 3 dimensions, never more and never less than that. Since I have no academic degree on computer science (or any degree for that matter, I'm a highschool sophomore), I have difficulties in analyzing algorithms for performance and resource consumption. So my question basically is: Is my "smallest enclosing sphere for dumbs" algoritm good in performance and resource consumption when compared with the fancy ones? Is there a point where my algorithm breaks while the professional ones don't, meaning it performs so bad it will cause noticeable loss (like, if I have too many points).
EDIT 1: I editted the code because it made no sense at all (I was hungry, it was 4pm and I haven't eaten all day). This one makes more sense I think, not sure if it's correct though. The original question stands: If this one solves the problem, does it do it well enough to compete with the stardard professional algorithms in case we know in advance that all points have 3 dimensions?
EDIT 2: Now I'm pretty sure the performance is bad, and I lost all hope of implementing a naive algorithm to find the smallest enclosing sphere. I just want to make something that work. Please, check the latest update.
EDIT 3: Doesn't work either. I quit.
EDIT 4: Finally, after, I don't know... some 5 hours. I figured it out. Jesus Christ. This one works. Could someone tell me about the performance issue? Is it really bad compared to the professional algorithms? What lines can I change to make it better? Is there a point where it breaks? Remember, I will always use it for 3D points.
EDIT 5: I learned from Bychenko the previous algorithm still didn't work. I slept on this issue, and this is my new version of the algorithm. I know it doesn't work, and I have a good clue where it is wrong, could anyone please tell why those particular calculations are wrong and how to fix them? I'm inclined to think this has something to do with trigonometry. My assumptions don't hold true for Euclidean space, because I can't stop seeing vectors as real numbers instead
of sets of real numbers that, in my case, I use to pin-point a location in Euclidean space. I'm pretty sure I'm missing some sine or cosine somewhere in the last loop (of course, not exactly sine or cosine, but the equivalent in cartesian coordinates, since we don't know any angles.
Addendum to EDIT 5: About the problems proposed by Eric Lippert:
(1) argh too trivial :p
(2) I will do it for the circle first; I will add a class Line for that.
Point a, b, c; //they are not collinear
Point midOfAB = a.Midpoint(b);
Point midOfBC = b.Midpoint(c);
//multiplying the vector by a scalar as I do bellow doesn't matter right?
Point perpendicularToAB = midOfAB.Perpendicular() * 3;
Point perpendicularToBC = midOfBC.Perpendicular() * 3;
Line bisectorAB = new Line(perpendicularToAB, midOfAB);
Line bisectorBC = new Line(perpendicularToBC, midOfBC);
Point center = bisectorAB.Intersection(bisectorBC);
float distA = center.Distance(a);
float distB = center.Distance(b);
float distC = center.Distance(c);
if(distA == distB && distB == distC)
//it works (spoiler alert: it doesn't)
else
//you're a failure, programmer, pick up your skate and practice some ollies
Sorry, but your algorithm is wrong. It doesn't solve the problem.
Counter example (3 points):
A = (0, 0, 0) - closest to origin (0)
B = (3, 3, 0) - farthest from origin (3 * sqrt(2) == 4.2426...)
C = (4, 0, 0)
your naive algorithm declares that the sphere has center at
P = (3 / sqrt(2), 3 / sqrt(2), 0)
and radius
R = 3 / sqrt(2)
and you can see that the point C = (4, 0, 0) is beyond the sphere
Edit the updated (but naive) algorithm is still wrong.
Counter example (3 points):
A = (0, 0, 0)
B = (1, 2, 0)
C = (4, 1, 0)
according the algorithm the sphere has its center at
P = (2, 1, 0)
with radius
R = sqrt(5)
and you can see that the sphere is not a minimal (smallest) one.
Nth Edit you still have an incorrect algorithm. When exploring gray zone (you know the problem, but partially, with holes) it's a good practice to invest into testing automatition. As you should know, in case of triangle all the vertexes should be on the sphere; let's validate your the solution on this fact:
public static class SphereValidator {
private static Random m_Random = new Random();
private static String Validate() {
var triangle = Enumerable
.Range(0, 3)
.Select(i => new Point(m_Random.Next(100), m_Random.Next(100), m_Random.Next(100)))
.ToArray();
Sphere solution = new Sphere(triangle);
double tolerance = 1.0e-5;
for (int i = 0; i < triangle.Length; ++i) {
double r = triangle[i].Distance(solution.Center);
if (Math.Abs(r - solution.Radius) > tolerance) {
return String.Format("Counter example\r\n A: {0}\r\n B: {1}\r\n C: {2}\r\n expected distance to \"{3}\": {4}; actual R {5}",
triangle[0], triangle[1], triangle[2], (char) ('A' + i), r, solution.Radius);
}
}
return null;
}
public static String FindCounterExample(int attempts = 10000) {
for (int i = 0; i < attempts; ++i) {
String result = Validate();
if (!String.IsNullOrEmpty(result))
Console.WriteLine(result);
return;
}
Console.WriteLine(String.Format("Yes! All {0} tests passed!", attempts));
}
}
I've just run the code above and got:
Counter example
A: (3, 30, 9)
B: (1, 63, 40)
C: (69, 1, 16)
expected distance to "A": 35.120849609375; actual R 53.62698
For a crude approximation, compute the Axis-Aligned Bounding Box, then the bounding sphere of that box (same center, diameter = √(W² + H² + D²) ).
You can refine by computing the largest distance from that center.

Calculating temporary coordinate if distance exceeds 100

I have a problem with coding a function that will do the following:
Function will take 2 sets of coordinates (x,y,z). First set is starting point and second one is end point.
Now first i will have to determine distance between those two points. If distance will be greater than lets say 100 then i will have to calculate a temporary point. I will then calculate distance between first set of coordinates and this temporary point. Please check illustration below i am sure things will be much more understandable.
Function that calculates new point between points A,B:
x = (x1+x2/2)
y = (y1+y2/2)
z = (z1+z2/2)
Function that calculates distance is:
public float DistanceTo(float x, float y, float z, float x2, float y2, float z2)
{
float a = x - x2;
float b = y - y2;
float c = z - z2;
return Math.Sqrt(a * a + b * b + c * c);
}
Link to illustration:
Perhaps my approach will be CPU heavy and perhaps slow (?) but currently i am out of ideas how to approach the problem.
Basically i need a function that will go from A to B in increments if (distance < 100).
Thank you for reading and thanks for any solution posted!
PS please dont make fun of my paint skills :)
Compute the distance d from (xb,yb,zb) (begin) to (xe,ye,ze) (end). Compute the number of parts N=(int)((d-1)/100)+1. Compute
xk = xb + (k*(xe-xb))/N
yk = yb + (k*(ye-yb))/N
zk = zb + (k*(ze-zb))/N
for k=1,...,N-1 to get equally spaced points on the segment with a distance not surpassing 100.
You can do it recursively
create a Point struct that represent a point in R3, with 2 utility methods to calculate the distance and midpoint.
struct Point
{
public double x;
public double y;
public double z;
public double Distance(Point b)
{
return Math.Sqrt(Math.Pow(b.x - this.x, 2) +
Math.Pow(b.y - this.y, 2) +
Math.Pow(b.z - this.z, 2));
}
public Point MidPoint(Point b)
{
return new Point()
{
x = (this.x + b.x) / 2,
y = (this.y + b.y) / 2,
z = (this.z + b.z) / 2
};
}
}
and write a simple recursive function that will calculate the distance and call itself recursively until the distance between point a and the temp point is less than maxSegmentLength which is 100 in your case:
public static Point GetPoint(Point a, Point b, double maxSegmentLength)
{
var distance = a.Distance(b);
if (distance < maxSegmentLength)
return b;
else
return GetPoint(a, a.MidPoint(b),maxSegmentLength);
}
Or more efficiently with vectors:
struct Vector
{
public double Vx;
public double Vy;
public double Vz;
public double R;
public Vector(Point a,Point b)
{
R = a.Distance(b);
Vx = (b.x - a.x)/R;
Vy = (b.y - a.y)/R;
Vz = (b.z - a.z)/R;
}
}
public static Point GetPoint(Point a, Point b,double maxSegmentLength)
{
var Vab = new Vector(a, b);
var dAC = Vab.R;
while (dAC > maxSegmentLength) { dAC /= 2; } //or replace this line and the one above it with var dAC=Math.Pow(0.5,(int)(-(Math.Log(maxSegmentLength / Vab.R) / Math.Log(2))) + 1)*Vab.R;
return new Point() {
x = a.x + Vab.Vx * dAC ,
y = a.y + Vab.Vy * dAC ,
z = a.z + Vab.Vz * dAC
};
}
If the point is always at a midpoint then its distance is always half of the original
public double Calc(Point A, Point B)
{
double d = Distance(A,B);
while(d>100)
{
d/=2;
}
return d;
}

Best method to check if a point lies on an arc in c#

What I want to do should be simple but it has been a while since I studied math.
Let's say I have Point and Arc classes as below. How can I check if the Point p lies on Arc a.
public class Point
{
public double X;
public double Y;
}
public class Arc
{
public double Radius;
public double StartAngle;
public double EndAngle;
// center of the arc
public double Xc;
public double Yc;
}
Point p = new Point() { X = 5, Y = 5 };
Arc a = new Arc()
{
Radius = 5,
StartAngle = 0,
EndAngle = Math.PI/2,
Xc = 0,
Yc = 0
};
I came up with this answer which is posted here for future reference. I know it is not the most efficient method but it does the job.
// first check if the point is on a circle with the radius of the arc.
// Next check if it is between the start and end angles of the arc.
public static bool IsPointOnArc(Point p, Arc a)
{
if (p.Y * p.Y == a.Radius * a.Radius - p.X * p.X)
{
double t = Math.Acos(p.X / a.Radius);
if (t >= a.StartAngle && t <= a.EndAngle)
{
return true;
}
}
return false;
}

Calculate a point along the line A-B at a given distance from A

I'm going quite mad trying to calculate the point along the given line A-B, at a given distance from A, so that I can "draw" the line between two given points. It sounded simple enough at the outset, but I can't seem to get it right. Worse still, I don't understand where I've gone wrong. Geometry (and math in general) is NOT my strong suite.
I have read similar questions and there answers on SO. In fact I lifted my current implementation of CalculatePoint function directly from Mads Elvheim's answer to: Given a start and end point, and a distance, calculate a point along a line (plus a correction in a later comment - if I understand him correctly) because my indepedent attempts to solve the problem were getting me nowhere, except a first class express ticket frusterpationland.
Here's my UPDATED code (please see the EDIT notes a bottom of post):
using System;
using System.Drawing;
using System.Windows.Forms;
namespace DrawLines
{
public class MainForm : Form
{
// =====================================================================
// Here's the part I'm having trouble with. I don't really understand
// how this is suposed to work, so I can't seem to get it right!
// ---------------------------------------------------------------------
// A "local indirector" - Just so I don't have go down and edit the
// actual call everytime this bluddy thing changes names.
private Point CalculatePoint(Point a, Point b, int distance) {
return CalculatePoint_ByAgentFire(a, b, distance);
}
#region CalculatePoint_ByAgentFire
//AgentFire: Better approach (you can rename the struct if you need):
struct Vector2
{
public readonly double X;
public readonly double Y;
public Vector2(double x, double y) {
this.X = x;
this.Y = y;
}
public static Vector2 operator -(Vector2 a, Vector2 b) {
return new Vector2(b.X - a.X, b.Y - a.Y);
}
public static Vector2 operator *(Vector2 a, double d) {
return new Vector2(a.X * d, a.Y * d);
}
public override string ToString() {
return string.Format("[{0}, {1}]", X, Y);
}
}
// For getting the midpoint you just need to do the (a - b) * d action:
//static void Main(string[] args)
//{
// Vector2 a = new Vector2(1, 1);
// Vector2 b = new Vector2(3, 1);
// float distance = 0.5f; // From 0.0 to 1.0.
// Vector2 c = (a - b) * distance;
// Console.WriteLine(c);
//}
private Point CalculatePoint_ByAgentFire(Point a, Point b, int distance) {
var vA = new Vector2(a.X, a.Y);
var vB = new Vector2(b.X, b.Y);
double lengthOfHypotenuse = LengthOfHypotenuseAsDouble(a,b);
double portionOfDistanceFromAtoB = distance / lengthOfHypotenuse;
var vC = (vA - vB) * portionOfDistanceFromAtoB;
Console.WriteLine("vC="+vC);
return new Point((int)(vC.X+0.5), (int)(vC.Y+0.5));
}
// Returns the length of the hypotenuse rounded to an integer, using
// Pythagoras' Theorem for right angle triangles: The length of the
// hypotenuse equals the sum of the square of the other two sides.
// Ergo: h = Sqrt(a*a + b*b)
private double LengthOfHypotenuseAsDouble(Point a, Point b) {
double aSq = Math.Pow(Math.Abs(a.X - b.X), 2); // horizontal length squared
double bSq = Math.Pow(Math.Abs(b.Y - b.Y), 2); // vertical length squared
return Math.Sqrt(aSq + bSq); // length of the hypotenuse
}
#endregion
//dbaseman: I thought something looked strange about the formula ... the question
//you linked was how to get the point at a distance after B, whereas you want the
//distance after A. This should give you the right answer, the start point plus
//distance in the vector direction.
//
// Didn't work as per: http://s1264.photobucket.com/albums/jj496/corlettk/?action=view&current=DrawLinesAB-broken_zps069161e9.jpg
//
private Point CalculatePoint_ByDbaseman(Point a, Point b, int distance) {
// a. calculate the vector from a to b:
double vectorX = b.X - a.X;
double vectorY = b.Y - a.Y;
// b. calculate the length:
double magnitude = Math.Sqrt(vectorX * vectorX + vectorY * vectorY);
// c. normalize the vector to unit length:
vectorX /= magnitude;
vectorY /= magnitude;
// d. calculate and Draw the new vector, which is x1y1 + vxvy * (mag + distance).
return new Point(
(int)((double)a.X + vectorX * distance) // x = col
, (int)((double)a.Y + vectorY * distance) // y = row
);
}
// MBo: Try to remove 'magnitude' term in the parentheses both for X and for Y expressions.
//
// Didn't work as per: http://s1264.photobucket.com/albums/jj496/corlettk/?action=view&current=DrawLinesAB-broken_zps069161e9.jpg
//
//private Point CalculatePoint_ByMBo(Point a, Point b, int distance) {
// // a. calculate the vector from a to b:
// double vectorX = b.X - a.X;
// double vectorY = b.Y - a.Y;
// // b. calculate the length:
// double magnitude = Math.Sqrt(vectorX * vectorX + vectorY * vectorY);
// // c. normalize the vector to unit length:
// vectorX /= magnitude;
// vectorY /= magnitude;
// // d. calculate and Draw the new vector, which is x1y1 + vxvy * (mag + distance).
// return new Point(
// (int)( ((double)a.X + vectorX * distance) + 0.5 )
// , (int)( ((double)a.X + vectorX * distance) + 0.5 )
// );
//}
// Didn't work
//private Point CalculatePoint_ByUser1556110(Point a, Point b, int distance) {
// Double magnitude = Math.Sqrt(Math.Pow(b.Y - a.Y, 2) + Math.Pow(b.X - a.X, 2));
// return new Point(
// (int)(a.X + distance * (b.X - a.X) / magnitude + 0.5)
// , (int)(a.Y + distance * (b.Y - a.Y) / magnitude + 0.5)
// );
//}
// didn't work
//private static Point CalculatePoint_ByCadairIdris(Point a, Point b, int distance) {
// // a. calculate the vector from a to b:
// double vectorX = b.X - a.X;
// double vectorY = b.Y - a.Y;
// // b. calculate the proportion of hypotenuse
// double factor = distance / Math.Sqrt(vectorX*vectorX + vectorY*vectorY);
// // c. factor the lengths
// vectorX *= factor;
// vectorY *= factor;
// // d. calculate and Draw the new vector,
// return new Point((int)(a.X + vectorX), (int)(a.Y + vectorY));
//}
// Returns a point along the line A-B at the given distance from A
// based on Mads Elvheim's answer to:
// https://stackoverflow.com/questions/1800138/given-a-start-and-end-point-and-a-distance-calculate-a-point-along-a-line
private Point MyCalculatePoint(Point a, Point b, int distance) {
// a. calculate the vector from o to g:
double vectorX = b.X - a.X;
double vectorY = b.Y - a.Y;
// b. calculate the length:
double magnitude = Math.Sqrt(vectorX * vectorX + vectorY * vectorY);
// c. normalize the vector to unit length:
vectorX /= magnitude;
vectorY /= magnitude;
// d. calculate and Draw the new vector, which is x1y1 + vxvy * (mag + distance).
return new Point(
(int)(((double)a.X + vectorX * (magnitude + distance)) + 0.5) // x = col
, (int)(((double)a.Y + vectorY * (magnitude + distance)) + 0.5) // y = row
);
}
// =====================================================================
private const int CELL_SIZE = 4; // width and height of each "cell" in the bitmap.
private readonly Bitmap _bitmap; // to draw on (displayed in picBox1).
private readonly Graphics _graphics; // to draw with.
// actual points on _theLineString are painted red.
private static readonly SolidBrush _thePointBrush = new SolidBrush(Color.Red);
// ... and are labeled in Red, Courier New, 12 point, Bold
private static readonly SolidBrush _theLabelBrush = new SolidBrush(Color.Red);
private static readonly Font _theLabelFont = new Font("Courier New", 12, FontStyle.Bold);
// the interveening calculated cells on the lines between actaul points are painted Black.
private static readonly SolidBrush _theLineBrush = new SolidBrush(Color.Black);
// the points in my line-string.
private static readonly Point[] _theLineString = new Point[] {
// x, y
new Point(170, 85), // A
new Point( 85, 70), // B
//new Point(209, 66), // C
//new Point( 98, 120), // D
//new Point(158, 19), // E
//new Point( 2, 61), // F
//new Point( 42, 177), // G
//new Point(191, 146), // H
//new Point( 25, 128), // I
//new Point( 95, 24) // J
};
public MainForm() {
InitializeComponent();
// initialise "the graphics system".
_bitmap = new Bitmap(picBox1.Width, picBox1.Height);
_graphics = Graphics.FromImage(_bitmap);
picBox1.Image = _bitmap;
}
#region actual drawing on the Grpahics
private void DrawCell(int x, int y, Brush brush) {
_graphics.FillRectangle(
brush
, x * CELL_SIZE, y * CELL_SIZE // x, y
, CELL_SIZE, CELL_SIZE // width, heigth
);
}
private void DrawLabel(int x, int y, char c) {
string s = c.ToString();
_graphics.DrawString(
s, _theLabelFont, _theLabelBrush
, x * CELL_SIZE + 5 // x
, y * CELL_SIZE - 8 // y
);
}
// ... there should be no mention of _graphics or CELL_SIZE below here ...
#endregion
#region draw points on form load
private void MainForm_Load(object sender, EventArgs e) {
DrawPoints();
}
// draws and labels each point in _theLineString
private void DrawPoints() {
char c = 'A'; // label text, as a char so we can increment it for each point.
foreach ( Point p in _theLineString ) {
DrawCell(p.X, p.Y, _thePointBrush);
DrawLabel(p.X, p.Y, c++);
}
}
#endregion
#region DrawLines on button click
private void btnDrawLines_Click(object sender, EventArgs e) {
DrawLinesBetweenPointsInTheString();
}
// Draws "the lines" between the points in _theLineString.
private void DrawLinesBetweenPointsInTheString() {
int n = _theLineString.Length - 1; // one less line-segment than points
for ( int i = 0; i < n; ++i )
Draw(_theLineString[i], _theLineString[i + 1]);
picBox1.Invalidate(); // tell the graphics system that the picture box needs to be repainted.
}
// Draws all the cells along the line from Point "a" to Point "b".
private void Draw(Point a, Point b) {
int maxDistance = LengthOfHypotenuse(a, b);
for ( int distance = 1; distance < maxDistance; ++distance ) {
var point = CalculatePoint(a, b, distance);
DrawCell(point.X, point.X, _theLineBrush);
}
}
// Returns the length of the hypotenuse rounded to an integer, using
// Pythagoras' Theorem for right angle triangles: The length of the
// hypotenuse equals the sum of the square of the other two sides.
// Ergo: h = Sqrt(a*a + b*b)
private int LengthOfHypotenuse(Point a, Point b) {
double aSq = Math.Pow(Math.Abs(a.X - b.X), 2); // horizontal length squared
double bSq = Math.Pow(Math.Abs(b.Y - b.Y), 2); // vertical length squared
return (int)(Math.Sqrt(aSq + bSq) + 0.5); // length of the hypotenuse
}
#endregion
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.picBox1 = new System.Windows.Forms.PictureBox();
this.btnDrawLines = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.picBox1)).BeginInit();
this.SuspendLayout();
//
// picBox1
//
this.picBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.picBox1.Location = new System.Drawing.Point(0, 0);
this.picBox1.Name = "picBox1";
this.picBox1.Size = new System.Drawing.Size(1000, 719);
this.picBox1.TabIndex = 0;
this.picBox1.TabStop = false;
//
// btnDrawLines
//
this.btnDrawLines.Location = new System.Drawing.Point(23, 24);
this.btnDrawLines.Name = "btnDrawLines";
this.btnDrawLines.Size = new System.Drawing.Size(77, 23);
this.btnDrawLines.TabIndex = 1;
this.btnDrawLines.Text = "Draw Lines";
this.btnDrawLines.UseVisualStyleBackColor = true;
this.btnDrawLines.Click += new System.EventHandler(this.btnDrawLines_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1000, 719);
this.Controls.Add(this.btnDrawLines);
this.Controls.Add(this.picBox1);
this.Location = new System.Drawing.Point(10, 10);
this.MinimumSize = new System.Drawing.Size(1016, 755);
this.Name = "MainForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Draw Lines on a Matrix.";
this.Load += new System.EventHandler(this.MainForm_Load);
((System.ComponentModel.ISupportInitialize)(this.picBox1)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.PictureBox picBox1;
private System.Windows.Forms.Button btnDrawLines;
#endregion
}
}
Sorry if it's a bit long, but this an is SSCCE exhumed from my real project, which is an implementation of the A* shortest route algorithm to run the MazeOfBolton... i.e. a maze runner.
What I actually want to do is pre-calculate a "fence" (i.e. a buffered MBR) around two given points (origin and goal) in the maze (a matrix), such that all points within the "fence" are within a given distance from "the straight line between the two points", in order to quickly eliminate the hundreds-of-thousands of possible paths which are heading away from the goal.
Note that this programming challenge closed years ago, so there's no issue with "competitive plagerism" here. No this is not homework, in fact I'm a professional programmer... I'm just WAAAAY out of my comfort zone here, even with relatively simple geometry. Sigh.
So... Please can anyone give me any pointers to help me get the CalculatePoint function to correctly: Calculate a point along the line A-B at the given distance from A?
Thanks in advance for your generosity... even in reading this far.
Cheers. Keith.
EDIT: I just updated the posted source code becuase:
(1) I just realised that it wasn't self contained. I forgot about the seperate MainForm.Designer.cs file, which I've appended to the bottom of the posted code.
(2) The latest version includes what I've tried so far, with a photobucket link to a picture of what each failure looks like... and they're all the same. Huy? WTF?
I suppose my problem may be elsewhere, like some funky windows form setting that was previously missed by everyone else because I forgot to post the designer-generated code... Except everythingelse (in my actual project) paints exactly where I expect it to, so why should a calculated point be any different. I don't know!?!?!? I'm pretty frustrated and I'm getting cranky, so I think I'll leave this for another day ;-)
Goes to show how much we routinely underestimate how much effort it'll take to make a computer do ANYthing... even just draw a simple line... it's not even a curve, let alone a great circle or a transverse mercator or anything fancy... just a simple bluddy line!?!?!? ;-)
A BIG Thank You to everyone who posted!
Cheers again. Keith.
Calculate the vector AB
First define the vector from point A(1,-1) to point B(2,4) substracting A from B.
The vector would be Vab(1,5).
Calculate the length of AB
Use Pythagorean theorem to calculate the length of vector AB.
|Vab| = SQRT(1²+5²)
The Length is (rounded) 5.1
Calculate the unit vector
Divide the vector by its length to get the unit vector (the vector with length 1).
V1(1/5.1,5/5.1) = V1(0.2, 0.98)
Calculate the vector with length 4
Now multiply V1 with the length you want, for example 4, to get Vt.
Vt(0.2*4,0.98*4) = Vt(0.8,3.92)
Calculate target point
Add the vector Vt to point A to get point T (target).
T = A + Vt = T(1.8,2.92)
EDIT: Answer to your edit
The method LengthOfHypotenuse should look like that
fixed an error on calculating bSq
and removed redundant Math.Abs call, because a pow of 2 is always positive
removed the addition of 0.5, don't know why you would need that
you should at least use a float as return value (double or decimal would work also)
//You should work with Vector2 class instead of Point and use their Length property
private double LengthOfHypotenuse(Point a, Point b) {
double aSq = Math.Pow(a.X - b.X, 2); // horizontal length squared
double bSq = Math.Pow(a.Y - b.Y, 2); // vertical length squared
return Math.Sqrt(aSq + bSq); // length of the hypotenuse
}
The method Draw(Point a, Point b) should look like that:
Corrected DrawCell() call
private void Draw(Point a, Point b) {
double maxDistance = LengthOfHypotenuse(a, b);
for (int distance = 0; distance < maxDistance; ++distance) {
var point = CalculatePoint(new Vector2(a), new Vector2(b), distance);
DrawCell(point.X, point.Y, _theLineBrush);
}
}
Your CalculatePoint(Point a, Point b, int distance) method:
Moved some calculations into Vector2 class
private Point CalculatePoint(Vector2 a, Vector2 b, int distance) {
Vector2 vectorAB = a - b;
return a + vectorAB.UnitVector * distance;
}
I have extended the Vector class for you to add the missing operators (credits to AgentFire)
//AgentFire: Better approach (you can rename the struct if you need):
struct Vector2 {
public readonly double X;
public readonly double Y;
public Vector2(Point p) : this(p.X,p.Y) {
}
public Vector2(double x, double y) {
this.X = x;
this.Y = y;
}
public static Vector2 operator -(Vector2 a, Vector2 b) {
return new Vector2(b.X - a.X, b.Y - a.Y);
}
public static Vector2 operator +(Vector2 a, Vector2 b) {
return new Vector2(b.X + a.X, b.Y + a.Y);
}
public static Vector2 operator *(Vector2 a, double d) {
return new Vector2(a.X * d, a.Y * d);
}
public static Vector2 operator /(Vector2 a, double d) {
return new Vector2(a.X / d, a.Y / d);
}
public static implicit operator Point(Vector2 a) {
return new Point((int)a.X, (int)a.Y);
}
public Vector2 UnitVector {
get { return this / Length; }
}
public double Length {
get {
double aSq = Math.Pow(X, 2);
double bSq = Math.Pow(Y, 2);
return Math.Sqrt(aSq + bSq);
}
}
public override string ToString() {
return string.Format("[{0}, {1}]", X, Y);
}
}
Better approach (you can rename the struct if you need):
struct Vector2
{
public readonly float X;
public readonly float Y;
public Vector2(float x, float y)
{
this.X = x;
this.Y = y;
}
public static Vector2 operator -(Vector2 a, Vector2 b)
{
return new Vector2(b.X - a.X, b.Y - a.Y);
}
public static Vector2 operator +(Vector2 a, Vector2 b)
{
return new Vector2(a.X + b.X, a.Y + b.Y);
}
public static Vector2 operator *(Vector2 a, float d)
{
return new Vector2(a.X * d, a.Y * d);
}
public override string ToString()
{
return string.Format("[{0}, {1}]", X, Y);
}
}
For getting the midpoint you just need to do the (a - b) * d + a action:
class Program
{
static void Main(string[] args)
{
Vector2 a = new Vector2(1, 1);
Vector2 b = new Vector2(3, 1);
float distance = 0.5f; // From 0.0 to 1.0.
Vector2 c = (a - b) * distance + a;
Console.WriteLine(c);
}
}
This will give you the point:
output:\> [2, 1]
All you need after that is to for(the distance; up toone; d += step) from 0.0 to 1.0 and draw your pixels.
private static Point CalculatePoint(Point a, Point b, int distance)
{
// a. calculate the vector from o to g:
double vectorX = b.X - a.X;
double vectorY = b.Y - a.Y;
// b. calculate the proportion of hypotenuse
double factor = distance / Math.Sqrt(vectorX * vectorX + vectorY * vectorY);
// c. factor the lengths
vectorX *= factor;
vectorY *= factor;
// d. calculate and Draw the new vector,
return new Point((int)(a.X + vectorX), (int)(a.Y + vectorY));
}
Try to remove 'magnitude' term in the parentheses both for X and for Y expressions:
(int)( ((double)a.X + vectorX * distance) + 0.5 )
private Point CalculatePoint(Point a, Point b, int distance) {
Point newPoint = new Point(10,10);
Double Magnitude = Math.Sqrt(Math.Pow((b.Y - a.Y),2) + Math.Pow((b.X - a.X),2));
newPoint.X = (int)(a.X + (distance * ((b.X - a.X)/magnitude)));
newPoint.Y = (int)(a.Y + (distance * ((b.Y - a.Y)/magnitude)));
return newPoint;
}
OK guys, I found my major bug. It was a classic Doh! My Draw method was painting at p.X, p.X
So, I finally got something that works. Please note that I am not saying that this a "good solution", or "the only working solution" I'm just saying that it does what I want it to do ;-)
Here's my UPDATED working code: (complete and selfcontained this time ;-)
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
namespace DrawLines
{
public class MainForm : Form
{
#region constants and readonly attributes
private const int CELL_SIZE = 4; // width and height of each "cell" in the bitmap.
private readonly Bitmap _myBitmap; // to draw on (displayed in picBox1).
private readonly Graphics _myGraphics; // to draw with.
// actual points on _theLineString are painted red.
private static readonly SolidBrush _thePointBrush = new SolidBrush(Color.Red);
// ... and are labeled in /*Bold*/ Black, 16 point Courier New
private static readonly SolidBrush _theLabelBrush = new SolidBrush(Color.Black);
private static readonly Font _theLabelFont = new Font("Courier New", 16); //, FontStyle.Bold);
// the interveening calculated cells on the lines between actaul points are painted Silver.
private static readonly SolidBrush _theLineBrush = new SolidBrush(Color.Silver);
// the points in my line-string.
private static readonly Point[] _thePoints = new Point[] {
// x, y c i
new Point(170, 85), // A 0
new Point( 85, 70), // B 1
new Point(209, 66), // C 2
new Point( 98, 120), // D 3
new Point(158, 19), // E 4
new Point( 2, 61), // F 5
new Point( 42, 177), // G 6
new Point(191, 146), // H 7
new Point( 25, 128), // I 8
new Point( 95, 24) // J 9
};
#endregion
public MainForm() {
InitializeComponent();
// initialise "the graphics system".
_myBitmap = new Bitmap(picBox1.Width, picBox1.Height);
_myGraphics = Graphics.FromImage(_myBitmap);
picBox1.Image = _myBitmap;
}
#region DrawPoints upon MainForm_Load
private void MainForm_Load(object sender, EventArgs e) {
DrawPoints();
}
// draws and labels each point in _theLineString
private void DrawPoints() {
char c = 'A'; // label text, as a char so we can increment it for each point.
foreach ( Point p in _thePoints ) {
DrawCell(p.X, p.Y, _thePointBrush);
DrawLabel(p.X, p.Y, c++);
}
}
#endregion
#region DrawLines on button click
// =====================================================================
// Here's the interesting bit. DrawLine was called Draw
// Draws a line from A to B, by using X-values to calculate the Y values.
private void DrawLine(Point a, Point b)
{
if ( a.Y > b.Y ) // A is below B
Swap(ref a, ref b); // make A the topmost point (ergo sort by Y)
Debug.Assert(a.Y < b.Y, "A is still below B!");
var left = Math.Min(a.X, b.X);
var right = Math.Max(a.X, b.X);
int width = right - left;
Debug.Assert(width >= 0, "width is negative!");
var top = a.Y;
var bottom = b.Y;
int height = bottom - top;
Debug.Assert(height >= 0, "height is negative!");
if ( width > height ) {
// use given X values to calculate the Y values,
// otherwise it "skips" some X's
double slope = (double)height / (double)width;
Debug.Assert(slope >= 0, "slope is negative!");
if (a.X <= b.X) // a is left-of b, so draw left-to-right.
for ( int x=1; x<width; ++x ) // xOffset
DrawCell( (left+x), (a.Y + ((int)(slope*x + 0.5))), _theLineBrush);
else // a is right-of b, so draw right-to-left.
for ( int x=1; x<width; ++x ) // xOffset
DrawCell( (right-x), (a.Y + ((int)(slope*x + 0.5))), _theLineBrush);
} else {
// use given Y values to calculate the X values,
// otherwise it "skips" some Y's
double slope = (double)width/ (double)height;
Debug.Assert(slope >= 0, "slope is negative!");
if (a.X <= b.X) { // a is left-of b, so draw left-to-right. (FG)
for ( int y=1; y<height; ++y ) // yOffset
DrawCell( (a.X + ((int)(slope*y + 0.5))), (top+y), _theLineBrush);
} else { // a is right-of b, so draw right-to-left. (DE,IJ)
for ( int y=1; y<height; ++y ) // yOffset
DrawCell( (b.X + ((int)(slope*y + 0.5))), (bottom-y), _theLineBrush);
}
}
}
private void btnDrawLines_Click(object sender, EventArgs e) {
DrawLines(); // join the points
DrawPoints(); // redraw the labels over the lines.
}
// Draws a line between each point in _theLineString.
private void DrawLines() {
int n = _thePoints.Length - 1; // one less line-segment than points
for ( int i=0; i<n; ++i )
DrawLine(_thePoints[i], _thePoints[i+1]);
picBox1.Invalidate(); // tell the graphics system that the picture box needs to be repainted.
}
private void Swap(ref Point a, ref Point b) {
Point tmp = a;
a = b;
b = tmp;
}
#endregion
#region actual drawing on _myGraphics
// there should be no calls to Draw or Fill outside of this region
private void DrawCell(int x, int y, Brush brush) {
_myGraphics.FillRectangle(
brush
, x*CELL_SIZE
, y*CELL_SIZE
, CELL_SIZE // width
, CELL_SIZE // heigth
);
}
private void DrawLabel(int x, int y, char c) {
string s = c.ToString();
_myGraphics.DrawString(
s, _theLabelFont, _theLabelBrush
, x * CELL_SIZE + 5 // x
, y * CELL_SIZE - 10 // y
);
}
#endregion
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.picBox1 = new System.Windows.Forms.PictureBox();
this.btnDrawLines = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.picBox1)).BeginInit();
this.SuspendLayout();
//
// picBox1
//
this.picBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.picBox1.Location = new System.Drawing.Point(0, 0);
this.picBox1.Name = "picBox1";
this.picBox1.Size = new System.Drawing.Size(1000, 719);
this.picBox1.TabIndex = 0;
this.picBox1.TabStop = false;
//
// btnDrawLines
//
this.btnDrawLines.Location = new System.Drawing.Point(23, 24);
this.btnDrawLines.Name = "btnDrawLines";
this.btnDrawLines.Size = new System.Drawing.Size(77, 23);
this.btnDrawLines.TabIndex = 1;
this.btnDrawLines.Text = "Draw Lines";
this.btnDrawLines.UseVisualStyleBackColor = true;
this.btnDrawLines.Click += new System.EventHandler(this.btnDrawLines_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1000, 719);
this.Controls.Add(this.btnDrawLines);
this.Controls.Add(this.picBox1);
this.Location = new System.Drawing.Point(10, 10);
this.MinimumSize = new System.Drawing.Size(1016, 755);
this.Name = "MainForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Draw Lines on a Matrix.";
this.Load += new System.EventHandler(this.MainForm_Load);
((System.ComponentModel.ISupportInitialize)(this.picBox1)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.PictureBox picBox1;
private System.Windows.Forms.Button btnDrawLines;
#endregion
}
}
EDIT - UPDATED ABOVE CODE: This version draws "solid" lines. The previously posted version skipped cells in nearly vertical lines, so I inverted the algorithm to calculate the X value (instead of the Y value) in these cases... now I can use it to set (and draw) a "solid fence" around a "navigable area" ;-)
Here's an UPDATED picture of the correct results.
Thanks again to everybody who helped... and you did help ;-)
Cheers. Keith.

Categories