Why does my Racket pen draw extra pixels where two lines join despite using 'butt and 'miter? - racket

I'm making two squares as seen in the following image.One red and one blue square
The yellow circle is not part of the image, but it shows some pixels that I'm expecting to not be there. I have no experience with computer graphics, but from what I've read in the documentation, these pixels should not be there. Do I have unrealistic expectations or am I doing something wrong to get these 'overflow' pixels as shown by the yellow circle in my above drawing?
Here is the code that generates the boxes.
#lang racket/gui
(define dc (new svg-dc%
[width 64]
[height 64]
[output "boxes.svg"]
[exists 'replace]))
(send dc start-doc "boxes.svg")
(send dc start-page)
(define old-brush (send dc get-brush))
(define old-pen (send dc get-pen))
(send dc set-brush
(new brush% [style 'solid]
[color "White"]))
(send dc set-pen
(new pen% [width 0]
[color "Black"]
[cap 'butt]
[join 'miter]))
(send dc set-pen old-pen)
(send dc set-brush old-brush)
(send dc set-pen
(new pen% [width 0]
[color "Black"]
[cap 'butt]
[join 'miter]))
(send dc set-brush
(new brush% [style 'solid]
[color "Red"]))
(define path (new dc-path%))
(send path move-to 0 0)
(send path line-to 10 0)
(send path line-to 10 10)
(send path line-to 0 10)
(send path close)
(send dc draw-path path 0 0)
(send dc set-pen old-pen)
(send dc set-brush old-brush)
(send dc set-pen
(new pen% [width 0]
[color "Black"]
[cap 'butt]
[join 'miter]))
(send dc set-brush
(new brush% [style 'solid]
[color "Blue"]))
(define path2 (new dc-path%))
(send path2 move-to 0 0)
(send path2 line-to 10 0)
(send path2 line-to 10 10)
(send path2 line-to 0 10)
(send path2 close)
(send dc draw-path path2 10 0)
(send dc set-pen old-pen)
(send dc set-brush old-brush)
(send dc end-page)
(send dc end-doc)

This is just a comment, but I needed some more space.
Things to look out for:
anti aliasing - turn it of
smoothing - is the mode unsmoothed or aligned?
Let's say the first pixel has opposite corners (0,0) and (1,1).
Without aligment, you can choose a square pen of size and
make a dot at (0.5,0.5) in order not to draw outside the pixel.
If things are aligned, you need to adjust accordingly.
See set-smoothing.
https://docs.racket-lang.org/draw/dc___.html#%28meth._%28%28%28lib._racket%2Fdraw..rkt%29._dc~3c~25~3e%29._set-smoothing%29%29
UPDATE
As far as I can tell, adding the line:
(send dc set-smoothing 'aligned)
at the beginning will fix the problem.

Related

How to make a color changing sky in Racket?

I have a variable that controls the number of blue in (color R, G, B). Now I am confused about how to use that variable in (color R, G, B). Also, I am totally new to Racket. I know I can combine these functions together, but I don't know how :( The purpose of this code is to make a color changing scene in animate.
Here is my code:
(require 2htdp/image)
(define(Skycolor num)
(remainder num 510))
(define(skycolor num)
(abs(- 255(Skycolor num))))
(define(sky-color num)
(color 0 0 (skycolor num)))
(define (SKY num )
(square 200 "solid" (color 0 0 (sky-color num)))))
It's not very clear what do you mean with "color changing", but you can take some inspiration from following code. See also this similar question, where I explain how animate works.
#lang racket
(require 2htdp/universe)
(require 2htdp/image)
(define speed 5)
(define (sky-color ticks)
(color 0 (modulo (* speed (- 255 ticks)) 255) 255))
(define bg
(empty-scene 125 125))
(define (make-sky ticks)
(square 250 "solid" (sky-color ticks)))
(define (draw-image ticks)
(place-image (make-sky ticks) 0 0 bg))
(animate draw-image)

Racket: How do I keep an image from going off screen to appear on the other side?

I'm currently making a game where your character must dodge objects going on and off the scene.
My problem is that, when the objects go off the scene, they do not reappear on the other side.
Each object is represented by a posn structure, and they move a certain distance on the scene each time there's a tick from left to right and vise versa. I've attached which part of the code I think needs to be edited.
For clarity, a world is a struct containing a chicken and car, both of which are structs containing x and y posns.
And MOVE-CAR is a constant set to (add1 (random 49)) that determines how fast or slow the car will move during gameplay.
;update-world: world -> world
;purpose: updates the position of the car
(define (update-world a-world)
(make-world (world-chicken a-world) (move-horiz (world-car a-world) (* -1 MOVE-CAR))))
;move-horiz: posn number -> posn
;purpose: moves the posn left or right
(define (move-horiz a-posn delta-x)
(make-posn (+ delta-x (posn-x a-posn)) (posn-y a-posn)))
If more code is necessary, I will try and sift through the rest of what I have.
Any help is much appreciated.
To calculate the new x position, you are currently using:
(+ delta-x (posn-x a-posn))
If the result is between 0 and the width, this gives the correct result.
If the result is greater than the width, then the new x should be 0.
If the result is less than 0, then the new x should be the width.
Let's write a function adjust-x that adjusts the x-position you have calculated:
(define WIDTH 100)
(define (adjust-x x)
(cond
[(and (<= 0 x) (<= x WIDTH)) x]
[(> x WIDTH) 0]
[(< x 0) WIDTH]
Then you can change move-horiz to:
(define (move-horiz a-posn delta-x)
(make-posn (adjust-x (+ delta-x (posn-x a-posn)))
(posn-y a-posn)))

Racket: Why can't set canvas's background in windows

This my code:
#lang racket
(require racket/gui)
(define-values (screen-width screen-height) (get-display-size))
(define *app-width* 400)
(define *app-height* 125)
(define *vm-frame* (new frame%
[label "Test"]
[width *app-width*]
[height *app-height*]
[x (- (quotient screen-width 2) (quotient *app-width* 2))]
[y (- (quotient screen-height 2) (quotient *app-height* 2))]
))
(define frame-canvas%
(class canvas%
(super-new)
(inherit get-dc)
(define/override (on-paint)
(let ([my-dc (get-dc)])
(send my-dc clear)
(send my-dc set-background "black")))))
(let ([frame-canvas (new frame-canvas% [parent *vm-frame*])])
(send *vm-frame* show #t))
On mac os, this is normal, show a app with a black background.
But on windows, background is white.
Why? Racket version is 5.3, it's a 5.3 bug?
Reverse the order of set-background and clear.
The call to clear uses the color of the current background to do the fill. If somehow your on-paint were called at least more than once, then you would observe a black background, since the second time around, the current background color would be black. I suspect this is what explains the platform-specific difference you observed.

How to set button%'s background in Racket?

I add a button% to a dialog% like below:
(new button%
[label "ok"]
[parent pop-dialog%]
[callback
(lambda (b e)
(exit))])
Sorry, my complete code is below:
#lang racket
(require racket/gui)
(define *my-frame* (new frame%
[label "VersionMonitor"]
[width 300]
[height 200]
))
(define pop-dialog
(new dialog%
[label "bogga wogga"]
[parent *my-frame*]
[width 200]
[height 100]
))
(new canvas%
[parent pop-dialog]
[paint-callback
(lambda (canvas info-dc)
(send info-dc clear)
(send info-dc set-background "white"))])
(new button%
[label "ok"]
[parent pop-dialog]
[callback
(lambda (b e)
(exit))])
(send *my-frame* show #t)
(send pop-dialog show #t)
And now you can see the gray area. My real problem is how to set button%'s area's background
?
But the button% has a rectangle around it, beyond itself. The background is gray, I want
set its color to white, but didn't find a way to do it.
I don't see the problem you're reporting. In particular, I'm running this program:
#lang racket
(require mred)
(define pop-dialog
(new dialog% [label "bogga wogga"]))
(new button%
[label "ok"]
[parent pop-dialog]
[callback
(lambda (b e)
(exit))])
(send pop-dialog show #t)
... and I don't see a rectangle around the button. I don't think I can attach a screenshot in ...
oh, wait, maybe I can:
If this doesn't match what you're seeing, see if you can create a small program that illustrates the problem.
Also, the racket mailing list is probably going to give you prompt-er responses, for issues like this.

Moving beyond world/universe

I thought I'd try a simple GUI app using the world/universe mutation-free approach,  but trying to implement the 'world/universe' program design myself.
I've got my little sketch below, but I quickly came to conclusion that while I could use the teachpack, I don't know how to achieve the teachpack functionality myself.
I'm guessing I should use continuations, but that doesn't seem to be the approach in the universe.rkt source.
I could always just stuff the program into the canvas class, (as earlier games like slidey and same seem to do), but I really want to get a handle on  how to implement the 'world/universe' style of program control.
;;;;----
#lang racket/gui
; simple drawing program
; mousedown starts recording a list of points
; mousechanged starts recording a new list
; paint callback paints the list of lists as lines.
(define diagramframe (new frame% [label "paint"] [width 300]
[height 300] [x 1000][y 300]))
;(define lines '(((0 . 0) (0 . 300) (250 . 250) (150 . 176))))
(define lines '(((0 . 0) (0 . 300) (250 . 250) (150 . 176))
                ((10 . 4) (280 . 10))))
(define paintcanvas%
  (class canvas%
    (init-field mouse-event-callback)
    (super-new)
    (define dc (send this get-dc))
    (define/override (on-event mouse-event)
      (mouse-event-callback mouse-event))))
(define (paint-cb c dc) 
  (for-each (λ (line) (send dc draw-lines line)) lines))
(define (me-cb mouse-event)
(let ((x (send mouse-event get-x))
        (y (send mouse-event get-y)))
    (when (and (send mouse-event get-left-down)
               (send mouse-event moving?))
      (if (send mouse-event button-changed?)
          ; if true append as new list
          '() 
          ; if false append existing list
          '()))))
(define Paintcanvas (new paintcanvas%
                         [parent diagramframe]
[paint-callback paint-cb]
[mouse-event-callback me-cb]))
(define (main world)
 (when world (main (??? world)))
  (send diagramframe show #t))
 
(main lines)
(send diagramframe show #t)
;;-----
Here is how I would do it.
Note that the GUI event loop acts as the program main.
Use timer events to implement on-tick.
#lang racket/gui
;;;
;;; WORLD
;;;
(define-struct world (lines))
(define the-world (make-world '((0 . 0) (0 . 300) (250 . 250) (150 . 176) (10 . 4) (280 . 10))))
;;;
;;; USER LAND
;;;
(define (on-mouse-event world event)
(if (and (send event get-left-down)
(send event moving?)
#; (send event button-changed?))
(let ((x (send event get-x))
(y (send event get-y)))
(make-world (cons (cons x y) (world-lines world))))
world))
(define (on-paint world dc)
(send dc draw-lines
(map pair->point (world-lines world))))
(define (pair->point p)
(make-object point% (car p) (cdr p)))
;;;
;;; SYSTEM
;;;
(define user:on-paint on-paint)
(define diagramframe (new frame% [label "paint"] [width 300] [height 300] [x 1000][y 300]))
(define paintcanvas%
(class canvas%
(inherit get-dc refresh)
(super-new)
(define/override (on-paint)
(send (get-dc) suspend-flush)
(user:on-paint the-world (get-dc))
(send (get-dc) resume-flush))
(define/override (on-event mouse-event)
(let* ([old-world the-world]
[new-world (on-mouse-event the-world mouse-event)])
(if (eq? old-world new-world)
(super on-event mouse-event)
(begin
(set! the-world new-world)
(refresh)))))))
(define paintcanvas (new paintcanvas% [parent diagramframe]))
(send diagramframe show #t)