DEV Community

Luca Sepe
Luca Sepe

Posted on

Craft beautiful geometric art using code.

Craft beautiful geometric art using code.

Use the code basics like loops, control flow and specialized functions to generate your geometry artworks.

Examples of g2D Geometry Art

   

   


Installation

Go get

$ go get -u github.com/lucasepe/g2d
Enter fullscreen mode Exit fullscreen mode

Ready-To-Use Releases

Here you can find g2d already compiled for:

  • MacOS
  • Linux
  • Windows

How to use

To execute a local g2d script:

$ g2d /path/to/my-script.g2d
Enter fullscreen mode Exit fullscreen mode

To execute a g2d script stored somewhere on the web:

$ g2d http://my-cool-site.com/remote/path/to/my-script.g2d
Enter fullscreen mode Exit fullscreen mode

Use the --directory (or the shorter -d) flag to specify a destination folder for the generated PNG images.


The g2D Programming Language Syntax

Example-programs can be found beneath examples/ which demonstrate these things, as well as parts of the standard-library.

Types

g2D has the following data types: bool, int, float, str, array, and fn.

Type Syntax Notes
bool true false
int 0 42 1234 -5 is a signed 64-bit integer
float 0.5 4.2 1.234 -5.5 is a 64-bit double-precision floating point
str "" "foo" "\"quotes\" and a\nline break" are immutable arrays of bytes
array [] [1, 2] [1, 2, 3] grow-able arrays (use the append() builtin)
fn fn(a, b) { ... } defines a custom function

Bindings

Variables are bounded using the := operator.

a := 3
b := 1.2
Enter fullscreen mode Exit fullscreen mode

Variables may be integers, floats, strings, or arrays/hashes.

To update a variable you can simply specify the equals = operator:

a := 3    // Binding
a = a + 5 // Updating
Enter fullscreen mode Exit fullscreen mode

Arithmetic operations

g2D supports all the basic arithmetic operation of int and float types.

a := 5
b := 3

c := a + b
d := c / 2
e := d * d
Enter fullscreen mode Exit fullscreen mode

Builtin containers

g2d has one builtin containers: array.

Arrays

An array is a list which organizes items by linear sequence. Arrays can hold multiple types.

a := [1, 2.3, "hello!"]
b := [false, true, "Hello World", 3, 3.13]
Enter fullscreen mode Exit fullscreen mode

Adding to an array is done via the push builtin function:

a = append(a, "another")
Enter fullscreen mode Exit fullscreen mode

You can iterate over the contents of an array like so:

i := 0
while( i < len(a) ) {
    print( "Array index ", i, " contains ", a[i], "\n")
    i = i + 1
}
Enter fullscreen mode Exit fullscreen mode

With the definition we included that produces this output:

Array index 0 contains 1
Array index 1 contains 2.3
Array index 2 contains hello!
Array index 3 contains another
Enter fullscreen mode Exit fullscreen mode

Functions

g2D uses fn to define a function which will be assigned to a variable for naming/invocation purposes:

sum := fn(a, b) { return a + b }

print(sum(5,3), "\n")       // Outputs: 8
print(sum(2.5,7.5), "\n")   // Outputs: 10
Enter fullscreen mode Exit fullscreen mode

Functions can be passed as values to others functions:

addTwo := fn(a, b, f) { 
    return 2 + f(a, b) 
}

tot := addTwo(68, 1, sum)
print(tot, "\n")            // Outputs: 71
Enter fullscreen mode Exit fullscreen mode

Functions inside functions

multiplier := fn(q) {
    return fn(x) {
        return x*q
    }
}

multThree := multiplier(3)

print(multThree(2), "\n")  // Outputs: 6
print(multThree(3), "\n")  // Outputs: 9
print(multThree(4), "\n")  // Outputs: 12
Enter fullscreen mode Exit fullscreen mode

If-else statements

g2D supports if-else statements.

max := fn(a, b) {
    if (a > b) {
        return a;
    } else {
        return b;
    }
}

print( max(1, 2) )  // Outputs: 2
Enter fullscreen mode Exit fullscreen mode

Switch Statements

g2D supports the switch and case expressions:

switch n := randi(10) {
    case n % 2 == 0 {
        print(n, " is even", "\n")
    }
    default {
        print(n, " is odd", "\n")
    }
}
Enter fullscreen mode Exit fullscreen mode

While Loops

g2D supports only one looping construct, the while loop:

i := 30
while (i > 0) {
    print(i, " ")
    i = i - 10
}
// 30 20 10
Enter fullscreen mode Exit fullscreen mode

Builtin functions

Core

