TinyLine 2D Programming Guide

5 Paths and shapes

TinyLine 2D provides a general path (TinyPath), which can be used to create a variety of graphical shapes, and also Tiny2D class provides drawing functions for common basic shapes such as rectangles and ellipses.

These basic shapes drawing functions are convenient for coding and may be used in the same ways as the more general paths.

5.1 Paths

The TinyPath class represents a geometric path constructed from straight lines, and quadratic and cubic (Bezier) curves. Paths are used to represent lines, curves and regions.

A path consists of a series of path segments. Path segments may be straight lines or quadratic and cubic (Bezier) curves. It can contain multiple subpaths. Path segments operators are: moveTo, lineTo, curveTo, curveToCubic, closePath. As a result of an applying these segments operators the correspondent segments are created.

Multiple subpaths can be expressed by using a "moveTo" segment operator to create a discontinuity in the geometry to move from the end of one subpath to the beginning of the next.

The following function of the Tiny2D class draw the outline of the specified TinyPath object.

Name Description
drawPath Draws the outline of the specified TinyPath.

Example: Beziers.java

beziers

View the example as applet (Java-enabled browsers only)

The example animates randomly generated TinyPath object.

The run function of the Beziers class performs animations and it has two parts. The first part draws the TinyPath object on the screen for the first time.


        /* Draws the scene (first time) if needed. */
        if(!drawn)
        {
            synchronized (this)
            {
  	       /* Draws the scene (first time) if needed */
               t2d.invalidate();
               /* Clears the clipRect area before production */
               t2d.clearRect(t2d.getClip());

               /* Overwrites the Tiny2D state */
               tstate.matrix = (mat);
               tstate.fillColor =  fillColor;

               /* Draws the path */
               t2d.drawPath(path, null, null);

               /* Sends the new pixels */
               t2d.sendPixels();
               drawn = true;
            }
        }

The second part is the animation itself and it calls the drawDemo function:

      /* Calculates and draws the current step. */
      drawDemo(imgWidth, imgHeight);

The drawDemo is the function that produces one animation step. It demonstrates several important things. First, it shows how to build the TinyPath object using the path segments operators:

  path.moveTo(midx<<Tiny2D.FIX_BITS, midy<<Tiny2D.FIX_BITS);
  path.curveToCubic(x1<<Tiny2D.FIX_BITS,y1<<Tiny2D.FIX_BITS,
x2<<Tiny2D.FIX_BITS, y2<<Tiny2D.FIX_BITS, midx<<Tiny2D.FIX_BITS, midy<<Tiny2D.FIX_BITS);

Second, it shows how to update only the damaged area of the TinyBuffer object and then send those new generated pixels onto the device screen.

      /* Clears the dirty area. */
      dirtyRect.setEmpty();
      bounds = path.getBBox();
      TinyRect r = t2d.getDevBounds(mat, strokeWidth, bounds);

      /* Adds the old bounds of the shape to the dirty area. */
      dirtyRect.union(r);

      /* Generates the new pata data. */
      bounds = path.getBBox();

      /* Adds the new bounds of the shape to the dirty area. */
      dirtyRect.union(t2d.getDevBounds(mat, strokeWidth, bounds));

      /* Sets the dirty area. */
//    t2d.invalidate(); // only for debug
      t2d.setClip(dirtyRect);

      /* clear the clipRect area before production */
      t2d.clearRect(t2d.getClip());

      /* Repaints the dirty area. */
      t2d.drawPath(path, bounds, null);
      /* Sends the new pixels to the display. */
      t2d.sendPixels();

Here the dirtyRect rectangle is the clip rectangle in device space.

Example: Paths.java

paths

View the example as applet (Java-enabled browsers only)

The example shows how to build TinyPath objects by reading from a data stream.

Here is the path data before and after compilation:

       /* The SVGT path before compilation (SVGT2Bin)
        * <path id="paths" fill="#45633C" 
        * d="M 60 20 Q -40 70 60 120 Q 160 70 60 20 z"/>
        */ 
       /* The binary path data. */
       byte pathdatabin[] = {6, 0, 0, 0, 121, 30, 0, 5, 0, 31, 96, 0, 
       - 116, 0, 60, 0, 60, 0, 53, 0, 1, 24, 0, 120, 0, 20, 0, -96, 0,
       0, 0, 0}; 

Reading the path from the stream:

       /* Reads the path data from the stream */
       try
       {
           ByteArrayInputStream bais = 
               new ByteArrayInputStream(pathdatabin);
           TinyInputStream tis = new TinyInputStream(bais);
           path = tis.readTinyPath();
           tis.close();
       }
       catch (IOException ioe)
       {
           System.out.println("Failed to read the stream");
           System.out.println("ioe" + ioe);
           ioe.printStackTrace();
       }

In addition, it demonstrates basic things like filling and stroking attributes, changing the current transformation matrix, etc.

