Simple SDF mesh generation in Python

Overview

sdf

Generate 3D meshes based on SDFs (signed distance functions) with a dirt simple Python API.

Special thanks to Inigo Quilez for his excellent documentation on signed distance functions:

Example

Here is a complete example that generates the model shown. This is the canonical Constructive Solid Geometry example. Note the use of operators for union, intersection, and difference.

from sdf import *

f = sphere(1) & box(1.5)

c = cylinder(0.5)
f -= c.orient(X) | c.orient(Y) | c.orient(Z)

f.save('out.stl')

Yes, that's really the entire code! You can 3D print that model or use it in a 3D application.

More Examples

Have a cool example? Submit a PR!

gearlike.py knurling.py blobby.py weave.py
gearlike knurling blobby weave
gearlike knurling blobby weave

Requirements

Note that the dependencies will be automatically installed by setup.py when following the directions below.

  • Python 3
  • numpy
  • Pillow
  • scikit-image
  • scipy

Installation

Use the commands below to clone the repository and install the sdf library in a Python virtualenv.

git clone https://github.com/fogleman/sdf.git
cd sdf
virtualenv env
. env/bin/activate
pip install -e .

Confirm that it works:

python examples/example.py # should generate a file named out.stl

You can skip the installation if you always run scripts that import sdf from the root folder.

Viewing the Mesh

Find and install a 3D mesh viewer for your platform, such as MeshLab.

I have developed and use my own cross-platform mesh viewer called meshview (see screenshot). Installation is easy if you have Go and glfw installed:

$ brew install go glfw # on macOS with homebrew
$ go get -u github.com/fogleman/meshview/cmd/meshview

Then you can view any mesh from the command line with:

$ meshview your-mesh.stl

See the meshview README for more complete installation instructions.

On macOS you can just use the built-in Quick Look (press spacebar after selecting the STL file in Finder) in a pinch.

API

In all of the below examples, f is any 3D SDF, such as:

f = sphere()

Bounds

The bounding box of the SDF is automatically estimated. Inexact SDFs such as non-uniform scaling may cause issues with this process. In that case you can specify the bounds to sample manually:

f.save('out.stl', bounds=((-1, -1, -1), (1, 1, 1)))

Resolution

The resolution of the mesh is also computed automatically. There are two ways to specify the resolution. You can set the resolution directly with step:

f.save('out.stl', step=0.01)
f.save('out.stl', step=(0.01, 0.02, 0.03)) # non-uniform resolution

Or you can specify approximately how many points to sample:

f.save('out.stl', samples=2**24) # sample about 16M points

By default, samples=2**22 is used.

Tip: Use the default resolution while developing your SDF. Then when you're done, crank up the resolution for your final output.

Batches

The SDF is sampled in batches. By default the batches have 32**3 = 32768 points each. This batch size can be overridden:

f.save('out.stl', batch_size=64) # instead of 32

