GithubHelp home page GithubHelp logo

raphael-isvelin / cq_enclosure_builder Goto Github PK

View Code? Open in Web Editor NEW
6.0 1.0 0.0 11.15 MB

Generate printable enclosures for projects in a few lines of code (STL export)

License: Apache License 2.0

Python 100.00%

cq_enclosure_builder's Introduction

cq_enclosure_builder

In just a few lines of code, generate printable enclosures for your projects that can resist >100 kg/220 lbs (*see Strength test).

The part shown in the Features and Strength test sections below weights 68g and would cost about 1.36€ in plastic (assuming a price of 20€/kg), but could be halved for a weaker prototyping version.

While the builder currently meets my needs, the project isn't battle-tested yet, as I've only used it for one ongoing project. If you encounter any problems or have features you'd like to see, please feel free to contribute or create an issue. Thanks!

Features

  • Parts library: includes jacks, barrel plugs, USBs, and more (22 parts across 16 categories so far—see List of built-in parts).
    • Easy to extend with your own parts (e.g. the specific model of SPST you're using).
    • Create custom parts from existing STEP files (converted from STL if necessary).
  • Screwable lid: supports heat set inserts and regular printed threads.
  • Layout builder: offers parametric lines and grids of parts.
  • STL export: generates ready-to-print files.

Below, you can find the code used to generate an enclosure, the 3D preview, and the printed result (the seamlines [Z-seam] and generate print quality can be improved by tweaking your printer and slicer settings):

Code, preview, and printed sample

A more complex enclosure using the Layout builder to align parts: (WIP, part of my soon-to-be released modular multi-effect guitar pedal)

Octopus


Summary


Install

Quick install

$ python setup.py install

Note: if you already have the required dependencies (see Manual install), this is not required to run the examples.

This will install cq_enclosure_builder on your system, as well as the required libraries (CadQuery and cq_warehouse.).

You'll also need to copy a file to your cq_warehouse install folder, as this project uses a custom type of screw. See flat_head_parameters.csv in the section below. (In future versions, the default type of screw used will be change, to reduce complexity; see issue #5.)

Manual install

First, you'll need to install CadQuery.

Then, install the library used to generate screws: cq_warehouse.

Finally, copy the custom screw used by the project in cq_warehouse's install folder:'

# Or wherever your cq_warehouse install folder is
$ cp src/cq_enclosure_builder/screws/flat_head_parameters.csv ~/miniconda3/lib/python3.10/site-packages/cq_warehouse/flat_head_parameters.csv

UI

There are a few available UIs you can choose from, including:

To run the examples, just open them with the UI you've picked, and they should work right away. If I missed a required dependency, please let me know!

Examples (with screenshots)

You can explore the provided examples. If you're using jupyter-cadquery, check out 00_all_examples.ipynb which groups all examples into a single Notebook.

For other UIs, navigate to the examples directory and open the individual .py files with your chosen UI.

01 – Panel with buttons

A single Panel (side of an enclosure) with two buttons.

Panel with buttons

01_panel_with_button.py

02 – Set default part types and parameters

Almost the same as above, but shows how PartsFactory's set_default_types and set_default_parameters can help you make your code more readable, by removing the need to repeat the part_type (e.g. with specific model of SPST you're using for your project), and removing the need to repeat common parameters such as enclosure_wall_thickness.

Panel with Set default part types and parameters

02_default_part_type_and_parameters.py

03 – Panel's optional parameters

Shows optional parameters for the Panel class (see API Reference). Here, we've updated the panel colour, the part colour, and the panel's transparency.

Panel's optional parameters

03_panel_optional_params.py

04 – Enclosure with buttons

A simple Enclosure with an 'exploded' view.

Enclosure with buttons

04_enclosure_with_button.py

05 – Enclosure: export STLs

Enclosure's export_printables will generate ready-to-print STLs files for each distinct part of your project. Most enclosures will typically require only to parts to print: the main section (box) and a lid, while others will require additional prints (such as brackets to hold a specific type of screen in this example).

