Draw level curves for an array of z values corresponding to points (x, y) in C#

When you click one of its radio buttons, the program builds an array of doubles where entry corresponds to a z value over a point (x, y). It then draws level curves for the data in the array.

Note that this is a non-analytic technique. The example uses functions to initialize its array of values but the technique works with any array of values, event those obtained by measuring or recording data that is not generated in this way.

How the program works is a bit tricky.

The DrawLevelCurve method finds level curves where the values in the array intersect a horizontal plane with a particular z value. To do that, it loops through the points and considers the triangle defined by the points (x, y)-->(x, y + 1)-->(x + 1, y + 1) and the triangle defined by the points (x, y)-->(x + 1, y + 1)-->(x + 1, y). For each of these triangles, the method calls the IntersectPlaneAndTriangle method to find the line where the triangle intersects the level plane with the given z value. If there is such a line segment of intersection, the method draws it.

The method draws lines with z values less than 0 in red, those greater than 0 in blue, and z values equal to 0 in black.

// Draw this level curve.
private void DrawLevelCurve(Graphics gr, Point3D[,] values, double z)
{
using (Pen thin_pen = new Pen(Color.Black, 0))
{
if (z > 0)
{
thin_pen.Color = Color.Blue;
}
else if (z < 0)
{
thin_pen.Color = Color.Red;
}

for (int x = 0; x < values.GetUpperBound(0); x++)
{
for (int y = 0; y < values.GetUpperBound(1); y++)
{
// Intersect this triangle with the level plane.
List points = new List();
IntersectPlaneAndTriangle(
points,
new Point3D(0, 0, z),
new Vector3D(0, 0, 1),
values[x, y],
values[x, y + 1],
values[x + 1, y + 1]);
if (points.Count == 2)
{
// The triangle intersects the plane.
gr.DrawLine(thin_pen,
(float)points[0].X, (float)points[0].Y,
(float)points[1].X, (float)points[1].Y);
}
if (points.Count > 2)
{
gr.DrawLine(thin_pen,
(float)points[0].X, (float)points[0].Y,
(float)points[2].X, (float)points[2].Y);
gr.DrawLine(thin_pen,
(float)points[1].X, (float)points[1].Y,
(float)points[2].X, (float)points[2].Y);
}

// Intersect this triangle with the level plane.
points.Clear();
IntersectPlaneAndTriangle(
points,
new Point3D(0, 0, z),
new Vector3D(0, 0, 1),
values[x, y],
values[x + 1, y + 1],
values[x + 1, y]);
if (points.Count == 2)
{
// The triangle intersects the plane.
gr.DrawLine(thin_pen,
(float)points[0].X, (float)points[0].Y,
(float)points[1].X, (float)points[1].Y);
}
if (points.Count > 2)
{
gr.DrawLine(thin_pen,
(float)points[0].X, (float)points[0].Y,
(float)points[2].X, (float)points[2].Y);
gr.DrawLine(thin_pen,
(float)points[1].X, (float)points[1].Y,
(float)points[2].X, (float)points[2].Y);
}
}
}
}
}

The IntersectPlaneAndTriangle method finds the line segment (if any) where a triangle intersects a plane. To do that, the code calls the IntersectPlaneAndSegment method to see where the triangle's edges intersect the plane (if they do). The line segment where the triangle intersects the plane is simply the line between the points where the edges intersect the plane.

// Return the line segment of intersection
// between a triangle and a plane.
private void IntersectPlaneAndTriangle(
Listpoints,
Point3D p0, Vector3D N,
Point3D p1, Point3D p2, Point3D p3)
{
// Find points of intersection between
// the triangle's edges and the plane.
IntersectPlaneAndSegment(points, p0, N, p1, p2);
IntersectPlaneAndSegment(points, p0, N, p2, p3);
IntersectPlaneAndSegment(points, p0, N, p3, p1);
}

The IntersectPlaneAndSegment method determines where a line segment intersects a plane (if it does).

// If the plane and line segment intersect, add the
// points of intersection to points and return true.
//
// The equation of the plane is:
// N dot (p - p0) = 0
//
// The equation of the line is:
// p1 + t * where 0 <= t <= 1
//
// The plane and line intersect where:
// t = [N dot ] / [N dot ]
private void IntersectPlaneAndSegment(List points,
Point3D p0, Vector3D N,
Point3D p1, Point3D p2)
{
// Get the denominator. If it's 0, the plane and line are parallel.
Vector3D v12 = p2 - p1;
double denominator = Vector3D.DotProduct(N, v12);
if (Math.Abs(denominator) < -0.0001) return;

// Get the numerator.
Vector3D v10 = p0 - p1;
double numerator = Vector3D.DotProduct(N, v10);

// Calculate t and see if the segment intersects the plane.
double t = numerator / denominator;
if ((t >= 0) && (t <= 1))
{
// The segment intersects the plane at p1 + t * v12.
points.Add(p1 + t * v12);
}
}

   

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.