Skip to content

Sid-Bhatia-0/SimpleDraw.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SimpleDraw

This is a lightweight self-contained package that attempts to provide efficient drawing methods for some simple shapes. So far, in this package, all the shapes and drawing algorithms are integer-based, and all the drawing algorithms are single-threaded.

Table of contents:

List of shapes:

  1. Background
  2. Point
  3. Line
  4. ThickLine
  5. Triangle
  6. FilledTriangle
  7. Rectangle
  8. FilledRectangle
  9. ThickRectangle
  10. Circle
  11. FilledCircle
  12. ThickCircle
  13. Bitmap
  14. Image
  15. Character
  16. TextLine

Getting Started

import SimpleDraw as SD

# create a canvas (could be any AbstractMatrix)
image = falses(32, 32) # (height, width)

# create the shape
shape = SD.Line(SD.Point(9, 5), SD.Point(14, 19))

# we will draw on the boolean image with the "color" true
color = true

# draw the shape on image
SD.draw!(image, shape, color)

# print the boolean image using Unicode block characters
SD.visualize(image)

Notes

API

The following types are part of the API.

  1. All types in List of shapes
  2. The abstract type AbstractShape
  3. The font constants TERMINUS_16_8, TERMINUS_BOLD_16_8, TERMINUS_24_12, TERMINUS_BOLD_24_12, TERMINUS_32_16, TERMINUS_BOLD_32_16.

The following functions are part of the API:

  1. draw!
  2. is_valid
  3. get_i_min
  4. get_i_max
  5. get_j_min
  6. get_j_max
  7. get_i_extrema
  8. get_j_extrema
  9. get_height
  10. get_width
  11. get_position
  12. move_i
  13. move_j
  14. move
  15. visualize

Everything else should be considered internal for now.

draw!

Being able to draw broadly requires three things:

  1. image: A canvas to draw on. It could be any AbstractMatrix.
  2. shape: The geometric shape to be drawn. Note that primitive shapes can easily be composed to create more complex shapes. For example,
    struct MyComplexShape{I <: Integer} <: SD.AbstractShape
        line::SD.Line{I}
        circle::SD.Circle{I}
    end
  3. color: The color to draw the shape with. This is what fills up the entries of the image matrix at appropriate positions, thereby drawing the geometric shape.

With this in mind, this package provides the draw! function, which is commonly invoked as follows:

SD.draw!(image, shape, color)

Under the hood, it calls internal _draw! methods that automatically take care of some basic optimizations (see Drawing optimizations). Then there are _draw! methods of the form SD._draw!(f, image, shape, color) that are heavily used internally. Here, f can roughly be thought of as a drawing function applied to every pixel of the shape. This offers a lot of flexibility with the "brush-stroke" and significantly decreases code duplication. At the same time, it does not adversely affect performance. Most users will not need to use these methods directly, but in case you do, please look up the source code as their usage is not very well documented as of now.

By default, the draw! function is safe, that is, it draws only those pixels of the shape that lie within the bounds of the image. So you don't have to worry about your program breaking even if it tries to draw something outside the bounds of the image. That being said, certain basic optimizations are already enabled for drawing most shapes. See Drawing optimizations.

Drawing optimizations

DrawingOptimizationStyle is trait whose subtypes are used to define generic draw! methods with different levels of optimization for drawing shapes:

  1. PUT_PIXEL: Iterate through all the positions needed to draw the shape. For each position, if it lies within the bounds of the image, put a pixel at that position else don't do anything.
  2. CHECK_BOUNDS: If the shape lies completely outside the bounds of the image, simply return nothing. If it lies completely inside the bounds of the image, then draw each pixel of the shape without any further bounds checking. If it is neither of the previous cases, fall back to the slow but safe method of drawing each pixel of the shape only if it lies within the bounds of the image.
  3. CLIP: Some shapes like VerticalLine, HorizontalLine, FilledRectangle can be direcly clipped into shapes that completely lie within the bounds of the image. In such cases, perform the clipping and draw the clipped shape without any further bounds checking.
  4. PUT_PIXEL_INBOUNDS: Iterate through all the positions needed to draw the shape. For each position, put a pixel at that position assuming without any bounds checking image.

Use get_drawing_optimization_style(shape) to get the default drawing optimization style for a shape. Shapes which do not fall within the above will implement custom draw! methods with relevant optimizations.

Visualization

The visualize function helps in visualizing a boolean image directly inside the terminal. This is a quick and effective tool to verify whether a shape is being drawn as expected. This is extremely handy when you want to know about the exact coordinates of the pixels that are being drawn for a shape.

It uses Unicode block characters to represent a pixel. This works well for low resolution images. To visualize slightly higher resolution images, you can maximize your terminal window and reduce its font size.

Benchmarks

