First, all the pict-related stuff is awesome. I've been using it a lot lately, and I probably haven't said thank you. So thank you, Racketeers.
I need to build pictures out of hexagons for a project I'm working on. (If an admin adds svg
to the allowed filetypes, I'll include SVGs.)
You'll notice there's some difficulty aligning the hexagons properly… in this case, with weird overlaps and edges not quite lining up the way I would hope.
I've spent some time doing some math, and I know exactly how I would like the bounding boxes for the hexagons to work (SVG available here, too):
Essentially, the bounding box should be the yellow rectangle, I think. Based on the rotate
docs, it comes out instead as a centered rectangle with height and width the sum of the colored lines (the "axes" in the bottom right that intersect the colored lines and rotated box are equivalent in height and width).
I think I can fix the box with inset
, but testing so far has shown that there are some slight irregularities on the right and top sides of the bounding box, and my naïve difference-between-old-and-new hasn't worked. Before I waste time changing it to use the precise code like in the diagram, I want to ask:
Regardless of whether it's through bounding boxes or something else, what's an easy way can I get my hexagons to line up as if they were on a hexagonal grid? (Perhaps there's a trick to put the bounding box inside the hexagon, and then center the bounding boxes on a normal XY grid? Some sketches don't show a way this works though, since I want the diagonal edges to touch.)
And, yes, for the time being it's important that the hexagon corners are north-south.
Prototypical code, including that for both diagrams:
#lang racket
(require (only-in 2htdp/image regular-polygon)
pict
file/convertible)
(define old (regular-polygon 20 6 'outline 'black))
(define old-width (pict-width old))
(define old-height (pict-height old))
(define new (rotate (regular-polygon 20 6 'outline 'black) (/ pi 6)))
(define new-height (pict-height new))
(define new-width (pict-width new))
(define h-amt (- (/ (- new-width old-height) 2)))
(define v-amt (- (/ (- new-height old-width) 2)))
(define (hex mode color [size 20])
(inset (rotate (regular-polygon size 6 mode color)
(/ pi 6))
h-amt (sub1 v-amt) (sub1 h-amt) v-amt))
(define x
(cc-superimpose
(hex "solid" "red")
(hex "outline" "black")
(colorize (text "X") "white")))
(define o
(cc-superimpose
(hex "solid" "blue")
(hex "outline" "black")
(hex "outline" "cyan" 15)))
(define m
(cc-superimpose
(hex "solid" "grey")
(hex "outline" "black")))
(define s
(cc-superimpose
(hex "outline" "black")))
#;
(cc-superimpose (filled-rectangle 400 400 #:color "white")
(vc-append
(translate (hc-append x x (ghost s)) (* 2 h-amt) (* -2 v-amt))
(hc-append x x o)
(translate (hc-append x x (ghost s)) (* 2 h-amt) (* 2 v-amt)))
(disk 2 #:color "black"))
(cc-superimpose (filled-rectangle 400 400 #:color "white")
(vc-append
(translate (hc-append x x (ghost s) (ghost s) (ghost s)) 0 (* -2 v-amt))
(translate (hc-append x x x m o) (* 2 (add1 h-amt)) 0)
(translate (hc-append x x (ghost s) (ghost s) (ghost s)) 0 (* 2 v-amt)))
(disk 2 #:color "black"))
#;(explain o)
#;(explain old)
#;(explain (inset new h-amt (sub1 v-amt) (sub1 h-amt) v-amt))
#;(explain (scale-to-fit new old-height old-width #:mode 'distort))
;; old width = 2s
;; old height = sqrt(3) * s
;; new height = 5/2 * s
;; new width = 3/2 * sqrt(3) * s
;; where s is side length of hexagon
;; diagram with s = 6
(require rackunit)
(define (diagram s*)
(define s (* 15 s*))
(define w (* 2 s))
(define h (* (sqrt 3) s))
(define h* (* 5/2 s))
(define w* (* 3/2 (sqrt 3) s))
(define w*-a (/ (* 4 s) (sqrt 3)))
(define w*-b (/ s 2 (sqrt 3)))
(define htl (* -3/2 s))
(define h*-a w)
(define h*-b (/ s 2))
(define wtr (* 1/2 s (sqrt 3)))
(check-equal? (+ w*-a w*-b) w*)
(check-equal? (+ h*-a h*-b) h*)
(cc-superimpose
;; bg
(filled-rectangle (* s 3) (* s 3) #:color "white")
;; desired bounding box for rotated hex
(filled-rectangle h w #:color "yellow")
(rt-superimpose
(lb-superimpose
;; hex + bounding box, rotated
(rotate (cc-superimpose (filled-rectangle w h #:color "white")
(regular-polygon s 6 'outline 'black))
(/ pi 6))
;; parts of width of new bounding box
(translate (colorize (hline w*-a 1) "blue") 0 htl)
(translate (colorize (hline w*-b 1) "green") w*-a htl)
(hline w* 1))
;; parts of height of new bounding box
(translate (colorize (vline 1 h*-a) "red") (- wtr) 0)
(translate (colorize (vline 1 h*-b) "purple") (- wtr) h*-a)
(vline 1 h*))
;; dead-center of picture
(disk s*)))
(diagram 6)
#;
(with-output-to-file (expand-user-path "~/Desktop/hexagon.svg")
(thunk
(write-bytes (convert (diagram 6) 'svg-bytes))))