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 876d49e commit f5a5c8e
Show file tree
Hide file tree
Showing 3 changed files with 376 additions and 9 deletions.
26 changes: 24 additions & 2 deletions dfn_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

from typing import Callable, List, Optional
from typing import Any, Callable, List, Optional

from common import format_float as ff
from entities.common import Angle, Circle, Diameter, Fill, GrabArea, Layer, Polygon, Position, Vertex, Width
Expand Down Expand Up @@ -54,6 +54,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[Callable[[Any, Any, Any], Any]] = None,
):
self.length = length
self.width = width
Expand Down Expand Up @@ -85,6 +86,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 @@ -285,7 +287,6 @@ def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -
))
return _draw


def draw_rect(x: float, y: float, width: float, height: float) -> Callable[[DfnConfig, Callable[[str], str], Footprint], None]:
def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -> None:
footprint.add_polygon(Polygon(
Expand All @@ -304,6 +305,24 @@ def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -
))
return _draw

def step_modification_sphere(diameter: float):
def _fn(body: Any, dot: Any, workplane: 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):
def _fn(body: Any, dot: Any, workplane: 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) -> 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 @@ -327,6 +346,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 @@ -346,6 +366,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 @@ -365,6 +386,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
95 changes: 88 additions & 7 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 Down Expand Up @@ -82,6 +83,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 @@ -445,23 +447,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 @@ -488,6 +567,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 @@ -518,6 +598,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 f5a5c8e

Please sign in to comment.