Enclosure: export STLs

05_export_enclosure_stls.py

06 – Enclosure: optional parameters

Shows optional parameters for the Enclosure class. Here, we've updated a few parameters, but the most visibles in the screenshot below is that we've removed the fillet (rounded corners) on the top and bottom of the enclosure.

We've also changed the project's name, which generated printables STLs with a customisd name.

Enclosure: optional parameters

06_enclosure_optional_params.py

06.5 – Enclosure: custom screws placement

Certainly! Here's a revised version of your description:

By default, the Enclosure includes four screws at its corners. However, you can customize this setup. In the following example, we added two M2 screws with printed threads, complementing the default four M3 heat set inserts.

Enclosure: custom screws placement

06_5_enclosure_custom_screws.py

07 – Layout builder: simple line

Using LayoutGroup to build a simple line of three components. See optional parameters to center the line on (0,0), add margin between each element, etc.

Layout builder: simple line

07_layout_builder_simple_line.py

08 – Layout builder: fixed-width line

Line of N components taking all the available space. Here, we're aligning the parts by their 'external footprint': the outward-facing section of the components, such as the hole of a USB or the knobs of potentiometers.

In the screenshot below, the beige rectangle represents the PCB onto which the USB A connector is mounted, which is larger than the USB port itself. Conversely, for the button and encoder, the cap and knob are more prominent than their respective base components.

Layout builder: fixed-width line

08_layout_builder_fixed_width_line.py

09 – Layout builder: fixed-width line with median part centred at (0,0)

In this fixed-width line layout, we aim to position the median element (in this instance, the second out of three) directly at the coordinate (0,0). By default, this positioning might not be achieved if the footprint of the element(s) to its left differs from that of the element(s) to its right. Though will make the spacing slightly uneven, it's useful when we want to force an element at (0,0).

Layout builder: fixed-width line with median part centred at (0,0)

09_layout_buider_fixed_width_line_centre_at_0_0.py

10 – Layout builder: grid of parts

Create a grid of any component (6.35mm jacks in this case). You can define the number of rows and columns, as well as the spacing between them.

Layout builder: grid of parts

10_layout_builder_grid_of_parts.py

11 – Layout builder: combining groups

You can combine multiple LayoutGroup (and LayoutElement instances. In this example, we've evenly spaced two grids of jacks (6.35mm and 3.5mm) along with a single USB A on the panel.

Layout builder: combining groups

11_layout_builder_combining_groups.py

12 – Text (cut and extruded)

You can add extruded and cut text (e.g. for your project's name and version).

Text

12_text.py

13 – Support for parts

For parts under heavy stress, such as the switch on a guitar pedal, you can add a support pillar underneath if there's available space.

Support for parts

13_support_for_part.py

14 – Holders for Raspberry Pi and protoboard

Screws to hold your PCBs in place.

For the protobard, the screws can be positioned arbitrarily (grid coordinates).

Support for Raspberry Pi and protoboard

14_holders_for_pi_and_protoboard.py

15 – Add a new Part

See Adding a new Part for more details.

Add a new Part

15_add_new_part.py

16 – Add a new Part from a STL/STEP file

In this example, I've made a model using Tinkercad, which I exported as a STL. Fusion 360 then allowed me to convert it to STEP. (You can also use online converters, though I've had some format issues with these.)

After creating a new Part and filling a few fields (size, etc.), you'll be able to add it to your enclosure.

Add a new Part from a STL/STEP file

16_add_new_part_from_step.py

17 – All parts

Show all available parts.

For a detailed list, scroll down to List of built-in parts.

Note: the default caps/knobs are shown, but there's a dozen available, and more can be added by taking four simple measurements.

All parts

17_all_parts.py


Available parts

List of built-in parts

For many parts, I've provided purchase links within the docstrings of the Python code, so you can obtain the exact item I used for modeling them.

Adding a new Part

See example 15 above.

Each part belongs to a category, such as button, encoder, screen, and so forth. (New categories can be added on the fly.)

Steps

  1. Copy the file __template.py to a location in your project.
  2. (Optional) Use the @register_part("<category>", "<part_type>") decorator.
    • <category> should match the sub-folder if contributing. Otherwise, it can be any valid Python identifier.
    • <part_type> represents the reference for your component (e.g. PBS 11-A).
  3. If your part's category doesn't exist, no problem! A new build method—build_<your new category>—will be automatically added to the PartsFactory.
    • For contributors: simply create a new sub-package in the previously mentioned folder.
  4. You'll now be able to use your part as follows:
from cq_enclosure_builder import PartsFactory as pf

my_part = pf.build_<category>(part_type="<part_type>")

Note 1: set your part as default for this category with PartsFactory's set_default_types.

Note 2: the @register_part decorator is optional but allows for integration with PartsFactory and its built-in caching. Without it, instantiate your object as usual, like MyPart().

Adding a new Part from a STL or STEP file

CadQuery only supports importing STEP files. If you're working with an STL, you can easily convert them to STEP using Fusion 360, or online converters (though I've had some format issues with these).