Function Description
exit([status]) exits the program immediately with the optional status or 0
input([prompt] reads a line from standard input optionally printing the specified prompt
print(...) output a string to stdout
printf(pattern, ...) output a string to stdout (formatted according the specified pattern)
sprintf(pattern, ...) like printf(...) but returns a string
bool(val) converts value to a bool
float(val) converts decimal value str to float - if val is invalid returns null
int(val) converts decimal value str to int - if val is invalid returns null
str(val) returns the string representation of val
len(iterable) returns the length of the iterable (string or array)
append(array, val) returns a new array with value pushed onto the end of array

Calculation

Function Description
abs(x) returns the absolute value of x
atan(x) returns the arc tangent, in radians, of x
atan2(x, y) returns the arc tangent of y/x
cos(x) returns the cosine of the radian argument x
degrees(angle) converts radians into degrees
hypot(p, q) returns sqrt(p*p + q*q)
lerp(start, stop, amt) calculates a number between two numbers at a specific increment
map(v, b1, e1, b2, e2) re-maps a number from one range to another
max(v1....vn) returns the largest value in a sequence of numbers
min(v1....vn) returns the smallest value in a sequence of numbers
pow(x, y) returns x**y, the base x exponential of y
sin(x) returns the sine of the radian argument x
sqrt(x) returns the square root of x
radians(angle) converts a degree measurement to its corresponding value in radians
randf([min], [max]) returns a random float between min and max - by default min=0.0 and max=1.0
randi([min], [max]) returns a random int between min and max

Basic graphic functions

Function Description
size(w,[h]) sets the size of the drawing; when both w and h are specified creates a rectangular image otherwise creates a squared one
viewport(xMin, xMax, yMin, yMax, xOffset, yOffset) sets up user-defined coordinate system; performs a screen reset (drawings are cleared)
clear() fills the entire image with the current color; clear all drawings
fillColor(hexcolor) sets the fill color to the specified hexcolor; example fillColor("#ff0000")
fillColor(r, g, b, [a]) sets the fill color to r,g,b,a values - should be between 0 and 255, inclusive
strokeColor(hexcolor) sets the stroke color to the specified hexcolor; example strokeColor("#ff0000")
strokeColor(r, g, b, [a]) sets the stroke color to r,g,b,a values - should be between 0 and 255, inclusive
strokeWeight(weight) sets the stroke thickness to the specified width
dashes([s1, s2, ...sn]) sets the current dash pattern to use (call with zero arguments to disable dashes)
stroke() strokes the current path with the current stroek color and line width the path is cleared after this operation
fill() fills the current path with the current fill color; open subpaths are implicity closed.
The path is cleared after this operation
fillAndStroke() fills the current path with the current fill color and strokes it with the current stroke color; the path is cleared after this operation
push() saves the current state of the graphic context by pushing it onto a stack
pop() restores the last saved graphic context state from the stack
snapshot([filename]) creates a PNG image with the current drawings.
If filename is omitted, it will be autogenerated with a progressive counter, that will be incremented on each
snapshot() invocation; this is useful if you wants to generate an animation later (using all the generated PNG images).
xpos() returns the current X position (if there is a current point)
ypos() returns the current Y position (if there is a current point)

Graphic primitives

Function Description
arc(x, y, r, sa, ea) draws a circular arc centered at (x, y) with a radius of r.
The path starts at sa angle_, ends at ea angle, and travels in the direction given by anticlockwise
circle(x, y, r) draws a circle centered at [x, y] coordinates and with the radius r
ellipse(x, y, rx ,ry) draws an ellipse centered at [x, y] coordinates and with the radii rx and ry
line(x1, y1, x2, y2) draws a line from point (x1, y1) to point (x2, y2)
point(x, y) draws a point at specified coordinates (the size is equal to the stroke weight)
quad(x1, y1, x2,y2, x3,y3, x4,y4) draws a a four sided polygon using the provided vertices
rect(x, y, w, h, [tl, tr, br, bl]) draws a (w x h) rectangle with upper left corner located at (x, y).
If only one radius is specified, all the corners have the same bending, if tl, tr, br, bl are specified, each corner can have a different curvature
triangle(x1,y1, x2,y2, x3,y3) draws a triangle using the provided vertices
star(cx, cy, n, or, ir) draws a star cx, cy is the center, n the number of spikes, or and ir the outer and inner radius

Paths

Function Description
beginPath() starts a new path
closePath() adds a line segment from the current point to the beginning of the current subpath
moveTo(x, y) sets the begin of a new subpath starting at the specified x, y point
lineTo(x, y) adds a line segment to the current path starting at the current point
arcTo(x1, y1, x2, y2, r) adds a circular arc to the current sub-path, using the given control points and radius
quadraticCurveTo(x1, y1, x2, y2) adds a quadratic Bézier curve to the current sub-path; x1, y1 is the control point and x2, y2 is the end point

Transform

Function Description
rotate(angle, [x, y] ) updates the current matrix with a anticlockwise rotation; when x, y are specified, rotation occurs about this point, otherwise rotation occurs about the origin (angle is in radians)
scale(sx, sy, [x, y]) updates the current matrix with sx, sy scaling factor; when x,y are specified, scaling occurs about this point, otherwise scaling occurs about origin.
translate(x, y) updates the current matrix with a translation to x and y
identity() resets the current transformation matrix to the identity matrix
transform(x, y) multiplies the point x, y by the current matrix, returning a transformed position

Text

Function Description
text(str, x, y, [ax, ay]) draws the specified text str at the specified anchor point x, y; the anchor point is x - w * ax, y - h * ay, where w, h is the size of the text (by default ax=0.5, ay=0.5 to center the text at the specified point)
textWidth(str) returns the rendered width of the specified text str given the current font face
fontSize(size) sets the font height

Images

Function Description
imageGet(path/to/png) loads a PNG image from the local filesystem
imageAt(im, x, y, [ax, ay]) draws the specified image im at the specified anchor point x, y; (ax and ay are the x and y offsets) use ax=0.5, ay=0.5 to center the image at the specified point

Top comments (1)

Collapse
 
stanley12qs profile image
stanley12qs

Well, honestly, for the last four months I’ve been drawing around 30 hours per week. I’ve gone through various books and videos, learned a ton, and even completed a couple 11 x 17 comic book pages of original art. However, I began suffering from the problem any learner faces in the age of the internet, which is the sheer overabundance of learning material available. Oftentimes I’d spend hours sifting through lists of the best drawing books and creating playlists of YouTube videos. I became more focused on curating the best resources than actually going through those resources. I would start one book, then wonder if I should be working on a different book, and I’d start jumping back and forth. Jumping around so often, I started to lose the big picture, and I didn’t give each resource the full attention it deserves. I was always focused on getting through one book so I could get get to the next. I realized that I needed 1) more structure and 2) a different attitude.