Browse Source

add tree

master
wes 12 months ago
parent
commit
a7f9a87cf5
  1. 31
      planter.py
  2. 118
      svg_path.py

31
planter.py

@ -1,16 +1,18 @@
from cadquery import exporters
from cq_warehouse.bearing import SingleRowDeepGrooveBallBearing
from cq_warehouse.extensions import Workplane
from cq_warehouse.fastener import *
from cq_warehouse.thread import *
from cqmore.curve import archimedeanSpiral, circle
from cqmore.polygon import regularPolygon, star
from cqmore.polyhedron import polarZonohedra, Polyhedron, superellipsoid
from cq_warehouse.extensions import Workplane
import functools as fnc
import itertools as it
from svg_path import addSvgPath
from svgpathtools import svg2paths
import cadquery as cq
import cqmore
Workplane = cqmore.extend(Workplane)
Workplane.addSvgPath = addSvgPath
planter_height = 210
planter_radius = 129
@ -29,8 +31,7 @@ result = Workplane().polyhedron(*outer_poly)
holder_angle_offset = 20
result = (
result.workplane(offset=-36)
planter_polygon = (result.workplane(offset=-36)
.makePolygon(
regularPolygon(
nSides=4,
@ -39,11 +40,29 @@ result = (
thetaEnd=360 + holder_angle_offset,
),
forConstruction=True,
)
))
result = (
planter_polygon
.vertices()
.sphere(8, combine="cut")
)
paths, attributes = svg2paths("/home/deck/cad_files/tree_of_gondor_small.svg")
#print(dir(result.addSvgPath(paths[0])))
tree = (Workplane("YZ")
.center(0, 75)
.addSvgPath(paths[0])
.extrude(-4)
.translate((94.8, -100, 0))
)
print(tree)
result = result.cut(tree, clean=False)
cone = cq.Solid.makeCone(planter_radius, 33, planter_height + 95)
result = result.workplane().cut(cone)

118
svg_path.py

@ -0,0 +1,118 @@
import svgpathtools
import numpy as np
from math import sin, cos, sqrt, pi, acos, fmod, degrees
# See https://gist.github.com/dov/8d9b0304ba85e3229aabccac3c6468ef/d007910a9b68201a6c95852a220f96711ba3faa1
def tpl(cplx):
"""Convert a complex number to a tuple"""
return (cplx.real, cplx.imag)
def angle_between(u, v):
"""Find the angle between the vectors u an v"""
ux, uy = u
vx, vy = v
sign = 1 if ux * vy - uy * vx > 0 else -1
arg = (ux * vx + uy * vy) / (sqrt(ux * ux + uy * uy) * sqrt(vx * vx + vy * vy))
return sign * acos(arg)
# Implementation of https://www.w3.org/TR/SVG/implnote.html#ArcConversionCenterToEndpoint
def arc_endpoint_to_center(start, end, flag_a, flag_s, radius, phi):
"""Convert a endpoint elliptical arc description to a center description"""
rx, ry = radius.real, radius.imag
x1, y1 = start.real, start.imag
x2, y2 = end.real, end.imag
cosphi = cos(phi)
sinphi = sin(phi)
rx2 = rx * rx
ry2 = ry * ry
# Step 1. Compute x1p,y1p
x1p, y1p = (
np.array([[cosphi, sinphi], [-sinphi, cosphi]])
@ np.array([x1 - x2, y1 - y2])
* 0.5
).flatten()
x1p2 = x1p * x1p
y1p2 = y1p * y1p
# Step 2: Compute (cx', cy')
cxyp = sqrt(
(rx2 * ry2 - rx2 * y1p2 - ry2 * x1p2) / (rx2 * y1p2 + ry2 * x1p2)
) * np.array([rx * y1p / ry, -ry * x1p / rx])
if flag_a == flag_s:
cxyp = -cxyp
cxp, cyp = cxyp.flatten()
# Step 3: compute (cx,cy) from (cx',cy')
cx, cy = (
cosphi * cxp - sinphi * cyp + 0.5 * (x1 + x2),
sinphi * cxp + cosphi * cyp + 0.5 * (y1 + y2),
)
# Step 4: compute theta1 and deltatheta
theta1 = angle_between((1, 0), ((x1p - cxp) / rx, (y1p - cyp) / ry))
delta_theta = fmod(
angle_between(
((x1p - cxp) / rx, (y1p - cyp) / ry), ((-x1p - cxp) / rx, (-y1p - cyp) / ry)
),
2 * pi,
)
# Choose the right edge according to the flags
if not flag_s and delta_theta > 0:
delta_theta -= 2 * pi
elif flag_s and delta_theta < 0:
delta_theta += 2 * pi
return (cx, cy), theta1, delta_theta
def addSvgPath(self, path):
"""Add the svg path object to the current workspace"""
res = self
path_start = None
arc_id = 0
for p in path:
if path_start is None:
path_start = p.start
res = res.moveTo(*tpl(p.start))
# Support the four svgpathtools different objects
if isinstance(p, svgpathtools.CubicBezier):
coords = (tpl(p.start), tpl(p.control1), tpl(p.control2), tpl(p.end))
res = res.bezier(coords)
print("cubic bezier")
elif isinstance(p, svgpathtools.QuadraticBezier):
coords = (tpl(p.start), tpl(p.control), tpl(p.end))
res = res.bezier(coords)
print("quadratic bezier")
pass
elif isinstance(p, svgpathtools.Arc):
arc_id += 1
center, theta1, delta_theta = arc_endpoint_to_center(
p.start, p.end, p.large_arc, p.sweep, p.radius, p.rotation
)
res = res.ellipseArc(
x_radius=p.radius.real,
y_radius=p.radius.imag,
rotation_angle=degrees(p.rotation),
angle1=degrees(theta1),
angle2=degrees(theta1 + delta_theta),
)
print("ellipse arc")
elif isinstance(p, svgpathtools.Line):
res = res.lineTo(p.end.real, p.end.imag)
print("line")
if path_start == p.end:
path_start = None
res = res.close()
return res
Loading…
Cancel
Save