Once you have a STEP file, follow the steps (ah!) shown in example 16.


Strength test

The enclosures should be strong enough for most common needs, including guitar pedals (which experience regular stomping!)

I conducted two tests using this Silk PLA. Standard PLA should be somewhat stronger, while PLA+ will significantly deform before it snaps. For thorough research on what makes a print strong, see CNC Kitchen on YouTube.

  • in the first test, the enclosure was constructed without any support beneath the SPST;
  • for the second test, a small 'pillar' was added underneath the SPST (see example 13 above), making it very solid (if you don't plan to stand on top of it).

The code used to generate the STLs for these tests can be found here.

Note: smart use of supports can make the print extremely strong in regular use [stomping on the button], and while it should resist some drops and other types of hits, at the end of the day, (including some drops), it's still just plastic!

With support, can resist >100 kg ('unlimited', as there's no floating part) Without support, resists 20-35 kg before the first crack... ...but likely won't break right away
Strength test: with support Strength test: without support Strength test: without support, partially broken

API Reference

class: Enclosure

Method or Value Name Parameters Description
__init__
  • size: EnclosureSize
  • project_info: ProjectInfo (default: ProjectInfo()): name and version are used for naming the exported STLs.
  • lid_on_faces: List[Face] (default: [Face.BOTTOM]): which side of the enclosure has a screwable lid. Only BOTTOM is supported as of now; see issues #2 and #3.
  • lid_panel_size_error_margin: float (default: 0.8): how small the lid panel is on both width and length compared to the lid hole.
  • lid_thickness_error_margin: float (default: 0.4): if >0, the lid screws and support will be slightly sunk in the enclosure.
  • add_corner_lid_screws: bool (default: True)
  • add_lid_support: bool (default: True): add a rim around the enclosure to prevent the lid from sinking in.
  • add_top_support: bool (default: True): small support 'skirt' to increase the strength of the top of the enclosure.
  • lid_screws_heat_set: bool (default: True): use heat-set inserts instead of printing a screw threads for the lid corner screws.
  • lid_screws_size_category: str (default: m2): size of screws to use for the default lid corner screws; see DefaultHeatSetScrewProvider or DefaultScrewProvider for the available sizes.
  • no_fillet_top: bool (default: False)
  • no_fillet_bottom: bool (default: False)
add_part_to_face -> None
  • face: Face
  • part_label: str: will be shown in the tree when using certain UIs such as jupyter-cadquery.
  • part: Part
  • rel_pos: Tuple[float, float] (default: None; either rel_pos or abs_pos must be specified): position relative to the centre of the Panel.
  • abs_pos: Tuple[float, float] (default: None; needs one): position from one corner of the Panel.
  • color: cq.Color (default: None; defaults to Panel's default)
assemble -> None
  • walls_explosion_factor: float (default: 1.0): a value >1 will move the enclosure's walls aways, giving a better inside view.
  • lid_panel_shift: float (default: 0.0): move the lid panel (default: BOTTOM) away from the enclosure.
Needs to be called before calling export_printables or using the assembly.
export_printables -> None none Export one STL per printable. By default, one for the lid and for the box. Some parts can require additional prints; any element added to Part's additional_printables will also be exported.
add_screw -> None
  • screw_size_category: str (default: m3): the size of your screw; the options available depends on your chosen screw_provider (by default, one of: m1.4, m2, m2.5, m3, m3.5, m4, and m5).
  • block_thickness: float (default: 8): the depth of your screw.
  • rel_pos: Tuple[float, float] (default: None; either rel_pos or abs_pos must be specified): position relative to the centre of the panel.
  • abs_pos: Tuple[float, float] (default: None; needs one): position from one corner of the panel.
  • pos_error_margin: float (default: 0.0): should match the value of lid_thickness_error_margin in Enclosure's constructor.
  • taper: TaperOptions (default: TaperOptions.NO_TAPER): generally, you'll want to opt for Z_TAPER_CORNER or Z_TAPER_SIDE, to prevent printing issues.
  • screw_provider (default: DefaultScrewProvider): the main difference is whether your screw has printed thread, or a hole for a heat set insert. See screws_providers.py if you have specific needs (e.g. a thinner screw block).
  • counter_sunk_screw_provider (default: DefaultScrewProvider): affects the shape of the countersunk hole in the lid. If you're using regular pan head or countersunk screws, they might be sticking out a bit of the enclosure, as the default provider uses flat head screws (see issue #5); you'll need to create a custom screw provider, based on the ones available in screws_providers.py. If this is important to you, please create an issue.
  • with_counter_sunk_block: bool (default: True): if False, it won't make any hole in the lid panel.
Used to add more screws than the four corner scresw that can be added automatically using __init__'s add_corner_lid_screws. See example 6.5.
(value) assembly: cq.Assembly N/A Contains a displayable assembly with the panels (incl. parts), frame, lid screws, and lid support.
(value) debug: cq.Assembly N/A Debug elements: footprints, holes, panels masks, printables, and other debug elements added by the parts (Part's debug_objects).
(value) assembly_with_debug: cq.Assembly N/A Assembly containing the two previous assemblies.
(value) all_printables_assembly: cq.Assembly N/A Contains all the printables models, which can be exported with export_printables.

Method Name Parameters Description
build -> Part
  • category_name: str
  • part_type: str (default: any default value for this category set with set_default_types).
  • throw_on_validation_error: bool (default: True): useful when adding new parts to make sure nothing's missing.
  • **kwargs: Any: any parameter needed by the part you're building.
build_<category_name> -> Part same as above (without category_name) Dynamically generated for each new category registered with @register_part.
list_categories -> List[str] N/A List all the categories registered in the factory, e.g. ["encoder", "midi", ...].
list_types_for_category -> List[str]
  • category_name: str
List all the types available for a given category (for instance, various types of USB C connectors).
list_types_of_<category_name> -> List[str] N/A Same as above, without needing to provide category_name as parameter. Dynamically generated.
set_default_types -> None
  • defaults: Dict[str, str]: the default part type to use per category; for example: {"<samecategory_name>": '<a type from that category>}.
Set the default part for any category, so you don't have to repeat part_type="<type>" each time you're building a part.
set_default_parameters -> None
  • defaults: Dict[str, Any]: the default values to use when encountering field with this name when building a part; for example: {"<param_name>": 123.45}.
For instance, if setting a default value for enclosure_wall_thickness, it won't have to be repeated explicitly each time you're building a part. Can be overridden.
set_defaults -> None
  • defaults: Dict[str, Dict]: should contains two keys, types and parameters.
Sets both set_default_types and set_default_parameters at once.

Method Name Parameters Description
__init__
  • label: str
  • part: Part
move_to -> Self
  • pos: Tuple[float, float]
translate -> Self
  • pos: Tuple[float, float]
get_pos -> Tuple[float, float] none Get the relative pos (centre is 0,0).
get_abs_pos -> Tuple[float, float] Get the absolute based on the size of the panel.
set_inside_footprint_x -> None
  • new_x: float
Override the real footprint of the element. See example 9 for use case.
set_outside_footprint_x -> None
  • new_x: float
see above
set_footprints_x -> None
  • new_x: float
see above

Set both inside and outside at once.
set_inside_footprint_y -> None
  • new_y: float
Override the real footprint of the element. See example 9 for use case.
set_outside_footprint_y -> None
  • new_y: float
see above
set_footprints_y -> None
  • new_y: float
see above

Set both inside and outside at once.

class: LayoutGroup (layout builder), inherits LayoutElement

Method Name Parameters Description
__init__ not needed
move_to -> Self
  • pos: Tuple[float, float]
Same as LayoutElement. Set the pos of the entire group.
translate -> Self
  • pos: Tuple[float, float]
Same as LayoutElement. Translate all the elements of the group.
get_pos -> Tuple[float, float] none Get the relative pos (centre is 0,0).
get_elements -> List[LayoutElement] none Returns all the elements of the group. If there's nested groups, it flatten them by recurisvely calling get_elements.
(static) line_of_parts -> LayoutGroup
  • parts: Union[Part, Tuple[str, Part]]: accepts either a list of parts or a list of tuples. Each tuple should contain a label for the part followed by the part itself.
  • margin: float (default: 5): the spacing between each element.
  • horizontal: bool (default: True): if False, the line will be vertical.
  • align_other_dimension_at_0: bool (default: True): if True, each element will be translate by inside_footprint_offset (if horizontal, it will only translate the Y position; and vice versa).
  • align_start_to_outside_footprint: bool (default: False): dietermines alignment for the starting point. If True, the ouside_footprint of the first element aligns with position 0 (this is relevant if the inside_footprint is larger than the outside). Otherwise, it uses the total_footprint, selecting whichever dimension is largest.
  • align_to_outside_footprint: bool (default: False): if True, the outside_footprint of all parts will directly be in context (when margin=0). Otherwise, it uses the total_footprint, selecting whichever dimension is largest.
Return a simple group where each part is next to each other in a line.
(static) line_of_elements -> LayoutGroup The rest is identical to line_of_parts. The element variant is useful to combine groups.
(static) fixed_width_line_of_parts -> LayoutGroup
  • size: float: the maximum space taken by the line.
  • parts: Union[Part, Tuple[str, Part]]: either a list of parts or a list of tuple containing a label for the part and part itself.
  • horizontal: bool (default: True)
  • add_margin_on_sides: bool (default True): if False, the first and last elements will be touching the start and end of the line; if True, the same margin found between each element will also be at the start and end.
  • group_center_at_0_0: bool (default: True): see line_of_parts.
  • align_other_dimension_at_0: bool (default: True): see line_of_parts.
  • align_to_outside_footprint: bool (default: False): see line_of_parts.
Return a line of element spaced equally, taking a set amount of space.
(static) fixed_width_line_of_elements -> LayoutGroup The rest is identical to fixed_width_line_of_parts (same order—elements is the second parameter). The element variant is useful to combine groups.
(static) line_of_parts -> LayoutGroup
  • parts: Union[Part, Tuple[str, Part]]: accepts either a list of parts or a list of tuples. Each tuple should contain a label for the part followed by the part itself.
  • margin: float (default: 5): the spacing between each element.
  • horizontal: bool (default: True): if False, the line will be vertical.
  • align_other_dimension_at_0: bool (default: True): if True, each element will be translate by inside_footprint_offset (if horizontal, it will only translate the Y position; and vice versa).
  • align_start_to_outside_footprint: bool (default: False): dietermines alignment for the starting point. If True, the ouside_footprint of the first element aligns with position 0 (this is relevant if the inside_footprint is larger than the outside). Otherwise, it uses the total_footprint, selecting whichever dimension is largest.
  • align_to_outside_footprint: bool (default: False): if True, the outside_footprint of all parts will directly be in context (when margin=0). Otherwise, it uses the total_footprint, selecting whichever dimension is largest.
Return a simple group where each part is next to each other in a line.
(static) grid_of_part -> LayoutGroup
  • label: str
  • part: Part
  • rows: int: number of rows.
  • cols: int: number of columns.
  • margin_rows: float (default: 5): margin between each row.
  • margin_cols: float (default: 5): margin between each col.
  • align_to_outside_footprint: bool (default: False): see line_of_parts.
Return a grid of rows x cols made up the same Part.

class: Panel

Method Name Parameters Description
__init__
  • face: Face: refers to the panel's face which is used to establish its orientation.
  • size: PanelSize: specifies the panel's dimensions: width, length, and wall_thickness.
  • color: Tuple[float, float, float] (default: None—uses the Face's default): the colour of the panel's wall.
  • part_color: Tuple[float, float, float] (default: None—uses the Face's default): the colour of the panel's parts.
  • alpha: float (default: 1.0): the panel wall's transparency (doesn't affect its parts).
  • lid_size_error_margin: float (default: 0.0): applicable only for the lid panel. If a value is provided, the actual size of the panel will be smaller than the defined size, but the mask will retain the provided size.
  • project_info: ProjectInfo (default: ProjectInfo()): only used for logging in this class.
add -> None
  • label: str: the name of the part.
  • part: Part
  • rel_pos: Tuple[float, float] (default: None; either rel_pos or abs_pos must be specified): position relative to the centre of the panel.
  • abs_pos: Tuple[float, float] (default: None; needs one): position from one corner of the panel.
  • color: Tuple[float, float, float] (default: None—will use the default of the panel's Face)
  • alpha: float (default: 1.0)
assemble -> None none Should be called before using the values below, otherwise you won't like it.
(value) panel: cq.Workplane N/A The panel 'wall' and all its parts.
(value) mask: cq.Workplane N/A A solid box of the size (size.width, size.length, size.wall_thickness)
(value) debug_assemblies: Dict[str, Union[Dict, cq.Workplane]] N/A Assemblies: footprint_in, footprint_out, hole, other (from the debug_objects field of the panel's part), combined.

class: Part

Method Name Parameters Description
__init__ none No-arg constructors; sets the variables below to their default values.
(value) part: cq.Workplane N/A The part that will be added to the panel.
(value) assembly_parts: List[AssemblyPart] (default: None) AssemblyPart consists of three fields: workplane: cq.Workplane, name: str, and color: cq.Color. It's utilized to visually distinguish sub-parts, like coloring screws differently. If AssemblyPart is present, it will be used for display; otherwise, the part field will be used. Even if they are equivalent, the part should still be set. Refer to the comments in Part for more details.
(value) mask: cq.Workplane N/A Will be cut from the panel, should likely be the same width/length as the part.
(value) size: PartSize N/A PartSize consists of three fields: width: float, length: float, and thickness: float.
(value) additional_printables: Dict[str, Tuple[float, float], cq.Workplane] N/A Workplanes in this map will be export when calling Enclosure's export_printables'. Dict of (, , )`.
(value) inside_footprint: Tuple[float, float] N/A Needed by the layout builder (LayoutGroup) to position elements.
(value) inside_footprint_thickness: float N/A Currently, only used when wanting to create a "pyramid" support to sit underneath another part, for added strength.
(value) inside_footprint_offset: Tuple[float, float] N/A The distance from the centre-point of the inside_footprint to the coordinate (0,0). This is used by the layout builder.
(value) outside_footprint: Tuple[float, float] N/A Needed by the layout builder (LayoutGroup) to position elements.
(value) outside_footprint_thickness: float N/A Unused at the moment; required field nonetheless.
(value) outside_footprint_offset: Tuple[float, float] (default: (0,0)) N/A The current design assumes the centre-point of the outside_footprint is at the coordinate (0,0). If this isn't the case for your specific part (for instance, if the center of your USB connector's hole isn't exactly at (0,0)), the layout builder may not function optimally.
(value) debug_objects: DebugObjects N/A Used to obtain visual insights about your part. For example, it can display how much an SPST is sticking out from an enclosure, including its caps.

Value Name Parameters Description
__init__ none
(value) footprint: DebugObjects.Footprint N/A Sub-classes has two fields, inside: cq.Workplane and outside: cq.Workplane (default for both: None). It is used to show the actual space taken by the part. If you're creating a new part, you likely want to set these fields if relevant.
(value) hole: cq.Workplane (default: None) N/A Visual representation of the hole in the enclosure (e.g. for a USB port, it will simply be the size of the connector).
(value) others: Dict[str, cq.Workplane] N.A Shown in the Panel's and Enclosure's debug assemblies.

If there's any problem, feel free to open a PR, or create an issue; thanks!

cq_enclosure_builder's People

Contributors

raphael-isvelin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

cq_enclosure_builder's Issues

Add tests

Need to add some tests. especially for the layout builder, which is the most complex and brittle part.

Could dig into cq.Workplane and cq.Assembly, and see if we can serialise them. An uglier way would be to simply diff an exported STL/STEP file. Would still be better than nothing.

CI to publish package on PyPI

Would be a neat way to simplify the install process.

Though it likely would first require to deal with the CSV that needs to be copied to cq_werahouse's folder: #5.

Support for multiple lids

Note if you're reading: I don't have a big need for it for now and might not for a while: if you do, feel free to comment on the issue.

While Enclosure's constructor takes lid_on_faces: List[Face], it throws if it's anything other than [Face.BOTTOM].

Allowing to have multiple lids could be convenient in some cases. Would need to have a way to move the screw away from the corners, so they don't collide.

First step: #2.

Add nut/washer to outside footprints of parts

For now, the nut and washer of screwable parts (mostly inheriting GenericThreadedPart or GenericThreadedWithStopPart) are not taken into account in the outside_footprint (neither reflected in the default outside footprint workplane).

This is generally non-consequential (especially for the parts with a cap/knob), but it can create some issues when building layouts automatically aligned based on their outside footprints.

Improve usability of `Enclosure#add_screw`

It's a bit cumbersome to use, because it requires you to--before calling it--create a ScrewBlock only to get its size, to be able to set the correct position for the screw, as the screw is centred on (0,0). (Or to hardcode the size.)

A neat solution could be to create a new method like add_screw_on_side/line, accepting a side (e.g. UP, DOWN, LEFT, RIGHT), and a position on the line. This could, it could even determine automatically whether to use Z_TAPER_CORNER or Z_TAPER_SIDE.

Stop using `FlatHeadScrew` as the default screw

This makes the install process a bit more complicated, as it requires to copy a CSV to cq_warehouse's install folder. Especially true when it comes to publishing the package on PyPI: #6.

Note: we can also check whether there's a way around the CSV needing to be present in cq_warehoue's folder.

Support for lid != `BOTTOM`

Note if you're reading: I don't have a big need for it for now and might not for a while: if you do, feel free to comment on the issue.

While Enclosure's constructor takes lid_on_faces: List[Face], it throws if it's anything other than [Face.BOTTOM].

We need to support this use case, which will also be a first step to handle multiple lids: #3.

Allow lid panel to have a different wall_thickness

Because it's a pretty large area (e.g. ~200x130mm for my Octopus pedal), with no hole, it requires a long print time and large amount of plastic, for likely barely any added strength (when the lid is the BOTTOM panel).

As such, it would be nice to be able to set a different wall_thickness for the lid panel (optionally: for each panels individually).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.