Index
Base.convert
Base.convert
Luxor.between
Luxor.between
Luxor.distance
Luxor.distance
Luxor.drawpath
Luxor.midpoint
Luxor.midpoint
Thebes.anglebetweenvectors
Thebes.anglebetweenvectors
Thebes.axes3D
Thebes.axes3D
Thebes.carpet
Thebes.carpet
Thebes.cartesiantospherical
Thebes.cartesiantospherical
Thebes.cartesiantospherical
Thebes.centerpoint
Thebes.crossproduct3D
Thebes.crossproduct3D
Thebes.dotproduct3D
Thebes.dotproduct3D
Thebes.drawcube
Thebes.drawcube
Thebes.eyepoint
Thebes.face
Thebes.helloworld
Thebes.hiddensurface
Thebes.import_off_file
Thebes.magnitude
Thebes.magnitude
Thebes.make
Thebes.moveby
Thebes.moveby
Thebes.moveby
Thebes.moveby!
Thebes.moveby!
Thebes.moveby!
Thebes.newprojection
Thebes.objecttopoly
Thebes.perspective
Thebes.pin
Thebes.pin
Thebes.pin
Thebes.pin
Thebes.pointsperpendicular
Thebes.pointsperpendicular
Thebes.project
Thebes.rotateX
Thebes.rotateX
Thebes.rotateY
Thebes.rotateY
Thebes.rotateZ
Thebes.rotateZ
Thebes.rotateby
Thebes.rotateby
Thebes.rotateby
Thebes.rotateby
Thebes.rotateby
Thebes.rotateby!
Thebes.rotateby!
Thebes.rotateby!
Thebes.rotateby!
Thebes.rotateby!
Thebes.scaleby!
Thebes.scaleby!
Thebes.scaleby!
Thebes.scaleby!
Thebes.sortfaces!
Thebes.sphericaltocartesian
Thebes.sphericaltocartesian
Thebes.sphericaltocartesian
Thebes.surfacenormal
Thebes.surfacenormal
Thebes.text3D
Thebes.text3D
Thebes.uppoint
Thebes.uppoint
Thebes.wireframe
Base.convert
— Methodconvert(Point3D, pt::Point, z)
Convert pt
to a Point3D(pt.x, pt.y, z).
Base.convert
— Methodconvert(Point3D, pt::Point)
Convert pt
to a Point3D(pt.x, pt.y, 0).
Luxor.between
— Functionbetween(p1::Point3D, p2::Point3D, x=0.5)
between((p1::Point3D, p2::Point3D), x=0.5)
Find a point on a line between two 3D points. If x
is 0.5, the returned point should be halfway between them.
Luxor.distance
— Methoddistance(p1::Point3D, p2::Point3D)
Return the distance between two points.
Luxor.drawpath
— Methoddrawpath(path::Path, k::Real, anchor::Point3D;
about=Point3D(0., 0., 0.),
rotation::Rotation=RotXYZ(0, 0, 0),
steps=20, # used when approximating Bezier curve segments
action=:none,
startnewpath=true,
pathlength = 0.0)
Draw a Luxor Path object on a 2D plane, starting at anchor
with rotation
about about
.
Luxor.midpoint
— Methodmidpoint(pt1::Point3D, pt2::Point3D)
Find the midpoint between two points. See also between()
.
Thebes.anglebetweenvectors
— Methodanglebetweenvectors(v1::Point3D, v2::Point3D)
Calclate the angle between two vectors.
Thebes.axes3D
— Functionaxes3D(n=100)
Draw labelled 3D axes at (0, 0, 0)
with length n
.
Thebes.carpet
— Functioncarpet(n; kind=:circular)
Draw a circular carpet centered at the origin, using current Luxor parameters.
If kind
is not :circular
, the carpet will be a square.
Points that can't be rendered are not included in the final shape.
Thebes.cartesiantospherical
— Methodcartesiantospherical(x, y, z)
Return (ρ, θ, ϕ)
(radius, longitude, colatitude) of the Point3D(x, y, z).
Thebes.cartesiantospherical
— Methodcartesiantospherical(pt::Point3D)
Return (ρ, θ, ϕ)
(radius, longitude, colatitude) of pt
.
Thebes.centerpoint
— Methodcenterpoint()
centerpoint(pt::Point3D)
Get or set the current center position.
Thebes.crossproduct3D
— Methodcrossproduct3D(A::Point3D, B::Point3D)
Find one of these.
Thebes.dotproduct3D
— Methoddotproduct3D(a::Point3D, b::Point3D)
Finds the dot product of a and b
Thebes.drawcube
— Functiondrawcube(n=10, action=:stroke)
Draw a cube. drawcube(1)
draws a wireframe unit cube.
Thebes.eyepoint
— Methodeyepoint()
eyepoint(pt::Point3D)
Get or set the current eye position.
Thebes.face
— Methodface(o::Object, n)
Thebes.helloworld
— Methodhelloworld()
Reset all the things. The equivalent of typing:
eyepoint(100, 100, 100)
centerpoint(0, 0, 0)
uppoint(0, 0, 10)
perspective(0)
hiddensurface(o::Object)
Given an object o
, sort the faces in o.faces
, then draw filled grey polygons for each face.
Thebes.import_off_file
— Methodimport_off_file(fname)
Import a file in OFF (Object File Format).
Returns a Tuple - vertices, and faces. Vertices is a vector of [x, y, z], and faces a vector of vectors of vertex numbers.
off_file = raw"
OFF
8 6 0
-0.500000 -0.500000 0.500000
0.500000 -0.500000 0.500000
-0.500000 0.500000 0.500000
0.500000 0.500000 0.500000
-0.500000 0.500000 -0.500000
0.500000 0.500000 -0.500000
-0.500000 -0.500000 -0.500000
0.500000 -0.500000 -0.500000
4 0 1 3 2
4 2 3 5 4
4 4 5 7 6
4 6 7 1 0
4 1 7 5 3
4 6 0 2 4
"
f = open("/tmp/cube.off", "w") do f
write(f, off_file)
end
@draw begin
o = make(import_off_file("/tmp/cube.off"))
scaleby!(o, 100)
pin(o)
end
Thebes.magnitude
— Methodmagnitude(a::Point3D)
Calculates magnitude of a.
Thebes.make
— Functionmake(primitive, name="unnamed")
primitive
contains two arrays, an array of 3D points, and an array of faces, where each face is a list of vertex numbers.
Returns a Object.
Example
make(Cube, "cube")
returns an Object object containing an array of vertices, an array of faces, and an array of labels.
@draw begin
helloworld()
tol = 0.01
a = []
sethue("black")
for t in -2pi:tol:2pi
push!(a, Point3D((50 + cos(5t)) * cos(3t), (50 + cos(5t)) * sin(2t), sin(5t)))
end
Knot = make((a, []), "knot")
pin(Knot, gfunction=(args...) -> begin
for verts in args[1].vertices
pin(verts)
end
end)
end
The default gfunction expects faces - if there aren't any, use a gfunction that draws vertices.
Thebes.moveby!
— Methodmoveby!(o::Object, x, y, z)
moveby!(o::Object, pt::Point3D)
Set the position of object to Point3D(x, y, z).
Thebes.moveby!
— Methodmoveby!(ptlist::Point3D, x, y, z)
moveby!(ptlist::Point3D, pt::Point3D)
Move all points in the list by a vector.
Thebes.moveby
— Methodmoveby(o::Object, x, y, z)
moveby(o::Object, pt::Point3D)
Set the position of a copy of the object to Point3D(x, y, z).
Thebes.moveby
— Methodmoveby(pt::Point3D, d::Point3D)
Return a new point that's the result of moving a point pt
by a vector d
.
Thebes.newprojection
— Functionnewprojection(ipos::Point3D, center::Point3D, up::Point3D, perspective=0.0)
Define a new Projection:
- ipos is the eye position
- center is the 3D point to appear in the center of the 2D image
- up is a point that is to appear vertically above the center
If perspective
is 0.0 (the default) the projection is parallel. Otherwise it's a vague magnification factor for perspective projections.
The three vectors U, V, W, and the three scalar products, ue, ve, and we:
- U is at right angles to line of sight w, and to t-e, so it corresponds to
the x axis of the 2D image
- V is at right angles to u and to the line of sight, so it's the y axis of the
2D image
W is the line of sight
we is the projection of the eye position onto w
ue is the projection of the eye position onto that x-axis
ve is the projection of the eye position onto that y axis
Thebes.objecttopoly
— Methodobjecttopoly(o::Object)
Return a tuple:
an array of 2D points representing the vertices of
o
an array of 2D polygons representing the faces of
o
Example
This example draws the faces of a cube in colors, and marks the vertices in black.
using Luxor, Thebes
@draw begin
helloworld()
o = make(Cube)
scaleby!(o, 100, 100, 100)
vs, fs = objecttopoly(o)
setopacity(0.4)
sethue("black")
for face in fs
randomhue()
poly(face, :fill)
end
sethue("black")
circle.(vs, 3, :fill)
end
Thebes.perspective
— Methodperspective()
perspective(n)
Get or set the current perspective.
Thebes.pin
— Methodpin(o::Object;
gfunction=(o) -> hiddensurface(o))
Draw a rendering of an object.
The default rendering function is hiddensurface()
.
You can also use the built-in wireframe()
rendering function.
Examples
@draw begin
o = make(Cube)
axes3D(200)
scaleby!(o, 200, 200, 200)
eyepoint(250, 270, 300)
pin(o) # use an attempted hiddensurface rendering
o = make(Tetrahedron)
axes3D(200)
scaleby!(o, 200, 200, 200)
eyepoint(250, 270, 300)
pin(o, gfunction=wireframe) # use a wireframe rendering
end
More help
You could write your own rendering function to draw objects.
function a_rendering_function(o::Object)
if !isempty(o.faces)
sortfaces!(o)
@layer begin
for (n, face) in enumerate(o.faces)
@layer begin
vertices = o.vertices[face]
sn = surfacenormal(vertices)
ang = anglebetweenvectors(sn, eyepoint())
setgrey(rescale(ang, 0, π, 1, 0))
pin(vertices, gfunction = (p3, p2) ->
begin
poly(p2, :fill)
sethue("white")
poly(p2, :stroke, close=true)
end)
end
end
end
end
end
Thebes.pin
— Methodpin(p3_1::Point3D, p3_2::Point3D;
gfunction = ((p3_1, p3_2), (p2_1, p2_2)) ->
line(p2_1, p2_2, :stroke))
Draw two 3D points.
The default action is to draw a line between two points.
The gfunction can access the 3D points as the first argument, the two 2D points in the second argument.
pin(p, Point3D(50cos(θ), 50sin(θ), p.z),
gfunction = (p3s, p2s) -> begin
line(p2s..., :stroke)
end)
Returns the two 2D points.
Thebes.pin
— Methodpin(pt::Point3D;
gfunction = (p3, p2) -> circle(p2, 1, :stroke))
Draw a single 3D point on the current Luxor drawing.
The default graphic is a circle. You can define others using a custom gfunction, which takes two arguments: the 3D point and its 2D counterpoint.
For example, this draws a circle whose radius is larger if the point is nearer to the eye.
pin(p, gfunction = (p3, p2) -> begin
d = distance(p3, eyepoint())
circle(p2, rescale(d, 0, 300, 20, 5), :fill)
end
)
Returns the 2D point.
Thebes.pin
— Methodpin(p3list::Array{Point3D, 1};
gfunction = (p3list, p2list) ->
poly(p2list, :stroke, close=true))
Draw an array of 3D points.
The default action is to draw a polygon through all the points.
The gfunction can access the 3D points as the first argument, the two 2D points in the second argument.
helix = [Point3D(100cos(θ), 100sin(θ), 20θ) for θ in 0:π/12:4π]
a_box = pin(helix, gfunction =
(p3list, p2list) -> prettypoly(p2list, :stroke)
)
Returns the list of 2D points.
Thebes.pointsperpendicular
— Functionpointsperpendicular(p1::Point3D, p2::Point3D, radius, angles = [0, π])
Find points perpendicular to a line joining p1 and p2. Points are radius
units away from the line.
Thebes.project
— Methodproject(P::Point3D)
Project a 3D point onto a 2D surface, as defined by the current projection.
TODO Currently this returns 'nothing' if the point is behind the eyepoint. This makes handling the conversion a bit harder, though, since the function now returns either a 2D Luxor point or nothing
.
using Thebes, Luxor
@svg begin
eyepoint(Point3D(250, 250, 100))
centerpoint(Point3D(0, 0, 0))
uppoint(Point3D(0, 0, 10))
sethue("grey50")
carpet(300)
axes3D(100)
sethue("red")
for i in 1:30
randpoint3D = Point3D(rand(0.0:150, 3)...)
sethue("red")
pt1 = pin(randpoint3D)
if pt1 != nothing
circle(pt1, 5, :fill)
end
end
end
Thebes.rotateX
— MethodrotateX(pt3D::Point3D, rad)
Return a new point resulting from rotating the point around the x axis by an angle in radians.
Rotations are anticlockwise when looking along axis from 0 to +axis.
Thebes.rotateY
— MethodrotateY(pt3D::Point3D, rad)
Return a new point resulting from rotating the point around the y axis by an angle in radians.
Rotations are anticlockwise when looking along axis from 0 to +axis.
Thebes.rotateZ
— MethodrotateZ(pt3D::Point3D, rad)
Return a new point resulting from rotating the point around the z axis by an angle in radians.
Thebes.rotateby!
— Methodrotateby!(o::Object, r::Rotation)
rotateby!(o::Object, angleX, angleY, angleZ)
Rotate an object through rotation r
, or around the x, y, and/or z axis by angleX
, angleY
, angleZ
.
Thebes.rotateby!
— Methodrotateby!(o::Object, pt::Point3D, angleX, angleY, angleZ)
rotateby!(o::Object, pt::Point3D, r::Rotation=RotXYZ(0, 0, 0))
Rotate an object around a point by rotation r, or angleX, angleY, angleZ.
Thebes.rotateby!
— Methodrotateby!(ptlist::Array{Point3D, 1}, angleX, angleY, angleZ)
Modify a list of points by rotating each one around the x, y, and z axes by angleX, angleY, angleZ.
Thebes.rotateby!
— Methodrotateby!(ptlist::Array{Point3D, 1}, existingpt::Point3D, angleX, angleY, angleZ)
rotateby!(ptlist::Array{Point3D, 1}, existingpt::Point3D, r::Rotation)
rotateby!(ptlist::Array{Point3D, 1}, r::Rotation=RotXYZ{Float64})
Rotate each point in the list by rotation (or angleX, angleY, angleZ) around another point (or origin).
Thebes.rotateby
— Methodrotateby(o::Object, angleX, angleY, angleZ)
Rotate a copy of the object by angleX, angleY, angleZ.
Thebes.rotateby
— Methodrotateby(o::Object, pt::Point3D, angleX, angleY, angleZ)
rotateby(o::Object, pt::Point3D, r::Rotation=RotXYZ(0, 0, 0))
Rotate a copy of the object around a point by rotation r, or angleX, angleY, angleZ.
Thebes.rotateby
— Methodrotateby(pt::Point3D, angleX, angleY, angleZ)
rotateby(ptlist::Array{Point3D, 1}, angleX, angleY, angleZ)
rotateby(point::Point3D, r::Rotation)
rotateby(ptlist::Array{Point3D, 1}, r::Rotation)
Return a new point/list of points resulting from rotating around the x, y, and z axes by angleX, angleY, angleZ.
The Z rotation is first, then the Y, then the X.
A 3×3 rotation matrix parameterized by the "Tait-Bryant" XYZ Euler angle convention, consisting of first a rotation about the Z axis by theta3, followed by a rotation about the Y axis by theta2, and finally a rotation about the X axis by theta1.
Thebes.rotateby
— Methodrotateby(point::Point3D, about::Point3D, angleX, angleY, angleZ)
rotateby(point::Point3D, about::Point3D, r::Rotation)
rotateby(ptlist::Array{Point3D, 1}, about::Point3D, r::Rotation)
Thebes.scaleby!
— Methodscaleby!(o::Object, x, y, z)
Scale object by x in x, y in y, and z in z.
Thebes.scaleby!
— Methodscaleby!(o::Object, d)
Scale object by d in x, d in y, and d in z.
Thebes.scaleby!
— Methodscaleby!(ptlist::Array{Point3D, 1}, x, y, z)
Scales a list of points by multiplying by x
in X, y
in Y, z
in Z.
Thebes.sortfaces!
— Methodsortfaces!(o::Object;
eyepoint::Point3D=eyepoint())
Find the averages of the z values of the faces in Object, and sort the faces of o so that the faces are in order of nearest (highest) z relative to eyepoint...
or something like that ? not sure how this works
Thebes.sphericaltocartesian
— Methodsphericaltocartesian(ρ, θ, ϕ)
Return Point3D(x, y, z)
corresponding to (ρ, θ, ϕ)
:
ρ is the distance from the origin (ie radius)
θ is the azimuthal angle (the longitude) 0 is +x, π is -x, 2π is +x
ϕ is the polar angle (the colatitude) 0 is North Pole, π is South Pole
There are two major conventions for spherical coordinate notation.
In physics books:
(ρ, θ, φ) gives the radial distance, polar angle (colatitude), and azimuthal angle (longitude)
In mathematics books:
(ρ, θ , φ ) gives the radial distance, azimuthal angle (longitude), and polar angle (colatitude)
So we're using the mathematics one here.
Thebes.sphericaltocartesian
— Methodsphericaltocartesian((ρ, θ, ϕ))
Return Point3D(x, y, z)
corresponding to (ρ, θ, ϕ)
.
Thebes.surfacenormal
— Methodsurfacenormal(ptlist::Array{Point3D, 1})
Finds one of these.
Thebes.text3D
— Method text3D(str, anchor::Point3D;
halign=:left,
valign=:baseline,
about=Point3D(0., 0., 0.),
rotation::Rotation=RotXYZ(0, 0, 0))
Draw text at point pt
, lying in the plane of the x axis. Angles in rotation
rotate the text about the about
point, defaulting to Point3D(0, 0, 0)
.
Uses Luxor's fontface()
and fontsize()
settings.
Specify rotations using functions from Rotations.jl, such as:
RotX(a)
RotZ(a)
RotXZ(a1, a2)
RotXYZ(a1, a2, a3)
Thebes.uppoint
— Methoduppoint(pt::Point3D)
Specify the "up" direction for the world: a line from the centerpoint to the uppoint defines the up direction.
Thebes.uppoint
— Methoduppoint()
uppoint(pt::Point3D)
The "up" direction for the world: a line from the centerpoint to the uppoint defines the up direction.
Thebes.wireframe
— Methodwireframe(o::Object)
Given an object o
, sort the faces in o.faces
, then draw grey stroked polygons for each face.