Skip to content

Commit

Permalink
Merge pull request #16 from gumyr/dev
Browse files Browse the repository at this point in the history
Plastic Bottle Thread
  • Loading branch information
gumyr committed Jan 24, 2022
2 parents d63fbc3 + 000f2e1 commit 6b4725a
Show file tree
Hide file tree
Showing 7 changed files with 453 additions and 111 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ or CAM systems.
- [AcmeThread](#acmethread)
- [MetricTrapezoidalThread](#metrictrapezoidalthread)
- [TrapezoidalThread](#trapezoidalthread)
- [PlasticBottleThread](#plasticbottlethread)
- [fastener sub-package](#fastener-sub-package)
- [Nut](#nut)
- [Nut Selection](#nut-selection)
Expand Down Expand Up @@ -520,6 +521,35 @@ This class exposes instance variables for the input parameters as well as:
### TrapezoidalThread
The base class of the AcmeThread and MetricTrapezoidalThread classes.

### PlasticBottleThread
The [ASTM D2911 Standard](https://www.astm.org/d2911-10.html) Plastic Bottle Thread.

![AcmeThread](doc/plasticThread.png)

The parameters are:
- `size` (str) : see below
- `external` (bool=True) : external or internal thread selector
- `hand` (Literal["right", "left"] = "right") : twist direction
- `manufacturingCompensation` (float=0.0) : a radius compensation for manufacturing errors

`size` as defined by the ASTM is specified as:
- [L|M][diameter(mm)]SP[100|103|110|200|400|410|415:425|444]
- e.g. M15SP425

where:
- L Style: All-Purpose Thread - trapezoidal shape with 30° shoulders, metal or platsic closures
- M Style: Modified Buttress Thread - asymmetric shape with 10° and 40/45/50° shoulders, plastic closures
- the three digit "Finish" encodes the number of turns, pitch, angles etc.

`manufacturingCompensation` can be used to compensate for over-extrusion of 3D printers. A value of 0.2mm will reduce the radius of an external thread by 0.2mm (and increase the radius of an internal thread) such that the resulting 3D printed part matches the target dimensions.

For example:
```python
thread = PlasticBottleThread(
size="M38SP444", external=False, manufacturingCompensation=0.2 * MM
)
```

## fastener sub-package
Many mechanical designs will contain threaded fasteners of some kind, either in a threaded hole or threaded screws or bolts holding two or more parts together. The fastener sub-package provides a set of classes with which raw threads can be created such that they can be integrated into other parts as well as a set of classes that create many different types of nuts, screws and washers - as follows:
![fastener_disc](doc/fastener_disc.png)
Expand Down
Binary file added doc/plasticThread.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
254 changes: 152 additions & 102 deletions examples/thread_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,110 +27,160 @@
"""
import timeit
import cadquery as cq
from cq_warehouse.thread import IsoThread, AcmeThread, MetricTrapezoidalThread
from cq_warehouse.thread import (
IsoThread,
AcmeThread,
MetricTrapezoidalThread,
PlasticBottleThread,
)

MM = 1
IN = 25.4 * MM

""" IsoThread Internal Example """
starttime = timeit.default_timer()
iso_internal_thread = IsoThread(
major_diameter=6 * MM,
pitch=1 * MM,
length=4.35 * MM,
external=False,
end_finishes=("square", "chamfer"),
hand="left",
)
elapsed_time = timeit.default_timer() - starttime
print(f"IsoThread internal elapsed time: {elapsed_time:.3f}s")
iso_internal_core = (
cq.Workplane("XY")
.polygon(6, iso_internal_thread.major_diameter * 1.5)
.circle(iso_internal_thread.major_diameter / 2)
.extrude(iso_internal_thread.length)
)
iso_internal = iso_internal_thread.cq_object.fuse(iso_internal_core.val())
print(f"{iso_internal.isValid()=}")

""" IsoThread External Example """
starttime = timeit.default_timer()
iso_external_thread = IsoThread(
major_diameter=6 * MM,
pitch=1 * MM,
length=10 * MM,
external=True,
end_finishes=("fade", "square"),
hand="left",
)
elapsed_time = timeit.default_timer() - starttime

iso_external_core = (
cq.Workplane("XY")
.circle(iso_external_thread.min_radius)
.extrude(iso_external_thread.length)
)
iso_external = iso_external_thread.cq_object.fuse(iso_external_core.val())
print(f"{iso_external.isValid()=}")

""" AcmeThread Example """
starttime = timeit.default_timer()
acme_thread = AcmeThread(size="1/4", length=1 * IN)
elapsed_time = timeit.default_timer() - starttime
print(f"AcmeThread elapsed time: {elapsed_time:.3f}s")
acme_core = (
cq.Workplane("XY").circle(acme_thread.root_radius).extrude(acme_thread.length)
)
acme = acme_thread.cq_object.fuse(acme_core.val())
print(f"{acme.isValid()=}")

""" MetricTrapezoidalThread example """
starttime = timeit.default_timer()
metric_thread = MetricTrapezoidalThread(size="8x1.5", length=20 * MM)
elapsed_time = timeit.default_timer() - starttime
print(f"MetricTrapezoidalThread elapsed time: {elapsed_time:.3f}s")
metric_core = (
cq.Workplane("XY").circle(metric_thread.root_radius).extrude(metric_thread.length)
)
metric = metric_thread.cq_object.fuse(metric_core.val())
print(f"{metric.isValid()=}")

""" end_finishes example """
end_finishes = [["raw", "fade"], ["square", "chamfer"]]
end_examples = []
end_examples_cores = []
for i in range(2):
for j in range(2):
iso_end_thread = IsoThread(
major_diameter=3 * MM,
pitch=1 * MM,
length=4 * MM,
end_finishes=("square", end_finishes[i][j]),
)
end_examples.append(
iso_end_thread.cq_object.translate(
cq.Vector((i - 0.5) * 5, (j - 0.5) * 5, 0)
ISO_INTERNAL = 0
ISO_EXTERNAL = 1
ACME = 2
METRIC_TRAPEZOIDAL = 3
END_FINISHES = 4
PLASTIC_EXTERNAL = 5
PLASTIC_INTERNAL = 6
example = PLASTIC_EXTERNAL


if example == ISO_INTERNAL:
"""IsoThread Internal Example"""
starttime = timeit.default_timer()
iso_internal_thread = IsoThread(
major_diameter=6 * MM,
pitch=1 * MM,
length=4.35 * MM,
external=False,
end_finishes=("square", "chamfer"),
hand="left",
)
elapsed_time = timeit.default_timer() - starttime
print(f"IsoThread internal elapsed time: {elapsed_time:.3f}s")
iso_internal_core = (
cq.Workplane("XY")
.polygon(6, iso_internal_thread.major_diameter * 1.5)
.circle(iso_internal_thread.major_diameter / 2)
.extrude(iso_internal_thread.length)
)
iso_internal = iso_internal_thread.cq_object.fuse(iso_internal_core.val())
print(f"{iso_internal.isValid()=}")

if "show_object" in locals():
show_object(iso_internal_thread.cq_object, name="iso_internal_thread")
show_object(iso_internal_core, name="iso_internal_core")
show_object(iso_internal, name="iso_internal")

elif example == ISO_EXTERNAL:

"""IsoThread External Example"""
starttime = timeit.default_timer()
iso_external_thread = IsoThread(
major_diameter=6 * MM,
pitch=1 * MM,
length=10 * MM,
external=True,
end_finishes=("fade", "square"),
hand="left",
)
elapsed_time = timeit.default_timer() - starttime

iso_external_core = (
cq.Workplane("XY")
.circle(iso_external_thread.min_radius)
.extrude(iso_external_thread.length)
)
iso_external = iso_external_thread.cq_object.fuse(iso_external_core.val())
print(f"{iso_external.isValid()=}")

if "show_object" in locals():
show_object(iso_external_thread.cq_object, name="iso_external_thread")
show_object(iso_external_core, name="iso_external_core")
show_object(iso_external, name="iso_external")

elif example == ACME:

"""AcmeThread Example"""
starttime = timeit.default_timer()
acme_thread = AcmeThread(size="1/4", length=1 * IN)
elapsed_time = timeit.default_timer() - starttime
print(f"AcmeThread elapsed time: {elapsed_time:.3f}s")
acme_core = (
cq.Workplane("XY").circle(acme_thread.root_radius).extrude(acme_thread.length)
)
acme = acme_thread.cq_object.fuse(acme_core.val())
print(f"{acme.isValid()=}")

if "show_object" in locals():
show_object(acme_thread.cq_object, name="acme_thread")
show_object(acme_core, name="acme_core")
show_object(acme, name="acme")

elif example == METRIC_TRAPEZOIDAL:

"""MetricTrapezoidalThread example"""
starttime = timeit.default_timer()
metric_thread = MetricTrapezoidalThread(size="8x1.5", length=20 * MM)
elapsed_time = timeit.default_timer() - starttime
print(f"MetricTrapezoidalThread elapsed time: {elapsed_time:.3f}s")
metric_core = (
cq.Workplane("XY")
.circle(metric_thread.root_radius)
.extrude(metric_thread.length)
)
metric = metric_thread.cq_object.fuse(metric_core.val())
print(f"{metric.isValid()=}")

if "show_object" in locals():
show_object(metric_thread.cq_object, name="metric_thread")
show_object(metric_core, name="metric_core")
show_object(metric, name="metric")

elif example == END_FINISHES:
"""end_finishes example"""
end_finishes = [["raw", "fade"], ["square", "chamfer"]]
end_examples = []
end_examples_cores = []
for i in range(2):
for j in range(2):
iso_end_thread = IsoThread(
major_diameter=3 * MM,
pitch=1 * MM,
length=4 * MM,
end_finishes=("square", end_finishes[i][j]),
)
)
end_examples_cores.append(
cq.Workplane("XY")
.cylinder(4 * MM, iso_end_thread.min_radius, centered=(True, True, False))
.translate(cq.Vector((i - 0.5) * 5, (j - 0.5) * 5, 0))
)


if "show_object" in locals():
show_object(iso_internal_thread.cq_object, name="iso_internal_thread")
show_object(iso_internal_core, name="iso_internal_core")
show_object(iso_internal, name="iso_internal")
show_object(iso_external_thread.cq_object, name="iso_external_thread")
show_object(iso_external_core, name="iso_external_core")
show_object(iso_external, name="iso_external")
show_object(acme_thread.cq_object, name="acme_thread")
show_object(acme_core, name="acme_core")
show_object(acme, name="acme")
show_object(metric_thread.cq_object, name="metric_thread")
show_object(metric_core, name="metric_core")
show_object(metric, name="metric")
show_object(end_examples, name="end_examples")
show_object(end_examples_cores, name="end_examples_cores")
end_examples.append(
iso_end_thread.cq_object.translate(
cq.Vector((i - 0.5) * 5, (j - 0.5) * 5, 0)
)
)
end_examples_cores.append(
cq.Workplane("XY")
.cylinder(
4 * MM, iso_end_thread.min_radius, centered=(True, True, False)
)
.translate(cq.Vector((i - 0.5) * 5, (j - 0.5) * 5, 0))
)

if "show_object" in locals():
show_object(end_examples, name="end_examples")
show_object(end_examples_cores, name="end_examples_cores")

elif example == PLASTIC_EXTERNAL:
"""asymmetric thread"""
plastic_thread = PlasticBottleThread("M40SP444", external=True)
# print(plastic_thread.__dict__)

if "show_object" in locals():
show_object(plastic_thread.cq_object, name="bottle thread")

elif example == PLASTIC_INTERNAL:
"""asymmetric thread"""
plastic_thread = PlasticBottleThread("M38SP444", external=False)
print(plastic_thread.__dict__)

if "show_object" in locals():
show_object(plastic_thread.cq_object, name="bottle thread")
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = cq_warehouse
version = 0.5.0
version = 0.5.1
author = Gumyr
author_email = gumyr9@gmail.com
description = A cadquery parametric part collection
Expand Down
32 changes: 31 additions & 1 deletion src/cq_warehouse.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: cq-warehouse
Version: 0.5.0
Version: 0.5.1
Summary: A cadquery parametric part collection
Home-page: https://github.com/gumyr/cq_warehouse
Author: Gumyr
Expand Down Expand Up @@ -46,6 +46,7 @@ or CAM systems.
- [AcmeThread](#acmethread)
- [MetricTrapezoidalThread](#metrictrapezoidalthread)
- [TrapezoidalThread](#trapezoidalthread)
- [PlasticBottleThread](#plasticbottlethread)
- [fastener sub-package](#fastener-sub-package)
- [Nut](#nut)
- [Nut Selection](#nut-selection)
Expand Down Expand Up @@ -537,6 +538,35 @@ This class exposes instance variables for the input parameters as well as:
### TrapezoidalThread
The base class of the AcmeThread and MetricTrapezoidalThread classes.

### PlasticBottleThread
The [ASTM D2911 Standard](https://www.astm.org/d2911-10.html) Plastic Bottle Thread.

![AcmeThread](doc/plasticThread.png)

The parameters are:
- `size` (str) : see below
- `external` (bool=True) : external or internal thread selector
- `hand` (Literal["right", "left"] = "right") : twist direction
- `manufacturingCompensation` (float=0.0) : a radius compensation for manufacturing errors

`size` as defined by the ASTM is specified as:
- [L|M][diameter(mm)]SP[100|103|110|200|400|410|415:425|444]
- e.g. M15SP425

where:
- L Style: All-Purpose Thread - trapezoidal shape with 30° shoulders, metal or platsic closures
- M Style: Modified Buttress Thread - asymmetric shape with 10° and 40/45/50° shoulders, plastic closures
- the three digit "Finish" encodes the number of turns, pitch, angles etc.

`manufacturingCompensation` can be used to compensate for over-extrusion of 3D printers. A value of 0.2mm will reduce the radius of an external thread by 0.2mm (and increase the radius of an internal thread) such that the resulting 3D printed part matches the target dimensions.

For example:
```python
thread = PlasticBottleThread(
size="M38SP444", external=False, manufacturingCompensation=0.2 * MM
)
```

## fastener sub-package
Many mechanical designs will contain threaded fasteners of some kind, either in a threaded hole or threaded screws or bolts holding two or more parts together. The fastener sub-package provides a set of classes with which raw threads can be created such that they can be integrated into other parts as well as a set of classes that create many different types of nuts, screws and washers - as follows:
![fastener_disc](doc/fastener_disc.png)
Expand Down
Loading

0 comments on commit 6b4725a

Please sign in to comment.