diff --git a/pkgs/draw-pkgs/draw-doc/scribblings/draw/dc-intf.scrbl b/pkgs/draw-pkgs/draw-doc/scribblings/draw/dc-intf.scrbl index 35d42c513e..bb9003816c 100644 --- a/pkgs/draw-pkgs/draw-doc/scribblings/draw/dc-intf.scrbl +++ b/pkgs/draw-pkgs/draw-doc/scribblings/draw/dc-intf.scrbl @@ -621,6 +621,36 @@ See also @method[dc<%> set-origin] and @method[dc<%> get-transformation]. Gets the current pen. See also @method[dc<%> set-pen]. } + + +@defmethod[(get-path-bounding-box [path (is-a?/c dc-path%)] + [type (or/c 'path 'stroke 'fill)]) + (values real? real? real? real?)]{ +Returns a rectangle that encloses the path’s points. +The return values are the left, top, width, and, height of the rectangle. +The numbers are in logical coordinates. + +For the type @racket['stroke] the rectangle covers the area that would be affected ("inked") +when drawn with the current pen by draw-path in the drawing context (with a transparent brush). +If the pen width is zero, then an empty rectangle will be returned. The size and clipping of the +drawing context is ignored. + +For the type @racket['fill] the rectangle covers the area that would be affected ("inked") +by draw-path in the drawing context (with a non-transparent pen and brush). If the line width +is zero, then an empty rectangle will be returned. The size and clipping of the drawing +context are ignored. + +For the type @racket['path] the rectangle covers the path, but the pen and brush are ignored. +The size and clipping of the drawing context are also ignored. +More precisely: The result is defined as the limit of the bounding boxes returned +by the 'stroke type for line widths approaching 0 with a round pen cap. The "limit +process" stops when an empty rectangle is returned. This that zero-area segments contributes +the rectangle. + +For all types if the path is empty, then an empty rectangle @racket[(values 0 0 0 0)] +will be returned. +} + @defmethod[(get-rotation) real?]{ diff --git a/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc-path.rkt b/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc-path.rkt index 902fc1c9db..99564ee013 100644 --- a/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc-path.rkt +++ b/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc-path.rkt @@ -33,7 +33,7 @@ (define dc-path% (class object% ;; A path is a list of pairs and vectors: - ;; * The pairs corerspond to points on the path + ;; * The pairs correspond to points on the path ;; * A vector must be between two pairs; it specifies ;; control points for a curve between the two points. @@ -173,6 +173,26 @@ (max b (vector-ref p 1) (vector-ref p 3)))]))]) (values l t (- r l) (- b t)))))) + (define/public (do-get-path-bounding-box cr type align-x align-y) + (flatten-closed!) + (flatten-open!) + (if (and (null? closed-points) + (null? open-points) + (not cr)) + (values 0. 0. 0. 0.) + (let () + (define cairo_op + (cond + [(eq? type 'path) cairo_path_extents] + [(eq? type 'fill) cairo_fill_extents] + [(eq? type 'stroke) cairo_stroke_extents] + [else (error 'get-tight-binding-boc "expected 'path, 'fill, or, 'stroke")])) + (cairo_save cr) + (do-path cr align-x align-y) + (define-values (x1 y1 x2 y2) (cairo_op cr)) + (cairo_restore cr) + (values x1 y1 y2 y2)))) + (define/public (move-to x y) (when (or (pair? open-points) (pair? rev-open-points)) diff --git a/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc.rkt b/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc.rkt index 0be6628e6a..624c1780b3 100644 --- a/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc.rkt +++ b/pkgs/draw-pkgs/draw-lib/racket/draw/private/dc.rkt @@ -1134,6 +1134,15 @@ (rounded-rect x y (sub1w width) (sub1h height) (lambda (x) (align-x x)) (lambda (y) (align-y y))) (draw cr #f #t))))) + + (define (bounding-box-type? o) (member o '(path fill stroke))) + + (def/public (get-path-bounding-box [dc-path% path] [bounding-box-type? type]) + (with-cr + (values 0. 0. 0. 0.) + cr + (send path do-get-path-bounding-box cr type + (lambda (x) (align-x x)) (lambda (y) (align-y y))))) (def/public (draw-spline [real? x1] [real? y1] [real? x2] [real? y2] [real? x3] [real? y3]) (with-cr diff --git a/pkgs/draw-pkgs/draw-lib/racket/draw/unsafe/cairo.rkt b/pkgs/draw-pkgs/draw-lib/racket/draw/unsafe/cairo.rkt index e20c5bc2a1..7052c7ee48 100644 --- a/pkgs/draw-pkgs/draw-lib/racket/draw/unsafe/cairo.rkt +++ b/pkgs/draw-pkgs/draw-lib/racket/draw/unsafe/cairo.rkt @@ -125,6 +125,22 @@ (set! warned? #t)) (values 0 0 0 0))))) +(define-cairo cairo_fill_extents (_cfun _cairo_t + (x1 : (_ptr o _double)) + (y1 : (_ptr o _double)) + (x2 : (_ptr o _double)) + (y2 : (_ptr o _double)) + -> _void + -> (values x1 y1 x2 y2))) + +(define-cairo cairo_stroke_extents (_cfun _cairo_t + (x1 : (_ptr o _double)) + (y1 : (_ptr o _double)) + (x2 : (_ptr o _double)) + (y2 : (_ptr o _double)) + -> _void + -> (values x1 y1 x2 y2))) + ;; Transforms (define-cairo cairo_translate (_cfun _cairo_t _double* _double* -> _void)) (define-cairo cairo_scale (_cfun _cairo_t _double* _double* -> _void)) @@ -440,6 +456,22 @@ (define-cairo cairo_copy_path (_cfun _cairo_t -> _cairo_path_t-pointer) #:wrap (allocator cairo_path_destroy)) +(define-cairo cairo_path_extents (_cfun _cairo_t + (x1 : (_ptr o _double)) + (y1 : (_ptr o _double)) + (x2 : (_ptr o _double)) + (y2 : (_ptr o _double)) + -> _void + -> (values x1 y1 x2 y2)) + ;; cairo_path_extents is in version 1.6 and later + #:fail (lambda () + (let ([warned? #f]) + (lambda (cr) + (unless warned? + (log-warning "cairo_path_extents is unavailable; returning the empty rectangle") + (set! warned? #t)) + (values 0 0 0 0))))) + (define-enum 0 CAIRO_PATH_MOVE_TO CAIRO_PATH_LINE_TO