在Python里应用Openscad实现3D建模(修改简化版)-1

文章目录

  • 在Python里应用Openscad实现3D建模(修改简化版)-1
    • 安装方法:
      • 加入简化码的方法:
    • 使用方法:
      • 几个例子
      • 句法彩蛋
        • solid.utils 这个模块还有一些有用的功能:
        • 移动(translate)和旋转(rotate)的简化
        • 还是那个打洞的模块

在Python里应用Openscad实现3D建模(修改简化版)-1

–SolidPython 学习笔记1

  • –form https://github.com/SolidCode/SolidPython

参考Parkinbotshortcuts.scad做了部分修改使得代码更为简洁易读

以下是对solidpython的readme的学习笔记(其中的部分code进行了简化):

–好像作者是在这个链接中得到启发,下面是个例子:

from solid import *
d = difference()(
    Cu(10),
    Sp(15)
)
print(scad_render(d))

这个改变似乎没啥意思呀,继续往下看:

from solid import *
from solid.utils import *
import viewscad
import os
import sys

r = viewscad.Renderer()

SEGMENTS = 60

d = Cu(5) + Tx(5)(Sp(5)) - Cy(2,6)

r.render(d)

这是OpenSCAD代码:

difference(){
    union(){
        cube(5);
        translate( [5, 0,0]){
            sphere(5);
        }
    }
    cylinder(r=2, h=6);
}
比原来的编码简单易读,好聪明的方法!

当然了,还可以应用Python实现更多的可能:

> 内置字典类型

> 可变,可切片的列表和字符串类型

> 递归

> 外部库(图像!3D几何!网页抓取!...)

安装方法:

  1. 直接pip:

     pip install solidpython
     
  2. 下载(或者直接克隆)并解压,并在解压目录内安装:


    python setup.py install

加入简化码的方法:

  • 在\solid\objects.py文件的最后粘贴以下代码:

Ci= circle #圆

Sq= square #方

Sp= sphere #(radius | d=diameter) 球

Cu= cube #(size, center) or cube([width,depth,height], center) 立方

Cy= cylinder #(h,r|d,center) or cylinder(h,r1|d1,r2|d2,center) 锥柱

Mi= mirror #镜像

Of = offset # 偏移

C= color #色

Le= linear_extrude #(height,center,convexity,twist,slices,scale) 线拖

Re= rotate_extrude #(angle,convexity) 旋拖

dxf_Le= dxf_linear_extrude #dxf拖

Pr= projection #(cut) 投影

Sf= surface #(file = “….dat”,center,convexity)

deb= debug ##

bac= background # !

roo= root # %

dis= disable # *

  • 在\solid\utils.py同样:

# 旋转和移动

def Tx(x):
return translate([x,0,0])

def Ty(y):
return translate([0,y,0])

def Tz(z):
return translate([0,0,z])

def Rx(x=90):
return rotate([x,0,0])

def Ry(y=90):
return rotate([0,y,0])

def Rz(z=90):
return rotate([0,0,z])

使用方法:

  • 导入模块
    from solid import *
    from solid.utils import *  # Not required, but the utils module is useful--非必须但是很有用
    
    import os
    import sys
    
  • 可以调用use和include模块,如下:(也不知道为啥老是出错)

use("/path/to/scadfile.scad")

include("/path/to/scadfile.scad")

use(r"C:\Program Files\OpenSCAD\libraries\shortcuts.scad")# 为啥出错呀?
use (r"C:\Users\Administrator\Documents\3dguide\testd.scad")这个就行!!!
    d = Cu(10) - Sp(15)
    scad_render_to_file(d,r"C:\Users\Administrator\Documents\3dguide\testd.scad")
  • scad_render(py_scad_obj) 返回OpenScad代码

  • scad_render_to_file(py_scad_obj, filepath) 另存为.scad文件

    d = Cu(10) - Sp(15)
    scad_render_to_file(d,r"C:\Users\Administrator\Documents\3dguide\testd.scad")
  • 这个命令还可以在OpenSCAD IDE中加载并预览编辑的图像(需要设置)

  • 还可以调用openscad的命令行格式可以直接导出为stl文件

