Skip to content

Commit

Permalink
dfn: Generate 3D models
Browse files Browse the repository at this point in the history
  • Loading branch information
ubruhin committed Nov 15, 2024
1 parent 77c0142 commit 5ce6bc4
Show file tree
Hide file tree
Showing 3 changed files with 385 additions and 11 deletions.
31 changes: 30 additions & 1 deletion dfn_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

from typing import Callable, Optional
from typing import Any, Callable, Optional, Tuple

from entities.common import Angle, Circle, Diameter, Fill, GrabArea, Layer, Polygon, Position, Vertex, Width
from entities.package import Footprint
Expand Down Expand Up @@ -32,6 +32,9 @@
0.35: 0.25
}

# The real CadQuery types are not known statically, thus allowing any type.
StepModificationFn = Callable[[Any, Any, Any], Tuple[Any, Any]]


class DfnConfig:
def __init__(self,
Expand All @@ -53,6 +56,7 @@ def __init__(self,
library: Optional[str] = None,
pin1_corner_dx_dy: Optional[float] = None, # Some parts have a triangular pin1 marking
extended_doc_fn: Optional[Callable[['DfnConfig', Callable[[str], str], Footprint], None]] = None,
step_modification_fn: Optional[StepModificationFn] = None,
):
self.length = length
self.width = width
Expand Down Expand Up @@ -84,6 +88,7 @@ def __init__(self,
self.library = library or "LibrePCB_Base.lplib"

self.extended_doc_fn = extended_doc_fn
self.step_modification_fn = step_modification_fn


JEDEC_CONFIGS = [
Expand Down Expand Up @@ -304,6 +309,27 @@ def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -
return _draw


def step_modification_sphere(diameter: float) -> StepModificationFn:
def _fn(body: Any, dot: Any, workplane: Any) -> Tuple[Any, Any]:
return body.cut(workplane.sphere(diameter / 2, centered=True)), dot
return _fn


def step_modification_cylinder(x: float, y: float, diameter: float, length: float) -> StepModificationFn:
def _fn(body: Any, dot: Any, workplane: Any) -> Tuple[Any, Any]:
cutout = workplane.transformed(offset=(x, y, 0), rotate=(0, 90, 0)) \
.cylinder(length, diameter / 2, centered=True)
return body.cut(cutout), dot
return _fn


def step_modification_sgp3x(body: Any, dot: Any, workplane: Any) -> Tuple[Any, Any]:
dot = workplane.cylinder(0.2, 0.6, centered=[True, True, False]) \
.transformed(offset=(0.5, 0.5, 0), rotate=(0, 0, 45)) \
.box(0.3, 0.3, 0.3, centered=[True, True, False])
return body, dot


THIRD_CONFIGS = [
# length, width, pitch, pin_count, height_nominal, height_max, lead_length, exposed_width, exposed_length, keywords

Expand All @@ -326,6 +352,7 @@ def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -
no_exp=False,
pin1_corner_dx_dy=0.2,
extended_doc_fn=draw_circle(diameter=0.9),
step_modification_fn=step_modification_sphere(0.9),
),
DfnConfig(
length=3.0,
Expand All @@ -345,6 +372,7 @@ def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -
no_exp=False,
pin1_corner_dx_dy=0.2,
extended_doc_fn=draw_rect(x=0, y=-0.7, width=2.2, height=0.6),
step_modification_fn=step_modification_cylinder(x=0, y=-0.7, diameter=0.6, length=2.2),
),
DfnConfig(
length=2.45,
Expand All @@ -364,6 +392,7 @@ def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -
no_exp=False,
pin1_corner_dx_dy=0.3,
extended_doc_fn=draw_circle(diameter=1.1),
step_modification_fn=step_modification_sgp3x,
),

# Microchip
Expand Down
101 changes: 91 additions & 10 deletions generate_dfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Generate DFN packages
"""
import sys
from os import path
from uuid import uuid4

Expand All @@ -16,9 +17,9 @@
generate_courtyard
)
from entities.package import (
AssemblyType, AutoRotate, ComponentSide, CopperClearance, Footprint, FootprintPad, LetterSpacing, LineSpacing,
Mirror, Package, PackagePad, PackagePadUuid, PadFunction, Shape, ShapeRadius, Size, SolderPasteConfig,
StopMaskConfig, StrokeText, StrokeWidth
AssemblyType, AutoRotate, ComponentSide, CopperClearance, Footprint, Footprint3DModel, FootprintPad, LetterSpacing,
LineSpacing, Mirror, Package, Package3DModel, PackagePad, PackagePadUuid, PadFunction, Shape, ShapeRadius, Size,
SolderPasteConfig, StopMaskConfig, StrokeText, StrokeWidth
)

GENERATOR_NAME = 'librepcb-parts-generator (generate_dfn.py)'
Expand Down Expand Up @@ -81,6 +82,7 @@ def generate_pkg(
keywords: str,
config: DfnConfig,
make_exposed: bool,
generate_3d_models: bool,
create_date: Optional[str] = None,
) -> str:
category = 'pkg'
Expand Down Expand Up @@ -444,23 +446,100 @@ def _generate_footprint(key: str, name: str, pad_extension: float) -> None:
value=Value('{{VALUE}}'),
))

# Approvals
package.add_approval(
"(approved missing_footprint_3d_model\n" +
" (footprint {})\n".format(uuid_footprint) +
")"
)

# Apply function to available footprints
_generate_footprint('reflow', 'reflow', 0.0)
_generate_footprint('hand-soldering', 'hand soldering', 0.3)

# Generate 3D models
uuid_3d = _uuid('3d')
if generate_3d_models:
generate_3d(full_name, uuid_pkg, uuid_3d, config, make_exposed)
package.add_3d_model(Package3DModel(uuid_3d, Name(full_name)))
for footprint in package.footprints:
footprint.add_3d_model(Footprint3DModel(uuid_3d))

# Save package
package.serialize(path.join('out', config.library, category))
return full_name


def generate_3d(
full_name: str,
uuid_pkg: str,
uuid_3d: str,
config: DfnConfig,
make_exposed: bool,
) -> None:
import cadquery as cq

from cadquery_helpers import StepAssembly, StepColor

print(f'Generating pkg 3D model "{full_name}": {uuid_3d}')

dot_diameter = min(config.width * 0.2, 0.6)
dot_position = min(config.width * 0.2, 0.8)
dot_depth = 0.05
dot_x = -(config.width / 2) + dot_position
dot_y = (config.length / 2) - dot_position
lead_standoff = 0.02
lead_height = 0.2

body = cq.Workplane('XY', origin=(0, 0, lead_standoff + (config.height_nominal / 2))) \
.box(config.width, config.length, config.height_nominal)
surface = cq.Workplane('back', origin=(0, 0, lead_standoff + config.height_nominal + 0.05))
dot = surface.cylinder(0.5, dot_diameter / 2, centered=(True, True, False)) \
.translate((dot_x, dot_y, 0))
lead = cq.Workplane("ZY") \
.box(lead_height, config.lead_width, config.lead_length)
if make_exposed:
exposed_lead = cq.Workplane('XY', origin=(0, 0, (lead_height / 2))) \
.box(config.exposed_length, config.exposed_width, lead_height)

if config.step_modification_fn:
body, dot = config.step_modification_fn(body, dot, surface)

body = body.cut(dot)

assembly = StepAssembly(full_name)
assembly.add_body(body, 'body', StepColor.IC_BODY)
assembly.add_body(dot, 'dot', StepColor.IC_PIN1_DOT,
location=cq.Location((0, 0, -0.05 - dot_depth)))
pins_per_side = config.pin_count // 2
for i in range(0, config.pin_count):
side = -1 if (i < pins_per_side) else 1
y1 = get_y(1 if (i < pins_per_side) else pins_per_side,
pins_per_side, config.pitch, False)
y_index = i % pins_per_side
assembly.add_body(
lead,
'lead-{}'.format(i + 1), StepColor.LEAD_SMT,
location=cq.Location((
(((config.width - config.lead_length) / 2) + lead_standoff) * side,
y1 + y_index * config.pitch * side,
lead_height / 2,
))
)
if make_exposed:
assembly.add_body(exposed_lead, 'lead-exposed', StepColor.LEAD_SMT)

# Save without fusing for massively better minification!
out_path = path.join('out', config.library, 'pkg', uuid_pkg, f'{uuid_3d}.step')
assembly.save(out_path, fused=False)


if __name__ == '__main__':
if '--help' in sys.argv or '-h' in sys.argv:
print(f'Usage: {sys.argv[0]} [--3d]')
print()
print('Options:')
print(' --3d Generate 3D models using cadquery')
sys.exit(1)

generate_3d_models = '--3d' in sys.argv
if not generate_3d_models:
warning = 'Note: Not generating 3D models unless the "--3d" argument is passed in!'
print(f'\033[1;33m{warning}\033[0m')

generated_packages: List[str] = []

for config in JEDEC_CONFIGS:
Expand All @@ -487,6 +566,7 @@ def _generate_footprint(key: str, name: str, pad_extension: float) -> None:
keywords='dfn,dual flat no-leads,mo-229f',
config=config,
make_exposed=make_exposed,
generate_3d_models=generate_3d_models,
create_date='2019-01-17T06:11:43Z',
)
if name not in generated_packages:
Expand Down Expand Up @@ -517,6 +597,7 @@ def _generate_footprint(key: str, name: str, pad_extension: float) -> None:
keywords='dfn,dual flat no-leads',
config=config,
make_exposed=make_exposed,
generate_3d_models=generate_3d_models,
create_date=config.create_date,
)
if name not in generated_packages:
Expand Down
Loading

0 comments on commit 5ce6bc4

Please sign in to comment.