Moved examples to CadQuery library and adapted the UI to use those.
This commit is contained in:
parent
fc5d11f2ef
commit
6a1aa83760
|
@ -1,19 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
length = 80.0 # Length of the block
|
||||
height = 60.0 # Height of the block
|
||||
thickness = 10.0 # Thickness of the block
|
||||
|
||||
# Create a 3D block based on the dimension variables above.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the X and Y origins to define the workplane, meaning that the
|
||||
# positive Z direction is "up", and the negative Z direction is "down".
|
||||
result = cq.Workplane("XY").box(length, height, thickness)
|
||||
|
||||
# The following method is now outdated, but can still be used to display the
|
||||
# results of the script if you want
|
||||
# from Helpers import show
|
||||
# show(result) # Render the result of this script
|
||||
|
||||
show_object(result)
|
|
@ -1,20 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
length = 80.0 # Length of the block
|
||||
height = 60.0 # Height of the block
|
||||
thickness = 10.0 # Thickness of the block
|
||||
center_hole_dia = 22.0 # Diameter of center hole in block
|
||||
|
||||
# Create a block based on the dimensions above and add a 22mm center hole.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the X and Y origins to define the workplane, meaning that the
|
||||
# positive Z direction is "up", and the negative Z direction is "down".
|
||||
# 2. The highest (max) Z face is selected and a new workplane is created on it.
|
||||
# 3. The new workplane is used to drill a hole through the block.
|
||||
# 3a. The hole is automatically centered in the workplane.
|
||||
result = cq.Workplane("XY").box(length, height, thickness) \
|
||||
.faces(">Z").workplane().hole(center_hole_dia)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,34 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
length = 80.0 # Length of the block
|
||||
height = 60.0 # Height of the block
|
||||
thickness = 10.0 # Thickness of the block
|
||||
center_hole_dia = 22.0 # Diameter of center hole in block
|
||||
cbore_hole_diameter = 2.4 # Bolt shank/threads clearance hole diameter
|
||||
cbore_diameter = 4.4 # Bolt head pocket hole diameter
|
||||
cbore_depth = 2.1 # Bolt head pocket hole depth
|
||||
|
||||
# Create a 3D block based on the dimensions above and add a 22mm center hold
|
||||
# and 4 counterbored holes for bolts
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the X and Y origins to define the workplane, meaning that the
|
||||
# positive Z direction is "up", and the negative Z direction is "down".
|
||||
# 2. The highest(max) Z face is selected and a new workplane is created on it.
|
||||
# 3. The new workplane is used to drill a hole through the block.
|
||||
# 3a. The hole is automatically centered in the workplane.
|
||||
# 4. The highest(max) Z face is selected and a new workplane is created on it.
|
||||
# 5. A for-construction rectangle is created on the workplane based on the
|
||||
# block's overall dimensions.
|
||||
# 5a. For-construction objects are used only to place other geometry, they
|
||||
# do not show up in the final displayed geometry.
|
||||
# 6. The vertices of the rectangle (corners) are selected, and a counter-bored
|
||||
# hole is placed at each of the vertices (all 4 of them at once).
|
||||
result = cq.Workplane("XY").box(length, height, thickness) \
|
||||
.faces(">Z").workplane().hole(center_hole_dia) \
|
||||
.faces(">Z").workplane() \
|
||||
.rect(length - 8.0, height - 8.0, forConstruction=True) \
|
||||
.vertices().cboreHole(cbore_hole_diameter, cbore_diameter, cbore_depth)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,29 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
circle_radius = 50.0 # Radius of the plate
|
||||
thickness = 13.0 # Thickness of the plate
|
||||
rectangle_width = 13.0 # Width of rectangular hole in cylindrical plate
|
||||
rectangle_length = 19.0 # Length of rectangular hole in cylindrical plate
|
||||
|
||||
# Extrude a cylindrical plate with a rectangular hole in the middle of it.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. The 2D geometry for the outer circle is created at the same time as the
|
||||
# rectangle that will create the hole in the center.
|
||||
# 2a. The circle and the rectangle will be automatically centered on the
|
||||
# workplane.
|
||||
# 2b. Unlike some other functions like the hole(), circle() takes
|
||||
# a radius and not a diameter.
|
||||
# 3. The circle and rectangle are extruded together, creating a cylindrical
|
||||
# plate with a rectangular hole in the center.
|
||||
# 3a. circle() and rect() could be changed to any other shape to completely
|
||||
# change the resulting plate and/or the hole in it.
|
||||
result = cq.Workplane("front").circle(circle_radius) \
|
||||
.rect(rectangle_width, rectangle_length) \
|
||||
.extrude(thickness)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,32 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
width = 2.0 # Overall width of the plate
|
||||
thickness = 0.25 # Thickness of the plate
|
||||
|
||||
# Extrude a plate outline made of lines and an arc
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Draws a line from the origin to an X position of the plate's width.
|
||||
# 2a. The starting point of a 2D drawing like this will be at the center of the
|
||||
# workplane (0, 0) unless the moveTo() function moves the starting point.
|
||||
# 3. A line is drawn from the last position straight up in the Y direction
|
||||
# 1.0 millimeters.
|
||||
# 4. An arc is drawn from the last point, through point (1.0, 1.5) which is
|
||||
# half-way back to the origin in the X direction and 0.5 mm above where
|
||||
# the last line ended at. The arc then ends at (0.0, 1.0), which is 1.0 mm
|
||||
# above (in the Y direction) where our first line started from.
|
||||
# 5. close() is called to automatically draw the last line for us and close
|
||||
# the sketch so that it can be extruded.
|
||||
# 5a. Without the close(), the 2D sketch will be left open and the extrude
|
||||
# operation will provide unpredictable results.
|
||||
# 6. The 2D sketch is extruded into a solid object of the specified thickness.
|
||||
result = cq.Workplane("front").lineTo(width, 0) \
|
||||
.lineTo(width, 1.0) \
|
||||
.threePointArc((1.0, 1.5), (0.0, 1.0)) \
|
||||
.close().extrude(thickness)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,35 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
circle_radius = 3.0 # The outside radius of the plate
|
||||
thickness = 0.25 # The thickness of the plate
|
||||
|
||||
# Make a plate with two cutouts in it by moving the workplane center point
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 1b. The initial workplane center point is the center of the circle, at (0,0).
|
||||
# 2. A circle is created at the center of the workplane
|
||||
# 2a. Notice that circle() takes a radius and not a diameter
|
||||
result = cq.Workplane("front").circle(circle_radius)
|
||||
|
||||
# 3. The work center is movide to (1.5, 0.0) by calling center().
|
||||
# 3a. The new center is specified relative to the previous center,not
|
||||
# relative to global coordinates.
|
||||
# 4. A 0.5mm x 0.5mm 2D square is drawn inside the circle.
|
||||
# 4a. The plate has not been extruded yet, only 2D geometry is being created.
|
||||
result = result.center(1.5, 0.0).rect(0.5, 0.5)
|
||||
|
||||
# 5. The work center is moved again, this time to (-1.5, 1.5).
|
||||
# 6. A 2D circle is created at that new center with a radius of 0.25mm.
|
||||
result = result.center(-1.5, 1.5).circle(0.25)
|
||||
|
||||
# 7. All 2D geometry is extruded to the specified thickness of the plate.
|
||||
# 7a. The small circle and the square are enclosed in the outer circle of the
|
||||
# plate and so it is assumed that we want them to be cut out of the plate.
|
||||
# A separate cut operation is not needed.
|
||||
result = result.extrude(thickness)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,32 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
plate_radius = 2.0 # The radius of the plate that will be extruded
|
||||
hole_pattern_radius = 0.25 # Radius of circle where the holes will be placed
|
||||
thickness = 0.125 # The thickness of the plate that will be extruded
|
||||
|
||||
# Make a plate with 4 holes in it at various points in a polar arrangement from
|
||||
# the center of the workplane.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. A 2D circle is drawn that will become though outer profile of the plate.
|
||||
r = cq.Workplane("front").circle(plate_radius)
|
||||
|
||||
# 3. Push 4 points on the stack that will be used as the center points of the
|
||||
# holes.
|
||||
r = r.pushPoints([(1.5, 0), (0, 1.5), (-1.5, 0), (0, -1.5)])
|
||||
|
||||
# 4. This circle() call will operate on all four points, putting a circle at
|
||||
# each one.
|
||||
r = r.circle(hole_pattern_radius)
|
||||
|
||||
# 5. All 2D geometry is extruded to the specified thickness of the plate.
|
||||
# 5a. The small hole circles are enclosed in the outer circle of the plate and
|
||||
# so it is assumed that we want them to be cut out of the plate. A
|
||||
# separate cut operation is not needed.
|
||||
result = r.extrude(thickness)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,39 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
width = 3.0 # The width of the plate
|
||||
height = 4.0 # The height of the plate
|
||||
thickness = 0.25 # The thickness of the plate
|
||||
polygon_sides = 6 # The number of sides that the polygonal holes should have
|
||||
polygon_dia = 1.0 # The diameter of the circle enclosing the polygon points
|
||||
|
||||
# Create a plate with two polygons cut through it
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. A 3D box is created in one box() operation to represent the plate.
|
||||
# 2a. The box is centered around the origin, which creates a result that may
|
||||
# be unituitive when the polygon cuts are made.
|
||||
# 3. 2 points are pushed onto the stack and will be used as centers for the
|
||||
# polygonal holes.
|
||||
# 4. The two polygons are created, on for each point, with one call to
|
||||
# polygon() using the number of sides and the circle that bounds the
|
||||
# polygon.
|
||||
# 5. The polygons are cut thru all objects that are in the line of extrusion.
|
||||
# 5a. A face was not selected, and so the polygons are created on the
|
||||
# workplane. Since the box was centered around the origin, the polygons end
|
||||
# up being in the center of the box. This makes them cut from the center to
|
||||
# the outside along the normal (positive direction).
|
||||
# 6. The polygons are cut through all objects, starting at the center of the
|
||||
# box/plate and going "downward" (opposite of normal) direction. Functions
|
||||
# like cutBlind() assume a positive cut direction, but cutThruAll() assumes
|
||||
# instead that the cut is made from a max direction and cuts downward from
|
||||
# that max through all objects.
|
||||
result = cq.Workplane("front").box(width, height, thickness) \
|
||||
.pushPoints([(0, 0.75), (0, -0.75)]) \
|
||||
.polygon(polygon_sides, polygon_dia) \
|
||||
.cutThruAll()
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,40 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# These can be modified rather than hardcoding values for each dimension.
|
||||
# Define up our Length, Height, Width, and thickness of the beam
|
||||
(L, H, W, t) = (100.0, 20.0, 20.0, 1.0)
|
||||
|
||||
# Define the points that the polyline will be drawn to/thru
|
||||
pts = [
|
||||
(0, H/2.0),
|
||||
(W/2.0, H/2.0),
|
||||
(W/2.0, (H/2.0 - t)),
|
||||
(t/2.0, (H/2.0-t)),
|
||||
(t/2.0, (t - H/2.0)),
|
||||
(W/2.0, (t - H/2.0)),
|
||||
(W/2.0, H/-2.0),
|
||||
(0, H/-2.0)
|
||||
]
|
||||
|
||||
# We generate half of the I-beam outline and then mirror it to create the full
|
||||
# I-beam.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. moveTo() is used to move the first point from the origin (0, 0) to
|
||||
# (0, 10.0), with 10.0 being half the height (H/2.0). If this is not done
|
||||
# the first line will start from the origin, creating an extra segment that
|
||||
# will cause the extrude to have an invalid shape.
|
||||
# 3. The polyline function takes a list of points and generates the lines
|
||||
# through all the points at once.
|
||||
# 3. Only half of the I-beam profile has been drawn so far. That half is
|
||||
# mirrored around the Y-axis to create the complete I-beam profile.
|
||||
# 4. The I-beam profile is extruded to the final length of the beam.
|
||||
result = cq.Workplane("front").moveTo(0, H/2.0) \
|
||||
.polyline(pts) \
|
||||
.mirrorY() \
|
||||
.extrude(L)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,27 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# 1. Establishes a workplane to create the spline on to extrude.
|
||||
# 1a. Uses the X and Y origins to define the workplane, meaning that the
|
||||
# positive Z direction is "up", and the negative Z direction is "down".
|
||||
s = cq.Workplane("XY")
|
||||
|
||||
# The points that the spline will pass through
|
||||
sPnts = [
|
||||
(2.75, 1.5),
|
||||
(2.5, 1.75),
|
||||
(2.0, 1.5),
|
||||
(1.5, 1.0),
|
||||
(1.0, 1.25),
|
||||
(0.5, 1.0),
|
||||
(0, 1.0)
|
||||
]
|
||||
|
||||
# 2. Generate our plate with the spline feature and make sure it is a
|
||||
# closed entity
|
||||
r = s.lineTo(3.0, 0).lineTo(3.0, 1.0).spline(sPnts).close()
|
||||
|
||||
# 3. Extrude to turn the wire into a plate
|
||||
result = r.extrude(0.5)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,20 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. A horizontal line is drawn on the workplane with the hLine function.
|
||||
# 2a. 1.0 is the distance, not coordinate. hLineTo allows using xCoordinate
|
||||
# not distance.
|
||||
r = cq.Workplane("front").hLine(1.0)
|
||||
|
||||
# 3. Draw a series of vertical and horizontal lines with the vLine and hLine
|
||||
# functions.
|
||||
r = r.vLine(0.5).hLine(-0.25).vLine(-0.25).hLineTo(0.0)
|
||||
|
||||
# 4. Mirror the geometry about the Y axis and extrude it into a 3D object.
|
||||
result = r.mirrorY().extrude(0.25)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,16 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a 3D box that will have a hole placed in it later.
|
||||
result = cq.Workplane("front").box(2, 3, 0.5)
|
||||
|
||||
# 3. Find the top-most face with the >Z max selector.
|
||||
# 3a. Establish a new workplane to build geometry on.
|
||||
# 3b. Create a hole down into the box.
|
||||
result = result.faces(">Z").workplane().hole(0.5)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,21 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a 3D box that will have a hole placed in it later.
|
||||
result = cq.Workplane("front").box(3, 2, 0.5)
|
||||
|
||||
# 3. Select the lower left vertex and make a workplane.
|
||||
# 3a. The top-most Z face is selected using the >Z selector.
|
||||
# 3b. The lower-left vertex of the faces is selected with the <XY selector.
|
||||
# 3c. A new workplane is created on the vertex to build future geometry on.
|
||||
result = result.faces(">Z").vertices("<XY").workplane()
|
||||
|
||||
# 4. A circle is drawn with the selected vertex as its center.
|
||||
# 4a. The circle is cut down through the box to cut the corner out.
|
||||
result = result.circle(1.0).cutThruAll()
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,20 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a 3D box that will have geometry based off it later.
|
||||
result = cq.Workplane("front").box(3, 2, 0.5)
|
||||
|
||||
# 3. The lowest face in the X direction is selected with the <X selector.
|
||||
# 4. A new wokrplane is created
|
||||
# 4a.The workplane is offset from the object surface so that it is not touching
|
||||
# the original box.
|
||||
result = result.faces("<X").workplane(offset=0.75)
|
||||
|
||||
# 5. Creates a thin disc on the offset workplane that is floating near the box.
|
||||
result = result.circle(1.0).extrude(0.5)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,22 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects the top-most Z face of the box.
|
||||
# 4. Creates a new workplane and then moves and rotates it with the
|
||||
# transformed function.
|
||||
# 5. Creates a for-construction rectangle that only exists to use for placing
|
||||
# other geometry.
|
||||
# 6. Selects the vertices of the for-construction rectangle.
|
||||
# 7. Places holes at the center of each selected vertex.
|
||||
# 7a. Since the workplane is rotated, this results in angled holes in the face.
|
||||
result = cq.Workplane("front").box(4.0, 4.0, 0.25).faces(">Z") \
|
||||
.workplane() \
|
||||
.transformed(offset=(0, -1.5, 1.0), rotate=(60, 0, 0)) \
|
||||
.rect(1.5, 1.5, forConstruction=True).vertices().hole(0.25)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,21 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Create a block with holes in each corner of a rectangle on that workplane.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects the top-most Z face of the box.
|
||||
# 4. Creates a new workplane to build new geometry on.
|
||||
# 5. Creates a for-construction rectangle that only exists to use for placing
|
||||
# other geometry.
|
||||
# 6. Selects the vertices of the for-construction rectangle.
|
||||
# 7. Places holes at the center of each selected vertex.
|
||||
result = cq.Workplane("front").box(2, 2, 0.5)\
|
||||
.faces(">Z").workplane() \
|
||||
.rect(1.5, 1.5, forConstruction=True).vertices() \
|
||||
.hole(0.125)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,14 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Create a hollow box that's open on both ends with a thin wall.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects faces with normal in +z direction.
|
||||
# 4. Create a shell by cutting out the top-most Z face.
|
||||
result = cq.Workplane("front").box(2, 2, 2).faces("+Z").shell(0.05)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,20 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Create a lofted section between a rectangle and a circular section.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the named plane orientation "front" to define the workplane, meaning
|
||||
# that the positive Z direction is "up", and the negative Z direction
|
||||
# is "down".
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects the top-most Z face of the box.
|
||||
# 4. Draws a 2D circle at the center of the the top-most face of the box.
|
||||
# 5. Creates a workplane 3 mm above the face the circle was drawn on.
|
||||
# 6. Draws a 2D circle on the new, offset workplane.
|
||||
# 7. Creates a loft between the circle and the rectangle.
|
||||
result = cq.Workplane("front").box(4.0, 4.0, 0.25).faces(">Z") \
|
||||
.circle(1.5).workplane(offset=3.0) \
|
||||
.rect(0.75, 0.5) \
|
||||
.loft(combine=True)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,19 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Create a plate with 4 counter-sunk holes in it.
|
||||
# 1. Establishes a workplane using an XY object instead of a named plane.
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects the top-most face of the box and established a workplane on that.
|
||||
# 4. Draws a for-construction rectangle on the workplane which only exists for
|
||||
# placing other geometry.
|
||||
# 5. Selects the corner vertices of the rectangle and places a counter-sink
|
||||
# hole, using each vertex as the center of a hole using the cskHole()
|
||||
# function.
|
||||
# 5a. When the depth of the counter-sink hole is set to None, the hole will be
|
||||
# cut through.
|
||||
result = cq.Workplane(cq.Plane.XY()).box(4, 2, 0.5).faces(">Z") \
|
||||
.workplane().rect(3.5, 1.5, forConstruction=True) \
|
||||
.vertices().cskHole(0.125, 0.25, 82.0, depth=None)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,13 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Create a plate with 4 rounded corners in the Z-axis.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the X and Y origins to define the workplane, meaning that the
|
||||
# positive Z direction is "up", and the negative Z direction is "down".
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects all edges that are parallel to the Z axis.
|
||||
# 4. Creates fillets on each of the selected edges with the specified radius.
|
||||
result = cq.Workplane("XY").box(3, 3, 0.5).edges("|Z").fillet(0.125)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,25 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Create a simple block with a hole through it that we can split.
|
||||
# 1. Establishes a workplane that an object can be built on.
|
||||
# 1a. Uses the X and Y origins to define the workplane, meaning that the
|
||||
# positive Z direction is "up", and the negative Z direction is "down".
|
||||
# 2. Creates a plain box to base future geometry on with the box() function.
|
||||
# 3. Selects the top-most face of the box and establishes a workplane on it
|
||||
# that new geometry can be built on.
|
||||
# 4. Draws a 2D circle on the new workplane and then uses it to cut a hole
|
||||
# all the way through the box.
|
||||
c = cq.Workplane("XY").box(1, 1, 1).faces(">Z").workplane() \
|
||||
.circle(0.25).cutThruAll()
|
||||
|
||||
# 5. Selects the face furthest away from the origin in the +Y axis direction.
|
||||
# 6. Creates an offset workplane that is set in the center of the object.
|
||||
# 6a. One possible improvement to this script would be to make the dimensions
|
||||
# of the box variables, and then divide the Y-axis dimension by 2.0 and
|
||||
# use that to create the offset workplane.
|
||||
# 7. Uses the embedded workplane to split the object, keeping only the "top"
|
||||
# portion.
|
||||
result = c.faces(">Y").workplane(-0.5).split(keepTop=True)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,19 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Set up the length, width, and thickness
|
||||
(L, w, t) = (20.0, 6.0, 3.0)
|
||||
s = cq.Workplane("XY")
|
||||
|
||||
# Draw half the profile of the bottle and extrude it
|
||||
p = s.center(-L / 2.0, 0).vLine(w / 2.0) \
|
||||
.threePointArc((L / 2.0, w / 2.0 + t), (L, w / 2.0)).vLine(-w / 2.0) \
|
||||
.mirrorX().extrude(30.0, True)
|
||||
|
||||
# Make the neck
|
||||
p.faces(">Z").workplane().circle(3.0).extrude(2.0, True)
|
||||
|
||||
# Make a shell
|
||||
result = p.faces(">Z").shell(0.3)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,77 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Parameter definitions
|
||||
p_outerWidth = 100.0 # Outer width of box enclosure
|
||||
p_outerLength = 150.0 # Outer length of box enclosure
|
||||
p_outerHeight = 50.0 # Outer height of box enclosure
|
||||
|
||||
p_thickness = 3.0 # Thickness of the box walls
|
||||
p_sideRadius = 10.0 # Radius for the curves around the sides of the bo
|
||||
p_topAndBottomRadius = 2.0 # Radius for the curves on the top and bottom edges
|
||||
|
||||
p_screwpostInset = 12.0 # How far in from the edges the screwposts should be
|
||||
p_screwpostID = 4.0 # Inner diameter of the screwpost holes, should be roughly screw diameter not including threads
|
||||
p_screwpostOD = 10.0 # Outer diameter of the screwposts. Determines overall thickness of the posts
|
||||
|
||||
p_boreDiameter = 8.0 # Diameter of the counterbore hole, if any
|
||||
p_boreDepth = 1.0 # Depth of the counterbore hole, if
|
||||
p_countersinkDiameter = 0.0 # Outer diameter of countersink. Should roughly match the outer diameter of the screw head
|
||||
p_countersinkAngle = 90.0 # Countersink angle (complete angle between opposite sides, not from center to one side)
|
||||
p_lipHeight = 1.0 # Height of lip on the underside of the lid. Sits inside the box body for a snug fit.
|
||||
|
||||
# Outer shell
|
||||
oshell = cq.Workplane("XY").rect(p_outerWidth, p_outerLength) \
|
||||
.extrude(p_outerHeight + p_lipHeight)
|
||||
|
||||
# Weird geometry happens if we make the fillets in the wrong order
|
||||
if p_sideRadius > p_topAndBottomRadius:
|
||||
oshell.edges("|Z").fillet(p_sideRadius)
|
||||
oshell.edges("#Z").fillet(p_topAndBottomRadius)
|
||||
else:
|
||||
oshell.edges("#Z").fillet(p_topAndBottomRadius)
|
||||
oshell.edges("|Z").fillet(p_sideRadius)
|
||||
|
||||
# Inner shell
|
||||
ishell = oshell.faces("<Z").workplane(p_thickness, True)\
|
||||
.rect((p_outerWidth - 2.0 * p_thickness), (p_outerLength - 2.0 * p_thickness))\
|
||||
.extrude((p_outerHeight - 2.0 * p_thickness), False) # Set combine false to produce just the new boss
|
||||
ishell.edges("|Z").fillet(p_sideRadius - p_thickness)
|
||||
|
||||
# Make the box outer box
|
||||
box = oshell.cut(ishell)
|
||||
|
||||
# Make the screwposts
|
||||
POSTWIDTH = (p_outerWidth - 2.0 * p_screwpostInset)
|
||||
POSTLENGTH = (p_outerLength - 2.0 * p_screwpostInset)
|
||||
|
||||
postCenters = box.faces(">Z").workplane(-p_thickness)\
|
||||
.rect(POSTWIDTH, POSTLENGTH, forConstruction=True)\
|
||||
.vertices()
|
||||
|
||||
for v in postCenters.all():
|
||||
v.circle(p_screwpostOD / 2.0).circle(p_screwpostID / 2.0)\
|
||||
.extrude((-1.0) * ((p_outerHeight + p_lipHeight) - (2.0 * p_thickness)), True)
|
||||
|
||||
# Split lid into top and bottom parts
|
||||
(lid, bottom) = box.faces(">Z").workplane(-p_thickness - p_lipHeight).split(keepTop=True, keepBottom=True).all()
|
||||
|
||||
# Translate the lid, and subtract the bottom from it to produce the lid inset
|
||||
lowerLid = lid.translate((0, 0, -p_lipHeight))
|
||||
cutlip = lowerLid.cut(bottom).translate((p_outerWidth + p_thickness, 0, p_thickness - p_outerHeight + p_lipHeight))
|
||||
|
||||
# Compute centers for counterbore/countersink or counterbore
|
||||
topOfLidCenters = cutlip.faces(">Z").workplane().rect(POSTWIDTH, POSTLENGTH, forConstruction=True).vertices()
|
||||
|
||||
# Add holes of the desired type
|
||||
if p_boreDiameter > 0 and p_boreDepth > 0:
|
||||
topOfLid = topOfLidCenters.cboreHole(p_screwpostID, p_boreDiameter, p_boreDepth, (2.0) * p_thickness)
|
||||
elif p_countersinkDiameter > 0 and p_countersinkAngle > 0:
|
||||
topOfLid = topOfLidCenters.cskHole(p_screwpostID, p_countersinkDiameter, p_countersinkAngle, (2.0) * p_thickness)
|
||||
else:
|
||||
topOfLid= topOfLidCenters.hole(p_screwpostID, 2.0 * p_thickness)
|
||||
|
||||
# Return the combined result
|
||||
result = topOfLid.combineSolids(bottom)
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,23 +0,0 @@
|
|||
# This example is meant to be used from within the CadQuery module of FreeCAD.
|
||||
import cadquery
|
||||
import FreeCAD
|
||||
|
||||
# Create a new document that we can draw our model on
|
||||
newDoc = FreeCAD.newDocument()
|
||||
|
||||
# Shows a 1x1x1 FreeCAD cube in the display
|
||||
initialBox = newDoc.addObject("Part::Box", "initialBox")
|
||||
newDoc.recompute()
|
||||
|
||||
# Make a CQ object
|
||||
cqBox = cadquery.CQ(cadquery.Solid(initialBox.Shape))
|
||||
|
||||
# Extrude a peg
|
||||
newThing = cqBox.faces(">Z").workplane().circle(0.5).extrude(0.25)
|
||||
|
||||
# Add a FreeCAD object to the tree and then store a CQ object in it
|
||||
nextShape = newDoc.addObject("Part::Feature", "nextShape")
|
||||
nextShape.Shape = newThing.val().wrapped
|
||||
|
||||
# Rerender the doc to see what the new solid looks like
|
||||
newDoc.recompute()
|
|
@ -1,21 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# The dimensions of the model. These can be modified rather than changing the
|
||||
# shape's code directly.
|
||||
rectangle_width = 10.0
|
||||
rectangle_length = 10.0
|
||||
angle_degrees = 360.0
|
||||
|
||||
# Revolve a cylinder from a rectangle
|
||||
# Switch comments around in this section to try the revolve operation with different parameters
|
||||
result = cq.Workplane("XY").rect(rectangle_width, rectangle_length, False).revolve()
|
||||
#result = cadquery.Workplane("XY").rect(rectangle_width, rectangle_length, False).revolve(angle_degrees)
|
||||
#result = cadquery.Workplane("XY").rect(rectangle_width, rectangle_length).revolve(angle_degrees,(-5,-5))
|
||||
#result = cadquery.Workplane("XY").rect(rectangle_width, rectangle_length).revolve(angle_degrees,(-5, -5),(-5, 5))
|
||||
#result = cadquery.Workplane("XY").rect(rectangle_width, rectangle_length).revolve(angle_degrees,(-5,-5),(-5,5), False)
|
||||
|
||||
# Revolve a donut with square walls
|
||||
#result = cadquery.Workplane("XY").rect(rectangle_width, rectangle_length, True).revolve(angle_degrees, (20, 0), (20, 10))
|
||||
|
||||
# Displays the result of this script
|
||||
show_object(result)
|
|
@ -1,56 +0,0 @@
|
|||
# This script can create any regular rectangular Lego(TM) Brick
|
||||
import cadquery as cq
|
||||
|
||||
#####
|
||||
# Inputs
|
||||
######
|
||||
lbumps = 1 # number of bumps long
|
||||
wbumps = 1 # number of bumps wide
|
||||
thin = True # True for thin, False for thick
|
||||
|
||||
#
|
||||
# Lego Brick Constants-- these make a lego brick a lego :)
|
||||
#
|
||||
pitch = 8.0
|
||||
clearance = 0.1
|
||||
bumpDiam = 4.8
|
||||
bumpHeight = 1.8
|
||||
if thin:
|
||||
height = 3.2
|
||||
else:
|
||||
height = 9.6
|
||||
|
||||
t = (pitch - (2 * clearance) - bumpDiam) / 2.0
|
||||
postDiam = pitch - t # works out to 6.5
|
||||
total_length = lbumps*pitch - 2.0*clearance
|
||||
total_width = wbumps*pitch - 2.0*clearance
|
||||
|
||||
# make the base
|
||||
s = cq.Workplane("XY").box(total_length, total_width, height)
|
||||
|
||||
# shell inwards not outwards
|
||||
s = s.faces("<Z").shell(-1.0 * t)
|
||||
|
||||
# make the bumps on the top
|
||||
s = s.faces(">Z").workplane(). \
|
||||
rarray(pitch, pitch, lbumps, wbumps, True).circle(bumpDiam / 2.0) \
|
||||
.extrude(bumpHeight)
|
||||
|
||||
# add posts on the bottom. posts are different diameter depending on geometry
|
||||
# solid studs for 1 bump, tubes for multiple, none for 1x1
|
||||
tmp = s.faces("<Z").workplane(invert=True)
|
||||
|
||||
if lbumps > 1 and wbumps > 1:
|
||||
tmp = tmp.rarray(pitch, pitch, lbumps - 1, wbumps - 1, center=True). \
|
||||
circle(postDiam / 2.0).circle(bumpDiam / 2.0).extrude(height - t)
|
||||
elif lbumps > 1:
|
||||
tmp = tmp.rarray(pitch, pitch, lbumps - 1, 1, center=True). \
|
||||
circle(t).extrude(height - t)
|
||||
elif wbumps > 1:
|
||||
tmp = tmp.rarray(pitch, pitch, 1, wbumps - 1, center=True). \
|
||||
circle(t).extrude(height - t)
|
||||
else:
|
||||
tmp = s
|
||||
|
||||
# Render the solid
|
||||
show_object(tmp)
|
|
@ -1,85 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
exploded = False # when true, moves the base away from the top so we see
|
||||
showTop = True # When true, the top is rendered.
|
||||
showCover = True # When true, the cover is rendered
|
||||
|
||||
width = 2.2 # Nominal x dimension of the part
|
||||
height = 0.5 # Height from bottom top to the top of the top :P
|
||||
length = 1.5 # Nominal y dimension of the part
|
||||
trapezoidFudge = 0.7 # ratio of trapezoid bases. set to 1.0 for cube
|
||||
xHoleOffset = 0.500 # Holes are distributed symetrically about each axis
|
||||
yHoleOffset = 0.500
|
||||
zFilletRadius = 0.50 # Fillet radius of corners perp. to Z axis.
|
||||
yFilletRadius = 0.250 # Fillet readius of the top edge of the case
|
||||
lipHeight = 0.1 # The height of the lip on the inside of the cover
|
||||
wallThickness = 0.06 # Wall thickness for the case
|
||||
coverThickness = 0.2 # Thickness of the cover plate
|
||||
holeRadius = 0.30 # Button hole radius
|
||||
counterSyncAngle = 100 # Countersink angle.
|
||||
|
||||
xyplane = cq.Workplane("XY")
|
||||
yzplane = cq.Workplane("YZ")
|
||||
|
||||
|
||||
def trapezoid(b1, b2, h):
|
||||
"Defines a symetrical trapezoid in the XY plane."
|
||||
|
||||
y = h / 2
|
||||
x1 = b1 / 2
|
||||
x2 = b2 / 2
|
||||
return (xyplane.moveTo(-x1, y)
|
||||
.polyline([(x1, y),
|
||||
(x2, -y),
|
||||
(-x2, -y)]).close())
|
||||
|
||||
|
||||
# Defines our base shape: a box with fillets around the vertical edges.
|
||||
# This has to be a function because we need to create multiple copies of
|
||||
# the shape.
|
||||
def base(h):
|
||||
return (trapezoid(width, width * trapezoidFudge, length)
|
||||
.extrude(h)
|
||||
.translate((0, 0, height / 2))
|
||||
.edges("Z")
|
||||
.fillet(zFilletRadius))
|
||||
|
||||
# start with the base shape
|
||||
top = (base(height)
|
||||
# then fillet the top edge
|
||||
.edges(">Z")
|
||||
.fillet(yFilletRadius)
|
||||
# shell the solid from the bottom face, with a .060" wall thickness
|
||||
.faces("<Z")
|
||||
.shell(-wallThickness)
|
||||
# cut five button holes into the top face in a cross pattern.
|
||||
.faces(">Z")
|
||||
.workplane()
|
||||
.pushPoints([(0, 0),
|
||||
(-xHoleOffset, 0),
|
||||
(0, -yHoleOffset),
|
||||
(xHoleOffset, 0),
|
||||
(0, yHoleOffset)])
|
||||
.cskHole(diameter=holeRadius,
|
||||
cskDiameter=holeRadius * 1.5,
|
||||
cskAngle=counterSyncAngle))
|
||||
|
||||
# the bottom cover begins with the same basic shape as the top
|
||||
cover = (base(coverThickness)
|
||||
# we need to move it upwards into the parent solid slightly.
|
||||
.translate((0, 0, -coverThickness + lipHeight))
|
||||
# now we subtract the top from the cover. This produces a lip on the
|
||||
# solid NOTE: that this does not account for mechanical tolerances.
|
||||
# But it looks cool.
|
||||
.cut(top)
|
||||
# try to fillet the inner edge of the cover lip. Technically this
|
||||
# fillets every edge perpendicular to the Z axis.
|
||||
.edges("#Z")
|
||||
.fillet(.020)
|
||||
.translate((0, 0, -0.5 if exploded else 0)))
|
||||
|
||||
# Conditionally render the parts
|
||||
if showTop:
|
||||
show_object(top)
|
||||
if showCover:
|
||||
show_object(cover)
|
|
@ -1,23 +0,0 @@
|
|||
import numpy as np
|
||||
import cadquery as cq
|
||||
|
||||
# Square side and offset in x and y.
|
||||
side = 10
|
||||
offset = 5
|
||||
|
||||
# Define the locations that the polyline will be drawn to/thru.
|
||||
# The polyline is defined as numpy.array so that operations like translation
|
||||
# of all points are simplified.
|
||||
pts = np.array([
|
||||
(side, 0),
|
||||
(side, side),
|
||||
(0, side),
|
||||
(0, 0),
|
||||
]) + [offset, offset]
|
||||
|
||||
result = cq.Workplane('XY') \
|
||||
.polyline(pts).close().extrude(2) \
|
||||
.faces('+Z').workplane().circle(side / 2).extrude(1)
|
||||
|
||||
# Render the solid
|
||||
show_object(result)
|
|
@ -1,182 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import unicode_literals, division
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
import cadquery as cq
|
||||
|
||||
# text_lines is a list of text lines.
|
||||
# FreeCAD in braille (converted with braille-converter:
|
||||
# https://github.com/jpaugh/braille-converter.git).
|
||||
text_lines = ['⠠ ⠋ ⠗ ⠑ ⠑ ⠠ ⠉ ⠠ ⠁ ⠠ ⠙']
|
||||
# See http://www.tiresias.org/research/reports/braille_cell.htm for examples
|
||||
# of braille cell geometry.
|
||||
horizontal_interdot = 2.5
|
||||
vertical_interdot = 2.5
|
||||
horizontal_intercell = 6
|
||||
vertical_interline = 10
|
||||
dot_height = 0.5
|
||||
dot_diameter = 1.3
|
||||
|
||||
base_thickness = 1.5
|
||||
|
||||
# End of configuration.
|
||||
BrailleCellGeometry = namedtuple('BrailleCellGeometry',
|
||||
('horizontal_interdot',
|
||||
'vertical_interdot',
|
||||
'intercell',
|
||||
'interline',
|
||||
'dot_height',
|
||||
'dot_diameter'))
|
||||
|
||||
|
||||
class Point(object):
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __add__(self, other):
|
||||
return Point(self.x + other.x, self.y + other.y)
|
||||
|
||||
def __len__(self):
|
||||
return 2
|
||||
|
||||
def __getitem__(self, index):
|
||||
return (self.x, self.y)[index]
|
||||
|
||||
def __str__(self):
|
||||
return '({}, {})'.format(self.x, self.y)
|
||||
|
||||
|
||||
def brailleToPoints(text, cell_geometry):
|
||||
# Unicode bit pattern (cf. https://en.wikipedia.org/wiki/Braille_Patterns).
|
||||
mask1 = 0b00000001
|
||||
mask2 = 0b00000010
|
||||
mask3 = 0b00000100
|
||||
mask4 = 0b00001000
|
||||
mask5 = 0b00010000
|
||||
mask6 = 0b00100000
|
||||
mask7 = 0b01000000
|
||||
mask8 = 0b10000000
|
||||
masks = (mask1, mask2, mask3, mask4, mask5, mask6, mask7, mask8)
|
||||
|
||||
# Corresponding dot position
|
||||
w = cell_geometry.horizontal_interdot
|
||||
h = cell_geometry.vertical_interdot
|
||||
pos1 = Point(0, 2 * h)
|
||||
pos2 = Point(0, h)
|
||||
pos3 = Point(0, 0)
|
||||
pos4 = Point(w, 2 * h)
|
||||
pos5 = Point(w, h)
|
||||
pos6 = Point(w, 0)
|
||||
pos7 = Point(0, -h)
|
||||
pos8 = Point(w, -h)
|
||||
pos = (pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8)
|
||||
|
||||
# Braille blank pattern (u'\u2800').
|
||||
blank = '⠀'
|
||||
points = []
|
||||
# Position of dot1 along the x-axis (horizontal).
|
||||
character_origin = 0
|
||||
for c in text:
|
||||
for m, p in zip(masks, pos):
|
||||
delta_to_blank = ord(c) - ord(blank)
|
||||
if (m & delta_to_blank):
|
||||
points.append(p + Point(character_origin, 0))
|
||||
character_origin += cell_geometry.intercell
|
||||
return points
|
||||
|
||||
|
||||
def get_plate_height(text_lines, cell_geometry):
|
||||
# cell_geometry.vertical_interdot is also used as space between base
|
||||
# borders and characters.
|
||||
return (2 * cell_geometry.vertical_interdot +
|
||||
2 * cell_geometry.vertical_interdot +
|
||||
(len(text_lines) - 1) * cell_geometry.interline)
|
||||
|
||||
|
||||
def get_plate_width(text_lines, cell_geometry):
|
||||
# cell_geometry.horizontal_interdot is also used as space between base
|
||||
# borders and characters.
|
||||
max_len = max([len(t) for t in text_lines])
|
||||
return (2 * cell_geometry.horizontal_interdot +
|
||||
cell_geometry.horizontal_interdot +
|
||||
(max_len - 1) * cell_geometry.intercell)
|
||||
|
||||
|
||||
def get_cylinder_radius(cell_geometry):
|
||||
"""Return the radius the cylinder should have
|
||||
|
||||
The cylinder have the same radius as the half-sphere make the dots (the
|
||||
hidden and the shown part of the dots).
|
||||
The radius is such that the spherical cap with diameter
|
||||
cell_geometry.dot_diameter has a height of cell_geometry.dot_height.
|
||||
"""
|
||||
h = cell_geometry.dot_height
|
||||
r = cell_geometry.dot_diameter / 2
|
||||
return (r ** 2 + h ** 2) / 2 / h
|
||||
|
||||
|
||||
def get_base_plate_thickness(plate_thickness, cell_geometry):
|
||||
"""Return the height on which the half spheres will sit"""
|
||||
return (plate_thickness +
|
||||
get_cylinder_radius(cell_geometry) -
|
||||
cell_geometry.dot_height)
|
||||
|
||||
|
||||
def make_base(text_lines, cell_geometry, plate_thickness):
|
||||
base_width = get_plate_width(text_lines, cell_geometry)
|
||||
base_height = get_plate_height(text_lines, cell_geometry)
|
||||
base_thickness = get_base_plate_thickness(plate_thickness, cell_geometry)
|
||||
base = cq.Workplane('XY').box(base_width, base_height, base_thickness,
|
||||
centered=(False, False, False))
|
||||
return base
|
||||
|
||||
|
||||
def make_embossed_plate(text_lines, cell_geometry):
|
||||
"""Make an embossed plate with dots as spherical caps
|
||||
|
||||
Method:
|
||||
- make a thin plate on which sit cylinders
|
||||
- fillet the upper edge of the cylinders so to get pseudo half-spheres
|
||||
- make the union with a thicker plate so that only the sphere caps stay
|
||||
"visible".
|
||||
"""
|
||||
base = make_base(text_lines, cell_geometry, base_thickness)
|
||||
|
||||
dot_pos = []
|
||||
base_width = get_plate_width(text_lines, cell_geometry)
|
||||
base_height = get_plate_height(text_lines, cell_geometry)
|
||||
y = base_height - 3 * cell_geometry.vertical_interdot
|
||||
line_start_pos = Point(cell_geometry.horizontal_interdot, y)
|
||||
for text in text_lines:
|
||||
dots = brailleToPoints(text, cell_geometry)
|
||||
dots = [p + line_start_pos for p in dots]
|
||||
dot_pos += dots
|
||||
line_start_pos += Point(0, -cell_geometry.interline)
|
||||
|
||||
r = get_cylinder_radius(cell_geometry)
|
||||
base = base.faces('>Z').vertices('<XY').workplane() \
|
||||
.pushPoints(dot_pos).circle(r) \
|
||||
.extrude(r)
|
||||
# Make a fillet almost the same radius to get a pseudo spherical cap.
|
||||
base = base.faces('>Z').edges() \
|
||||
.fillet(r - 0.001)
|
||||
hidding_box = cq.Workplane('XY').box(
|
||||
base_width, base_height, base_thickness, centered=(False, False, False))
|
||||
result = hidding_box.union(base)
|
||||
return result
|
||||
|
||||
_cell_geometry = BrailleCellGeometry(
|
||||
horizontal_interdot,
|
||||
vertical_interdot,
|
||||
horizontal_intercell,
|
||||
vertical_interline,
|
||||
dot_height,
|
||||
dot_diameter)
|
||||
|
||||
if base_thickness < get_cylinder_radius(_cell_geometry):
|
||||
raise ValueError('Base thickness should be at least {}'.format(dot_height))
|
||||
|
||||
show_object(make_embossed_plate(text_lines, _cell_geometry))
|
|
@ -1,45 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# The dimensions of the model. These can be modified rather than changing the
|
||||
# object's code directly.
|
||||
width = 400
|
||||
height = 500
|
||||
thickness = 2
|
||||
|
||||
# Create a plate with two polygons cut through it
|
||||
result = cq.Workplane("front").box(width, height, thickness)
|
||||
|
||||
h_sep = 60
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(157,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(157,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
|
||||
|
||||
h_sep4DB9 = 30
|
||||
for idx in range(8):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(91,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(25,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(25,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(8):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-41,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-107,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-107,-30-idx*h_sep).circle(14).rect(24.7487,24.7487, forConstruction=True).vertices().hole(3.2).cutThruAll()
|
||||
|
||||
for idx in range(8):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-173,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
|
||||
|
||||
for idx in range(4):
|
||||
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-173,-30-idx*h_sep).moveTo(-2.9176,-5.3).threePointArc((-6.05,0),(-2.9176,5.3)).lineTo(2.9176,5.3).threePointArc((6.05,0),(2.9176,-5.3)).close().cutThruAll()
|
||||
|
||||
# Render the solid
|
||||
show_object(result)
|
|
@ -1,40 +0,0 @@
|
|||
import cadquery as cq
|
||||
|
||||
# Points we will use to create spline and polyline paths to sweep over
|
||||
pts = [
|
||||
(0, 1),
|
||||
(1, 2),
|
||||
(2, 4)
|
||||
]
|
||||
|
||||
# Spline path generated from our list of points (tuples)
|
||||
path = cq.Workplane("XZ").spline(pts)
|
||||
|
||||
# Sweep a circle with a diameter of 1.0 units along the spline path we just created
|
||||
defaultSweep = cq.Workplane("XY").circle(1.0).sweep(path)
|
||||
|
||||
# Sweep defaults to making a solid and not generating a Frenet solid. Setting Frenet to True helps prevent creep in
|
||||
# the orientation of the profile as it is being swept
|
||||
frenetShell = cq.Workplane("XY").circle(1.0).sweep(path, makeSolid=False, isFrenet=True)
|
||||
|
||||
# We can sweep shapes other than circles
|
||||
defaultRect = cq.Workplane("XY").rect(1.0, 1.0).sweep(path)
|
||||
|
||||
# Switch to a polyline path, but have it use the same points as the spline
|
||||
path = cq.Workplane("XZ").polyline(pts)
|
||||
|
||||
# Using a polyline path leads to the resulting solid having segments rather than a single swept outer face
|
||||
plineSweep = cq.Workplane("XY").circle(1.0).sweep(path)
|
||||
|
||||
# Switch to an arc for the path
|
||||
path = cq.Workplane("XZ").threePointArc((1.0, 1.5), (0.0, 1.0))
|
||||
|
||||
# Use a smaller circle section so that the resulting solid looks a little nicer
|
||||
arcSweep = cq.Workplane("XY").circle(0.5).sweep(path)
|
||||
|
||||
# Translate the resulting solids so that they do not overlap and display them left to right
|
||||
show_object(defaultSweep)
|
||||
show_object(frenetShell.translate((5, 0, 0)))
|
||||
show_object(defaultRect.translate((10, 0, 0)))
|
||||
show_object(plineSweep.translate((15, 0, 0)))
|
||||
show_object(arcSweep.translate((20, 0, 0)))
|
|
@ -1,215 +0,0 @@
|
|||
# 3d printer for mounting hotend to X-carriage inspired by the P3steel Toolson
|
||||
# edition - http://www.thingiverse.com/thing:1054909
|
||||
import cadquery as cq
|
||||
|
||||
|
||||
def move_to_center(cqObject, shape):
|
||||
'''
|
||||
Moves the origin of the current Workplane to the center of a given
|
||||
geometry object
|
||||
'''
|
||||
|
||||
# transform to workplane local coordinates
|
||||
shape_center = shape.Center().sub(cqObject.plane.origin)
|
||||
|
||||
# project onto plane using dot product
|
||||
x_offset = shape_center.dot(cqObject.plane.xDir)
|
||||
y_offset = shape_center.dot(cqObject.plane.yDir)
|
||||
|
||||
return cqObject.center(x_offset, y_offset)
|
||||
|
||||
# Parameter definitions
|
||||
|
||||
main_plate_size_y = 67 # size of the main plate in y direction
|
||||
main_plate_size_x = 50. # size of the main plate in x direction
|
||||
main_plate_thickness = 10. # thickness of the main plate
|
||||
|
||||
wing_size_x = 10. # size of the side wing supporting the bridge in x direction
|
||||
wing_size_y = 10. # size of the side wing supporting the bridge in y direction
|
||||
|
||||
bridge_depth = 35. # depth of the bridge
|
||||
|
||||
support_depth = 18. # depth of the bridge support
|
||||
|
||||
cutout_depth = 15. # depth of the hotend cutout
|
||||
cutout_rad = 8. # radius of the cutout (cf groove mount sizes of E3D hotends)
|
||||
cutout_offset = 2. # delta radius of the second cutout (cf groove mount sizes of E3D hotends)
|
||||
|
||||
extruder_hole_spacing = 50. # spacing of the extruder mounting holes (Wade's geared extruder)
|
||||
|
||||
m4_predrill = 3.7 # hole diameter for m4 tapping
|
||||
m3_predrill = 2.5 # hole diameter for m3 tapping
|
||||
m3_cbore = 5. # counterbore size for m3 socket screw
|
||||
|
||||
mounting_hole_spacing = 28. # spacing of the mounting holes for attaching to x-carriage
|
||||
|
||||
aux_hole_depth = 6. # depth of the auxiliary holes at the sides of the object
|
||||
aux_hole_spacing = 5. # spacing of the auxiliary holes within a group
|
||||
aux_hole_N = 2 # number of the auxiliary hole per group
|
||||
|
||||
# make the main plate
|
||||
res = cq.Workplane('front').box(main_plate_size_x,
|
||||
main_plate_size_y,
|
||||
main_plate_thickness)
|
||||
|
||||
|
||||
def add_wing(obj, sign=1):
|
||||
'''
|
||||
Adds a wing to the main plate, defined to keep the code DRY
|
||||
'''
|
||||
obj = obj.workplane()\
|
||||
.hLine(sign*wing_size_x)\
|
||||
.vLine(-wing_size_y)\
|
||||
.line(-sign*wing_size_x, -2*wing_size_y)\
|
||||
.close().extrude(main_plate_thickness)
|
||||
return obj
|
||||
|
||||
# add wings
|
||||
|
||||
# add right wing
|
||||
res = res.faces('<Z').vertices('>XY')
|
||||
res = add_wing(res)
|
||||
|
||||
# store sides of the plate for further reuse, their area is used later on to calculate "optimum" spacing of the aux hole groups
|
||||
face_right = res.faces('>X[1]').val()
|
||||
face_left = res.faces('>X[-2]').val()
|
||||
|
||||
# add left wing
|
||||
res = res.faces('<Z').vertices('>Y').vertices('<X')
|
||||
res = add_wing(res, -1)
|
||||
|
||||
# make the bridge for extruder mounting
|
||||
wp = res.faces('>Z') # select top face
|
||||
e = wp.edges('>Y') # select most extreme edge in Y direction
|
||||
|
||||
bridge_length = e.val().Length() # the width of the bridge equals to the length of the selected edge
|
||||
|
||||
# draw the bridge x-section and extrude
|
||||
res = e.vertices('<X'). \
|
||||
workplane(). \
|
||||
hLine(bridge_length). \
|
||||
vLine(-10). \
|
||||
hLine(-bridge_length). \
|
||||
close().extrude(bridge_depth)
|
||||
|
||||
faces = res.faces('>Z[1]') # take all faces in Z direction and select the middle one; note the new selector syntax
|
||||
edge = faces.edges('>Y') # select the top edge of this face...
|
||||
res = move_to_center(faces.workplane(), edge.val()).\
|
||||
transformed(rotate=(0, 90, 0)) # ...and make a workplane that is centered in this edge and oriented along X direction
|
||||
|
||||
res = res.vLine(-support_depth).\
|
||||
line(-support_depth, support_depth).\
|
||||
close() # draw a triangle
|
||||
|
||||
res = res.extrude(main_plate_size_x/2, both=True, clean=True) # extrude the triangle, now the bridge has a nice support making it much more stiff
|
||||
|
||||
# Start cutting out a slot for hotend mounting
|
||||
face = res.faces('>Y') # select the most extreme face in Y direction, i.e. top ot the "bridge"
|
||||
res = move_to_center(face.workplane(), face.edges('>Z').val()) # shift the workplane to the center of the most extreme edge of the bridge
|
||||
|
||||
|
||||
def make_slot(obj, depth=None):
|
||||
'''
|
||||
Utility function that makes a slot for hotend mounting
|
||||
'''
|
||||
obj = obj.moveTo(cutout_rad, -cutout_depth).\
|
||||
threePointArc((0, -cutout_depth-cutout_rad),
|
||||
(-cutout_rad, -cutout_depth)).\
|
||||
vLineTo(0).hLineTo(cutout_rad).close()
|
||||
|
||||
if depth is None:
|
||||
obj = obj.cutThruAll()
|
||||
else:
|
||||
obj = obj.cutBlind(depth)
|
||||
|
||||
return obj
|
||||
|
||||
res = make_slot(res, None) # make the smaller slot
|
||||
|
||||
cutout_rad += cutout_offset # increase the cutout radius...
|
||||
res = make_slot(res.end().end(), -main_plate_thickness/2) # ...and make a slightly larger slot
|
||||
|
||||
res = res.end().moveTo(0, 0) \
|
||||
.pushPoints([(-extruder_hole_spacing/2, -cutout_depth), (extruder_hole_spacing/2, -cutout_depth)]) \
|
||||
.hole(m4_predrill) # add extruder mounting holes at the top of the bridge
|
||||
|
||||
|
||||
# make additional slot in the bridge support which allows the hotend's radiator to fit
|
||||
cutout_rad += 3*cutout_offset
|
||||
res = make_slot(res.end().moveTo(0, 0).workplane(offset=-main_plate_thickness))
|
||||
|
||||
# add reinforcement holes
|
||||
cutout_rad -= 2*cutout_offset
|
||||
res = res.faces('>Z').workplane().\
|
||||
pushPoints([(-cutout_rad, -main_plate_thickness/4),
|
||||
(cutout_rad, -main_plate_thickness/4)]).\
|
||||
hole(m3_predrill)
|
||||
|
||||
# add aux holes on the front face
|
||||
res = res.moveTo(-main_plate_size_x/2., 0).workplane().rarray(aux_hole_spacing, 1, aux_hole_N, 1) \
|
||||
.hole(m3_predrill, depth=aux_hole_depth)
|
||||
res = res.moveTo(main_plate_size_x, 0).workplane().rarray(aux_hole_spacing, 1, aux_hole_N, 1) \
|
||||
.hole(m3_predrill, depth=aux_hole_depth)
|
||||
|
||||
# make a hexagonal cutout
|
||||
res = res.faces('>Z[1]')
|
||||
res = res.workplane(offset=bridge_depth). \
|
||||
transformed(rotate=(0, 0, 90)). \
|
||||
polygon(6, 30).cutThruAll()
|
||||
|
||||
# make 4 mounting holes with cbores
|
||||
res = res.end().moveTo(0, 0). \
|
||||
rect(mounting_hole_spacing,
|
||||
mounting_hole_spacing, forConstruction=True)
|
||||
|
||||
res = res.vertices(). \
|
||||
cboreHole(m3_predrill,
|
||||
m3_cbore,
|
||||
bridge_depth+m3_cbore/2)
|
||||
|
||||
# make cutout and holes for mounting of the fan
|
||||
res = res.transformed(rotate=(0, 0, 45)). \
|
||||
rect(35, 35).cutBlind(-bridge_depth).end(). \
|
||||
rect(25, 25, forConstruction=True).vertices().hole(m3_predrill)
|
||||
|
||||
|
||||
def make_aux_holes(workplane, holes_span, N_hole_groups=3):
|
||||
'''
|
||||
Utility function for creation of auxiliary mouting holes at the sides of the object
|
||||
'''
|
||||
res = workplane.moveTo(-holes_span/2).workplane().rarray(aux_hole_spacing, 1, aux_hole_N, 1) \
|
||||
.hole(m3_predrill, depth=aux_hole_depth)
|
||||
for i in range(N_hole_groups-1):
|
||||
res = res.moveTo(holes_span/(N_hole_groups-1.)).workplane().rarray(aux_hole_spacing, 1, aux_hole_N, 1) \
|
||||
.hole(m3_predrill, depth=aux_hole_depth)
|
||||
|
||||
return res
|
||||
|
||||
# make aux holes at the bottom
|
||||
res = res.faces('<Y').workplane()
|
||||
res = make_aux_holes(res, main_plate_size_x*2/3., 3)
|
||||
|
||||
# make aux holes at the side (@overhang)
|
||||
res = res.faces('<X').workplane().transformed((90, 0, 0))
|
||||
res = make_aux_holes(res, main_plate_size_x*2/3., 3)
|
||||
res = res.faces('>X').workplane().transformed((90, 0, 0))
|
||||
res = make_aux_holes(res, main_plate_size_x*2/3., 3)
|
||||
|
||||
# make aux holes at the side (@main plate)
|
||||
res = res.faces('|X').edges('<Y').edges('>X')
|
||||
res = res.workplane()
|
||||
res = move_to_center(res, face_right)
|
||||
res = res.transformed((90, 0, 0))
|
||||
hole_sep = 0.5*face_right.Area()/main_plate_thickness
|
||||
res = make_aux_holes(res, hole_sep, 2)
|
||||
|
||||
# make aux holes at the side (@main plate)
|
||||
res = res.faces('|X').edges('<Y').edges('<X')
|
||||
res = res.workplane()
|
||||
res = move_to_center(res, face_left)
|
||||
res = res.transformed((0, 180, 0))
|
||||
hole_sep = 0.5*face_right.Area()/main_plate_thickness
|
||||
res = make_aux_holes(res, hole_sep, 2)
|
||||
|
||||
# show the result
|
||||
show_object(res)
|
|
@ -1,10 +0,0 @@
|
|||
# Example using advanced logical operators in string selectors to select only
|
||||
# the inside edges on a shelled cube to chamfer.
|
||||
import cadquery as cq
|
||||
|
||||
result = cq.Workplane("XY").box(2, 2, 2).\
|
||||
faces(">Z").shell(-0.2).\
|
||||
faces(">Z").edges("not(<X or >X or <Y or >Y)").\
|
||||
chamfer(0.125)
|
||||
|
||||
show_object(result)
|
|
@ -101,7 +101,7 @@ class CadQueryExecuteExample:
|
|||
|
||||
# Start off defaulting to the Examples directory
|
||||
module_base_path = module_locator.module_path()
|
||||
exs_dir_path = os.path.join(module_base_path, 'Examples')
|
||||
exs_dir_path = os.path.join(module_base_path, 'Libs/cadquery/examples/FreeCAD')
|
||||
|
||||
# Append this script's directory to sys.path
|
||||
sys.path.append(os.path.dirname(exs_dir_path))
|
||||
|
@ -247,7 +247,7 @@ class CadQueryOpenScript:
|
|||
if self.previousPath is None:
|
||||
# Start off defaulting to the Examples directory
|
||||
module_base_path = module_locator.module_path()
|
||||
exs_dir_path = os.path.join(module_base_path, 'Examples')
|
||||
exs_dir_path = os.path.join(module_base_path, 'Libs/cadquery/examples/FreeCAD')
|
||||
|
||||
self.previousPath = exs_dir_path
|
||||
|
||||
|
@ -288,7 +288,7 @@ class CadQuerySaveScript:
|
|||
|
||||
# If the code pane doesn't have a filename, we need to present the save as dialog
|
||||
if len(cqCodePane.file.path) == 0 or os.path.basename(cqCodePane.file.path) == 'script_template.py' \
|
||||
or os.path.split(cqCodePane.file.path)[-2].endswith('Examples'):
|
||||
or os.path.split(cqCodePane.file.path)[0].endswith('FreeCAD'):
|
||||
FreeCAD.Console.PrintError("You cannot save over a blank file, example file or template file.\r\n")
|
||||
|
||||
CadQuerySaveAsScript().Activated()
|
||||
|
|
|
@ -99,7 +99,7 @@ class CadQueryWorkbench (Workbench):
|
|||
|
||||
# List all of the example files in an order that makes sense
|
||||
module_base_path = module_locator.module_path()
|
||||
exs_dir_path = os.path.join(module_base_path, 'Examples')
|
||||
exs_dir_path = os.path.join(module_base_path, 'Libs/cadquery/examples/FreeCAD')
|
||||
dirs = os.listdir(exs_dir_path)
|
||||
dirs.sort()
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 654f04c2e7e21fb1ebefcca519da86bcb342ee83
|
||||
Subproject commit 0a107cf9350c779c20e87342213021811113e244
|
Loading…
Reference in New Issue
Block a user