Vec.jl: 2D and 3D Vectors and Their Operations for Julia


Provides 2D and 3D vector types for vector operations in Julia.


Run one of those commands in the Julia REPL:

Through the SISL registry:

] registry add
add Vec

Through Pkg

import Pkg


Vec.jl provides several vector types, named after their groups. All types are immutable and are subtypes of 'StaticArrays'' FieldVector, so they can be indexed and used as vectors in many contexts.

  • VecE2 provides an (x,y) type of the Euclidean-2 group.
  • VecE3 provides an (x,y,z) type of the Euclidean-3 group.
  • VecSE2 provides an (x,y,theta) type of the special-Euclidean 2 group.
v = VecE2(0, 1)
v = VecSE2(0,1,0.5)
v = VecE3(0, 1, 2)

Additional geometry types include Quat for quaternions, Line, LineSegment, and Projectile.

The switch to StaticArrays brings several breaking changes. If you need a backwards-compatible version, please checkout the v0.1.0 tag with cd(Pkg.dir("Vec")); run(`git checkout v0.1.0`).

Download Details:

Author: sisl
Source Code: 
License: View license

#julia #vector #3d 

Vec.jl: 2D and 3D Vectors and Their Operations for Julia
Nat  Grady

Nat Grady


Vis3D: 3D Visualization using Vis.js Library


R package, using vis.js library for 3D visualization



nb <- 10
don <- expand.grid(x = 1:nb, y = 1:nb)
don$z <-rnorm(nb*nb)


shiny::runApp(system.file("shiny", package = "vis3D"))

Download Details:

Author: Datastorm-open
Source Code: 

#r #3d #visualization 

 Vis3D: 3D Visualization using Vis.js Library

3D Room Acoustics Finite Difference Time Domain (FDTD) Simulator

AcFDTD (this library is unmantained)

Finite Difference Time Domain (FDTD) method for room acoustic simulation


From the Julia command line hit:


Once the package is installed you can update it along with the others issuing Pkg.update() in the command line.


Import the package by typing using AcFDTD. First you need to specify an acoustic environment and FDTD scheme:

using AcFDTD
X = 0.1                   # spatial sampling
env = FDTDEnv(X,IISO())   # create new acoustic env with default values

where IISO() returns the Interpolated Isotropic scheme. Alternatively one can choose a samplng frequency instead of a spatial sampling:

Fs = 2000.                          # sampling frequency in Hz
env = FDTDEnv(IISO(),Fs; c = 340)   # create new acoustic env with default values

notice that in the latter line the speed of sound was chosen to be 340 m/s. By default this is set to 343 m/s. Set the acoustic impedance ξ and room geometry room geometry:

ξ = [50.;50.;100.;30.;50.;50.]; # [   ξx1    ;    ξx2   ;    ξy1   ;    ξy2    ;  ξz1 ;   ξz2  ]
                                # [front wall; rear wall; left wall; right wall; floor; ceiling]
geo = CuboidRoom(10, 11, 12, ξ, env)

The first three parameters indicate the number of spatial samples of the x, y and z directions.
Alternatively one can specify the room dimensions in meters:

geo = CuboidRoom(4., 5., 3., ξ, env)

which are then approximated on the grid. Set the number of time steps Nt Create a band-limited sound source with e.g. the DSP package:

using DSP
Nt = round(Int,env.Fs)         # number of time steps (1 sec)
s = zeros(Nt)                    # source signal
s[3] = 1
f2 = geo.env.Fs/2*0.175          # cut-off frequency of source
filt!(s,digitalfilter(Bandpass(10,f2;fs = geo.env.Fs),Butterworth(5)),s)

Define the position of microphone and sound sources:

xr = [(2, 2, 2), (2, geo.Ny-1, geo.Nz-1)] # mic positions
xs = (geo.Nx-1, geo.Ny-1, geo.Nz-1) # sound source position
#positions must be Tuple{Int,Int,Int} or Array{Tuple{Int,Int,Int},1} 

Now type:

p = fdtd(xr,xs,Nt,geo,s)

to obtain the sound pressure of the microphones.

For more details on the methods type:



AcFDTD.jl is developed by Niccolò Antonello at KU Leuven, ESAT/Stadius.

Download Details:

Author: Nantonel
Source Code: 
License: View license

#julia #3d #time 

3D Room Acoustics Finite Difference Time Domain (FDTD) Simulator

Rotations.jl: 3D rotations made easy in Julia


3D rotations made easy in Julia

This package implements various 3D rotation parameterizations and defines conversions between them. At their heart, each rotation parameterization is a 3×3 unitary (orthogonal) matrix (based on the StaticArrays.jl package), and acts to rotate a 3-vector about the origin through matrix-vector multiplication.

While the RotMatrix type is a dense representation of a 3×3 matrix, we also have sparse (or computed, rather) representations such as quaternions, angle-axis parameterizations, and Euler angles.

For composing rotations about the origin with other transformations, see the CoordinateTransformations.jl package.


The following operations are supported by all of the implemented rotation parameterizations.


Any two rotations of the same type can be composed with simple multiplication:

q3 = q2*q1

Rotations can be composed with the opposite (or inverse) rotation with the appropriate division operation

q1 = q2\q3
q2 = q3/q1


Any rotation can operate on a 3D vector (represented as a SVector{3}), again through simple multiplication:

r2 = q*r

which also supports multiplication by the opposite rotation

r = q\r2

Rotation Angle / Axis

The rotation angle and axis can be obtained for any rotation parameterization using



All rotation types support one(R) to construct the identity rotation for the desired parameterization. A random rotation, uniformly sampled over the space of rotations, can be sampled using rand(R). For example:

r = one(QuatRotation)  # equivalent to QuatRotation(1.0, 0.0, 0.0, 0.0)
q = rand(QuatRotation)
p = rand(MRP{Float32})


All rotatations can be converted to another parameterization by simply calling the constructor for the desired parameterization. For example:

q = rand(QuatRotation)
aa = AngleAxis(q)
r = RotMatrix(aa)

Example Usage

using Rotations, StaticArrays

# create the identity rotation (identity matrix)
id = one(RotMatrix{3, Float64})

# create a random rotation matrix (uniformly distributed over all 3D rotations)
r = rand(RotMatrix{3}) # uses Float64 by default

# create a point
p = SVector(1.0, 2.0, 3.0) # from StaticArrays.jl, but could use any AbstractVector...

# convert to a quaternion (QuatRotation) and rotate the point
q = QuatRotation(r)
p_rotated = q * p

# Compose rotations
q2 = rand(QuatRotation)
q3 = q * q2

# Take the inverse (equivalent to transpose)
q_inv = transpose(q)
q_inv == inv(q)
p ≈ q_inv * (q * p)
q4 = q3 / q2  # q4 = q3 * inv(q2)
q5 = q3 \ q2  # q5 = inv(q3) * q2

# convert to a Modified Rodrigues Parameter (aka Stereographic quaternion projection, recommended for applications with differentiation)
spq = MRP(r)

# convert to the Angle-axis parameterization, or related Rotation vector
aa = AngleAxis(r)
rv = RotationVec(r)
ϕ = rotation_angle(r)
v = rotation_axis(r)

# convert to Euler angles, composed of X/Y/Z axis rotations (Z applied first)
# (all combinations of "RotABC" are defined)
r_xyz = RotXYZ(r)

# Rotation about the X axis by 0.1 radians
r_x = RotX(0.1)

# Composing axis rotations together automatically results in Euler parameterization
RotX(0.1) * RotY(0.2) * RotZ(0.3) === RotXYZ(0.1, 0.2, 0.3)

