How to draw a triangle with OpenGL in Racket - opengl

I'm trying to get this triangle example from the Racket OpenGL documentation working inside a simple GUI window, but I'm just seeing a black box. What am I missing to get something to show up?
#lang racket
(require racket/gui/base
sgl
sgl/gl-vectors)
(define frame (new frame% [label "OpenGL"]))
(define (draw self dc)
(send self
with-gl-context
(lambda ()
(gl-begin 'triangles)
(gl-vertex 1 2 3)
(gl-vertex-v (gl-float-vector 1 2 3 4))
(gl-end))))
(define canvas (new canvas%
[parent frame]
[min-width 500]
[min-height 500]
[style '(gl)]
[paint-callback draw]))
(send frame show #t)

Following code draws red triangle into canvas. You can replace code inside draw-triangle with that example code, but it seems that it only shows some naming conventions and actually does nothing.
#lang racket/base
(require racket/gui
sgl)
(define (draw-triangle)
(gl-begin 'triangles)
(gl-color 1 0 0)
(gl-vertex 0 0 0)
(gl-vertex 0.75 0 0)
(gl-vertex 0.75 0.75 0)
(gl-end))
(define my-canvas%
(class* canvas% ()
(inherit with-gl-context swap-gl-buffers)
(define/override (on-paint)
(with-gl-context (lambda ()
(draw-triangle)
(swap-gl-buffers))))
(super-instantiate () (style '(gl)))))
(define frame (new frame%
[label "OpenGL"]
[min-width 500]
[min-height 500]))
(define canvas (new my-canvas%
[parent frame]))
(send frame show #t)

Related

Draftsight LISP, problems building a list of x coordinates with the (cons ) function

I am trying to loop through some rectangles and put the x and y coordinates separately in a list. However the list I am trying to fill looks terrible, the code:
(setq sspnls (ssget '((0 . "LWPOLYLINE"))))
(while (= 1 (getvar 'cmdactive))
(command pause)
)
(setq pnlslength (sslength sspnls))
(setq xlist (list))
(setq ylist (list))
(setq pnlname(ssname sspnls 0))
(setq sssort (ssadd))
(setq tllr 0)
(while (< tllr pnlslength)
(setq pnlname(ssname sspnls tllr))
(Command "hatch" "S" pnlname "")
(setq xs (cadr (assoc 10 (entget pnlname)))); y cordinate
(setq ys (caddr (assoc 10 (entget pnlname)))); x cordinate
(setq xlist (cons xlist xs))
(setq ylist (cons ylist ys))
(setq tllr (+ tllr 1))
);while end
The xlist or y list comes out like:
((((nil . 12057.63625954) . 12057.63625954) . 10345.63625954) . 10345.63625954)
I need it to look like:
(12057.63625954 12057.63625954 10345.63625954 10345.63625954)
What am I doing wrong? Please note I am using Draftsight, I also used the append function but the append function does not work at all?
Thanks a lot for your help!
The main issue is that you are using the cons function to create a dotted pair of the list and the X & Y coordinate values, instead of pushing the X & Y coordinate values onto the head of the existing list.
For example, your code is doing this:
_$ (cons '(1 2 3 4) 5)
((1 2 3 4) . 5)
Instead of this:
_$ (cons 5 '(1 2 3 4))
(5 1 2 3 4)
In general, your code could be reduced to the following:
(if (setq sel (ssget '((0 . "LWPOLYLINE"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
ent (ssname sel idx)
enx (entget ent)
xls (cons (cadr (assoc 10 enx)) xls)
yls (cons (caddr (assoc 10 enx)) yls)
)
(command "_.hatch" "_S" ent "")
)
)
Note also that you are only retrieving the coordinates of the first polyline vertex - I'm unsure whether or not this is intentional.
Was a bit hesitant to try at first but CMS IntelliCAD turned out to be a good alternative for me. The free trial worked immediately, which was good to try it out before paying for it. All the features it offers are user-friendly and easy to work with, which was another win for me. Good job.

glViewport incorrectly mapping normal coordinates to window coordinates?

I thought I could make opengl map the coordinates (-1, -1) and (1, 1) to the pixels (0,0) and (width,height) with these calls:
(gl-viewport 0 0 width height)
(gl-ortho -1 1 -1 1 -1 1)
However a rectangle drawn from (-1,-1) to (1,1) only reaches across two thirds of the window's left and bottom edges. I can fix that by using
(gl-viewport 0 0 (* 3/2 width) (* 3/2 height))
but this doesn't seem correct to me. What am I doing wrong?
This is the snippet for DrRacket
#lang racket/base
(require racket/class)
(require racket/gui/base)
(require sgl)
(require sgl/gl-vectors)
(define game-canvas%
(class canvas%
(inherit refresh with-gl-context swap-gl-buffers)
(super-new)
(define (next x)
(modulo (+ 1 x) 100))
(define x-factor 0)
(define/override (on-paint)
(with-gl-context
(lambda ()
(gl-clear-color 0.0 0.0 0.0 0.0)
(gl-clear 'color-buffer-bit 'depth-buffer-bit)
(gl-color 1 1 0) (gl-rect -1 -1 (+ -1 (* 2 x-factor 1/100)) 1)
(swap-gl-buffers)
(gl-flush))))
(define/public (STEP)
(set! x-factor (next x-factor))
(refresh)
(sleep/yield 1/60)
(queue-callback (lambda _ (send this STEP) #f)))
(define/override (on-event e)
(when (is-a? e mouse-event%)
(when (eq? (send e get-event-type) 'left-down)
(exit 0))))
(define/override (on-size width height)
(with-gl-context
(lambda ()
(let ((aspect (/ width height)))
;(gl-viewport 0 0 width height)
(gl-viewport 0 0 (* 3/2 width) (* 3/2 height))
(gl-matrix-mode 'projection)
(gl-load-identity)
(gl-ortho (* aspect -1) (* aspect 1) -1 1 -1 1)
(gl-enable 'depth-test))))
(refresh))))
(module+ main
(define-values (W H) (get-display-size #t))
(define f (new frame%
[style '(no-resize-border
no-caption
no-system-menu
hide-menu-bar)]
[label "glui"]
[width (/ W 2)]
[height (/ H 2)]))
(define c (new game-canvas%
[parent f]
[style '(gl)]))
(send f show #t)
(send f center 'both)
(send c STEP))
It seems that you have Display Zoom setting equals 150% on your Windows system. OpenGL isn't aware about it, you need to scale manually.
(define/override (on-size width height)
...
(let ([scale (get-display-backing-scale)]
[scaled-width (exact-truncate (* width scale))]
[scaled-height (exact-truncate (* height scale))])
...
(gl-viewport 0 0 scaled-width scaled-height)
It seems that you are not using (gl-ortho -1 1 -1 1 -1 1) directly but instead you additionally multiply left and right values by aspect in (gl-ortho (* aspect -1) (* aspect 1) -1 1 -1 1). It is wrong, as -1 and 1 will always point to left and right border (if other values are as specified) independently of your aspect ratio. So I would remove aspect altogether and use -1 and 1. Here is the code that works for my 16/9 display:
#lang racket/base
(require racket/class)
(require racket/gui/base)
(require sgl)
(require sgl/gl-vectors)
(define game-canvas%
(class canvas%
(inherit refresh with-gl-context swap-gl-buffers)
(super-new)
(define (next x)
(modulo (+ 1 x) 100))
(define x-factor 0)
(define/override (on-paint)
(with-gl-context
(lambda ()
(gl-clear-color 0.0 0.0 0.0 0.0)
(gl-clear 'color-buffer-bit 'depth-buffer-bit)
(gl-color 1 1 0) (gl-rect -1 -1 (+ -1 (* 2 x-factor 1/100)) 1)
(swap-gl-buffers)
(gl-flush))))
(define/public (STEP)
(set! x-factor (next x-factor))
(refresh)
(sleep/yield 1/60)
(queue-callback (lambda _ (send this STEP) #f)))
(define/override (on-event e)
(when (is-a? e mouse-event%)
(when (eq? (send e get-event-type) 'left-down)
(exit 0))))
(define/override (on-size width height)
(with-gl-context
(lambda ()
;; Changes here
(gl-viewport 0 0 width height)
(gl-matrix-mode 'projection)
(gl-load-identity)
(gl-ortho -1 1 -1 1 -1 1)
(gl-enable 'depth-test)))
;; End of changes
(refresh))))
(module+ main
(define-values (W H) (get-display-size #t))
(define f (new frame%
[style '(no-resize-border
no-caption
no-system-menu
hide-menu-bar)]
[label "glui"]
[width (/ W 2)]
[height (/ H 2)]))
(define c (new game-canvas%
[parent f]
[style '(gl)]))
(send f show #t)
(send f center 'both)
(send c STEP))

LISP compare an Element in a Board

I'm doing a project for college in Common Lisp
And I need to compare a 4x4 list
Example:
(
((white full circle) (black empty circle) (black full circle) (white empty circle))
(0 0 0 0)
(0 0 0 0)
(0 0 0 0)
)
I need to compare if a line have 4 lists that share an element, in this case "circle"
and I can't use any defvar like intersection, need to use it recursively, and I can't find a way to do it
Try this:
(defun find-common (x)
(labels ((compare (items lst)
(cond ((null items) nil)
((not (remove-if #'(lambda (k) (member (car items) k)) lst))
(cons (car items) (compare (cdr items) lst)))
(t (compare (cdr items) lst)))))
(cond ((null x) nil)
(t (cons (compare (caar x) (car x))
(find-common (cdr x)))))))
To see if a list of list shares a common element, we have to check if each element in the car of that list also occurs in each list of its cdr. That's what the compare function does. It checks if an element occurs in all the lists recursively.
The find-common function recursively searches for all common occurrences in the list of lists.
Let's assume table is your 4 x 4 list:
(setf table
'(((white full circle) (black empty circle) (black full circle) (white empty circle))
((3 2 8 5) (2 9 1 8) (23 8 2 1) (3 8 0 2))
((one five six) (six one five) (five one six) (one six five))
((green blue red) (green red blue) (silver red white) (green yellow blue))))
Calling the find-common function:
>(find-common table)
((CIRCLE) (2 8) (ONE FIVE SIX) NIL)

Getting modulus from seq->stream

The code below draws me the sine wave throughout the screen, and beyond.
However, I want that x never exceeds (width). At that point, the window should be cleared, and the wave should be drawn again, starting at 0. I tried
(set-state! :x (mod (seq->stream x) (width)))
but it didn't work. I checked some examples, tried some code which made use of checking whether (> x (width)), tried to put the logic into the draw function, but they don't work either.
I would like to draw a continuous waveform (like an electrocardiogram) on a limited display. I would appreciate any help.
(ns soso.core
(:require [quil.core :refer :all]
[quil.helpers.seqs :refer [seq->stream range-incl]]))
(defn setup []
(smooth)
(frame-rate 100)
(background 255)
(let [x (range-incl)]
(set-state! :x (seq->stream x))))
(defn draw []
(stroke 0)
(stroke-weight 2)
(let [x ((state :x))
y (round (* 100 (abs (sin x))))]
(ellipse x y 4 4)))
Edit
When I tried to put the logic into the draw function, I wrote (set-state! :x 0) in the setup function, and put the following code into the draw function:
(let [x (if (> ((state :x)) 10)
0
(inc ((state :x))))])
But it didn't work, and didn't throw any error in any of the nrepl buffers. To see what happened, I tried this code in the user repl:
(let [x 0]
(take 20
(if (> x 10)
0
(inc x))))
Even if I tried this code by wrapping the if statement inside (into '()), the code complained with: "IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom". It is the same with:
(loop [x 0]
(if (> x 10)
0
(recur (inc x))))
What is wrong with this if statement? The clojure api says that if tests the test condition, and then evaluates and yields then or else branches, accordingly. If it yields, it should spit out that integer, which in turn gets added to the list, which in turn should be listed by take function, I think.
Something more like this seems to give the effect you are looking for.
(defn draw []
(stroke 0)
(stroke-weight 2)
(let [x ((state :x))
y (+ 100 (* 100 (sin (/ x 100))))]
(ellipse (mod x (width)) y 4 4)))
Couple of issues you are encountering:
The input to sin is a floating value in radians. My hackery of divide by 100 here just makes sure that we're getting a nice continuous output. Practically if you want to cycle every n pixels you need to use 2 PI / n to adjust x.
Rounding off the value is going to give you points, as the domain of sin is 1 to -1. Here I'm adjusting by adding on 100.
Where you fiddle with x will depend on the exact requirement. Here I'm simply wrapping your x value by taking it's modulus in the draw function.
Hope this helps.

counter in if statement

I prepared a few lines in Scheme and I am new to Scheme. Please post your comments about my code below:
(define new3
(lambda(y)
(define points 444)
(define add3 (lambda (x)(+ x 3)))
(display "--")
(display points)
(if (and (= 1 1)(= 2 2))(add3 points))
(display "--")
(display points)
(list points points)
))
(new3 7)
OUTPUT
--444--444(444 444)
I wonder why the "points" after the "if" are not equal to "447"?
Thank you.
That's because you didn't update points in-place. You computed 477 with (add3 points), but without storing that result anywhere.