
@laurent.orseau has joined the channel

@laurent.orseau set the channel purpose: Anything related to the metapict package

@soegaard2 has joined the channel

@soegaard2 How do I set the set-curve-pict-size and the window so as to remove all the blanks surrounding the effective part of the picture?

Also, any other comment on the code is welcome :slightly_smiling_face:

(this is an actual use case)

I don’t know a way to do automatic cropping. We need something like crop
from 2htdp/image
- and I am almost certain there must be a pict equivalent, but where…

I see

That’s why I’d prefer something where you don’t even specify the bounding boxes, you just place picts where you want (assuming the center 0, 0 is always including), and the bounding box should be adjusted automatically. I believe it should be fairly easy to do with `pict’, since it’s already its default behaviour

Personally, I would do everything in pixel coordinates, in particular since picts can be scaled.

That would simplify the whole design

How would something like (draw (draw c1) (draw c2)) work?

cc-superimpose, adjusted to the largest bounding box

Let’s say c1 is a line from (0,0) to (1,1) and c2 is a line from (2,2) to (3,3).

(0, 0) must always be included in the picture, so maybe instead align on 0, 0

so not exactly cc-superimpose, but superimposing of the origins

Never thought about that.

It requires a computation of the tight bounding box for each bezier curve though?

don’t you get the bounding box for free with the pict constructors?

oh, you’re drawing them as a dc-path maybe


> Thus, the bounding box does not always tightly bound the path.

Here is the conversion of curves to picts: (define (curves->pict cs)
(def w (curve-pict-width))
(def h (curve-pict-height))
(def T (stdtrans (curve-pict-window) w h))
(dc (λ (dc dx dy)
(def old-brush (send dc get-brush))
(def old-smoothing (send dc get-smoothing))
(send dc set-smoothing 'smoothed)
(send dc set-brush (find-white-transparent-brush))
; todo: use draw-bezs (takes care of t and pt)
(for ([c cs])
(defm (curve closed? bs) c)
(def Tp (bezs->dc-path (map T bs)))
(send dc draw-path Tp dx dy))
(send dc set-brush old-brush)
(send dc set-smoothing old-smoothing)
)
w h))

So computing the transformation T would need an “1 x-unit to device measurement” and “1 y-unit to device measurement” instead of the width and height.

To output the pict, it is neccessary to compute the width and height from the drawn curves.

Or you do like `pict’, and draw potentially outside the box. Let the user extend the box when it needs it.

(e.g., draw an empty node at (–10, –10))

but of course it’s nicer if you can do this automatically

Maybe there is something in Cairo that can detect the bounding box of the “inked” area?

Simply create a cairo context, draw it and then get an bounding box.

Wishful thinking, but we might be lucky.

Or we could do it my making a custom drawing context, that doesn’t draw anything, but instead computes a bounding box.

Such a solution wouldn’t affect existing code.

The code for the tree looks fine btw - only suggestion: make a function p
to compute the position (pt (- (* dx 2)) (- (* 1 dy)))
so you can write (p -2 -1)
.


I think cairo_recording_surface_ink_extents
is the solution.

that would be cool!

fwiw, `inset’ with negative arguments allows to reduce the bounding box

I can use that as a dirty workaround for now

Nice trick about inset - odd that pict
doesn’t have a crop
.

I wrote a small example of using cairo_recording_surface_ink_extents
and it seems to work. I haven’t figured out how to render a pict to a cairo_recording_surface_t
.

#lang racket/base
(require ffi/unsafe
ffi/unsafe/define
racket/draw/unsafe/cairo
racket/draw/unsafe/cairo-lib)
; The functions in draw/unsafe/cairo uses _ptr/immobile
; to prevent objects moving during garbage collection.
; We need an io version. For now we use (_ptr io _double),
; but that doesn't make the objects immovable (I think).
(define-fun-syntax _ptr/immobile
(syntax-id-rules (_ptr/immobile o)
[(_ptr/immobile o t) (type: _pointer
pre: (malloc t 'atomic-interior)
post: (x => (ptr-ref x t)))]))
(define-ffi-definer define-cairo cairo-lib
#:provide provide-protected)
(define-syntax-rule (_cfun . rest)
(_fun #:lock-name "cairo-pango-lock" . rest))
;; void
;; cairo_recording_surface_ink_extents (cairo_surface_t *surface,
;; double *x0,
;; double *y0,
;; double *width,
;; double *height);
(define-cairo cairo_recording_surface_ink_extents
(_cfun _cairo_surface_t
(x0 : (_ptr io _double))
(y0 : (_ptr io _double))
(width : (_ptr io _double))
(height : (_ptr io _double))
-> _void
-> (values x0 y0 width height)))
(define s (cairo_recording_surface_create CAIRO_CONTENT_COLOR_ALPHA #f))
(define cr (cairo_create s)) ; drawing context
(cairo_scale cr 1. 1.)
(cairo_set_line_cap cr CAIRO_LINE_CAP_ROUND)
(cairo_set_line_width cr 2.)
(cairo_move_to cr 0. 0.)
(cairo_rel_line_to cr 0. 20.)
(cairo_stroke cr)
; cairo_recording_surface_ink_extents(rec, &x0, &y0, &width, &height);
(cairo_recording_surface_ink_extents s 0. 0. 10. 10.)
(cairo_surface_destroy s)
(cairo_destroy cr)

The output: -1.0
-1.0
2.0
22.0

With a round cap and a line width 2 the endpoints have two circles around them with radius 1. Therefore we get +1 from each end and the line drawn had length 20. This gives 22 in total.