# Can calculate Jacobian - derivatives of rotations with respect to parameters
j1 = Rotations.jacobian(RotMatrix, q) # How does the matrix change w.r.t the 4 Quat parameters?
j2 = Rotations.jacobian(q, p) # How does the rotated point q*p change w.r.t. the 4 Quat parameters?
# ... all Jacobian's involving RotMatrix, MRP and Quat are implemented
# (MRP is ideal for optimization purposes - no constaints/singularities)

Rotation Parameterizations

Rotation Matrix RotMatrix{N, T}

An N×N rotation matrix storing the rotation. This is a simple wrapper for a StaticArrays SMatrix{N,N,T}. A rotation matrix R should have the property I = R * R', but this isn't enforced by the constructor. On the other hand, all the types below are guaranteed to be "proper" rotations for all input parameters (equivalently: parity conserving, in SO(3), det(r) = 1, or a rotation without reflection).

Arbitrary Axis Rotation AngleAxis{T}

A 3D rotation with fields theta, axis_x, axis_y, and axis_z to store the rotation angle and axis of the rotation. Like all other types in this package, once it is constructed it acts and behaves as a 3×3 AbstractMatrix. The axis will be automatically renormalized by the constructor to be a unit vector, so that theta always represents the rotation angle in radians.

Quaternions QuatRotation{T}

A 3D rotation parameterized by a unit quaternion. Note that the constructor will renormalize the quaternion to be a unit quaternion, and that although they follow the same multiplicative algebra as quaternions, it is better to think of QuatRotation as a 3×3 matrix rather than as a quaternion number.

Previously Quat, UnitQuaternion.

Rotation Vector RotationVec{T}

A 3D rotation encoded by an angle-axis representation as angle * axis. This type is used in packages such as OpenCV.

Note: If you're differentiating a Rodrigues Vector check the result is what you expect at theta = 0. The first derivative of the rotation should behave, but higher-order derivatives of it (as well as parameterization conversions) should be tested. The Stereographic Quaternion Projection (MRP) is the recommended three parameter format for differentiation.

Previously RodriguesVec.

Rodrigues Parameters RodriguesParam{T} A 3-parameter representation of 3D rotations that has a singularity at 180 degrees. They can be interpreted as a projection of the unit quaternion onto the plane tangent to the quaternion identity. They are computationally efficient and do not have a sign ambiguity.

Modified Rodrigues Parameter MRP{T} A 3D rotation encoded by the stereographic projection of a unit quaternion. This projection can be visualized as a pin hole camera, with the pin hole matching the quaternion [-1,0,0,0] and the image plane containing the origin and having normal direction [1,0,0,0]. The "identity rotation" Quaternion(1.0,0,0,0) then maps to the MRP(0,0,0)

These are similar to the Rodrigues vector in that the axis direction is stored in an unnormalized form, and the rotation angle is encoded in the length of the axis. This type has the nice property that the derivatives of the rotation matrix w.r.t. the MRP parameters are rational functions, making the MRP type a good choice for differentiation / optimization.

They are frequently used in aerospace applications since they are a 3-parameter representation whose singularity happens at 360 degrees. In practice, the singularity can be avoided with some switching logic between one of two equivalent MRPs (obtained by projecting the negated quaternion).

Previously SPQuat.

Cardinal axis rotations RotX{T}, RotY{T}, RotZ{T}

Sparse representations of 3D rotations about the X, Y, or Z axis, respectively.

Two-axis rotations RotXY{T}, etc

Conceptually, these are compositions of two of the cardinal axis rotations above, so that RotXY(x, y) == RotX(x) * RotY(y) (note that the order of application to a vector is right-to-left, as-in matrix-matrix-vector multiplication: RotXY(x, y) * v == RotX(x) * (RotY(y) * v)).

Euler Angles - Three-axis rotations RotXYZ{T}, RotXYX{T}, etc

A composition of 3 cardinal axis rotations is typically known as a Euler angle parameterization of a 3D rotation. The rotations with 3 unique axes, such as RotXYZ, are said to follow the Tait Bryan angle ordering, while those which repeat (e.g. EulerXYX) are said to use Proper Euler angle ordering.

Like the two-angle versions, the order of application to a vector is right-to-left, so that RotXYZ(x, y, z) * v == RotX(x) * (RotY(y) * (RotZ(z) * v)). This may be interpreted as an "extrinsic" rotation about the Z, Y, and X axes or as an "intrinsic" rotation about the X, Y, and Z axes. Similarly, RotZYX(z, y, x) may be interpreted as an "extrinsic" rotation about the X, Y, and Z axes or an "intrinsic" rotation about the Z, Y, and X axes.

The Rotation Error state and Linearization

It is often convenient to consider perturbations or errors about a particular 3D rotation, such as applications in state estimation or optimization-based control. Intuitively, we expect these errors to live in three-dimensional space. For globally non-singular parameterizations such as unit quaternions, we need a way to map between the four parameters of the quaternion to this three-dimensional plane tangent to the four-dimensional hypersphere on which quaternions live.

There are several of these maps provided by Rotations.jl:

ExponentialMap: A very common mapping that uses the quaternion exponential and the quaternion logarithm. The quaternion logarithm converts a 3D rotation vector (i.e. axis-angle vector) to a unit quaternion. It tends to be the most computationally expensive mapping.

CayleyMap: Represents the differential quaternion using Rodrigues parameters. This parameterization goes singular at 180° but does not inherit the sign ambiguities of the unit quaternion. It offers an excellent combination of cheap computation and good behavior.

MRPMap: Uses Modified Rodrigues Parameters (MRPs) to represent the differential unit quaternion. This mapping goes singular at 360°.

QuatVecMap: Uses the vector part of the unit quaternion as the differential unit quaternion. This mapping also goes singular at 180° but is the computationally cheapest map and often performs well.

Rotations.jl provides the RotationError type for representing rotation errors, that act just like a SVector{3} but carry the nonlinear map used to compute the error, which can also be used to convert the error back to a QuatRotation (and, by extention, any other 3D rotation parameterization). The following methods are useful for computing RotationErrors and adding them back to the nominal rotation:

rotation_error(R1::Rotation, R2::Rotation, error_map::ErrorMap)  # compute the error between `R1` and `R2` using `error_map`
add_error(R::Rotation, err::RotationError)  # "adds" the error to `R` by converting back a `UnitQuaterion` and composing with `R`

or their aliases

R1 ⊖ R2   # caclulate the error using the default error map
R1 ⊕ err  # alias for `add_error(R1, err)`

For a practical application of these ideas, see the quatenrion-multiplicative Extended Kalman Filter (MEKF). This article provides a good description.

When taking derivatives with respect to quaternions we need to account both for these mappings and the fact that local perturbations to a rotation act through composition instead of addition, as they do in vector space (e.g. q * dq vs x + dx). The following methods are useful for computing these Jacobians for QuatRotation, RodriguesParam or MRP

  • ∇rotate(q,r): Jacobian of the q*r with respect to the rotation
  • ∇composition1(q2,q1): Jacobian of q2*q1 with respect to q1
  • ∇composition2(q2,q1,b): Jacobian of q2*q1 with respect to q2
  • ∇²composition1(q2,q1): Jacobian of ∇composition1(q2,q2)'b where b is an arbitrary vector
  • ∇differential(q): Jacobian of composing the rotation with an infinitesimal rotation, with respect to the infinitesimal rotation. For unit quaternions, this is a 4x3 matrix.
  • ∇²differential(q,b): Jacobian of ∇differential(q)'b for some vector b.

Import / Export

All parameterizations can be converted to and from (mutable or immutable) 3×3 matrices, e.g.

using StaticArrays, Rotations

# export
q = QuatRotation(1.0,0,0,0)
matrix_mutable = Array(q)
matrix_immutable = SMatrix{3,3}(q)

