ANYtk3D
Fast dependency-free 3D drawing on a Tkinter Canvas.
ANYtk3D is the standalone 3D viewport extracted from
ANYstructure. It renders
solids, stiffened plates, cylinders and arbitrary meshes directly on a
tkinter.Canvas — no OpenGL, no matplotlib, only numpy and the standard
library.
Features
- Typical shapes out of the box — box, sphere, cone, truncated cone, cylinder, tube/pipe, torus, pyramid, wedge, prism, swept extrusion, disk/annulus, plane, arrow, ground grid, structural beam profiles (FB, T, I, L, C, BOX) and arbitrary index meshes
- Directional lighting — ambient + Lambert diffuse + Blinn-Phong highlight, flat-shaded per face, two-sided, world-fixed or head-lamp
- Correct depth order — every face is painted back to front by camera-space depth, closed solids cull their back faces, faces straddling the near plane are clipped instead of dropped, and 3D lines take part in the same sort
- Layered transparency — 16 screen-door density steps with non-overlapping windows per layer, so a transparent shell shows its far wall, its contents and its near wall at once
- Built for speed — geometry is compiled to numpy arrays once and every frame is vectorised; canvas items are pooled and only reconfigured when their appearance changes; the interactive level of detail self-tunes from measured frame times
- Result fields and animation — a batched
add_facescall for meshes coloured per element, plus frame capture and playback that adapts its detail to the requested frame rate - Camera orbit, zoom and pan; plate colour-coding by thickness (or any scalar) with a fixed legend; X/Y/Z axis overlay and optional rulers; animation caching and playback
Installation
pip install ANYtk3D
Tkinter ships with the standard CPython installers.
Quick start
import tkinter as tk
from anytk3d import Point3D, Tkinter3DCanvas
root = tk.Tk()
canvas = Tkinter3DCanvas(root, width=900, height=600, bg='white')
canvas.pack(fill='both', expand=True)
canvas.add_box(2.0, 1.0, 0.5, center=Point3D(-3, 0, 0.25), color='#4e79a7')
canvas.add_sphere(0.8, center=Point3D(0, 0, 0.8), color='#f28e2b')
canvas.add_tube(0.8, 0.5, 2.0, center=Point3D(3, 0, 1.0), color='#59a14f')
canvas.add_beam(Point3D(-4, 3, 0), Point3D(4, 3, 0), kind='I',
web_height=0.6, flange_width=0.3)
canvas.add_grid(size_x=12, size_y=10)
canvas.fit_to_scene()
root.mainloop()
Shapes
add_box, add_box_from_bounds, add_sphere, add_cone,
add_frustum, add_cylinder, add_tube, add_torus, add_pyramid,
add_wedge, add_prism, add_extrusion, add_disk, add_plane,
add_arrow, add_beam, add_grid, add_mesh, add_shape,
plus the original add_polygon, add_line, add_text,
add_rectangular_plate, add_flat_stiffener, add_flat_girder,
add_longitudinal_stiffener and add_ring_stiffener.
Every shape builder takes center/axis placement and the same material
keywords — color, outline, opacity, layer, cull_backface,
lit, back_color, face_colors, tags.
The tessellation lives in anytk3d.shapes as plain functions returning a
Mesh (vertices plus index faces), so it can be used, combined and
tested without a display:
from anytk3d import shapes
mesh = shapes.torus(2.0, 0.4).merged(shapes.sphere(0.5))
canvas.add_shape(mesh, position=Point3D(0, 0, 3), color='#b07aa1')
Lighting
canvas.set_light(direction=Point3D(0.4, -0.6, 0.7), ambient=0.45,
diffuse=0.55, specular=0.12)
canvas.set_light(follow_camera=True) # head lamp that orbits with the view
canvas.set_shading(False) # flat colours, no shading
Ambient and diffuse sum to 1.0 by default, so a face turned toward the light renders in its exact base colour and every other face only darkens. That keeps colour-coded scenes matching their legend.
Transparency
opacity runs from 0 to 1 in 16 usable steps. A Tk canvas has no alpha
channel, so this is screen-door stippling — but the front and back of a
surface are given non-overlapping dither windows, sized so that stacking
them reproduces ordinary alpha compositing (1 - (1 - a)^2). Passing an
explicit stipple= string still uses that exact Tk pattern.
canvas.add_sphere(2.0, color='#7fb3d5', opacity=0.35) # see the contents
canvas.add_box(1.0, 1.0, 1.0, color='#c0392b') # ...through the shell
Result fields
add_faces is the batched path for a mesh where every element carries its
own colour — an FE stress plot, a deformed shape, a utilisation map. It
takes the whole element set in one call and computes all the centroids and
normals as array operations:
canvas.add_faces(polygons, colors=element_colors, outline='#64748b')
canvas.set_thickness_legend([0, 80, 160, 240], unit='MPa', title='von Mises')
polygons is a sequence of vertex sequences (Point3D or (x, y, z)), or
an (faces, vertices, 3) array. On a 4900-element field this compiles in
4.5 ms against 48 ms for the same elements added one at a time.
Animation
Capture a scene per step, then replay it:
canvas.begin_animation_cache()
for step in range(frames):
canvas.clear(keep_canvas=True)
canvas.add_faces(deformed_shape(step), colors=field_colors(step))
canvas.capture_animation_frame()
canvas.play_animation(fps=30) # fast=None/True/False
A scene without cylinders or stiffeners compiles to a single shared
representation, so each captured frame costs one build rather than two.
Playback defaults to fast=None, which starts at full detail and drops to
the reduced-detail path as soon as a frame overruns its slot; pass True
or False to pin it. animation_frames, animation_frame_index and
is_playing_animation are available for a progress readout.
Performance
Interactive frames use a reduced-detail scene with a face budget that adapts to the measured frame rate, so orbiting stays responsive on dense models and full detail returns when the mouse is released.
canvas.set_interactive_detail(4000) # starting face budget while dragging
canvas.set_mesh_lines(False) # drop per-face outlines
canvas.set_occlude_lines(False) # keep 3D lines on top of geometry
Demos
The interactive showcase — shapes with live light controls, a colour-coded FE result field, animation playback with a measured frame rate, and a stiffened cylinder — is a single file you can run straight from an IDE (right-click → Run in PyCharm) or from a shell:
python -m anytk3d.demo
The original four-viewport demo is still there:
python -m anytk3d
or embed it in an existing Tk application with
anytk3d.create_stiffened_cylinder_demo(root).
Relation to ANYstructure
ANYstructure uses this package for its 3D previews. The module keeps its
original API (Tkinter3DCanvas, Point3D, Camera3D and every
add_* method) so it stays a drop-in dependency.
Development
pip install -e .[dev]
pytest
License
GPL-3.0-or-later. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anytk3d-0.2.0.tar.gz.
File metadata
- Download URL: anytk3d-0.2.0.tar.gz
- Upload date:
- Size: 84.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a3f3ffdcb6eb2cfa7635e60d5b468a8e093fe9661978949a5ca7f813beb4a0b
|
|
| MD5 |
44c98b9d0f146d6591ffca5858923fe0
|
|
| BLAKE2b-256 |
bc76fa7a4b6b91ac310564bf0fe3f93ab846ae18f2a3d7f4c9eef7fa39b4ddec
|
File details
Details for the file anytk3d-0.2.0-py3-none-any.whl.
File metadata
- Download URL: anytk3d-0.2.0-py3-none-any.whl
- Upload date:
- Size: 77.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c07ad42eb63b87da9e8e7942db0c939868d0e8dd58ecabcece52e02a2517cb98
|
|
| MD5 |
f3257697ec66abcbb86924d3a27963d3
|
|
| BLAKE2b-256 |
50b125a8edfc0cac2ca08afcbb6a2b461ee01893d0ce3f7408a60af4b31a5c00
|