laurent.orseau
2019-9-18 13:26:33

@laurent.orseau has joined the channel


laurent.orseau
2019-9-18 13:26:34

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


soegaard2
2019-9-18 13:26:34

@soegaard2 has joined the channel


laurent.orseau
2019-9-18 13:27:36

@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?


laurent.orseau
2019-9-18 13:27:49

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


laurent.orseau
2019-9-18 13:27:59

(this is an actual use case)


soegaard2
2019-9-18 13:37:35

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…


laurent.orseau
2019-9-18 13:37:47

I see


laurent.orseau
2019-9-18 13:39:32

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


laurent.orseau
2019-9-18 13:40:24

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


laurent.orseau
2019-9-18 13:40:46

That would simplify the whole design


soegaard2
2019-9-18 13:42:59

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


laurent.orseau
2019-9-18 13:43:55

cc-superimpose, adjusted to the largest bounding box


soegaard2
2019-9-18 13:44:49

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


laurent.orseau
2019-9-18 13:45:13

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


laurent.orseau
2019-9-18 13:45:32

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


soegaard2
2019-9-18 13:46:59

Never thought about that.


soegaard2
2019-9-18 13:47:44

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


laurent.orseau
2019-9-18 13:48:19

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


laurent.orseau
2019-9-18 13:48:48

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



soegaard2
2019-9-18 13:50:46

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


soegaard2
2019-9-18 13:55:42

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))


soegaard2
2019-9-18 13:57:33

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.


soegaard2
2019-9-18 13:58:23

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


laurent.orseau
2019-9-18 13:59:08

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


laurent.orseau
2019-9-18 13:59:38

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


laurent.orseau
2019-9-18 14:00:23

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


soegaard2
2019-9-18 14:02:01

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


soegaard2
2019-9-18 14:02:36

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


soegaard2
2019-9-18 14:03:03

Wishful thinking, but we might be lucky.


soegaard2
2019-9-18 14:05:18

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


soegaard2
2019-9-18 14:05:41

Such a solution wouldn’t affect existing code.


soegaard2
2019-9-18 14:09:14

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).



soegaard2
2019-9-18 14:15:26

I think cairo_recording_surface_ink_extents is the solution.


laurent.orseau
2019-9-18 15:07:34

that would be cool!


laurent.orseau
2019-9-18 15:13:35

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


laurent.orseau
2019-9-18 15:13:45

I can use that as a dirty workaround for now


soegaard2
2019-9-18 21:34:25

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


soegaard2
2019-9-18 21:35:50

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.


soegaard2
2019-9-18 21:36:02
#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)

soegaard2
2019-9-18 21:36:24

The output: -1.0 -1.0 2.0 22.0


soegaard2
2019-9-18 21:42:03

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.