The code attempts to skip any batches that are far away from the surface of the mesh. Inexact SDFs such as non-uniform scaling may cause issues with this process, resulting in holes in the output mesh (where batches were skipped when they shouldn't have been). To avoid this, you can disable sparse sampling:

f.save('out.stl', sparse=False) # force all batches to be completely sampled

Worker Threads

The SDF is sampled in batches using worker threads. By default, multiprocessing.cpu_count() worker threads are used. This can be overridden:

f.save('out.stl', workers=1) # only use one worker thread

Without Saving

You can of course generate a mesh without writing it to an STL file:

points = f.generate() # takes the same optional arguments as `save`
print(len(points)) # print number of points (3x the number of triangles)
print(points[:3]) # print the vertices of the first triangle

If you want to save an STL after generate, just use:

write_binary_stl(path, points)

Visualizing the SDF

You can plot a visualization of a 2D slice of the SDF using matplotlib. This can be useful for debugging purposes.

f.show_slice(z=0)
f.show_slice(z=0, abs=True) # show abs(f)

You can specify a slice plane at any X, Y, or Z coordinate. You can also specify the bounds to plot.

Note that matplotlib is only imported if this function is called, so it isn't strictly required as a dependency.


How it Works

The code simply uses the Marching Cubes algorithm to generate a mesh from the Signed Distance Function.

This would normally be abysmally slow in Python. However, numpy is used to evaluate the SDF on entire batches of points simultaneously. Furthermore, multiple threads are used to process batches in parallel. The result is surprisingly fast (for marching cubes). Meshes of adequate detail can still be quite large in terms of number of triangles.

The core "engine" of the sdf library is very small and can be found in mesh.py.

In short, there is nothing algorithmically revolutionary here. The goal is to provide a simple, fun, and easy-to-use API for generating 3D models in our favorite language Python.

Files

  • sdf/d2.py: 2D signed distance functions
  • sdf/d3.py: 3D signed distance functions
  • sdf/dn.py: Dimension-agnostic signed distance functions
  • sdf/ease.py: Easing functions that operate on numpy arrays. Some SDFs take an easing function as a parameter.
  • sdf/mesh.py: The core mesh-generation engine. Also includes code for estimating the bounding box of an SDF and for plotting a 2D slice of an SDF with matplotlib.
  • sdf/progress.py: A console progress bar.
  • sdf/stl.py: Code for writing a binary STL file.
  • sdf/text.py: Generate 2D SDFs for text (which can then be extruded)
  • sdf/util.py: Utility constants and functions.

SDF Implementation

It is reasonable to write your own SDFs beyond those provided by the built-in library. Browse the SDF implementations to understand how they are implemented. Here are some simple examples:

@sdf3
def sphere(radius=1, center=ORIGIN):
    def f(p):
        return np.linalg.norm(p - center, axis=1) - radius
    return f

An SDF is simply a function that takes a numpy array of points with shape (N, 3) for 3D SDFs or shape (N, 2) for 2D SDFs and returns the signed distance for each of those points as an array of shape (N, 1). They are wrapped with the @sdf3 decorator (or @sdf2 for 2D SDFs) which make boolean operators work, add the save method, add the operators like translate, etc.

@op3
def translate(other, offset):
    def f(p):
        return other(p - offset)
    return f

An SDF that operates on another SDF (like the above translate) should use the @op3 decorator instead. This will register the function such that SDFs can be chained together like:

f = sphere(1).translate((1, 2, 3))

Instead of what would otherwise be required:

f = translate(sphere(1), (1, 2, 3))

Remember, it's Python!

Remember, this is Python, so it's fully programmable. You can and should split up your model into parameterized sub-components, for example. You can use for loops and conditionals wherever applicable. The sky is the limit!

See the customizable box example for some starting ideas.


Function Reference

3D Primitives

sphere

sphere(radius=1, center=ORIGIN)

f = sphere() # unit sphere
f = sphere(2) # specify radius
f = sphere(1, (1, 2, 3)) # translated sphere

box

box(size=1, center=ORIGIN, a=None, b=None)

f = box(1) # all side lengths = 1
f = box((1, 2, 3)) # different side lengths
f = box(a=(-1, -1, -1), b=(3, 4, 5)) # specified by bounds

rounded_box

rounded_box(size, radius)

f = rounded_box((1, 2, 3), 0.25)

wireframe_box

wireframe_box(size, thickness)

f = wireframe_box((1, 2, 3), 0.05)

torus

torus(r1, r2)

f = torus(1, 0.25)

capsule

capsule(a, b, radius)

f = capsule(-Z, Z, 0.5)

capped_cylinder

capped_cylinder(a, b, radius)

f = capped_cylinder(-Z, Z, 0.5)

rounded_cylinder

rounded_cylinder(ra, rb, h)

f = rounded_cylinder(0.5, 0.1, 2)

capped_cone

capped_cone(a, b, ra, rb)

f = capped_cone(-Z, Z, 1, 0.5)

rounded_cone

rounded_cone(r1, r2, h)

f = rounded_cone(0.75, 0.25, 2)

ellipsoid

ellipsoid(size)

f = ellipsoid((1, 2, 3))

pyramid

pyramid(h)

f = pyramid(1)

Platonic Solids

tetrahedron

tetrahedron(r)

f = tetrahedron(1)

octahedron

octahedron(r)

f = octahedron(1)

dodecahedron

dodecahedron(r)

f = dodecahedron(1)

icosahedron

icosahedron(r)

f = icosahedron(1)

Infinite 3D Primitives

The following SDFs extend to infinity in some or all axes. They can only effectively be used in combination with other shapes, as shown in the examples below.

plane

plane(normal=UP, point=ORIGIN)

plane is an infinite plane, with one side being positive (outside) and one side being negative (inside).

f = sphere() & plane()

slab

slab(x0=None, y0=None, z0=None, x1=None, y1=None, z1=None, k=None)

slab is useful for cutting a shape on one or more axis-aligned planes.

f = sphere() & slab(z0=-0.5, z1=0.5, x0=0)

cylinder

cylinder(radius)

cylinder is an infinite cylinder along the Z axis.

f = sphere() - cylinder(0.5)

Text

Yes, even text is supported!

Text

text(name, text, width=None, height=None, texture_point_size=512)

FONT = 'Arial'
TEXT = 'Hello, world!'

w, h = measure_text(FONT, TEXT)

f = rounded_box((w + 1, h + 1, 0.2), 0.1)
f -= text(FONT, TEXT).extrude(1)

Positioning

translate

translate(other, offset)

f = sphere().translate((0, 0, 2))

scale

scale(other, factor)

Note that non-uniform scaling is an inexact SDF.

f = sphere().scale(2)
f = sphere().scale((1, 2, 3)) # non-uniform scaling

rotate

rotate(other, angle, vector=Z)

f = capped_cylinder(-Z, Z, 0.5).rotate(pi / 4, X)

orient

orient(other, axis)

orient rotates the shape such that whatever was pointing in the +Z direction is now pointing in the specified direction.

c = capped_cylinder(-Z, Z, 0.25)
f = c.orient(X) | c.orient(Y) | c.orient(Z)

Boolean Operations

The following primitives a and b are used in all of the following boolean operations.

a = box((3, 3, 0.5))
b = sphere()

The named versions (union, difference, intersection) can all take one or more SDFs as input. They all take an optional k parameter to define the amount of smoothing to apply. When using operators (|, -, &) the smoothing can still be applied via the .k(...) function.

union

f = a | b
f = union(a, b) # equivalent

difference

f = a - b
f = difference(a, b) # equivalent

intersection

f = a & b
f = intersection(a, b) # equivalent

smooth_union

f = a | b.k(0.25)
f = union(a, b, k=0.25) # equivalent

smooth_difference

f = a - b.k(0.25)
f = difference(a, b, k=0.25) # equivalent

smooth_intersection

f = a & b.k(0.25)
f = intersection(a, b, k=0.25) # equivalent

Repetition

repeat

repeat(other, spacing, count=None, padding=0)

repeat can repeat the underlying SDF infinitely or a finite number of times. If finite, the number of repetitions must be odd, because the count specifies the number of copies to make on each side of the origin. If the repeated elements overlap or come close together, you made need to specify a padding greater than zero to compute a correct SDF.

f = sphere().repeat(3, (1, 1, 0))

circular_array

circular_array(other, count, offset)

circular_array makes count copies of the underlying SDF, arranged in a circle around the Z axis. offset specifies how far to translate the shape in X before arraying it. The underlying SDF is only evaluated twice (instead of count times), so this is more performant than instantiating count copies of a shape.

f = capped_cylinder(-Z, Z, 0.5).circular_array(8, 4)

Miscellaneous

blend

blend(a, *bs, k=0.5)

f = sphere().blend(box())

dilate

dilate(other, r)

f = example.dilate(0.1)

erode

erode(other, r)

f = example.erode(0.1)

shell

shell(other, thickness)

f = sphere().shell(0.05) & plane(-Z)

elongate

elongate(other, size)

f = example.elongate((0.25, 0.5, 0.75))

twist

twist(other, k)

f = box().twist(pi / 2)

bend

bend(other, k)

f = box().bend(1)

bend_linear

bend_linear(other, p0, p1, v, e=ease.linear)

f = capsule(-Z * 2, Z * 2, 0.25).bend_linear(-Z, Z, X, ease.in_out_quad)

bend_radial

bend_radial(other, r0, r1, dz, e=ease.linear)

f = box((5, 5, 0.25)).bend_radial(1, 2, -1, ease.in_out_quad)

transition_linear

transition_linear(f0, f1, p0=-Z, p1=Z, e=ease.linear)

f = box().transition_linear(sphere(), e=ease.in_out_quad)

transition_radial

transition_radial(f0, f1, r0=0, r1=1, e=ease.linear)

f = box().transition_radial(sphere(), e=ease.in_out_quad)

wrap_around

wrap_around(other, x0, x1, r=None, e=ease.linear)

FONT = 'Arial'
TEXT = ' wrap_around ' * 3
w, h = measure_text(FONT, TEXT)
f = text(FONT, TEXT).extrude(0.1).orient(Y).wrap_around(-w / 2, w / 2)

2D to 3D Operations

extrude

extrude(other, h)

f = hexagon(1).extrude(1)

extrude_to

extrude_to(a, b, h, e=ease.linear)

f = rectangle(2).extrude_to(circle(1), 2, ease.in_out_quad)

revolve

revolve(other, offset=0)

f = hexagon(1).revolve(3)

3D to 2D Operations

slice

slice(other)

f = example.translate((0, 0, 0.55)).slice().extrude(0.1)

2D Primitives

circle

line

rectangle

rounded_rectangle

equilateral_triangle

hexagon

rounded_x

polygon

Comments
  • slab() is broken

    slab() is broken

    To reproduce:

    from sdf import *
    f = slab()
    

    Output:

      File "example.py", line 3, in <module>
        f = slab()
      File "C:\Users\Brandon\Documents\GitHub\sdf\sdf\d3.py", line 49, in wrapper
        return SDF3(f(*args, **kwargs))
      File "C:\Users\Brandon\Documents\GitHub\sdf\sdf\d3.py", line 133, in slab
        return intersection(*fs, k=k)
      File "C:\Users\Brandon\Documents\GitHub\sdf\sdf\d3.py", line 54, in wrapper
        return SDF3(f(*args, **kwargs))
    TypeError: intersection() missing 1 required positional argument: 'a'```
    opened by pomeroyb 5
  • Unable to recreate displacement example

    Unable to recreate displacement example

    I am unable to recreate the displacement example from https://iquilezles.org/www/articles/distfunctions/distfunctions.htm

    My attempt

    diff --git a/sdf/d3.py b/sdf/d3.py
    index 237c1cd..44829c5 100644
    --- a/sdf/d3.py
    +++ b/sdf/d3.py
    @@ -500,6 +500,16 @@ def wrap_around(other, x0, x1, r=None, e=ease.linear):
             return other(q)
         return f
     
    +@op3
    +def displace(other):
    +    def f(p):
    +        x = p[:,0]
    +        y = p[:,1]
    +        z = p[:,2]
    +        d2 = np.sin(20*x)*np.sin(20*y)*np.sin(20*z)
    +        return other(p) + d2
    +    return f
    +
    

    results in

     % python3 test.py
    Traceback (most recent call last):
      File "test.py", line 10, in <module>
        f.save('out.stl')
      File "/vanfiles/repos/sdf/sdf/d3.py", line 43, in save
        return mesh.save(path, self, *args, **kwargs)
      File "/vanfiles/repos/sdf/sdf/mesh.py", line 152, in save
        points = generate(*args, **kwargs)
      File "/vanfiles/repos/sdf/sdf/mesh.py", line 92, in generate
        bounds = _estimate_bounds(sdf)
      File "/vanfiles/repos/sdf/sdf/mesh.py", line 77, in _estimate_bounds
        volume = sdf(P).reshape((len(X), len(Y), len(Z)))
    ValueError: cannot reshape array of size 16777216 into shape (16,16,16)
    

    Any tips on getting this to work?

    opened by zumpchke 4
  • Dual contouring

    Dual contouring

    Dual contouring is a meshing technique which is better at producing sharp corner than marching cube.

    Do you think the technique would be suitable in this case? I've been looking for excuse to play with it. Is it something you already working on? If not I'm calling dibs

    opened by LeLocTai 4
  • Feature request: infinite cone

    Feature request: infinite cone

    A cone without end caps would be really useful.

    I tried to roll my own, but it seems not quite as straightforward as I expected - I'm unsure of exactly how the vectorised maths should be handled.

    For my purposes it would be ideal if it had the same interface as rounded_cone if that's possible, i.e. cone(r1, r2, d) should produce a vertically-oriented cone that has a radius of r1 at z=0 and r2 at z=1.

    Inigo Quilez gives the following function for the exact sdf of an infinite cone, in case this helps. I got stuck because the vectors 'q' and 'c' have different dimensions due to vectorisation, so I don't know the efficient way to dot them together.

    float sdCone( vec3 p, vec2 c )
    {
        // c is the sin/cos of the angle
        vec2 q = vec2( length(p.xz), -p.y );
        float d = length(q-c*max(dot(q,c), 0.0));
        return d * ((q.x*c.y-q.y*c.x<0.0)?-1.0:1.0);
    }
    
    opened by nathanielvirgo 3
  • How does batching work?

    How does batching work?

    Cool library! I was just reading your code and noticed you call marching_cubes on subsections of the SDF, but I don't see any "stitching" code when you put the subsections back together. Doesn't that lead to lots of extra triangles on the inside of the mesh on the subsection boundaries? Just wondering if you could explain how this works :)

    opened by Korijn 3
  • Global install

    Global install

    This is a bit of a noob question, but is there a way to install this library instead of running in a virtualenv? After following the install instructions I can run the examples, but I can't work out how to import the library into code that's not located in the source folder.

    (I know my way around Python pretty well, but I'm an academic rather than a developer and have never used virtualenv.)

    opened by nathanielvirgo 2
  • example.py saves STL file, but it's empty

    example.py saves STL file, but it's empty

    Hi ! I have ran your examples (examples.example.py), which seemed to work well. However, saved STL file was empty, with no information stored in it, as Meshlab didn't show anything.

    Here's logs I've got (base) D:\Source\Research\sdf>python examples/example.py min -0.84543, -0.84543, -0.84543 max 0.845431, 0.845431, 0.845431 step 0.0104847, 0.0104847, 0.0104847 4657463 samples in 216 batches with 16 workers 100% (216 of 216) [##############################] 0:00:00 0:00:00 44 skipped, 172 empty, 0 nonempty 0 triangles in 0.442999 seconds

    It says I have 0 triangles.

    opened by PavelSavkin 2
  • Error running Example

    Error running Example

    $ python examples/example.py

    Traceback (most recent call last):
      File "examples/example.py", line 1, in <module>
        from sdf import *
      File "/Users/jimmygunawan/sdf/sdf/__init__.py", line 1, in <module>
        from . import d2, d3, ease
      File "/Users/jimmygunawan/sdf/sdf/d2.py", line 5, in <module>
        from . import dn, d3, ease
      File "/Users/jimmygunawan/sdf/sdf/dn.py", line 7
        def union(a, *bs, k=None):
                          ^
    SyntaxError: invalid syntax
    
    opened by enzyme69 2
  • Capped cylinder fails

    Capped cylinder fails

    Wonderful work, but I stumbeled over the following:

    import sdf
    screw_hole =  sdf.capped_cylinder(0, 10, 6)
    screw_hole.save('out.stl', workers=1) 
    
    
    
    -------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    c:\Work\kufe.py in 
          28 import sdf
          29 screw_hole =  sdf.capped_cylinder(0, 10, 6)
    ----> 30 screw_hole.save('out.stl', workers=1)
    
    c:\work\sdf\sdf\d3.py in save(self, path, *args, **kwargs)
         41         return mesh.generate(self, *args, **kwargs)
         42     def save(self, path, *args, **kwargs):
    ---> 43         return mesh.save(path, self, *args, **kwargs)
         44     def show_slice(self, *args, **kwargs):
         45         return mesh.show_slice(self, *args, **kwargs)
    
    c:\work\sdf\sdf\mesh.py in save(path, *args, **kwargs)
        150 
        151 def save(path, *args, **kwargs):
    --> 152     points = generate(*args, **kwargs)
        153     stl.write_binary_stl(path, points)
        154 
    
    c:\work\sdf\sdf\mesh.py in generate(sdf, step, bounds, samples, workers, batch_size, verbose, sparse)
         90 
         91     if bounds is None:
    ---> 92         bounds = _estimate_bounds(sdf)
         93     (x0, y0, z0), (x1, y1, z1) = bounds
         94 
    
    c:\work\sdf\sdf\mesh.py in _estimate_bounds(sdf)
         75         prev = threshold
         76         P = _cartesian_product(X, Y, Z)
    ---> 77         volume = sdf(P).reshape((len(X), len(Y), len(Z)))
         78         where = np.argwhere(np.abs(volume) <= threshold)
         79         x1, y1, z1 = (x0, y0, z0) + where.max(axis=0) * d + d / 2
    
    c:\work\sdf\sdf\d3.py in __call__(self, p)
         23         self.f = f
         24     def __call__(self, p):
    ---> 25         return self.f(p).reshape((-1, 1))
         26     def __getattr__(self, name):
         27         if name in _ops:
    
    c:\work\sdf\sdf\d3.py in f(p)
        190         baba = np.dot(ba, ba)
        191         paba = np.dot(pa, ba).reshape((-1, 1))
    --> 192         x = _length(pa * baba - ba * paba) - radius * baba
        193         y = np.abs(paba - baba * 0.5) - baba * 0.5
        194         x = x.reshape((-1, 1))
    
    ValueError: operands could not be broadcast together with shapes (4096,3) (12288,1) 
    
    opened by Tillsten 2
  • Can not generate triangles

    Can not generate triangles

    OS: Debian 10 Python 3.7.3

    python3 example.py

    min -0.84543, -0.84543, -0.84543 max 0.845431, 0.845431, 0.845431 step 0.0104847, 0.0104847, 0.0104847 4492125 samples in 64 batches with 8 workers 0 triangles in 0.741009 seconds

    opened by blackball 2
  • Running pawn example fails

    Running pawn example fails

    Running the pawn.py example fails. I followed the steps in the README and used virtualenv and pip as suggested.

    All other examples work for me.

    $ python examples/pawn.py
    Traceback (most recent call last):
      File "examples/pawn.py", line 8, in <module>
        f = section(0, 0.2, 1, 1.25)
      File "examples/pawn.py", line 4, in section
        f = cylinder(d0/2).transition(
      File "...../sdf/sdf/d3.py", line 30, in __getattr__
        raise AttributeError
    AttributeError
    

    Any idea what causes this?

    opened by rdvdijk 1
  • Volume from SDF

    Volume from SDF

    Hello developers,

    I would like to calculate the total volume of an arbitrary sphere based SDF object. For now I am casting the SDF to a mesh and then use that to calculate the volume. However, writing the mesh is by far the most expensive step. I guess this is mainly due to the marching cubes. I was wondering if there is a way to get the volume from the voxels generated for the marching cubes directly. Or even better get the 'analytical' volume of the SDF without going to voxels at all?

    Cheers and thanks in advance.

    Bart

    PS If we get this working we will probably write a small algorithm about it and if you are interested you can partake in this publication. We can talk about the details later.

    opened by BartBruininks 0
  • Point cloud to SDF?

    Point cloud to SDF?

    Dear developer,

    I am trying to convert a point cloud to an SDF object. I have an array of XYZs. I have been trying the following:

    from sdf import *
    
    def place_bead(x, y, z, size):
        """
        Creates a SDF sphere of given size at the 
        indicated position.
        """
        bead = sphere(size)
        bead.translate(X*x)
        bead.translate(Y*y)
        bead.translate(Z*z)
        return bead
    
    # Setting some sphere properties
    size = dict()
    aa_names_list = ['oxygen', 'hydrogen', 'carbon']
    aa_sizes_list = [.152, .120, .170]
    size_dict = dict(zip(aa_names_list, aa_sizes_list))
    
    # Generating some data, the goal is a some spheres on a line. However
    #  this will be practically random XYZs in the real case.
    aa_xpositions = np.arange(100)
    aa_ypositions = np.zeros(100)
    aa_zpositions = np.zeros(100)
    aa_types = np.random.choice(aa_names_list[:3], 100)
    aa_sizes = np.asarray([size_dict[aa_type] for aa_type in aa_types])
    aa_array = np.vstack([aa_xpositions, aa_ypositions, aa_zpositions, aa_sizes]).T
    aa_objects = [place_bead(*bead) for bead in aa_array]
    
    # Generating the unified SDF
    s = aa_objects[0]
    for aa_object in aa_objects[1:]:
        s.union(aa_object)
    

    However, I always end up with just a single sphere. Also it feels pretty convoluted, but as I am only aiming at small point clouds for now (for sure less than a 1000) I do do not worry too much about the performance.

    It would be great if you could nudge me in the right direction.

    Cheers,

    Bart

    opened by BartBruininks 5
  • Merge request from my fork to yours

    Merge request from my fork to yours

    Thank you for the wonderful starting pad. I've been working on making this useful for doing machining work for my workbench, and thought I should present all the changes to you for your review

    opened by pschou 0
  • stl.py:9: RuntimeWarning: invalid value encountered in true_divide

    stl.py:9: RuntimeWarning: invalid value encountered in true_divide

    from sdf import *

    f = sphere(1) & box(1.5)

    c = cylinder(0.5) f -= c.orient(X) | c.orient(Y) | c.orient(Z)

    f.save('out.stl', step=0.002)

    Encounter divide problem when step=0.002 or 0.001

    opened by FieldsYeh 0
  • how to get an existing stl?

    how to get an existing stl?

    i get an array from existing stl by numpy-stl.Maybe i need a function and then decorate with @sdf3,i want to know how to return ?i look the source code like sphere ,i am confused what kind of value to return.array?

    opened by Herryjames 1
Owner
Michael Fogleman
Software Engineer at Formlabs
Michael Fogleman
MeshToGeotiff - A fast Python algorithm to convert a 3D mesh into a GeoTIFF

MeshToGeotiff - A fast Python algorithm to convert a 3D mesh into a GeoTIFF Python class for converting (very fast) 3D Meshes/Surfaces to Raster DEMs

null 8 Sep 10, 2022
Genalog is an open source, cross-platform python package allowing generation of synthetic document images with custom degradations and text alignment capabilities.

Genalog is an open source, cross-platform python package allowing generation of synthetic document images with custom degradations and text alignment capabilities.

Microsoft 235 Dec 22, 2022
Code related to "Have Your Text and Use It Too! End-to-End Neural Data-to-Text Generation with Semantic Fidelity" paper

DataTuner You have just found the DataTuner. This repository provides tools for fine-tuning language models for a task. See LICENSE.txt for license de

null 81 Jan 1, 2023
Text-to-Image generation

Generate vivid Images for Any (Chinese) text CogView is a pretrained (4B-param) transformer for text-to-image generation in general domain. Read our p

THUDM 1.3k Jan 5, 2023
Code for CVPR 2022 paper "Bailando: 3D dance generation via Actor-Critic GPT with Choreographic Memory"

Bailando Code for CVPR 2022 (oral) paper "Bailando: 3D dance generation via Actor-Critic GPT with Choreographic Memory" [Paper] | [Project Page] | [Vi

Li Siyao 237 Dec 29, 2022
A simple document layout analysis using Python-OpenCV

Run the application: python main.py *Note: For first time running the application, create a folder named "output". The application is a simple documen

Roinand Aguila 109 Dec 12, 2022
BoxToolBox is a simple python application built around the openCV library

BoxToolBox is a simple python application built around the openCV library. It is not a full featured application to guide you through the w

František Horínek 1 Nov 12, 2021
A simple QR-Code Reader in Python

A simple QR-Code Reader written in Python, that copies the content of a QR-Code directly into the copy clipboard.

Eric 1 Oct 28, 2021
A simple python program to record security cam footage by detecting a face and body of a person in the frame.

SecurityCam A simple python program to record security cam footage by detecting a face and body of a person in the frame. This code was created by me,

null 1 Nov 8, 2021
A simple Digits Recogniser made in Python

⭐ Python Digit Recogniser A simple digit Recogniser made in Python Demo Run Locally Clone the project git clone https://github.com/yashraj-n/python-

Yashraj narke 4 Nov 29, 2021
This is an API written in python that uses FastAPI. It is a simple API that can detect discord tokens in Images.

Welcome This is an API written in python that uses FastAPI. It is a simple API that can detect discord tokens in Images. Installation There are curren

null 8 Jul 29, 2022
A simple Security Camera created using Opencv in Python where images gets saved in realtime in your Dropbox account at every 5 seconds

Security Camera using Opencv & Dropbox This is a simple Security Camera created using Opencv in Python where images gets saved in realtime in your Dro

Arpit Rath 1 Jan 31, 2022
Simple app for visual editing of Page XML files

Name nw-page-editor - Simple app for visual editing of Page XML files. Version: 2021.02.22 Description nw-page-editor is an application for viewing/ed

Mauricio Villegas 27 Jun 20, 2022
A simple OCR API server, seriously easy to be deployed by Docker, on Heroku as well

ocrserver Simple OCR server, as a small working sample for gosseract. Try now here https://ocr-example.herokuapp.com/, and deploy your own now. Deploy

Hiromu OCHIAI 541 Dec 28, 2022
"Very simple but works well" Computer Vision based ID verification solution provided by LibraX.

ID Verification by LibraX.ai This is the first free Identity verification in the market. LibraX.ai is an identity verification platform for developers

LibraX.ai 46 Dec 6, 2022
EQFace: An implementation of EQFace: A Simple Explicit Quality Network for Face Recognition

EQFace: A Simple Explicit Quality Network for Face Recognition The first face recognition network that generates explicit face quality online.

DeepCam Shenzhen 141 Dec 31, 2022
A simple demo program for using OpenCV on Android

Kivy OpenCV Demo A simple demo program for using OpenCV on Android Build with: buildozer android debug deploy run Run (on desktop) with: python main.p

Andrea Ranieri 13 Dec 29, 2022
This is a passport scanning web service to help you scan, identify and validate your passport created with a simple and flexible design and ready to be integrated right into your system!

Passport-Recogniton-System This is a passport scanning web service to help you scan, identify and validate your passport created with a simple and fle

Mo'men Ashraf Muhamed 7 Jan 4, 2023
A Screen Translator/OCR Translator made by using Python and Tesseract, the user interface are made using Tkinter. All code written in python.

About An OCR translator tool. Made by me by utilizing Tesseract, compiled to .exe using pyinstaller. I made this program to learn more about python. I

Fauzan F A 41 Dec 30, 2022