JMU
Vector Graphics
A Simplified Approach with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Representation of Visual Content
Rendering of Visual Content
Some Observations
Simplified Vector Graphics
Simplified Vector Graphics (cont.)

Coordinates

images/Drafter-coordinates.gif
A Vector Graphics Class

Drafter

images/Drafter-overview.gif
Required of the Analytic Geometry Classes
A ConcreteDrafter

A Floor Plan

javaexamples/navigation/FloorPlanExample.java
        import java.util.Enumeration;

/**
 * A concrete child of the Drafter class that draws
 * a "hard coded" floor plan
 */
public class FloorPlanExample extends Drafter
{
    protected LineSegment                    wall;
    protected PiecewiseLinearCurve[]         rooms;
    
    /**
     * Default Constructor
     */
    public FloorPlanExample()
    {
       double[]      p, q;
       

       // Create a single wall
       p = new double[2];
       q = new double[2];
       p[0] = 330.0; p[1] = 210.0;
       q[0] = 390.0; q[1] = 210.0;
       wall = new LineSegment(new Point(p), new Point(q));
       
       // Create all of the rooms
       rooms = new PiecewiseLinearCurve[5];
       rooms[0] = new PiecewiseLinearCurve();
       addTo(rooms[0], 490,  40);
       addTo(rooms[0], 390,  40);
       addTo(rooms[0], 390, 210);
       addTo(rooms[0], 490, 210);
       addTo(rooms[0], 490,  40);
       
       rooms[1] = new PiecewiseLinearCurve();
       addTo(rooms[1], 390,  60);
       addTo(rooms[1], 350,  60);
       addTo(rooms[1], 350, 100);
       addTo(rooms[1], 390, 100);
       addTo(rooms[1], 390,  60);
       
       rooms[2] = new PiecewiseLinearCurve();
       addTo(rooms[2], 350,  60);
       addTo(rooms[2], 290,  60);
       addTo(rooms[2], 290, 120);
       addTo(rooms[2], 330, 120);
       addTo(rooms[2], 350, 110);
       addTo(rooms[2], 350,  60);
       
       rooms[3] = new PiecewiseLinearCurve();
       addTo(rooms[3], 330, 120);
       addTo(rooms[3], 240, 120);
       addTo(rooms[3], 240, 210);
       addTo(rooms[3], 260, 220);
       addTo(rooms[3], 310, 220);
       addTo(rooms[3], 330, 210);
       addTo(rooms[3], 330, 120);
       
       rooms[4] = new PiecewiseLinearCurve();
       addTo(rooms[4], 240, 120);
       addTo(rooms[4], 170, 120);
       addTo(rooms[4], 170, 210);
       addTo(rooms[4], 240, 210);
       addTo(rooms[4], 240, 120);
    }


    


    /**
     * A convenience method for adding a point to a 
     * PiecewiseLinearCurve
     *
     * @param line   The curve being added to
     * @param x      The x-coordinate of the new point
     * @param y      The y-coordinate of the new point
     */
    private void addTo(PiecewiseLinearCurve line, double x, double y)
    {
       double[]        v;
       
       v = new double[2];
       v[0] = x;
       v[1] = y;
       line.add(new Point(v));
    }

    

    /**
     * Draw the floor plan
     *
     * This method is called by the parent Drafter whenever
     * the floor plan needs to be drawn.
     *
     * @param max    The upper-right corner of the paper
     */
    public void draw(Point max)
    {
       Enumeration          e;
       Point                p;
       
       // Draw the wall
       e = wall.points();
       p = (Point)e.nextElement();
       moveTo(p);
       while (e.hasMoreElements())
       {
          p = (Point)e.nextElement();
          drawTo(p);
       }
       

       // Draw the rooms
       for (int i=0; i<rooms.length; i++)
       {
          e = rooms[i].points();
          p = (Point)e.nextElement();
          moveTo(p);
          while (e.hasMoreElements())
          {
             p = (Point)e.nextElement();
             drawTo(p);
          }
       }
    }
}
        
Drawing Features

LineSegment

javaexamples/navigation/FeatureDrafter1.java (Fragment: 1)
            protected void drawLineSegment(LineSegment segment)
    {
       Enumeration        points;
       Point              p;
       

       // Get an Enumeration of the Point objects
       points = segment.points();

       // Get one end point
       p = (Point)points.nextElement();

       // Move the pen to the end point
       moveTo(p);

       // Get the other end point
       p = (Point)points.nextElement();

       // Draw a line to the other end point
       drawTo(p);
    }
        
Drawing Features (cont.)

PiecewiseLinearCurve

javaexamples/navigation/FeatureDrafter1.java (Fragment: 2)
            protected void drawCurve(PiecewiseLinearCurve curve)
    {
       Enumeration        points;
       Point              p;
       

       // Get an Enumeration of the Point objects
       points = curve.points();

       // Get one end point
       p = (Point)points.nextElement();

       // Move the pen to the end point
       moveTo(p);

       // Get and draw a line to each of the remaining break points
       while (points.hasMoreElements())
       {
          // Get the other end Point
          p = (Point)points.nextElement();

          // Draw a line to the other end Point
          drawTo(p);
       }
    }
        
