fix region bounding-box and hit-test; catch up docs

This commit is contained in:
Matthew Flatt 2010-08-01 20:16:33 -06:00
parent d10669d34e
commit e0a2a66dc8
2 changed files with 144 additions and 97 deletions

View File

@ -19,7 +19,7 @@
(define region% (define region%
(class object% (class object%
(init [the-dc #f]) (init [(the-dc dc) #f])
(define dc the-dc) (define dc the-dc)
(when dc (when dc
(unless (dc . is-a? . dc<%>) (unless (dc . is-a? . dc<%>)
@ -62,7 +62,36 @@
[r r] [r r]
[b b]) [b b])
(if (null? paths) (if (null? paths)
(values l t r b) (if matrix
;; Convert absolute coordinates back to the DC's
;; logical space by inverting its transformation
(let ([m (send dc get-clipping-matrix)])
;; Matrix is [ma mc
;; mb md]
(let ([ma (vector-ref m 0)]
[mb (vector-ref m 2)]
[mc (vector-ref m 1)]
[md (vector-ref m 3)]
[dx (vector-ref m 4)]
[dy (vector-ref m 5)])
(let ([det (- (* ma md) (* mb mc))])
(if (zero? det)
;; determinant is 0 => dc's matrix maps any area to 0
(values 0.0 0.0 0.0 0.0)
;; tx and ty apply inverse matrix
(let ([tx (lambda (x y)
(let ([x (- x dx)]
[y (- y dy)])
(/ (- (* md x) (* mb y)) det)))]
[ty (lambda (x y)
(let ([x (- x dx)]
[y (- y dy)])
(/ (- (* ma y) (* mc x)) det)))])
;; unwind bound-box points to pre-transformed
(values (tx l t) (ty l t)
(tx r b) (ty r b)))))))
;; no dc un-transformation needed
(values l t r b))
(let-values ([(l2 t2 r2 b2) (send (caar paths) get-bounding-box)]) (let-values ([(l2 t2 r2 b2) (send (caar paths) get-bounding-box)])
(loop (cdr paths) (loop (cdr paths)
(min l l2) (min l l2)
@ -126,7 +155,19 @@
(set! temp-cr (set! temp-cr
(cairo_create (cairo_create
(cairo_image_surface_create CAIRO_FORMAT_A8 1 1)))) (cairo_image_surface_create CAIRO_FORMAT_A8 1 1))))
(install-region temp-cr #t (lambda (cr v) (and v (cairo_in_fill temp-cr x y))))))) (let-values ([(x y)
(if matrix
;; need to use the DC's current transformation
(let ([m (send dc get-clipping-matrix)])
(values (+ (* x (vector-ref m 0))
(* y (vector-ref m 2))
(vector-ref m 4))
(+ (* x (vector-ref m 1))
(* y (vector-ref m 3))
(vector-ref m 5))))
;; no transformation needed
(values x y))])
(install-region temp-cr #t (lambda (cr v) (and v (cairo_in_fill temp-cr x y))))))))
(def/public (set-arc [real? x] (def/public (set-arc [real? x]
[real? y] [real? y]

View File

@ -7,40 +7,51 @@ A @scheme[region%] object specifies a portion of a drawing area
(possibly discontinuous). It is normally used for clipping drawing (possibly discontinuous). It is normally used for clipping drawing
operations. operations.
Each @scheme[region%] object is associated to a particular A @scheme[region%] object can be associated to a particular
@scheme[dc<%>] object, specified when the region is created. A region @scheme[dc<%>] object when the region is created. In that case, the
can only be used with its associated @scheme[dc<%>] object. The origin region uses the drawing context's current transformation matrix,
and scale of a drawing context determine the bounding box and drawing translation, scaling, and rotation, independent of the transformation
location of a region at the time that a region is created (or set); a that is in place when the region is installed. Otherwise, the region
region is independent of the current scale and origin when the region is transformed as usual when it is installed into a
is used. For an auto-scrolled canvas, the canvas's current scrolling @scheme[dc<%>]. For an auto-scrolled canvas, the canvas's current
applies when the region is used (and it does not affect the region's scrolling always applies when the region is used (and it does not
bounding box). affect the region's bounding box).
Region combination with operations like @racket[region% union] are
approximate, and they are implemented by combining paths. Certain
combinations work only if the paths have a suitable fill mode, which
can be either @racket['winding], @racket['even-odd], or a
@deftech{flexible fill} mode. When a region is installed as a device
context's clipping region, any subpath with a @deftech{flexible fill}
mode uses @racket['even-odd] mode if any other path uses
@racket['even-odd] mode.
See also @xmethod[dc<%> set-clipping-region] and @xmethod[dc<%> See also @xmethod[dc<%> set-clipping-region] and @xmethod[dc<%>
get-clipping-region]. get-clipping-region].
@defconstructor[([dc (is-a?/c dc<%>)])]{ @defconstructor[([dc (or/c (is-a?/c dc<%>) #f)])]{
Creates an empty region. Creates an empty region. If @racket[dc] is a @scheme[dc<%>] object,
the @scheme[dc<%>]'s current transformation matrix is essentially
recorded in the region.
} }
@defmethod[(get-bounding-box) @defmethod[(get-bounding-box)
(values real? real? real? real?)]{ (values real? real? real? real?)]{
Returns a rectangle that encloses the region. The return values are Returns a rectangle that approximately encloses the region. The
the left, top, width, and height of the rectangle. The bounding box return values are the left, top, width, and height of the
is precisely correct for unsmoothed drawing, but it is only rectangle. If the region has an associated drawing context, the
approximate for smoothed drawing. bounding box is in the drawing context's current logical coordinates.
} }
@defmethod[(get-dc) @defmethod[(get-dc)
(is-a?/c dc<%>)]{ (or/c (is-a?/c dc<%>) #f)]{
Returns the region's drawing context. Returns the region's drawing context, if it was created for one.
} }
@ -49,12 +60,9 @@ Returns the region's drawing context.
boolean?]{ boolean?]{
Returns @scheme[#t] if the given point is approximately within the Returns @scheme[#t] if the given point is approximately within the
region, @scheme[#f] otherwise. The given point is scaled and region, @scheme[#f] otherwise. If the region has an associated
translated according to the region's @scheme[dc<%>]'s current scale drawing context, the given point is effectively transformed according
and translation. to the region's @scheme[dc<%>]'s current transformation matrix.
The approximate in-region test represents the true result for
unsmoothed drawing, but it not necessarily for smoothed drawing.
} }
@ -63,18 +71,18 @@ The approximate in-region test represents the true result for
Sets the region to the intersection of itself with the given region. Sets the region to the intersection of itself with the given region.
The DC of @scheme[rgn] and @this-obj[] must be the same. The drawing context of @scheme[rgn] and @this-obj[] must be the same,
or they must both be unassociated to any drawing context.
The result is always reliable for unsmoothed and smoothed drawing. For An intersect corresponds to clipping with this region's path, and then
smoothed drawing, an intersect corresponds to clipping with this clipping with the given region's path. Further combining sends to
region's path, and then clipping with the given region's path. this region correspond to combination with the original path before
Further combining sends to this region correspond to combination with initial clip, and further combination with this region as an argument
the original path before initial clip, and further combination with correspond to a combination with the given path after the initial
this region as an argument correspond to a combination with the given clip. Thus, an intersecting region is a poor input for
path after the initial clip. Thus, an intersecting region is a poor @method[region% union], @method[region% subtract], or @method[region%
input for @method[region% union], @method[region% subtract], or xor], but it intersects properly in further calls to @method[region%
@method[region% xor], but it intersects properly in further calls to intersect].
@method[region% intersect].
} }
@ -82,8 +90,7 @@ The result is always reliable for unsmoothed and smoothed drawing. For
boolean?]{ boolean?]{
Returns @scheme[#t] if the region is approximately empty, @scheme[#f] Returns @scheme[#t] if the region is approximately empty, @scheme[#f]
otherwise. An approximately empty region is truly empty for otherwise.
unsmoothed drawing, but it may contain points for smoothed drawing.
} }
@ -100,10 +107,9 @@ Sets the region to the interior of the specified wedge.
See also @xmethod[dc<%> draw-ellipse], since the region content is See also @xmethod[dc<%> draw-ellipse], since the region content is
determined the same way as brush-based filling in a @scheme[dc<%>]. determined the same way as brush-based filling in a @scheme[dc<%>].
The result is reliable for both unsmoothed and smoothed drawing. For The region corresponds to a clockwise path with a @tech{flexible
smoothed drawing, the region corresponds to a clockwise path with a fill}. The region is also @tech{atomic} for the purposes of region
@scheme['winding] fill. The region is also @defterm{atomic} for the combination.
purposes of region combination.
} }
@ -118,10 +124,9 @@ Sets the region to the interior of the specified ellipse.
See also @xmethod[dc<%> draw-ellipse], since the region content is See also @xmethod[dc<%> draw-ellipse], since the region content is
determined the same way as brush-based filling in a @scheme[dc<%>]. determined the same way as brush-based filling in a @scheme[dc<%>].
The result is reliable for both unsmoothed and smoothed drawing. For The region corresponds to a clockwise path with a @tech{flexible
smoothed drawing, the region corresponds to a clockwise path with a fill}. The region is also @tech{atomic} for the purposes of region
@scheme['winding] fill. The region is also @defterm{atomic} for the combination.
purposes of region combination.
@|DrawSizeNote| @|DrawSizeNote|
@ -138,11 +143,10 @@ Sets the region to the content of the given path.
See also @xmethod[dc<%> draw-path], since the region content is See also @xmethod[dc<%> draw-path], since the region content is
determined the same way as brush-based filling in a @scheme[dc<%>]. determined the same way as brush-based filling in a @scheme[dc<%>].
The result is reliable for both unsmoothed and smoothed drawing. For The fill style affects how well the region reliably combines with
smoothed drawing, the fill style affects how well the region reliably other regions (via @method[region% union], @method[region% xor], and
combines with other regions (via @method[region% union], @method[region% subtract]). The region is also @tech{atomic} for the
@method[region% xor], and @method[region% subtract]). The region is purposes of region combination.
also @defterm{atomic} for the purposes of region combination.
} }
@ -156,11 +160,10 @@ Sets the region to the interior of the specified polygon.
See also @xmethod[dc<%> draw-polygon], since the region content is See also @xmethod[dc<%> draw-polygon], since the region content is
determined the same way as brush-based filling in a @scheme[dc<%>]. determined the same way as brush-based filling in a @scheme[dc<%>].
The result is reliable for both unsmoothed and smoothed drawing. For The fill style affects how well the region reliably combines with
smoothed drawing, the fill style affects how well the region reliably other regions (via @method[region% union], @method[region% xor], and
combines with other regions (via @method[region% union], @method[region% subtract]). The region is also @tech{atomic} for the
@method[region% xor], and @method[region% subtract]). The region is purposes of region combination.
also @defterm{atomic} for the purposes of region combination.
} }
@ -172,13 +175,9 @@ The result is reliable for both unsmoothed and smoothed drawing. For
Sets the region to the interior of the specified rectangle. Sets the region to the interior of the specified rectangle.
See also @xmethod[dc<%> draw-rectangle], since the region content is The region corresponds to a clockwise path with a @tech{flexible
determined the same way as brush-based filling in a @scheme[dc<%>]. fill}. The region is also @tech{atomic} for the purposes of region
combination.
The result is reliable for both unsmoothed and smoothed drawing. For
smoothed drawing, the region corresponds to a clockwise path with a
@scheme['winding] fill. The region is also @defterm{atomic} for the
purposes of region combination.
@|DrawSizeNote| @|DrawSizeNote|
@ -197,10 +196,9 @@ See also @xmethod[dc<%> draw-rounded-rectangle], since the region
content is determined the same way as brush-based filling in a content is determined the same way as brush-based filling in a
@scheme[dc<%>]. @scheme[dc<%>].
The result is reliable for both unsmoothed and smoothed drawing. For The region corresponds to a clockwise path with a @tech{flexible
smoothed drawing, the region corresponds to a clockwise path with a fill}. The region is also @tech{atomic} for the purposes of region
@scheme['winding] fill. The region is also @defterm{atomic} for the combination.
purposes of region combination.
@|DrawSizeNote| @|DrawSizeNote|
@ -214,15 +212,16 @@ Sets the region to the subtraction of itself minus the given region.
in the given region. (The given region may contain points that are in the given region. (The given region may contain points that are
not in the current region; such points are ignored.) not in the current region; such points are ignored.)
This region's DC and given region's DC must be the same. This region's drawing context and given region's drawing context must
be the same, or they must both be unassociated to any drawing
context.
The result is always reliable for unsmoothed drawing. For smoothed The result is consistent across platforms and devices, but it is never
drawing, the result is consistent across platforms and devices, but a true subtraction. A subtraction corresponds to combining the
it is never a true subtraction. A subtraction corresponds to sub-paths of this region with the reversed sub-paths of the given
combining the sub-paths of this region with the reversed sub-paths of region, then intersecting the result with this region. This fails as
the given region, then intersecting the result with this region. This a true subtraction, because the boundary of loops (with either
fails as a true subtraction, because the boundary of loops (with @scheme['odd-even] or @scheme['winding] filling) is ambiguous.
either @scheme['odd-even] or @scheme['winding] filling) is ambiguous.
} }
@ -231,18 +230,22 @@ The result is always reliable for unsmoothed drawing. For smoothed
Sets the region to the union of itself with the given region. Sets the region to the union of itself with the given region.
This region's DC and given region's DC must be the same. This region's drawing context and given region's drawing context must
be the same, or they must both be unassociated to any drawing
context.
The result is always reliable for unsmoothed drawing. For smoothed A union corresponds to combining the sub-paths of each region into one
drawing, a union corresponds to combining the sub-paths of each path, using an @scheme['odd-even] fill if either of the region uses
region into one path, using an @scheme['odd-even] fill if either of an @scheme['odd-even] fill (otherwise using a @scheme['winding]
the region uses an @scheme['odd-even] fill (otherwise using a fill), a @scheme['winding] fill in either region uses a
@scheme['winding] fill). Consequently, while the result is consistent @scheme[winding] fill, or the fill remains a @tech{flexible fill}
across platforms and devices, it is a true union only for certain if both paths have a @tech{flexible fill}. Consequently, while the
input regions. For example, it is a true union for non-overlapping result is consistent across platforms and devices, it is a true union
atomic and union regions. It is also a true union for atomic and only for certain input regions. For example, it is a true union for
union regions (potentially overlapping) that are all clockwise and non-overlapping @deftech{atomic} and union regions. It is also a true
use @scheme['winding] fill. union for @tech{atomic} and union regions (potentially overlapping)
that are all clockwise and use @scheme['winding] fill or if the fills
are all @tech{flexible fills}.
} }
@ -252,17 +255,20 @@ The result is always reliable for unsmoothed drawing. For smoothed
Sets the region to the xoring of itself with the given region (i.e., Sets the region to the xoring of itself with the given region (i.e.,
contains points that are enclosed by exactly one of the two regions). contains points that are enclosed by exactly one of the two regions).
This region's DC and given region's DC must be the same. This region's drawing context and given region's drawing context must
be the same, or they must both be unassociated to any drawing
context.
The result is always reliable for unsmoothed drawing. For smoothed The result is consistent across platforms and devices, but it is not
drawing, the result is consistent across platforms and devices, but necessarily a true xoring. An xoring corresponds to combining the
it is not necessarily a true xoring. An xoring corresponds to sub-paths of this region with the reversed sub-paths of the given
combining the sub-paths of this region with the reversed sub-paths of region. The result uses an @scheme['odd-even] fill if either of the
the given region. The result uses an @scheme['odd-even] fill if either region uses an @scheme['odd-even] fill, a @scheme['winding] fill in
of the region uses an @scheme['odd-even] fill (otherwise using a either region uses a @scheme[winding] fill, or the fill remains a
@scheme['winding] fill). Consequently, the result is a reliable xoring @tech{flexible fill} if both paths have a @tech{flexible
only for certain input regions. For example, it is reliable for fill}. Consequently, the result is a reliable xoring only for certain
atomic and xoring regions that all use @scheme['even-odd] fill. input regions. For example, it is reliable for @tech{atomic} and
xoring regions that all use @scheme['even-odd] fill.
}} }}