几个例子

可以用如下代码打开例子的目录:

import os, solid; print(os.path.dirname(solid.__file__) + '\examples')#例子在这里

原链接:here

solid/examples/solidpython_template.py
这是模板文件

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division#1.在python2 中导入未来的支持的语言特征中division(精确除法),即from __future__ import division ,当我们在程序中没有导入该特征时,"/"操作符执行的只能是整除,也就是取整数,只有当我们导入division(精确算法)以后,"/"执行的才是精确算法。2.但是在python3中已经支持了精确算法,所以无需再导入division(精确算法):
import os
import sys

# Assumes SolidPython is in site-packages or elsewhwere in sys.path
from solid import *
from solid.utils import *

SEGMENTS = 48


def assembly():
    # Your code here!在这里输入代码?这是个assembly函数还不懂啥意思以后在研究吧
    a = union()

    return a

if __name__ == '__main__':
    a = assembly()
    scad_render_to_file(a, file_header='$fn = %s;' % SEGMENTS, include_orig_code=True)

句法彩蛋

  • 应用 + 表示合集,- 表示差集, 表示交集* 很有创意,如下:
c = Cy(r=10, h=5) + Cy(r=2, h=30)

r.render(c)

  • 还有这种方式:
c = Cy(r=10, h=5)
c -= Cy(r=2, h=30)

r.render(c)
  • 还有个打洞的模块:
outer = Cy(5, 30)
inner = Cy(3,35)
pipe_a = outer - hole()(inner)

r.render(pipe_a)
  • 这里提到了一个 part() 函数,以利于组装以后再看吧

  • See solid/examples/animation_example.py 动画模块。。。以后再看吧

solid.utils 这个模块还有一些有用的功能:

solid/utils.py.
比如:

移动(translate)和旋转(rotate)的简化

Directions: (up, down, left, right, forward, back) for arranging things:–作者自定义的方向函数,我做了了一些修改:

  • Tx(x)(py_scad_obj)
  • Ty(y)(py_scad_obj)
  • Tz(z)(py_scad_obj)
  • Rx(x=90)(py_scad_obj)
  • Ry(y=90)(py_scad_obj)
  • Rz(z=90)(py_scad_obj)
b = Tx(5)(Cu(5))

r.render(b)

还是那个打洞的模块

outer = Cy(5, 30)
inner = Cy(3,35)
pipe_a = outer - hole()(inner)

r.render(pipe_a)

这里solid/examples/hole_example.py有一个示范文件,分段分析一下。。。

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
import os
import sys

# Assumes SolidPython is in site-packages or elsewhwere in sys.path
from solid import *
from solid.utils import *

SEGMENTS = 120#相当于fn
  • 通过hole()声明负空间,这个管子的内部总是空的,即使将两个交叉合并
def pipe_intersection_hole():
    pipe_od = 12
    pipe_id = 10
    seg_length = 30

    outer = Cy(r=pipe_od, h=seg_length, center=True)
    inner = Cy(r=pipe_id, h=seg_length + 2, center=True)

    # By declaring that the internal void of pipe_a should
    # explicitly remain empty, the combination of both pipes
    # is empty all the way through.
    # -通过hole()声明负空间,这个管子的内部总是空的,即使将两个
    # -交叉合并

    # Any OpenSCAD / SolidPython object can be declared a hole(),
    # and after that will always be empty
    pipe_a = outer + hole()(inner)
    # Note that "pipe_a = outer - hole()(inner)" would work identically;
    # inner will always be subtracted now that it's a hole

    pipe_b = Ry()(pipe_a)
    return pipe_a + pipe_b

r.render(pipe_intersection_hole())
  • 不用hole()就是这个结果
def pipe_intersection_no_hole():
    pipe_od = 12
    pipe_id = 10
    seg_length = 30

    outer = Cy(r=pipe_od, h=seg_length, center=True)
    inner = Cy(r=pipe_id, h=seg_length + 2, center=True)
    pipe_a = outer - inner

    pipe_b = rotate(a=90, v=FORWARD_VEC)(pipe_a)
    # pipe_a and pipe_b are both hollow, but because
    # their central voids aren't explicitly holes,
    # the union of both pipes has unwanted internal walls
    # 没有用hole()就是这个结果

    return pipe_a + pipe_b

