diff --git a/README.md b/README.md index 2976406..1061450 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,17 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i ## Library +- `(pos ~x ~y)` Returns a position shape. +- `(size w h)` Returns a size shape. +- `(rect x y w h)` Returns a rect shape. +- `(circle cx cy r)` Returns a circle shape. +- `(ellipse cx cy rx ry)` Returns a ellipse shape. +- `(line ax ay bx by)` Returns a line shape. +- `(poly ...pos)` Returns a poly shape. +- `(text x y p t ~a ~f)` Returns a text shape. +- `(svg x y d)` Returns a svg shape. +- `(arc cx cy r sa ea)` Returns an arc shape. +- `(color r g b ~a)` Returns a color object. - `(import path shape ~alpha)` Imports a graphic file with format. - `(export path ~format ~quality)` Exports a graphic file with format. - `(open path ~ratio)` Imports a graphic file and resizes the frame. @@ -58,16 +69,6 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(resetTransform)` - `(pushTransform)` - `(popTransform)` -- `(pos ~x ~y)` Returns a position shape. -- `(size w h)` Returns a size shape. -- `(rect x y w h)` Returns a rect shape. -- `(circle cx cy r)` Returns a circle shape. -- `(ellipse cx cy rx ry)` Returns a ellipse shape. -- `(line ax ay bx by)` Returns a line shape. -- `(poly ...pos)` Returns a poly shape. -- `(text x y p t ~a ~f)` Returns a text shape. -- `(svg x y d)` Returns a svg shape. -- `(color r g b ~a)` Returns a color object. - `(stroke shape color ~thickness)` Strokes a shape. - `(fill ~rect)` Fills a shape. - `(gradient line ~colors 'black'])` Defines a gradient color. @@ -89,6 +90,8 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(mul ...args)` Multiplies values. - `(div ...args)` Divides values. - `(mod a b)` Returns the modulo of a and b. +- `(rad degrees)` Convert radians to degrees. +- `(deg radians)` Convert degrees to radians. - `(clamp val min max)` Clamps a value between min and max. - `(step val step)` - `(min)` Returns lowest value. diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js index 792f5dd..791ae1e 100644 --- a/desktop/sources/scripts/commander.js +++ b/desktop/sources/scripts/commander.js @@ -182,6 +182,7 @@ function Commander (ronin) { if (word === 'pos') { return `(pos ${shape.x} ${shape.y})` } if (word === 'line') { return `(line ${shape.a.x} ${shape.a.y} ${shape.b.x} ${shape.b.y})` } if (word === 'circle') { return `(circle ${shape.cx} ${shape.cy} ${shape.r})` } + if (word === 'arc') { return `(arc ${shape.cx} ${shape.cy} ${shape.r} ${shape.sa} ${shape.ea})` } if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh') { return `${shape}` } return '' } @@ -263,7 +264,7 @@ function Commander (ronin) { // Splash this.splash = `; welcome to ronin -; v2.25 +; v2.26 (clear) (def logo-path "M60,60 L195,60 A45,45 0 0,1 240,105 A45,45 0 0,1 195,150 L60,150 M195,150 A45,45 0 0,1 240,195 L240,240 ") (stroke diff --git a/desktop/sources/scripts/library.js b/desktop/sources/scripts/library.js index 393f244..a98ef5c 100644 --- a/desktop/sources/scripts/library.js +++ b/desktop/sources/scripts/library.js @@ -3,6 +3,55 @@ function Library (ronin) { // Composition: Design programs to be connected to other programs. // Parsimony: Write a big program only when it is clear by demonstration that nothing else will do. + // Shapes + + this.pos = (x = 0, y = 0) => { // Returns a position shape. + return { x, y } + } + + this.size = (w, h) => { // Returns a size shape. + return { w, h } + } + + this.rect = (x, y, w, h) => { // Returns a rect shape. + return { x, y, w, h, pos: { x, y }, size: { w, h } } + } + + this.circle = (cx, cy, r) => { // Returns a circle shape. + return { cx, cy, r } + } + + this.ellipse = (cx, cy, rx, ry) => { // Returns a ellipse shape. + return { cx, cy, rx, ry } + } + + this.line = (ax, ay, bx, by) => { // Returns a line shape. + return { a: this.pos(ax, ay), b: this.pos(bx, by) } + } + + this.poly = (...pos) => { // Returns a poly shape. + return pos + } + + this.text = (x, y, p, t, a = 'left', f = 'Arial') => { // Returns a text shape. + return { x, y, p, t, a, f } + } + + this.svg = (x, y, d) => { // Returns a svg shape. + return { x, y, d } + } + + this.arc = (cx, cy, r, sa, ea) => { // Returns an arc shape. + return { cx, cy, r, sa, ea } + } + + this.color = (r, g, b, a = 1) => { // Returns a color object. + const hex = '#' + ('0' + parseInt(r, 10).toString(16)).slice(-2) + ('0' + parseInt(g, 10).toString(16)).slice(-2) + ('0' + parseInt(b, 10).toString(16)).slice(-2) + return { r, g, b, a, hex, toString: () => { return `rgba(${r},${g},${b},${a})` }, 0: r, 1: g, 2: b, 3: a, f: [r / 255, g / 255, b / 255, a] } + } + + // + this.import = async (path, shape, alpha = 1) => { // Imports a graphic file with format. const img = new Image() img.src = path @@ -125,49 +174,6 @@ function Library (ronin) { ronin.surface.context.restore() } - // Shapes - - this.pos = (x = 0, y = 0) => { // Returns a position shape. - return { x, y } - } - - this.size = (w, h) => { // Returns a size shape. - return { w, h } - } - - this.rect = (x, y, w, h) => { // Returns a rect shape. - return { x, y, w, h, pos: { x, y }, size: { w, h } } - } - - this.circle = (cx, cy, r) => { // Returns a circle shape. - return { cx, cy, r } - } - - this.ellipse = (cx, cy, rx, ry) => { // Returns a ellipse shape. - return { cx, cy, rx, ry } - } - - this.line = (ax, ay, bx, by) => { // Returns a line shape. - return { a: this.pos(ax, ay), b: this.pos(bx, by) } - } - - this.poly = (...pos) => { // Returns a poly shape. - return pos - } - - this.text = (x, y, p, t, a = 'left', f = 'Arial') => { // Returns a text shape. - return { x, y, p, t, a, f } - } - - this.svg = (x, y, d) => { // Returns a svg shape. - return { x, y, d } - } - - this.color = (r, g, b, a = 1) => { // Returns a color object. - const hex = '#' + ('0' + parseInt(r, 10).toString(16)).slice(-2) + ('0' + parseInt(g, 10).toString(16)).slice(-2) + ('0' + parseInt(b, 10).toString(16)).slice(-2) - return { r, g, b, a, hex, toString: () => { return `rgba(${r},${g},${b},${a})` }, 0: r, 1: g, 2: b, 3: a, f: [r / 255, g / 255, b / 255, a] } - } - // Actions this.stroke = (shape, color, thickness = 2) => { // Strokes a shape. @@ -288,6 +294,14 @@ function Library (ronin) { return a % b } + this.rad = (degrees) => { // Convert radians to degrees. + return degrees * (Math.PI / 180) + } + + this.deg = (radians) => { // Convert degrees to radians. + return radians * (180 / Math.PI) + } + this.clamp = (val, min, max) => { // Clamps a value between min and max. return this.min(max, this.max(min, val)) } diff --git a/desktop/sources/scripts/ronin.js b/desktop/sources/scripts/ronin.js index 82eb691..44c8cc3 100644 --- a/desktop/sources/scripts/ronin.js +++ b/desktop/sources/scripts/ronin.js @@ -161,10 +161,16 @@ function Ronin () { const circle = { cx: this.mouseOrigin.x, cy: this.mouseOrigin.y, - r: d.toFixed(2), - edge: { x: rect.x - rect.w, y: rect.y - rect.h, w: rect.w * 2, h: rect.h * 2 } + r: d.toFixed(2) } - return { x, y, xy, wh, d, line, rect, pos, circle, type, 'is-down': type !== 'mouse-up' ? true : null } + const arc = { + cx: this.mouseOrigin.x, + cy: this.mouseOrigin.y, + r: d.toFixed(2), + sa: 0, + ea: Math.atan2(position.y - this.mouseOrigin.y, position.x - this.mouseOrigin.x).toFixed(2) + } + return { x, y, xy, wh, d, line, rect, pos, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null } } // Zoom diff --git a/desktop/sources/scripts/surface.js b/desktop/sources/scripts/surface.js index ef449c0..68213c4 100644 --- a/desktop/sources/scripts/surface.js +++ b/desktop/sources/scripts/surface.js @@ -84,7 +84,9 @@ function Surface (ronin) { } else if (isPoly(shape)) { this.tracePoly(shape, context) } - if (isCircle(shape)) { + if (isArc(shape)) { + this.traceArc(shape, context) + } else if (isCircle(shape)) { this.traceCircle(shape, context) } else if (isEllipse(shape)) { this.traceEllipse(shape, context) @@ -129,6 +131,10 @@ function Surface (ronin) { context.arc(circle.cx, circle.cy, circle.r, 0, 2 * Math.PI) } + this.traceArc = function (arc, context) { + context.arc(arc.cx, arc.cy, arc.r, arc.sa, arc.ea) + } + this.traceEllipse = function (ellipse, context) { context.ellipse(ellipse.cx, ellipse.cy, ellipse.rx, ellipse.ry, 0, 2 * Math.PI, false) } @@ -304,6 +310,9 @@ function Surface (ronin) { function isCircle (shape) { return shape && !isNaN(shape.cx) && !isNaN(shape.cy) && !isNaN(shape.r) } + function isArc (shape) { + return shape && !isNaN(shape.cx) && !isNaN(shape.cy) && !isNaN(shape.r) && !isNaN(shape.sa) && !isNaN(shape.ea) + } function isEllipse (shape) { return shape && !isNaN(shape.cx) && !isNaN(shape.cy) && !isNaN(shape.rx) && !isNaN(shape.ry) } diff --git a/examples/basics/shapes.lisp b/examples/basics/shapes.lisp index 71b6d57..c80fa98 100644 --- a/examples/basics/shapes.lisp +++ b/examples/basics/shapes.lisp @@ -1,4 +1,3 @@ - (clear) ; stroke rect (stroke @@ -11,6 +10,10 @@ (line 0 150 300 150) "red") (stroke (text 600 300 60 "hell") "white") +(stroke + (arc 600 298 296 + (rad 180) + (rad -90)) "white") (stroke (poly (pos 300 300) @@ -27,6 +30,10 @@ (line 0 150 300 150) "red") (fill (text 600 300 60 "hell") "white") +(fill + (arc 600 298 296 + (rad 180) + (rad -90)) "white") (fill (poly (pos 300 300) diff --git a/examples/demo/spiral.lisp b/examples/demo/spiral.lisp index e4de4c7..a187107 100644 --- a/examples/demo/spiral.lisp +++ b/examples/demo/spiral.lisp @@ -1,5 +1,6 @@ ; animated recusive spiral ; by @local_guru +(def frame-rect (frame)) (defn rec (v) (if (gt v 0) diff --git a/examples/demo/stars.lisp b/examples/demo/stars.lisp index 139fc38..c9e65db 100644 --- a/examples/demo/stars.lisp +++ b/examples/demo/stars.lisp @@ -1,6 +1,8 @@ ; stars (clear) ; times + +(def frame-rect (frame)) (defn times (v f) ( @@ -28,8 +30,11 @@ (cx cy r a) ( (stroke - (line cx cy (:x (circle-pos cx cy r a)) (:y (circle-pos cx cy r a)) - ) "white" 2))) + (line cx cy + (:x + (circle-pos cx cy r a)) + (:y + (circle-pos cx cy r a))) "white" 2))) ; (defn draw-star (cx cy r c)