5.2 Basic Shapes

In addition to the paths drawing functions, Tiny2D supports the following set of drawing functions for basic shapes:

Name Description
drawLine Draws a line between the points (x1, y1) and (x2, y2)
drawRect Draws the outline of the specified rectangle.
drawRoundRect Draws an outlined round-cornered rectangle.
drawOval Draws the outline of an oval.
drawPolyline Draws a sequence of connected lines defined by a vector of points.
drawPolygon Draws a closed polygon defined by vector of points.

Mathematically speaking, each of these basic shapes is equivalent to a path that would construct the same shape.

Example: Lines.java

line

View the example as applet (Java-enabled browsers only)

The example draws several lines with growing stoke widths:

            /* Draws the lines */
            tstate.strokeWidth = (1<<Tiny2D.FIX_BITS);
            t2d.drawLine(20<<Tiny2D.FIX_BITS,
			 150<<Tiny2D.FIX_BITS,
                         60<<Tiny2D.FIX_BITS,
                         50<<Tiny2D.FIX_BITS);

            tstate.strokeWidth = (2<<Tiny2D.FIX_BITS);
            t2d.drawLine(40<<Tiny2D.FIX_BITS,
			 150<<Tiny2D.FIX_BITS,
                         80<<Tiny2D.FIX_BITS,
                         50<<Tiny2D.FIX_BITS);

Example: Ovals.java

ovals

View the example as applet (Java-enabled browsers only)

The example draws the ovals with different fill and stroke colors:

            /* Overwrites the Tiny2D state */
            tstate.matrix    = new TinyMatrix();
            tstate.fillRule  = (Tiny2D.FILL_STYLE_EO);
            tstate.fillColor = (greenColor);
            tstate.strokeWidth = (1<<Tiny2D.FIX_BITS);
            /* Draws the first oval */
            t2d.drawOval(20<<Tiny2D.FIX_BITS,
			 60<<Tiny2D.FIX_BITS,
                         100<<Tiny2D.FIX_BITS,
                         50<<Tiny2D.FIX_BITS);

Example: Polys.java

polys

View the example as applet (Java-enabled browsers only)

The example shows how to build vector of points and


       /* The poins data. */
       static int pointsdata[] = {    
       59,45,95,63,108,105,82,139, 39,140,11,107,19,65 };

       /* Fills the points vector */
       cnt = pointsdata.length;
       i = 0;
       points = new TinyVector(1 + cnt / 2);
       while (i < cnt)
       {
           p = new TinyPoint(pointsdata[i++] << Tiny2D.FIX_BITS, 
                             pointsdata[i++] << Tiny2D.FIX_BITS);
           points.addElement(p);
       }

Then draw these points using Tiny2D API

       /* Overwrites the Tiny2D state */
       tstate.matrix = (mat1);
       tstate.fillColor = (blueColor);
       tstate.fillAlpha = (117);
       tstate.strokeColor = (redColor);
       tstate.strokeAlpha = (150);
       tstate.strokeWidth = (5<<Tiny2D.FIX_BITS);

       /* Draws the polyline  */
       t2d.drawPolyline(points);

5.3 Bounds and hit test

Every shape has a bounding box. The bounding box is a rectangle that fully encloses the shape's geometry. Bounding boxes are used to determine whether an object has been selected or "hit" by the user or what area the object occupies on the canvas.

We use TinyRect class for bounding boxes. The TinyRect class specifies an area in coordinate space that is enclosed by the TinyRect object's top-left point (xmin, ymin ) and down-right point (xmax, ymax ) in coordinate space.

The following example is interesting from many points of view including bounding boxes and coordinate spaces.

Example: HitPath.java

hitpath

View the example as applet (Java-enabled browsers only)

The example shows how to use hitPath function for example for moving shape around the canvas.

We will move an oval over the canvas with the help of pointer device (or mouse in the case of the desktop). Make sure that you run this example on devices with a pointer device otherwise, you will not have a fun with it.

Please look at the HitPath.java code.

Because the hitTest function in Tiny2D class needs a TinyPath object as its input, we need to create an oval outline for the later use.

       /* Create the outline. */
       path = Tiny2D.ovalToPath(20<<Tiny2D.FIX_BITS,
			  60<<Tiny2D.FIX_BITS,
                          100<<Tiny2D.FIX_BITS,
                          50<<Tiny2D.FIX_BITS);

When the mouse or the pointer has been pressed in the canvas we define if the pixel where the pointer device has been pressed "hits" our path.

       hit = t2d.hitPath(pressedX, pressedY, path, null);

If the path was hit, we want to move it onto the new position. For that, we change the transformation matrix:

       if(hit)
       {
          matrix.tx -= (pressedX - x) <<Tiny2D.FIX_BITS;
          matrix.ty -= (pressedY - y) <<Tiny2D.FIX_BITS;
       }
© 2008 TinyLine. All rights reserved.