r.render(pipe_intersection_no_hole())
- 当我们需要在hole()所形成的负空间里插入一个物体时,我们需要用到另一个函数part(),以消除负空间,看看下面这个例子:
def multipart_hole():
    # It's good to be able to keep holes empty, but often we want to put
    # things (bolts, etc.) in them.  The way to do this is to declare the
    # object containing the hole a "part".  Then, the hole will remain
    # empty no matter what you add to the 'part'.  But if you put an object
    # that is NOT part of the 'part' into the hole, it will still appear.

    # On the left (not_part), here's what happens if we try to put an object
    # into an explicit hole:  the object gets erased by the hole.

    # On the Tx (is_part), we mark the Cu-with-hole as a "part",
    # and then insert the same 'bolt' Cy into it.  The entire
    # bolt rematins.

    b = Cu(10, center=True)
    c = Cy(r=2, h=12, center=True)

    # A Cu with an explicit hole
    not_part = b - hole()(c)

    # Mark this Cu-with-hole as a separate part from the Cy
    is_part = part()(not_part.copy())

    # This fits in the holes
    bolt = Cy(r=1.5, h=14, center=True) + Tz(8)(Cy(r=2.5, h=2.5, center=True))

    # The section of the bolt inside not_part disappears.  The section
    # of the bolt inside is_part is still there.
    a = not_part + bolt + Tx(45)(is_part + bolt)

    return a

if __name__ == '__main__':
    out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
    file_out = os.path.join(out_dir, 'hole_example.scad')

    # On the left, pipes with no explicit holes, which can give
    # unexpected walls where we don't want them.
    # On the Tx, we use the hole() function to fix the problem
    a = pipe_intersection_no_hole() + Tx(45)(pipe_intersection_hole())

    # Below is an example of how to put objects into holes and have them
    # still appear
    b = up(40)(multipart_hole())
    a += b

    # print("%(__file__)s: SCAD file written to: \n%(file_out)s" % vars())
    # scad_render_to_file(a, file_out, file_header='$fn = %s;' % SEGMENTS, include_orig_code=True)
    
r.render(multipart_hole())
    b = Cu(10, center=True)
    c = Cy(r=2, h=12, center=True)

    # A Cu with an explicit hole
    not_part = b - hole()(c)

    # Mark this Cu-with-hole as a separate part from the Cy
    is_part = part()(not_part.copy())

    # This fits in the holes
    bolt = Cy(r=1.5, h=14, center=True) + Tz(8)(Cy(r=2.5, h=2.5, center=True))

    # The section of the bolt inside not_part disappears.  The section
    # of the bolt inside is_part is still there.
    a = not_part + bolt + Tx(45)(is_part + bolt)
    
    r.render(a)
  • 接下来根据作者的arc()函数,做一个Sec()函数(已经加到了utils,py):
def Sec1(rad = 10, start_degrees = 15, end_degrees = 165, thick = 5, segments= 60):
    # Note: the circle that this arc is drawn from gets segments,
    # not the arc itself.  That means a quarter-circle arc will
    # have segments/4 segments.
    # 加上了厚度thick

    bottom_half_square = Ty(-rad)(Sq([3 * rad, 2 * rad], center=True))
    top_half_square = Ty(rad)(Sq([3 * rad, 2 * rad], center=True))

    start_shape = Ci(rad, segments=segments)

    if abs((end_degrees - start_degrees) % 360) <= 180:
        end_angle = end_degrees - 180
        ret = start_shape
        ret -= Rz(start_degrees)(bottom_half_square.copy())
        ret -= Rz(end_angle)(bottom_half_square.copy())
    else:
        ret = start_shape
        ret *= Rz(start_degrees)(top_half_square.copy()) + Rz(end_degrees)(bottom_half_square.copy())
        
        
    return Le(thick)(ret)        
    d = Sec1()
    r.render(d)

未完待续。。。

你可能感兴趣的:(3D打印)