Computer Graphics (CS 4300) 2010S: Lecture 8
Today
- HW1 graded and will return by email today
- HW2 due weds!
- finish from last time:
- Model-View-Controller (MVC) architecture
- common user interaction techniques
- rectangles in 2D
- polygons in 2D
- tessellation by ear-clipping
Rectangles in 2D
- axis-aligned rectangles are very common in 2D graphics, especially GUIs
- typically represented as a point giving the *upper left corner (i.e. the corner with minimum and coordinates) plus (non-negative) width and height (horizontal and vertical extents, respectively)
- often are all integers (pixel coords) but some APIs allow floating point rects as well
- easy to check if a given point is in a rect: and
- two axis-aligned rects and overlap iff
- also easy to rasterize, e.g.
- for to
- non-aligned rectangles are less common
- can treat as an axis-aligned in a rotated coordinate system (we will cover rotations in detail later this week)
- or, just don’t special-case, and handle like any other convex polygon
Polygons in 2D
- def: a simple polygon in 2D is an ordered sequence of line segments , , such that
- each edge is the segment from a start vertex to an end vertex
- for
- non-adjacent edges do not intersect
- the only intersection of adjacent edges is at their shared vertex
- note that it is sufficient to store e.g. only the start vertices, and this also enforces the connectivity constraints by construction
- this also illustrates that the number of sides equals the number of vertices
- the polygon degenerates to a segment if (it’s also possible to have degenerate polygons for )
- nomenclature: sometimes even an open chain of segments is called a polygon
- definition of inside is intuitive for a simple polygon
- how to check if a point is inside a simple polygon?
- a polygon is convex if, for any two points and both inside the polygon, all points along the segment from to are also inside the polygon
- have already covered point-in-polygon test for convex simple polygons: e.g. consider the edges in counter-clockwise order (this is conventional) and then check if is on or to the left of every edge
- for non-convex polygons, one solution is to tessellate: break the polygon into a set of convex pieces, and then check each piece separately (will cover this later)
- it is also possible (and classical) to perform insideness checks without tessellating
- two common conventions: “even-odd” rule, and “nonzero” (aka “winding”) rule
- in each case, construct a ray in an arbitrary direction from the test point
- even-odd rule
- count number of intersections of with the polygon. is defined to be inside the poly if the intersection count is odd.
- reasoning: each time an edge is crossed, either switch from inside to outside or outside to inside
- but since poly is closed, know that ray must end up outside
- nonzero rule
- again compute all intersections of with the poly edges , but this time keep track of whether the edge crossed from left to right (i.e. on left side of and on right side of ) or right to left
- count +1 for left-to-right and –1 for right-to-left
- is defined to be inside the poly if and only if (iff) final count is nonzero
- reasoning: consider sweeping a point along the perimeter of the poly
- take the integral of the orientation angle of the line segment from to
- turns out that, for one complete sweep of the polygon, the integrated winding angle will be an integer multiple of
- intuition: reasonable definition of inside-ness is to check if the poly “circled around” in CCW direction different number times than in CW direction
- nonzero intersection test turns out to be a shortcut to compute (proof is a little subtle and we will not cover it)
- these two rules can produce different results!
- note that nonzero rule requires external boundary of poly to be in opposite winding order than holes (e.g. CCW for outside, CW for holes)
- no clear “winner”, simply a matter of choice
- some APIs only implement one rule or the other
- Both rules can run into problems if intersects polygon right on a vertex. In that case, just start over with a different . A random choice of (remember, any ray will do) will not touch any vertex “with probability 1” (in continuous coords; “with high probability” in discrete coords, like floating point or integer).
- to rasterize a convex simple polygon, one general approach is
- for to
- the details of figuring out the top, bottom, and horizontal extent of the poly at each line can be worked out, even in extensions to non-convex and non-simple polys (using either even-odd or nonzero fill rule)
- we will not cover the details, because in practice, it is becoming less common to rasterize polygons in this way
- instead, most systems are now simply tessellating the polygon into triangles (even if convex) and then rasterizing the triangles
- we will cover tessellation into triangles later today, and rasterizing triangles next time
- what about non-simple polygons?
- the edges may self-intersect
- there may be holes
- there may be degenerate components
- these complicate both point-in-polygon testing and rasterization algorithms
- in practice, self-intersecting polys don’t seem to have many important uses
- but still generally good to be able to handle them, because e.g. a poly may accidentally become self-intersecting due e.g. to numerical imprecision
- or user may simply draw a self-intersecting poly
- holes are sometimes useful: consider drawing a picture of a donut!
- how to even define “inside-ness” for a non-simple polygon?
- even-odd and nonzero rules still can be applied, and in this case can be considered definitional
Tesselation
- in general, tessellation is the process of dividing an arbitrary polygon into a disjoint union of smaller polys
- most common case in practice is to tessellate into triangles because
- triangles are the simplest non-degenerate polygon
- triangles are always convex
- tessellation into triangles is specifically called triangulation
- fact: any simple polygon with sides can always be tessellated into exactly triangles
- this is minimal, though it is also possible to use more triangles
- easy to see for convex simply polys
- pick any arbitrary vertex
- draw diagonals from to all other vertices
- done!
- number of diagonals will always be
- there will be one triangle per diagonal, plus “the last one”
- the resulting array of triangles can be efficiently stored as a triangle fan, which we will discuss in more detail next time
- in fact, even non-convex simple polys can be tessellated into triangles, but a more involved algorithm is required
- extensions also exist for non-simple polys, but we will not cover them
- what is the computational complexity of triangluating a simple polygon?
- note that a lower bound is , because at least triangles must be produced
- in 1991, Chazelle demonstrated an algorithm, but it’s complex and not typically implemented
- reasonably simple algorithms exist, and are used in practice
- a randomized alg that is probabilistically is also often used
- we will study a particularly simple algorithm called ear clipping that is
- hence, not optimal, but can still be reasonably fast in practice for polys with relatively few vertices
- We have already defined “convexity” in terms of a whole polygon. We can also say that an individual vertex is convex if the internal angle at that vertex is less than radians; otherwise it’s convcave or reflex.
- an ear is a sequence of three consecutive vertices , , where
- is convex and
- the triangle formed by the three vertices includes no other vertex
- terminology: the segment from to is a diagonal of the polygon, and the vertex is the ear tip
- fact: a poly with always has at least two ears
- basic idea:
- while
- find an ear and cut it off!
- naive implementation is
- : until remaining polygon is a triangle
- : check each sequence of three consecutive vertices
- : check if every other vertex is outside the candidate ear
- note that the resulting triangulation will have exactly triangles, because each time an ear is cut off one triangle is produced and one vertex is consumed
- a faster implementation is also relatively simple
- : label all original vertices as either convex or reflex
- : find all ear tips of the original poly by checking for each convex vertex whether any reflex vertex is inside the corresponding candidate ear
- : repeat until
- using e.g. linked list datastructures: cut off the first currently known ear , ,
- “repair” the datastructures for the adjacent vertices and
- if vertex was convex, then it is still convex
- if vertex was reflex, it may become convex
- : each adjacent vertex that ends up convex needs to be (re-)tested for “ear-tip-ness”, again by checking if any reflex vertex is inside the ear
- example
- writing a fast, small, portable, and general triangulation library is apparently a tall order
- almost like writing a good image compression/decompression library
- in practice, a number of algorithms exist, with licenses ranging from public domain to proprietary
- see e.g. here for an account many commonly available libraries and their advantages and disadvantages
Next Time
- reading on website
- triangle meshes
- barycentric coordinates
- rasterizing triangles