# import
q2 = Quaternion(matrix_mutable)
q3 = Quaternion(matrix_immutable)


This package assumes active (right handed) rotations where applicable.

Why use immutables / StaticArrays?

They're faster (Julia's Array and BLAS aren't great for 3×3 matrices) and don't need preallocating or garbage collection. For example, see this benchmark case where we get a 20× speedup:

julia> cd(Pkg.dir("Rotations") * "/test")

julia> include("benchmark.jl")

julia > BenchMarkRotations.benchmark_mutable()
Rotating using mutables (Base.Matrix and Base.Vector):
  0.124035 seconds (2 allocations: 224 bytes)
Rotating using immutables (Rotations.RotMatrix and StaticArrays.SVector):
  0.006006 seconds

Download Details:

Author: JuliaGeometry
Source Code: 
License: View license

#julia #3d #rotated 

Rotations.jl: 3D rotations made easy in Julia
Nat  Grady

Nat Grady


D3rain: An Htmlwidget Bringing D3 Drip to R


According to the authorities at Urban Dictionary, ‘drip’ is synonymous with ‘immense swag.’ This package brings some D3 drip to R.


You can install d3rain from GitHub via:



‘Rain’ visualizations are useful aids to observe the relationship between a ranked, numeric variable (e.g. percentile, rank, etc.) and any factored, categorical variable.