Drawing Features (cont.)

Polygon

javaexamples/navigation/FeatureDrafter1.java (Fragment: 3)
            protected void drawPolygon(Polygon polygon)
    {
       Enumeration        points;
       Point              p;
       

       // Get an Enumeration of the Point objects
       points = polygon.points();

       // Get one end point
       p = (Point)points.nextElement();

       // Move the pen to the end point
       moveTo(p);

       // Get and draw a line to each of the remaining break points
       while (points.hasMoreElements())
       {
          // Get the other end Point
          p = (Point)points.nextElement();

          // Draw a line to the other end Point
          drawTo(p);
       }
    }
        
Drawing Features (cont.)
Drawing Features (cont.)

All Classes that Implement Feature

javaexamples/navigation/FeatureDrafter2.java (Fragment: 1)
            protected void drawFeature(Feature feature)
    {
       Enumeration       points;
       Point             p;
       

       points = feature.points();

       p = (Point)e.nextElement();
       moveTo(p);
          
       if (!e.hasMoreElements()) // The Feature is a Point
       {
          drawTo(p);
       }
       else                     // The Feature is a LineSegment, etc...
       {
          while (e.hasMoreElements())
          {
             p = (Point)e.nextElement();
             drawTo(p);
          }
       }
    }
        
What About Re-Sizing?
What About Re-Sizing? (cont.)

Coordinates

images/world-to-screen.gif
Scaling
Scaling (cont.)
Translating the Scaled Points
Translating the Scaled Points (cont.)
The Rectangular Hull
The Rectangular Hull (cont.)
The Rectangular Hull (cont.)

One Possible Implementation

javaexamples/navigation/RectangularHull.java
        /**
 * The smallest rectangle containing a set of Point objects (represented
 * as two Point objects, one containing the minimal coordinates and
 * one containing the maximal coordinates).
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class RectangularHull
{
    private Point max, min;


    /**
     * Explicit Value Constructor
     */
    public RectangularHull(Point min, Point max)
    {
       double[]          v;
       int               n;
       
       n = min.getDimension();
       v = new double[n];

       for (int i=0; i<n; i++) v[i] = min.getCoordinate(i);
       this.min = new Point(v);

       for (int i=0; i<n; i++) v[i] = max.getCoordinate(i);
       this.max = new Point(v);
    }
    

    /**
     * Adjust this RectangularHull (if necessary) 
     * so that it includes the given Point
     *
     * @param p   The new Point
     */
    public void adjustFor(Point p)
    {
       min = Point.min(p, min);
       max = Point.max(p, max);
    }
    

    

    /**
     * Adjust this RectangularHull (if necessary) 
     * so that it includes another RectangularHull
     *
     * @param other   The other RectangularHull
     */
    public void adjustFor(RectangularHull other)
    {
       min = Point.min(other.getMin(), min);
       max = Point.max(other.getMax(), max);
    }
    



    /**
     * Get the maximal Point (e.g., the upper right corner)
     *
     * @return   The maximal point
     */
    public Point getMax()
    {
       return max;
    }


    /**
     * Get the minimal Point (e.g., the lower left corner)
     *
     * @return   The minimal point
     */
    public Point getMin()
    {
       return min;
    }
    
}
        
Drawing Re-sized Features
javaexamples/navigation/FeatureDrafter3.java (Fragment: 1)
        
    // The RectangularHull of all of the Feature objects
    protected RectangularHull         hull;
    
    // The coordinate-by-coordinate maximum of the screen coordinates
    protected Point                   smax;
    


    /**
     * Draw a Feature scaled to fit the paper
     *
     * @param feature    The Feature to draw
     */
    protected void drawFeature(Feature feature)
    {
       double               alpha;
       Enumeration          points;
       Point                p, q, rho, sigma, wmax, wmin, wminhat;
       
       // Determine the range in world coorinates
       wmax = hull.getMax();
       wmin = hull.getMin();
       rho = wmax.minus(wmin);

       // Determine the scale for each coordinate
       sigma = screenMax.cover(rho);
       
       // Maintain the aspect ratio by using the smallest element of scale
       alpha = sigma.smallestCoordinate();

       // Scale the minimum in world coordinates (for the translation)
       wminhat = wmin.times(alpha);
       

       // Scale and translate each point
       //
       points = feature.points();

       // The first Point in the feature
       p = (Point)e.nextElement();
       q = (p.times(alpha)).minus(wminhat);
       moveTo(q);
          
       if (!e.hasMoreElements()) // The Feature is a Point
       {
          drawTo(q);
       }
       else                     // The Feature is a LineSegment, etc...
       {
          while (e.hasMoreElements())
          {
             // The subsequent Point objects in the feature
             p = (Point)e.nextElement();
             q = (q.times(alpha)).minus(wminhat);
             drawTo(q);
          }
       }
    }