Below are the benchmarks for v0.5.0 of this package:

julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 12 × AMD Ryzen 5 6600H with Radeon Graphics
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, znver3)
  Threads: 1 on 12 virtual cores

julia>

Timestamp: 2023_01_11_03_20_28 (yyyy_mm_dd_HH_MM_SS)

Shapes are drawn on an image of type Matrix{UInt32} with a color of type UInt32

shape type image height image width median time memory shape
Background 64 64 121.069 ns 0 bytes SimpleDraw.Background()
Background 256 256 2.140 μs 0 bytes SimpleDraw.Background()
Background 1024 1024 59.781 μs 0 bytes SimpleDraw.Background()
Point 64 64 2.585 ns 0 bytes SimpleDraw.Point{Int64}(33, 33)
Point 256 256 2.334 ns 0 bytes SimpleDraw.Point{Int64}(129, 129)
Point 1024 1024 2.585 ns 0 bytes SimpleDraw.Point{Int64}(513, 513)
Line 64 64 70.601 ns 0 bytes SimpleDraw.Line{Int64}(SimpleDraw.Point{Int64}(9, 2), SimpleDraw.Point{Int64}(56, 63))
Line 256 256 342.824 ns 0 bytes SimpleDraw.Line{Int64}(SimpleDraw.Point{Int64}(33, 2), SimpleDraw.Point{Int64}(224, 255))
Line 1024 1024 1.470 μs 0 bytes SimpleDraw.Line{Int64}(SimpleDraw.Point{Int64}(129, 2), SimpleDraw.Point{Int64}(896, 1023))
ThickLine 64 64 834.514 ns 0 bytes SimpleDraw.ThickLine{Int64}(SimpleDraw.Point{Int64}(9, 9), SimpleDraw.Point{Int64}(56, 56), 7)
ThickLine 256 256 49.472 μs 0 bytes SimpleDraw.ThickLine{Int64}(SimpleDraw.Point{Int64}(33, 33), SimpleDraw.Point{Int64}(224, 224), 31)
ThickLine 1024 1024 1.273 ms 0 bytes SimpleDraw.ThickLine{Int64}(SimpleDraw.Point{Int64}(129, 129), SimpleDraw.Point{Int64}(896, 896), 127)
Triangle 64 64 185.163 ns 0 bytes SimpleDraw.Triangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(63, 32), SimpleDraw.Point{Int64}(32, 63))
Triangle 256 256 749.029 ns 0 bytes SimpleDraw.Triangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(255, 128), SimpleDraw.Point{Int64}(128, 255))
Triangle 1024 1024 4.349 μs 0 bytes SimpleDraw.Triangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(1023, 512), SimpleDraw.Point{Int64}(512, 1023))
FilledTriangle 64 64 433.065 ns 0 bytes SimpleDraw.FilledTriangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(63, 32), SimpleDraw.Point{Int64}(32, 63))
FilledTriangle 256 256 2.377 μs 0 bytes SimpleDraw.FilledTriangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(255, 128), SimpleDraw.Point{Int64}(128, 255))
FilledTriangle 1024 1024 28.884 μs 0 bytes SimpleDraw.FilledTriangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(1023, 512), SimpleDraw.Point{Int64}(512, 1023))
Rectangle 64 64 56.104 ns 0 bytes SimpleDraw.Rectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 63, 63)
Rectangle 256 256 908.600 ns 0 bytes SimpleDraw.Rectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 255, 255)
Rectangle 1024 1024 9.859 μs 0 bytes SimpleDraw.Rectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1023, 1023)
FilledRectangle 64 64 518.203 ns 0 bytes SimpleDraw.FilledRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 63, 63)
FilledRectangle 256 256 3.588 μs 0 bytes SimpleDraw.FilledRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 255, 255)
FilledRectangle 1024 1024 49.322 μs 0 bytes SimpleDraw.FilledRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1023, 1023)
ThickRectangle 64 64 841.000 ns 0 bytes SimpleDraw.ThickRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 63, 63, 16)
ThickRectangle 256 256 3.241 μs 0 bytes SimpleDraw.ThickRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 255, 255, 64)
ThickRectangle 1024 1024 53.329 μs 0 bytes SimpleDraw.ThickRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1023, 1023, 256)
Circle 64 64 95.229 ns 0 bytes SimpleDraw.Circle{Int64}(SimpleDraw.Point{Int64}(2, 2), 62)
Circle 256 256 366.939 ns 0 bytes SimpleDraw.Circle{Int64}(SimpleDraw.Point{Int64}(2, 2), 254)
Circle 1024 1024 3.228 μs 0 bytes SimpleDraw.Circle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1022)
FilledCircle 64 64 608.218 ns 0 bytes SimpleDraw.FilledCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 62)
FilledCircle 256 256 3.966 μs 0 bytes SimpleDraw.FilledCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 254)
FilledCircle 1024 1024 52.016 μs 0 bytes SimpleDraw.FilledCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1022)
ThickCircle 64 64 923.326 ns 0 bytes SimpleDraw.ThickCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 62, 16)
ThickCircle 256 256 24.506 μs 0 bytes SimpleDraw.ThickCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 254, 64)
ThickCircle 1024 1024 1.730 ms 0 bytes SimpleDraw.ThickCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1022, 256)
Bitmap 64 64 4.490 μs 0 bytes SimpleDraw.Bitmap{Int64, BitMatrix}(SimpleDraw.Point{Int64}(2, 2), Bool[1 0 … 1 0; 0 1 … 0 1; … ; 1 0 … 1 0; 0 1 … 0 1])
Bitmap 256 256 71.583 μs 0 bytes SimpleDraw.Bitmap{Int64, BitMatrix}(SimpleDraw.Point{Int64}(2, 2), Bool[1 0 … 1 0; 0 1 … 0 1; … ; 1 0 … 1 0; 0 1 … 0 1])
Bitmap 1024 1024 1.181 ms 0 bytes SimpleDraw.Bitmap{Int64, BitMatrix}(SimpleDraw.Point{Int64}(2, 2), Bool[1 0 … 1 0; 0 1 … 0 1; … ; 1 0 … 1 0; 0 1 … 0 1])
Image 64 64 2.285 μs 0 bytes SimpleDraw.Image{Int64, Matrix{UInt32}}(SimpleDraw.Point{Int64}(2, 2), UInt32[0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001; … ; 0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001])
Image 256 256 38.742 μs 0 bytes SimpleDraw.Image{Int64, Matrix{UInt32}}(SimpleDraw.Point{Int64}(2, 2), UInt32[0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001; … ; 0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001])
Image 1024 1024 814.004 μs 0 bytes SimpleDraw.Image{Int64, Matrix{UInt32}}(SimpleDraw.Point{Int64}(2, 2), UInt32[0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001; … ; 0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001])
Character 64 64 873.814 ns 0 bytes SimpleDraw.Character{Int64, Char, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(2, 2), 'A', SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]))
Character 256 256 874.355 ns 0 bytes SimpleDraw.Character{Int64, Char, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(2, 2), 'A', SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]))
Character 1024 1024 881.478 ns 0 bytes SimpleDraw.Character{Int64, Char, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(2, 2), 'A', SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]))
TextLine 64 64 3.548 μs 0 bytes SimpleDraw.TextLine{Int64, String, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(1, 1), "BUDB", SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]))
TextLine 256 256 14.377 μs 0 bytes SimpleDraw.TextLine{Int64, String, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(1, 1), "ZZPEKEEOUGIIHKGY", SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]))
TextLine 1024 1024 58.398 μs 0 bytes SimpleDraw.TextLine{Int64, String, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(1, 1), "ZBXMZBNLSOTGROCLZJTOONNIEIFUOLCSLIUTYUGDMIEWKIWMYJLOPHGYPLTWBIDF", SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]))

Follow these steps to generate benchmarks. Take care to double-check the version of the package you are benchmarking:

  1. Clone the project

    $ git clone https://github.com/Sid-Bhatia-0/SimpleDraw.jl.git
    
  2. Start the julia REPL inside the /benchmark directory

    benchmark $ julia
    
  3. Activate and instantiate the project

    julia> import Pkg; Pkg.activate("."); Pkg.instantiate()
    
  4. Exit the REP and run generate_benchmarks.jl with the Project.toml and Manifest.toml files in this directory

    benchmark $ julia --project=. generate_benchmarks.jl
    

This will print a bunch of outputs and produce a markdown file named with a timestamp containing the final benchmarks. Using a timestamp in the name helps ensure that running generate_benchmarks.jl multiple times does not overwrite the same file.

List of shapes

  1. Background

    struct Background <: AbstractShape end
  2. Point

    struct Point{I <: Integer} <: AbstractShape
        i::I
        j::I
    end
  3. Line

    struct Line{I <: Integer} <: AbstractLine
        point1::Point{I}
        point2::Point{I}
    end

    Line(point1, point2) will draw the same thing as Line(point2, point1) as they are always sorted internally. But note that the visual representation of the line may not symmetric with respect to the end points in general.

  4. ThickLine

    struct ThickLine{I <: Integer} <: AbstractLine
        point1::Point{I}
        point2::Point{I}
        thickness::I
    end

    An instance of ThickLine is considered valid only if the following conditions hold true:

    • thickness > 0
  5. Triangle

    struct Triangle{I <: Integer} <: AbstractTriangle
        point1::Point{I}
        point2::Point{I}
        point3::Point{I}
    end
  6. FilledTriangle

    struct FilledTriangle{I <: Integer} <: AbstractTriangle
        point1::Point{I}
        point2::Point{I}
        point3::Point{I}
    end
  7. Rectangle

    struct Rectangle{I <: Integer} <: AbstractRectangle
        position::Point{I}
        height::I
        width::I
    end

    An instance of Rectangle is considered valid only if the following conditions hold true:

    • height > 0
    • width > 0
  8. FilledRectangle

    struct FilledRectangle{I <: Integer} <: AbstractRectangle
        position::Point{I}
        height::I
        width::I
    end

    An instance of FilledRectangle is considered valid only if the following conditions hold true:

    • height > 0
    • width > 0
  9. ThickRectangle

    struct ThickRectangle{I <: Integer} <: AbstractRectangle
        position::Point{I}
        height::I
        width::I
        thickness::I
    end

    An instance of ThickRectangle is considered valid only if the following conditions hold true:

    • height > 0
    • width > 0
    • thickness > 0
    • thickness <= min(height, width)
  10. Circle

    struct Circle{I <: Integer} <: AbstractCircle
        position::Point{I}
        diameter::I
    end

    An instance of Circle is considered valid only if the following conditions hold true:

    • diameter > 0
  11. FilledCircle

    struct FilledCircle{I <: Integer} <: AbstractCircle
        position::Point{I}
        diameter::I
    end

    An instance of FilledCircle is considered valid only if the following conditions hold true:

    • diameter > 0
  12. ThickCircle

    struct ThickCircle{I <: Integer} <: AbstractCircle
        position::Point{I}
        diameter::I
        thickness::I
    end

    An instance of ThickCircle is considered valid only if the following conditions hold true:

    • diameter > 0
    • thickness > 0
    • if diameter is odd, then 2 * thickness <= diameter + 1
    • if diameter is even, then 2 * thickness <= diameter
  13. Bitmap

    struct Bitmap{I <: Integer, B <: AbstractMatrix{Bool}} <: AbstractShape
        position::Point{I}
        bitmap::B
    end

    Can be used to draw a 1-bit image using some color on an image. For example, it is used for drawing character glyphs in Character or TextLine.

  14. Image

    struct Image{I <: Integer, A} <: AbstractShape
        position::Point{I}
        image::A
    end

    Can be used to draw an existing image on top of an image at some position. No need to pass color explicitly, the sub-image should already be colored. Whereas in Bitmap, one needs to pass color explicitly and it can only be of a single color.

  15. Character

    struct Character{I <: Integer, C <: AbstractChar, F <: AbstractFont} <: AbstractShape
        position::Point{I}
        character::C
        font::F
    end

    There are 6 monospace ASCII fonts are available at this point:

    1. TERMINUS_16_8 (height 16 pixels, width 8 pixels)
    2. TERMINUS_BOLD_16_8 (height 16 pixels, width 8 pixels)
    3. TERMINUS_24_12 (height 24 pixels, width 12 pixels)
    4. TERMINUS_BOLD_24_12 (height 24 pixels, width 12 pixels)
    5. TERMINUS_32_16 (height 32 pixels, width 16 pixels)
    6. TERMINUS_BOLD_32_16 (height 32 pixels, width 16 pixels)

    Only glyphs for ASCII characters are available as of now.

  16. TextLine

    struct TextLine{I <: Integer, S, F <: AbstractFont} <: AbstractShape
        position::Point{I}
        text::S
        font::F
    end

    There are 6 monospace ASCII fonts are available at this point:

    1. TERMINUS_16_8 (height 16 pixels, width 8 pixels)
    2. TERMINUS_BOLD_16_8 (height 16 pixels, width 8 pixels)
    3. TERMINUS_24_12 (height 24 pixels, width 12 pixels)
    4. TERMINUS_BOLD_24_12 (height 24 pixels, width 12 pixels)
    5. TERMINUS_32_16 (height 32 pixels, width 16 pixels)
    6. TERMINUS_BOLD_32_16 (height 32 pixels, width 16 pixels)

    Only glyphs for ASCII characters are available as of now.

References and License Information

  1. Octant drawing: https://en.wikipedia.org/w/index.php?title=Midpoint_circle_algorithm&oldid=1073593456
  2. Line drawing: https://en.wikipedia.org/w/index.php?title=Bresenham%27s_line_algorithm&oldid=1073834153
  3. Fonts: This package supports bitmap fonts for ASCII characters at this point. We use a subset of Terminus Font for drawing the glyphs. Terminus Font is licensed under the SIL Open Font License, Version 1.1. The license is included as OFL.TXT in the /src/fonts directory in this repository, and is also available with a FAQ at http://scripts.sil.org/OFL.
  4. Everything else is under LICENSE.