armed_levels <- c('No', 'Knife', 'Non-lethal firearm', 'Firearm')
pk <- fivethirtyeight::police_killings %>% 
  filter(armed %in% armed_levels,
         ! %>% 
  mutate(armed = factor(armed, levels = armed_levels)) 

pk %>% 
  d3rain(age, armed, toolTip = raceethnicity, title = "2015 Police Killings by Age, Armed Status") %>% 
  drip_settings(dripSequence = 'iterate',
                ease = 'bounce',
                jitterWidth = 20,
                dripSpeed = 1000,
                dripFill = 'firebrick') %>% 
  chart_settings(fontFamily = 'times',
                 yAxisTickLocation = 'left')


drip_settings adjusts the drip sequence, easing animation, jitter width, drip speed, and color. chart_settings controls the axes displays, font size, font family, and background color.

You can adjust the drip iteration by reordering the data frame:

pk %>% 
  arrange(age) %>% 
  d3rain(age, armed, toolTip = raceethnicity, title = "2015 Police Killings by Age, Armed Status") %>% 
  drip_settings(dripSequence = 'iterate',
                ease = 'linear',
                jitterWidth = 25,
                dripSpeed = 500,
                dripFill = 'steelblue') %>% 
  chart_settings(fontFamily = 'times',
                 yAxisTickLocation = 'left')


Rain Histograms

Create rain histograms with d3rain_hist and the accompanying functions:

d <- readr::read_csv("") %>% 
  rename(Downloaded = downloaded, 
         Contacted = contacted, 
         Replied = reply_received, 
         Received = data_received) %>% 
  mutate(Total = TRUE,
         `Downloaded and Received` = case_when(
           Downloaded ~ TRUE,
           Received ~ TRUE,
           TRUE ~ FALSE)

d %>% 
  d3rain_hist(x = year, 
              levels = c("Total", "Contacted", "Replied", "Downloaded and Received"), 
              title = "Citation Statuses, 1960-2019") %>% 
  hist_chart_settings(annotations = c("Total Sample: 560", "475 (95%)", "309 (65%)", "147 (26%)"),
                      levelLabelLocation = "right") %>% 
  hist_drip_settings(colors = c("black", "forestgreen", "orange", "firebrick"),
                     transitionIntervals = 2500,
                     dripSpeed = 300)

Future Work

  • Additional drip behaviors (e.g. by group)
  • Conditional fill colors

Download Details:

Author: Daranzolin
Source Code: 
License: Unknown, MIT licenses found

#r #datavisualization #3d 

D3rain: An Htmlwidget Bringing D3 Drip to R
Elian  Harber

Elian Harber


Fauxgl: Software-only 3D Renderer Written in Go


3D software rendering in pure Go. No OpenGL, no C extensions, no nothin'.




It's like OpenGL, but it's not. It's FauxGL.

It doesn't use your graphics card, only your CPU. So it's slow and unsuitable for realtime rendering. But it's still pretty fast. It works the same way OpenGL works - rasterizing.


  • STL, OBJ, PLY, 3DS file formats
  • triangle rasterization
  • vertex and fragment "shaders"
  • view volume clipping
  • face culling
  • alpha blending
  • textures
  • triangle & line meshes
  • depth biasing
  • wireframe rendering
  • built-in shapes (plane, sphere, cube, cylinder, cone)
  • anti-aliasing (via supersampling)
  • voxel rendering
  • parallel processing


FauxGL uses all of your CPU cores. But none of your GPU.

Rendering the Stanford Dragon shown above (871306 triangles) at 1920x1080px takes about 150 milliseconds on my machine. With 4x4=16x supersampling, it takes about 950 milliseconds. This is the time to render a frame and does not include loading the mesh from disk.

Go Get

go get -u

Go Run

cd go/src/
go run examples/hello.go

Go Doc

Complete Example

package main

import (
    . ""

const (
    scale  = 1    // optional supersampling
    width  = 1920 // output width in pixels
    height = 1080 // output height in pixels
    fovy   = 30   // vertical field of view in degrees
    near   = 1    // near clipping plane
    far    = 10   // far clipping plane

var (
    eye    = V(-3, 1, -0.75)               // camera position
    center = V(0, -0.07, 0)                // view center position
    up     = V(0, 1, 0)                    // up vector
    light  = V(-0.75, 1, 0.25).Normalize() // light direction
    color  = HexColor("#468966")           // object color

func main() {
    // load a mesh
    mesh, err := LoadOBJ("examples/dragon.obj")
    if err != nil {

    // fit mesh in a bi-unit cube centered at the origin

    // smooth the normals

    // create a rendering context
    context := NewContext(width*scale, height*scale)

    // create transformation matrix and light direction
    aspect := float64(width) / float64(height)
    matrix := LookAt(eye, center, up).Perspective(fovy, aspect, near, far)

    // use builtin phong shader
    shader := NewPhongShader(matrix, light, eye)
    shader.ObjectColor = color
    context.Shader = shader

    // render

    // downsample image for antialiasing
    image := context.Image()
    image = resize.Resize(width, height, image, resize.Bilinear)

    // save image
    SavePNG("out.png", image)


Download Details:

Author: fogleman
Source Code: 
License: MIT license

#go #golang #3d #opengl #graphic 

Fauxgl: Software-only 3D Renderer Written in Go

Compose3D.jl: A Library to Try and Extend Compose.jl To 3D


Compose3D is a Julia package written to try and extend Compose to 3-D. Currently, only WebGL backends using Three.JS are supported which allows you to draw 3D in a Jupyter notebook. The long term goal would be to integrate this package with the Compose package.

Please check the exp folder for some example IJulia notebooks.



Contexts are the things that you are able to draw. Contexts are created by specifying an origin point and the width, height and depth of the required context.

You can use the Context constructor to create a Context.

  • Context(x0,y0,z0,width,height,depth) - This will return a Context created which has it's coordinate system relative to (x0,y0,z0) and a width of 'width', height of 'height', and depth of 'depth'.

Geometries (Forms)

Geometries look to provide the user with primitives for creation of 3-D shapes.

Current primitives implemented are :

  • Cubes
  • Spheres
  • Pyramids

Functions available for users to use to create such geometries are:

  • cube(x0,y0,z0,side) - Returns a cube centered at (x0,y0,z0) and of the specified side
  • sphere(x0,y0,z0,radius) - Returns a sphere centered at (x0,y0,z0) with the specified radius.
  • pyramid(x0,y0,z0,baseLength, h) - Returns a square base pyramid of base length 'baseLength' with a corner at (x0,y0,z0) and the specified height 'h'.

Materials (Properties)

Materials are to add properties to the 3D objects like color and texture maps.

Functions available currently are:

  • mesh_color(color) - color can be a string or any Color in Color.jl that can be converted to RGB. All geometries that are children of this node and are part of the subtree at the same level will be coloured with this color.


Drawing things is done by composing a root Context with other Contexts or Geometries.

Compositions work exactly like in Compose except for :

  • Measures of the parent Context is resolved by adding 'w','h' and 'd' rather than just providing numbers in Compose.
  • There is no support for using the width, height and the depth of the root box as of now like 'w','h' and 'd' do in Compose.
  • The root Context has to have absolute values rather than relative values.

The function to be used by the user is the compose function.

  • compose(Context, Geometry) - Returns a new context after adding the geometry object to the context. The geometry's relative measures are converted to absolute measures based on the parent context.
  • compose(Context, Context) - Returns a new context after adding the context object to the parent context. The contexts relative measures are converted to absolute measures based on the parent context.

Compose can also take inputs in S-tree formats to build a tree. This saves the user from having to call compose again and again.


Compose3D makes use of a similar measure system to Compose. The basic unit is of 'mm'.

Absolute measure units can be used like :

  • cm - 10mm
  • inch - 25.4mm
  • pt - inch/72

Relative measures can also be used where the units will be :

  • w - width
  • h - height
  • d - depth

Absolute and relative measures can be combined.


cube1 = cube(0mm,0mm,0mm,1mm) # a cube of size 1 unit at the origin.
sphere1 = sphere(-5mm,0mm,0mm,0.1w) # a sphere with radius 1/10th of the width of the parent context and centered at (-5,0,0).
pyramid1 = pyramid(0mm,0mm,0.4d,2mm,1mm) # a pyramid with a corner at (0,0, 0.4*depth of parent context) of base 2mm and height 1mm.
context1 = Context(0mm,0mm,0mm,10mm,10mm,10mm) # context with origin at (0,0,0) and all dimensions of 10 units 
context2 = compose(context1,cube1) # Returns context with the cube.
context3 = compose(context2, sphere1, pyramid1) # Returns a context with all the geometries. Notice how we added 2 children in one line.

The drawing of a Sierpenski Pyramid can be done with the following code:

function sierpinski(n)
    if n == 0
        t = sierpinski(n - 1)
        (Context(0w,0h,0d,(1/2)w,(1/2)h,(1/2)d), t),
        (Context(0.5w,0h,0d,(1/2)w,(1/2)h,(1/2)d), t),
        (Context(0.5w,0.5h,0d,(1/2)w,(1/2)h,(1/2)d), t),
        (Context(0w,0.5h,0d,(1/2)w,(1/2)h,(1/2)d), t),
        (Context(0.25w,0.25h,0.5d,(1/2)w,(1/2)h,(1/2)d), t))



pranavtbhat for supplying the initial JavaScript code and getting this project started.

Download Details:

Author: Rohitvarkey
Source Code: 
License:  View license

#julia #compose #3d 

Compose3D.jl: A Library to Try and Extend Compose.jl To 3D

MeshIO.jl: IO for Meshes


This package supports loading 3D model file formats: obj, stl, ply, off and 2DM. More 3D model formats will be supported in the future.


Enter package mode in the Julia REPL and run the following command:

pkg> add FileIO MeshIO


Loading works over the FileIO interface. This means loading a mesh is as simple as this:

using FileIO
mesh = load("path/to/mesh.obj")

Displaying a mesh can be achieved with Makie.

Functions for mesh manipulation can be found in Meshes and JuliaGeometry

Additional Information

MeshIO now has the HomogenousMesh type. Name is still not settled, but it's supposed to be a dense mesh with all attributes either having the length of one (constant over the whole mesh) or the same length (per vertex). This meshtype holds a large variability for all the different attribute mixtures that I've encountered while trying to visualize things over at GLVisualize. This is the best type I've found so far to encode this large variability, without an explosion of functions.

The focus is on conversion between different mesh types and creation of different mesh types. This has led to some odd seeming design choices. First, you can get an attribute via decompose(::Type{AttributeType}, ::Mesh). This will try to get this attribute, and if it has the wrong type try to convert it, or if it is not available try to create it. So decompose(Point3{Float32}, mesh) on a mesh with vertices of type Point3{Float64} will return a vector of type Point3{Float32}. Similarly, if you call decompose(Normal{3, Float32}, mesh) but the mesh doesn't have normals, it will call the function normals(mesh.vertices, mesh.faces, Normal{3, Float32}, which will create the normals for the mesh. As most attributes are independent, this enables us to easily create all kinds of conversions. Also, I can define decompose for arbitrary geometric types. decompose{T}(Point3{T}, r::Rectangle) can actually return the needed vertices for a rectangle. This together with convert enables us to create mesh primitives like this:

MeshType(Volume, 0.4f0) #0.4f0 => isovalue

Similarly, I can pass a meshtype to an IO function, which then parses only the attributes that I really need. So passing Mesh{Point3{Float32}, Face3{UInt32}} to the obj importer will skip normals, uv coordinates etc, and automatically converts the given attributes to the right number type.

To put this one level further, the Face type has the index offset relative to Julia's indexing as a parameter (e.g. Face3{T, 0} is 1 indexed). Also, you can index into an array with this face type, and it will convert the indexes correctly while accessing the array. So something like this always works, independent of the underlying index offset:

v1, v2, v3 = vertices[face]

Also, the importer is sensitive to this, so if you always want to work with 0-indexed faces (like it makes sense for opengl based visualizations), you can parse the mesh already as an 0-indexed mesh, by just defining the mesh format to use Face3{T, -1}. (only the OBJ importer yet)

Small example to demonstrate the advantage for IO:

#Export takes any mesh
function write{M <: Mesh}(msh::M, fn::File{:ply_binary})
    # even if the native mesh format doesn't have an array of dense points or faces, the correct ones will
    # now be created, or converted:
    vts = decompose(Point3{Float32}, msh) # I know ply_binary needs Point3{Float32}
    fcs = decompose(Face3{Int32, -1}, msh) # And 0 indexed Int32 faces.
    #write code...


  1. Port all the other importers/exporters to use the new mesh type and the FileIO API
  2. Include more meshtypes for more exotic formats
  3. Write tests

Download Details:

Author: JuliaIO
Source Code: 
License: View license

#julia #3d 

MeshIO.jl: IO for Meshes
Nat  Grady

Nat Grady


D3 Coffee Wheel Visualization Ported to R Via Htmlwidgets Framework

An R Interface to D3-based Coffee Wheel

This is an htmlwidgets-based visualization tool for hierarchical data. It is zoomable, meaning that you can interact with the hierarchy and zoom in/out accordingly. 



This package is currently not on CRAN, but you can install it from GitHub via devtools:


Sample Plotting

coffeewheel(sampleWheelData, width=500, height=500, main="Sample Wheel Title", partitionAttribute="value");

Zoomable Wheel

Sample Data Structure

sampleWheelData <- list(
            list(name="R_1", colour="#110000"),
            list(name="R_3", colour="#330000"),
            list(name="R_5", colour="#550000"),
            list(name="R_7", colour="#770000"),
            list(name="R_9", colour="#990000"),
            list(name="R_b", colour="#bb0000"),
            list(name="R_d", colour="#dd0000"),
            list(name="R_f", colour="#ff0000")
            list(name="G_1", colour="#001100"),
            list(name="G_3", colour="#003300"),
            list(name="G_5", colour="#005500"),
            list(name="G_7", colour="#007700"),
            list(name="G_9", colour="#009900"),
            list(name="G_b", colour="#00bb00"),
            list(name="G_d", colour="#00dd00"),
            list(name="G_f", colour="#00ff00")
            list(name="B_1", colour="#000011"),
            list(name="B_3", colour="#000033"),
            list(name="B_5", colour="#000055"),
            list(name="B_7", colour="#000077"),
            list(name="B_9", colour="#000099"),
            list(name="B_b", colour="#0000bb"),
            list(name="B_d", colour="#0000dd"),
            list(name="B_f", colour="#0000ff")


This version of the wheel was adapted from Jason Davies's Coffee Wheel example. Built with D3.js. Sunburst zooming based on an example by Mike Bostock.

The visualization is D3-based and the actual wheel visualization code is adapted from:

Download Details:

Author: Armish
Source Code: 

#r #visualization #3d 

D3 Coffee Wheel Visualization Ported to R Via Htmlwidgets Framework
Oral  Brekke

Oral Brekke


5 Favorite Node.js 3D Libraries

In today's post we will learn about 5 Favorite Node.js 3D Libraries.

D3 (or D3.js) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.

1 - Math3d

Vectors, Quaternions, Matrices and Transforms for 3D graphics in Node.js


With npm:

npm install math3d


About Classes

All classes except Transform provide immutable objects.

Coordinate System

As I used this project later on with Unity3D, I tried to keep everything as similar as possible. The coordinate system is the same as in Unity: y-Axis up, x-Axis right, z-Axis forward. The rotation order for Euler angles (used in Quaternion) is z then x then y.


A three-dimensional vector with x, y, z values; used for positions, directions or scales in 3D space.

var Vector3 = math3d.Vector3;

var v1 = new Vector3(42, 42, 42);
v1.add(Vector3.up); // Vector3(42, 43, 42);

View on Github

2 - Node-occ

Build BREP Solids with OpenCascade and NodeJS - 3D Modeling

Installing node-occ from npm

$npm install node-occ

building node-occ from source : prerequisites

on (linux Ubuntu

(use nodejs 12 or 14)

# installing nodejs and gyp utility to build extensions
sudo apt-get install nodejs npm
sudo npm install node-pre-gyp -g
sudo npm install mocha@7 -g

#installing cmake
sudo apt-get install cmake cmake-curses-gui g++ build-essential libtbb2

# ------------------------------------
git clone --recursive
cd node-occ

# download prebuild OpenCascade Library and header files
bash ./

export OCCT_PACKAGE=occt-7.2.0
npm install --build-from-source

# verify that everything is working OK
make test

View on Github

3 - Node-shapeways

Node client for shapeways api



npm install shapeways


git clone git://
cd ./node-shapeways
npm install


You can build documentation with.

git clone git://
cd ./node-shapeways
make docs

Then access documentation at /docs/index.html

View on Github

4 - Aspose-3d-cloud-node

Node.js SDK to communicate with Aspose.3D REST API. Create, Edit or Convert 3D files & objects in the Cloud.

Get Started with Aspose.3D Cloud SDK for Node.js

Register an account at Aspose Cloud Dashboard to get you application information. Next, get the SDK package from NPM Distribution using the command npm install aspose3dcloud --save.

Convert PLY to PDF in Node.Js

// Get your ClientId and ClientSecret from (free registration required).
	const threeDCloudApi = new ThreeDCloudApi("MY_CLIENT_ID", "MY_CLIENT_SECRET");

	var req = new model.postConvertByFormatRequest() = "sample.ply";
    req.newformat = "pdf";
    req.newfilename = "saveasformat.pdf";
    req.folder = "3DTest";
    req.isOverwrite = true; = "My_Storage_Name";
    return threeDCloudApi.postConvertByFormat(req)
      .then((result) => {

View on Github

5 - Webgl-3d-animation

An interactive 3D animation using WebGL to depict a 2D predator prey ecology on a grid real-time mapped onto the surface of a 3D torus. Sound file is parsed then visualized both in time and frequency domains as well as rendered using Web Audio API - this is an exercise where I taught myself how to display data for an ongoing project on sound synthesis


Visit and install Node.js.

Clone this repository to your local machine:

git clone

Change directory into the project folder:

cd webgl-3d-animation

Then install the dependent modules:

npm install

Launch the nodejs app:

npm start

Using a WebGL savvy browser, point it at URL :


View on Github

Thank you for following this article. 

Related videos:

Top 5 JavaScript Libraries to Check Out Right Now!

#node #3d 

5 Favorite Node.js 3D Libraries

A toolbox To Represent 3D Rotations Of Coordinate Frames for Julia


This module contains functions related to the representation of 3D rotations of reference frames. It is used on a daily basis on projects at the Brazilian National Institute for Space Research (INPE).


This package can be installed using:

julia> Pkg.update()
julia> Pkg.add("ReferenceFrameRotations")


See the package documentation.

Download Details:

Author: JuliaSpace
Source Code: 
License: View license

#julia #3d 

A toolbox To Represent 3D Rotations Of Coordinate Frames for Julia

Fast and Robust 2D & 3D incircle/intriangle/etc. for Julia


Fast, robust 2D and 3D geometrical predicates on generic point types. Implementation follows algorithms described in the Arepo paper and used (for e.g.) in the Illustris Simulation. License: MIT. Bug reports welcome!

How does it work?

Calculations are initially performed on Float64 while bounding max absolute errors. If unable to determine result, fall back to exact calculation using BigInts. This is a form of floating point filtering. Most calculations are cached for fast repeated testing of incircle/intriangle predicates.

Current limitations

  • Due to the numerical methods used, all coordinates are internally represented as Float64. In addition all must reside in the range 1.0<=x<2.0. In this range, according to IEEE754, Float64s have a constant exponent, hence their mantissa can be used for a one to one mapping to integers, which in turn are used for exact calculations using BigInts.
  • It is assumed that primitive vertices don't overlap. It is currently the responsibility of the user to make sure this is the case.
  • It is assumed tetrahedron vertices don't all lie in the same line. It is the user's responsibility to make sure it is so.
  • Testing points are assumed not to overlap any vertices. As usual, it is the user's responsibility to make sure this is the case. Except for the 1st restriction, all others could be easily implemented. Currently these features are not needed by me. If you need missing features, please open an issue I may develop it!

How to use?


]add GeometricalPredicates

For Julia 0.6 and older



using GeometricalPredicates

# create a 2D point in (x, y) = (1.1, 1.9)
mypoint = Point(1.1, 1.9)
typeof(mypoint) # -> Point2D

# create a 3D point in (x, y, z) = (1.1, 1.9, 1.5)
mypoint = Point(1.1, 1.9, 1.5)
typeof(mypoint) # -> Point3D

# getting coordinates:
getx(mypoint) # -> 1.1
gety(mypoint) # -> 1.9
getz(mypoint) # -> 1.5

Point2D is a subtype of AbstractPoint2D, and Point3D is a subtype of AbstractPoint3D. You can implement custom point types by subtyping these abstract types. These custom point types can be used with the rest of the package:

type MyCustomPointType <: AbstractPoint2D

getx(p::MyCustomPointType) = p._x
gety(p::MyCustomPointType) = p._y

implementing getx, gety, and getz for 3D points is necessary as this is the interface the package is expecting. These function should return Float64. Points can be either immutables or types. Default Point2D and Point3D are immutables.

The point coordinates must reside in a region 1.0 <= x < 2.0. Read above on why this limitation is necessary. For convenience there are 2 constants defined, min_coord and max coord representing the minimal and maximal feasible values of coordinates.

Triangles and Tetrahedrons (..aka Primitives)

A triangle is the 2D primitive, and a tetrahedron is the 3D primitive.

# create a triangle using 3 points
a = Point(1.1, 1.1)
b = Point(1.9, 1.1)
c = Point(1.1, 1.9)
mytriangle = Primitive(a, b, c)
typeof(mytriangle) # -> UnOrientedTriangle{Point2D}

The triangle is unoriented in the sense that orientation is not-known in advance, it is not immutable and it could change if points in the triangle are updated. The orientation needs to be calculated when the triangle is created and when points within are updated. Read below for the definition of orientation. The triangle could be created using any points inheriting from AbstractPoint2D which implement getx and gety, or using coordinates directly:

mytriangle = Primitive(1.1, 1.1, 1.9, 1.1, 1.1, 1.9)

# Getting point `a` in the triangle
geta(mytriangle) # -> Point2D(1.1, 1.1)
getb(mytriangle) # -> Point2D(1.9, 1.1)
getc(mytriangle) # -> Point2D(1.1, 1.9)

The same goes for tetrahedrons, except we now use 4 3D points instead of 3 2D ones:

# create a tetrahedron using 4 points
a = Point(1.1, 1.1, 1.1)
b = Point(1.9, 1.1, 1.1)
c = Point(1.1, 1.9, 1.1)
d = Point(1.1, 1.1, 1.9)
mytetraedron = Primitive(a, b, c, d)
typeof(mytetrahedron) # -> UnOrientedTetrahedron{Point3D}

For certain applications we use primitives with known orientation. In those cases there should be no need to calculate it. This is achieved by passing an orientation flag to the Primitive creation function:

mytetrahedron = Primitive(a, b, c, d, positivelyoriented)
typeof(mytetrahedron) # -> PositivelyOrientedTetrahedron{Point3D}
orientation(mytetrahedron) # -> constant 1, not calculated
mytetrahedron = Primitive(a, b, c, d, negativelyoriented)
typeof(mytetrahedron) # -> NegativelyOrientedTetrahedron{Point3D}
orientation(mytetrahedron) # -> constant -1, not calculated

Note that when the primitive is oriented the real orientation is never calculated. It is assumed that the user knows what he's doing. If in doubt, just use unoriented primitives at the cost of actual calculation.

Updating points in primitives can be done with seta, setb, etc. methods:

seta(mytriangle, Point(1.7, 1.7))

Updating a point in a primitive will fire all relevant pre-calculations. i.e. if the triangle is unoriented then orientation will be calculated. If it is oriented then still a few other pre-calculations will be done, but a few less. If there is need to update a number of points it is thus more efficient to do so in a group update:

setab(mytriangle, Point(1.7, 1.7), Point(1.3, 1.1))
setbcd(mytetrahedron, Point(1.1, 1.1, 1.2), Point(1.2,1.1,1.3), Point(1.4,1.1,1.2))

combinations for all points exist. The name always contains the point names in alphabetical order. As long as inner primitive data is not changed manually, it will keep giving correct results for all functions in this package.


incircle is the popular name to test whether a point lies inside of the sphere defined by the primitive points:

a = Point(1.1, 1.1)
b = Point(1.5, 1.1)
c = Point(1.1, 1.5)
mytriangle = Primitive(a, b, c)
incircle(mytriangle, Point(1.9, 1.9)) # -> -1, i.e. outside
incircle(mytriangle, Point(1.2, 1.2)) # -> +1, i.e. inside
incircle(mytriangle, Point(1.5, 1.5)) # ->  0, i.e. point is exactly on circle

There is one more possibility. If the circle defined by our primitive has infinite radius then it is impossible to tell whether the point is inside or outside:

a = Point(1.1, 1.1)
b = Point(1.2, 1.2)
c = Point(1.3, 1.3)
mytriangle = Primitive(a, b, c)
incircle(mytriangle, Point(1.3, 1.4)) # -> +2, i.e. cannot tell

intriangle is a popular name to test whether a point lies inside of the primitive:

a = Point(1.1, 1.1)
b = Point(1.5, 1.1)
c = Point(1.1, 1.5)
mytriangle = Primitive(a, b, c)
intriangle(mytriangle, Point(1.2, 1.2)) # -> +1, i.e. inside
intriangle(mytriangle, Point(1.6, 1.6)) # -> -1, i.e. outside
intriangle(mytriangle, Point(1.3, 1.1)) # ->  4, i.e. exactly on ab
intriangle(mytriangle, Point(1.1, 1.3)) # ->  3, i.e. exactly on ac
intriangle(mytriangle, Point(1.3, 1.3)) # ->  2, i.e. exactly on bc

Here any negative number means outside. The exact value gives some information regarding the direction in which the point lies outside:

  • -1 means the test point is in front of a, and outside of the triangle
  • -2 means the test point is in front of b, and outside of the triangle
  • -3 means the test point is in front of c, and outside of the triangle same goes for tetrahedrons. Note that the point could be both in front of a and b. In cases as this one is arbitrarily chosen, all in name of performance.

1 means test point is inside. But there are other possible positive values:

  • 1 + 1 = 2 means the test point is in front of a, exactly on the triangle
  • 1 + 2 = 3 means the test point is in front of b, exactly on the triangle
  • 1 + 3 = 4 means the test point is in front of c, exactly on the triangle

same extends for tetrahedrons.

Lines and Polygons

orientation tests for the primitive orientation. In 2D this means:

  • 1 --> point c is to the left of the line defined by ab (with directionality from a to b)
  • -1 --> point c is to the right
  • 0 --> point c is exactly on the line

in 3D it means:

  • 1 --> point d is above the plane defined by abc (note "above" here means the direction of the plane normal, which depends on its orientation)
  • -1 --> point d is below the plane
  • 0 --> point c is exactly on the plane

Another convenience API to test for orientation in 2D is using a line. It has some performance advantages over creating a triangle:

a = Point(1.1, 1.1)
b = Point(1.5, 1.5)

l = Line(a, b)
println(orientation(l, Point(1.4, 1.6))) # -->  1
println(orientation(l, Point(1.4,1.05))) # --> -1
println(orientation(l, Point(1.4,1.40))) # -->  0

One can also create simple 2D polygons:

ll = Point(1.0,1.0)
lr = Point(1.2,1.0)
ur = Point(1.2,1.2)
ul = Point(1.0,1.2)
poly = Polygon(ll, lr, ur, ul)
inpolygon(poly, Point(1.1,1.1))  # assumes it is convex

Basic geometrical properties

orientation gives the primitive orientation. area, volume, centroid, circumcenter, circumradius2 are all exported and I hope self descriptive.

Spatial ordering

Scale and scale-free Peano-Hilbert ordering is available. Look here for a nice explanation on Hilbert sorting and here for a nice explanation of multiscale sort. Both are implemented here:

p = Point(1.1, 1.2)
peanokey(p, 4) # -> 6, the peano key in a regular grid of 2^4 X 2^4 cells

p = Point(1.1, 1.2, 1.3)
peanokey(p, 4) # -> 94, the peano key in a regular grid of 2^4 X 2^4 X 2^4 cells

The number of cells doesn't need to be specified. The default for 2D is 2^31 X 2^31 and for 3D 2^21 X 2^21 X 2^21. You can also do the inverse, and get a point from a key:

Point2D(6, 4) # -> Point2D(1.0625,1.1875)

in a finer grid we would get back something more accurate.

So that was scale-dependent Hilbert stuff, which is good to say balance workload between computing nodes. When you need to order particles spatially it is better to use a scale independent method, like the Hilbert ordering here:

a = [Point(1.0+rand(), 1.0+rand() for i in 1:1e6]

Here keys are never calculated, and there is no grid, it uses a median policy, adjusting to the actual point distribution. There are a few parameters with good defaults, see links above to understand what they mean. For an algorithm such a Delaunay tesselation it is sometimes better to use a multi-scale sort with a Hilbert sort, like this:


of course this adds a few more default parameters, again with decent defaults, read above links to understand.

Download Details:

Author: JuliaGeometry
Source Code: 
License: View license

#julia #3d 

Fast and Robust 2D & 3D incircle/intriangle/etc. for Julia
Monty  Boehm

Monty Boehm


MeshCat.jl: WebGL-based 3D Visualizer in Julia

MeshCat.jl: Julia bindings to the MeshCat WebGL viewer

MeshCat is a remotely-controllable 3D viewer, built on top of three.js. The viewer contains a tree of objects and transformations (i.e. a scene graph) and allows those objects and transformations to be added and manipulated with simple commands. This makes it easy to create 3D visualizations of geometries, mechanisms, and robots. MeshCat.jl runs on macOS, Linux, and Windows.

The MeshCat viewer runs entirely in the browser, with no external dependencies. All files are served locally, so no internet connection is required. Communication between the browser and your Julia code is managed by HTTP.jl. That means that MeshCat should work:

As much as possible, MeshCat.jl tries to use existing implementations of its fundamental types. In particular, we use:

That means that MeshCat should play well with other tools in the JuliaGeometry ecosystem like MeshIO.jl, Meshing.jl, etc.


Basic Usage

For detailed examples of usage, check out demo.ipynb.


To learn about the animation system (introduced in MeshCat.jl v0.2.0), see animation.ipynb.

Related Projects

MeshCat.jl is a successor to DrakeVisualizer.jl, and the interface is quite similar (with the exception that we use setobject! instead of setgeometry!). The primary difference is that DrakeVisualizer required Director, LCM, and VTK, all of which could be difficult to install, while MeshCat just needs a web browser. MeshCat also has better support for materials, textures, point clouds, and complex meshes.

You may also want to check out:


Create a visualizer and open it

using MeshCat
vis = Visualizer()

## In an IJulia/Jupyter notebook, you can also do:
# IJuliaCell(vis)


using GeometryBasics
using CoordinateTransformations

setobject!(vis, HyperRectangle(Vec(0., 0, 0), Vec(1., 1, 1)))
settransform!(vis, Translation(-0.5, -0.5, 0))


Point Clouds

using ColorTypes
verts = rand(Point3f, 100_000)
colors = [RGB(p...) for p in verts]
setobject!(vis, PointCloud(verts, colors))



# Visualize a mesh from the level set of a function
using Meshing
f = x -> sum(sin, 5 * x)
sdf = SignedDistanceField(f, HyperRectangle(Vec(-1, -1, -1), Vec(2, 2, 2)))
mesh = HomogenousMesh(sdf, MarchingTetrahedra())
setobject!(vis, mesh,
           MeshPhongMaterial(color=RGBA{Float32}(1, 0, 0, 0.5)))



See here for a notebook with the example.

# Visualize the permutahedron of order 4 using Polyhedra.jl
using Combinatorics, Polyhedra
v = vrep(collect(permutations([0, 1, 2, 3])))
using CDDLib
p4 = polyhedron(v, CDDLib.Library())

# Project that polyhedron down to 3 dimensions for visualization
v1 = [1, -1,  0,  0]
v2 = [1,  1, -2,  0]
v3 = [1,  1,  1, -3]
p3 = project(p4, [v1 v2 v3])

# Show the result
setobject!(vis, Polyhedra.Mesh(p3))





Author: rdeits
Source Code: 
License: MIT license

#julia #3d #webgl 

MeshCat.jl: WebGL-based 3D Visualizer in Julia
Reid  Rohan

Reid Rohan


Graphosaurus: 3D Graph Viewer Powered By WebGL (three.js)


A three-dimensional static graph viewer.

(click the image to try it out)

Twenty second tutorial

    #graph {
      width: 500px;
      height: 500px;
      border: 1px solid grey;
    <div id="graph"></div>

    <script src="graphosaurus.min.js"></script>
      // JavaScript will go here

If you open this up in your web browser, you'll see something that looks like this:

Look at that amazing square! Now let's create a graph, a couple nodes, and an edge between the nodes:

var graph = G.graph()

// Create a red node with cartesian coordinates x=0, y=0, z=0
var redNode = G.node([0, 0, 0], {color: "red"});

// You can also use the addTo method to add to the graph
var greenNode = G.node([1, 1, 1], {color: "green"}).addTo(graph);

var edge = G.edge([redNode, greenNode], {color: "blue"});
graph.addEdge(edge);  // or edge.addTo(graph)

// Render the graph in the HTML element with id='graph'

After inserting this JavaScript in the <script> block, you should see this:

While this is a very basic example, I hope I've demonstrated how simple it is to create graphs with Graphosaurus.


  1. Run git clone to clone this repository
  2. Install node, npm, and grunt-cli
  3. Run npm install to install all the build requirements
  4. Run grunt to build Graphosaurus. The resulting compiled JavaScript will be in dist/ and the docs will be in doc/



JSDoc generated API documentation can be found here.



John Conway's illustration of our glorious leader, the gryposaurus graphosaurus.

Similar projects


All files in this repository are licensed under version two of the Mozilla Public License.

Graphosaurus has some third party dependencies listed in the package.json file in the devDependencies and dependencies sections. Their licenses can be found on their respective project pages.

Author: frewsxcv
Source Code: 
License: MPL-2.0 license

#javascript #visualization #3d #webgl 

Graphosaurus: 3D Graph Viewer Powered By WebGL (three.js)

Как легко рендерить 3D в React с помощью React-three-fiber

Что, если бы я сказал вам… что вы тоже можете научиться кодировать 3D-объекты в React, которые удивят клиентов? Изучите основы рендеринга трех волокон, и достаточно скоро вы сможете превратить статическую страницу в художественную галерею, интерактивную карту или любую другую метавселенную.

Причины использования средства визуализации React 

3D-графика теперь расширяет возможности пользователей приложений, позволяя компаниям привлекать новых клиентов с помощью запоминающихся визуальных эффектов. Они могут представлять почти реалистичные продукты, такие как кроссовки или рюкзаки, которые можно персонализировать.

Усовершенствованные рендеры помогут вам совершить виртуальную экскурсию по корпоративному офису или даже выполнить упражнения по вождению в виртуальной реальности. Галерея, о которой я упоминал ранее, дала мне 10-минутный опыт выхода из тела.

Испытайте мечтательность реактивного 3D-пространства. Источник: пульсация

Из проектов трех волокон, которые я видел в Интернете, я заметил, что они нацелены на то, чтобы сделать продукт/услугу запоминающимся или понятным. Но вы также можете использовать свои навыки интерфейса, чтобы просто создать экспериментальную страницу портфолио как произведение искусства.

Это трудно сделать? Создание сцены с помощью Three.js

Обычно вы используете WebGL — API браузера для рендеринга 3D, что довольно сложно. Список определений, необходимых для обычного куба, сумасшедший. См. этот пример WebGL от Mozilla.

Визуализация упрощается с помощью высокоуровневой библиотеки Three.js, которая позволяет создавать 3D-среду с помощью более простого API. Введите всего несколько строк кода, и вы сможете создать проект React с простой сценой, в которой размещается куб.

// Setting up a scene that will be used to place objects
const scene = new THREE.Scene();
// Camera is the camera, eyes of your character
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
// We can set some WebGL parameters like antialiasing (softening sharp edges) 
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
// Boom, let's append our scene to the body
document.body.appendChild( renderer.domElement );
// Add light to the scene with Harry Potter's Lumos spell
const mainLight = new THREE.AmbientLight( '#FFFFFF' ); 
const pointLight = new THREE.PointLight( '#FFFFFF' ); 
scene.add( mainLight );
scene.add( pointLight );

Чтобы что-то увидеть, нужно объявить свой куб. Довольно просто.

// This is how we create simple cube
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: '#BADA55' } );
const cube = new THREE.Mesh( geometry, material );
// And add it to the existing scene
scene.add( cube );

Еще ничего? Хорошо, есть еще один шаг.

// recurring function that will render our scene and camera in WebGL renderer
// and request window to draw next frame of animation
const main = () => {
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  renderer.render(scene, camera);

Хотя это было довольно ясно, остальная часть кода имеет раздражающий стиль 2000-2010 годов.

const btn = document.createElement('button');
btn.innerText = 'Click Me';
btn.onclick = () => console.log('I am imperative');

Теперь импортируйте реактивное три волокна

Смешивание современных приложений React с кодом, подобным jQuery, — не лучшая идея для улучшения качества кода. Но здесь нашим спасением является реактивное трехволокно (R3F). Рендерер является декларативным, как и React , позволяя вам создавать автономный компонент 3D-сцены без затуманивающей сложности.

Добавьте R3Fи Three.js в качестве зависимостей к существующему приложению Create React . В качестве альтернативы используйте стартер TSH React с использованием yarn add three @react-three/fiberили npm install three @react-three/fiber –save.

Создайте функциональный компонент, который возвращает настройку сцены со светом.

import { Canvas, Camera } from 'react-three-fiber'

const MyAwesomeDeclarativeScene = () => {
  return (
    <Canvas camera={{ position: [0, 0, 1], fov: 45 }}>
      {/* We declare three.js object lowerCase without importing */}
      <ambientLight intensity={0.3} color="#FFFFFF" />
      <pointLight intensity={1.0} position={[10, 10, 10]} />

ReactDOM.render(MyAwesomeDeclarativeScene, document.getElementById('root'));

Ваша сцена почти готова. Теперь добавим куб, чтобы мы могли двигаться вперед и исследовать захватывающие возможности, которые предлагает R3F.

<mesh position={[0, 0, -1]}> 
  <boxGeometry args={[1, 1, 1]} /> 
  <meshStandardMaterial color='#BADA55' />

Вы используете сетчатый компонент React, который является оболочкой для различных  геометрий Three.js . Один из них boxGeometry представляет собой прямоугольный параллелепипед (или, как говорится, — коробку ). Добавьте один из возможных материалов Three.js, имитирующих глубину, чтобы увидеть своего чудесного малыша.

import { Canvas, Camera } from 'react-three-fiber'

const MyAwesomeDeclarativeScene = () => {
  return (
    <Canvas camera={{ position: [0, 0, 5], fov: 45 }}>
      <ambientLight intensity={0.3} color="#FFFFFF" />
      <pointLight intensity={1.0} position={[10, 10, 10]} />
      <mesh position={[0, 0, -1]}> 
        <boxGeometry args={[1, 1, 1]} /> 
        <meshStandardMaterial color='#BADA55' />

ReactDOM.render(MyAwesomeDeclarativeScene, document.getElementById('root'));

Что вам дает декларативный способ создания 3D в React? Прямой доступ ко всем наворотам React! Вы можете создавать собственные автономные компоненты, использовать реактивное состояние и делать все, что уже есть в React, простым и эффективным способом.

Как создать сцену с несколькими кубоидами

Клиент выходит из вашего шкафа и просит простое приложение с вращающимися и кликабельными 3D-боксами. Пользователь должен иметь возможность контролировать скорость вращения. Вам нужно доказательство концепции, сделанное на обед (за который вы платите). Как бы вы подошли к проекту?

Используйте компонент пользовательской Boxфункции для указания size, colorи speedFactor. Код ниже присваивает значение по умолчанию некоторым дополнительным свойствам, которые можно изменить позже — не беспокойтесь.

Используйте обычные useStateоператоры для отслеживания зависания и активного состояния. Добавьте boxRef , чтобы сохранить ссылку на вашу сетку, так как это позволяет вам манипулировать объектом через useFrame обратный вызов. Пожалуйста, анализируйте приведенный ниже код в своем темпе, пока не поймете его.

import React, { useMemo, useRef, useState } from 'react';
import { MeshProps, useFrame } from 'react-three-fiber';

type BoxProps = {
  size?: [number, number, number];
  color?: string;
  boxSpeed?: number;
} & MeshProps;

export const Box = ({ size = [1, 1, 1], color = '#FFFFFF', boxSpeed = 0.01, ...meshProps }: BoxProps) => {
  const boxRef = useRef<MeshProps | null>(null);
  const [isHovered, setIsHovered] = useState(false);
  const [isSelected, setIsSelected] = useState(false);

  // It is react-three-fiber way to trigger animation
  // each frame we are changing x, y, z rotation of our box
  useFrame(() => {
    if (!boxRef.current) {
    boxRef.current.rotation.x += boxSpeed;
    boxRef.current.rotation.y += boxSpeed;
  // it is color memo which indicates state of an item
  const calculatedColor = useMemo(() => {
    if (isSelected && isHovered) {
      return 'orange';
    if (isSelected) {
      return 'yellow';
    if (isHovered && !isSelected) {
      return 'red';
    return color;
  }, [color, isHovered, isSelected]);

  return (
      onPointerOver={() => setIsHovered(true)}
      onPointerLeave={() => setIsHovered(false)}
      onClick={() => setIsSelected((prev) => !prev)}
      scale={isSelected ? [1.2, 1.2, 1.2] : [1, 1, 1]}
      <boxGeometry args={size} />
      <meshStandardMaterial color={calculatedColor} />

Итак, ваша сцена теперь использует потрясающе настраиваемый Boxкомпонент. Для того, чтобы дать пользователю возможность управлять скоростью вращения, добавьте диапазон ввода в ваш JSX structureи useState, который будет содержать информацию о скорости.

export const Scene = () => {
  const [speedFactor, setSpeedFactor] = useState(1);

  return (
      <label htmlFor="speedFactor">
        Speed factor:
          onChange={(e) => setSpeedFactor(+e.currentTarget.value)}
      <Canvas camera={{ position: [0, 0, 5], fov: 45 }}>
        <ambientLight intensity={0.3} color="#FFFFFF" />
        <pointLight intensity={1.0} position={[10, 10, 10]} />
        <Box position={[-2, 1, 0]} rotation={[3, 1, 0]} color="hotpink" boxSpeed={0.02 * speedFactor} />
        <Box position={[2, 1, 0]} rotation={[1, 1, 0]} color="cyan" boxSpeed={0.01 * speedFactor} />
        <Box position={[0, -1, 0]} size={[1, 2, 2]} boxSpeed={0.005 * speedFactor} />

Небольшой пакет кода может содержать много чудес! Как только вы освоите react-three-fiber, вы будете готовы играть с Three.jsего богатыми функциями. И результат?

React-three-fiber предлагает потрясающий опыт разработчика в одной таблетке

Средство визуализации имеет собственный опыт разработки, выходящий за рамки декларативного стиля. R3F имеет выдающуюся поддержку Typescript , которая постоянно проверяет ваши типы.

Оптимизация производительности в R3F меняет правила игры, поскольку цикл рендеринга сцены three.js полностью отделен от виртуального DOM React.

Кроме того, у react-three-fiber есть отличная экосистема служебных библиотек. Существует @react-three/cannon для создания контента, основанного на физике, или @react-three/drei . Последний предлагает множество функций React с тремя волокнами, которые могут сэкономить часы на создании впечатляющей 3D-сцены, обогащенной потрясающими эффектами постобработки.


#react #3d

Как легко рендерить 3D в React с помощью React-three-fiber