Draw level curves for an array of z values in C#

example

Sometimes you might have data for a three-dimensional surface but you don’t have an equation to generate the data. In that case, you can draw level curves for an array of z values representing the surface.

When you click one of its radio buttons, the program builds an array of doubles where each 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, even those obtained by measuring or recording data that is not generated in this way.

The following DrawLevelCurve method draws the level curve for a particular z value.

// 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.
                DrawPlaneTriangleIntersections(
                    gr, thin_pen,
                    new Point3D(0, 0, z),
                    new Vector3D(0, 0, 1),
                    values[x, y],
                    values[x, y + 1],
                    values[x + 1, y + 1]);

                // Intersect this triangle with the level plane.
                DrawPlaneTriangleIntersections(
                    gr, thin_pen,
                    new Point3D(0, 0, z),
                    new Vector3D(0, 0, 1),
                    values[x, y],
                    values[x + 1, y + 1],
                    values[x + 1, y]);
            }
        }
    }
}

This method first picks an appropriate pen color. For this example, it uses a black pen if the z value equals 0, a red pen if z < 0, and a blue pen if z > 0.

Next the 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 (x, y) 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 DrawPlaneTriangleIntersections method to draw the line segments where the triangles intersects the level plane with the given z value (if there are any such segments).

The following code shows the DrawPlaneTriangleIntersections method.

// Draw the line segment of intersection
// between a triangle and a plane.
private void DrawPlaneTriangleIntersections(
    Graphics gr, Pen pen,
    Point3D p0, Vector3D N,
    Point3D p1, Point3D p2, Point3D p3)
{
    List<Point3D> points = new List<Point3D>();
    IntersectPlaneAndTriangle(
        points, p0, N, p1, p2, p3);
    if (points.Count == 2)
    {
        // The triangle intersects the plane.
        gr.DrawLine(pen,
            (float)points[0].X, (float)points[0].Y,
            (float)points[1].X, (float)points[1].Y);
    }
    if (points.Count > 2)
    {
        gr.DrawLine(pen,
            (float)points[0].X, (float)points[0].Y,
            (float)points[2].X, (float)points[2].Y);
        gr.DrawLine(pen,
            (float)points[1].X, (float)points[1].Y,
            (float)points[2].X, (float)points[2].Y);
    }
}

This method calls the IntersectPlaneAndTriangle method to find the points of intersection between a triangle and a plane. If it finds any segments of intersection, the method draws them.

The following code shows the IntersectPlaneAndTriangle method.

// Return the line segment of intersection
// between a triangle and a plane.
private void IntersectPlaneAndTriangle(
    List<Point3D>points,
    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);
}

This method calls IntersectPlaneAndSegment to find the intersections between a plane and a triangle’s three edges.

Finally, the following code shows the program’s most mathy method, IntersectPlaneAndSegment.

// 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 * <p2 - p1> where 0 <= t <= 1
//
// The plane and line intersect where:
//      t = [N dot <p0 - p1>] / [N dot <p2 - p1>]
private void IntersectPlaneAndSegment(List<Point3D> 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);
    }
}

This method calculates the point where the plane and segment intersect, if they do.


Download Example   Follow me on Twitter   RSS feed




This entry was posted in algorithms, graphics, mathematics and tagged , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *