[Blender export][Added] Support for pcb2blender 2.7
- Solder mask and silk screen color - PCB finish - PCB thickness
This commit is contained in:
parent
299e06ae3e
commit
3cd644d19d
|
|
@ -25,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `forced_name` option to force the name displayed at the top left corner
|
||||
(#470)
|
||||
- Blender export:
|
||||
- Support for pcb2blender v2.6 (Blender 3.5.1)
|
||||
- Support for pcb2blender v2.6/2.7 (Blender 3.5.1/3.6)
|
||||
- `auto_camera_z_axis_factor`: used to control the default camera distance
|
||||
- Options to create simple animations:
|
||||
- PoV `steps`: to create rotation angle increments
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ outputs:
|
|||
type: 'render'
|
||||
# [string|dict] Options to export the PCB to Blender.
|
||||
# You can also specify the name of the output that generates the PCB3D file.
|
||||
# See the `PCB2Blender_2_1` and `PCB2Blender_2_1_haschtl` templates
|
||||
# See the `PCB2Blender_2_1`, `PCB2Blender_2_7` and `PCB2Blender_2_1_haschtl` templates
|
||||
pcb3d:
|
||||
# [string|list(string)='_none'] Name of the filter to mark components as not fitted.
|
||||
# A short-cut to use for simple cases where a variant is an overkill
|
||||
|
|
@ -211,8 +211,8 @@ outputs:
|
|||
solder_paste_for_populated: true
|
||||
# [string=''] Board variant to apply
|
||||
variant: ''
|
||||
# [string='2.1'] [2.1,2.1_haschtl] Variant of the format used
|
||||
version: '2.1'
|
||||
# [string='2.7'] [2.1,2.1_haschtl,2.7] Variant of the format used
|
||||
version: '2.7'
|
||||
# Options to configure how Blender imports the PCB.
|
||||
# The default values are good for most cases
|
||||
pcb_import:
|
||||
|
|
@ -2176,12 +2176,14 @@ outputs:
|
|||
# [list(string)|string=all] [none,all] List of components to include in the pads list,
|
||||
# can be also a string for `none` or `all`. The default is `all`
|
||||
show_components: all
|
||||
# [boolean=false] Create a JSON file containing the board stackup
|
||||
# [boolean=false] Create a file containing the board stackup
|
||||
stackup_create: false
|
||||
# [string='.'] Directory for the stackup file
|
||||
# [string='.'] Directory for the stackup file. Use 'layers' for 2.7+
|
||||
stackup_dir: '.'
|
||||
# [string='board.yaml'] Name for the stackup file
|
||||
# [string='board.yaml'] Name for the stackup file. Use 'stackup' for 2.7+
|
||||
stackup_file: 'board.yaml'
|
||||
# [string='JSON'] [JSON,BIN] Format for the stackup file. Use 'BIN' for 2.7+
|
||||
stackup_format: 'JSON'
|
||||
# [string='bounds'] File name for the sub-PCBs bounds
|
||||
sub_boards_bounds_file: 'bounds'
|
||||
# [boolean=true] Extract sub-PCBs and their Z axis position
|
||||
|
|
|
|||
|
|
@ -272,7 +272,8 @@ Here is a list of currently defined templates and their outputs / groups:
|
|||
- `P-Ban_stencil <https://www.p-ban.com/>`__: same as **P-Ban**, but
|
||||
also generates gerbers for *F.Paste* and *B.Paste* layers.
|
||||
|
||||
- `PCB2Blender_2_1 <https://github.com/30350n/pcb2blender>`__
|
||||
- `PCB2Blender_2_1 <https://github.com/30350n/pcb2blender>`__: Exports the PCB in a format that can be imported by the
|
||||
pcb2blender tool v2.1 or newer.
|
||||
|
||||
- **_PCB2Blender_layers_2_1**: The layers in SVG format. Disabled by default.
|
||||
- **_PCB2Blender_vrml_2_1**: The VRML for the board. Disabled by default.
|
||||
|
|
@ -280,7 +281,11 @@ Here is a list of currently defined templates and their outputs / groups:
|
|||
- **_PCB2Blender_2_1**: The PCB3D file. Is enabled and creates the other files.
|
||||
- **_PCB2Blender_elements_2_1**: **_PCB2Blender_tools_2_1** + **_PCB2Blender_layers_2_1** + **_PCB2Blender_vrml_2_1**
|
||||
|
||||
- `PCB2Blender_2_1_haschtl <https://github.com/haschtl/pcb2blender>`__
|
||||
- `PCB2Blender_2_7 <https://github.com/30350n/pcb2blender>`__: Similar to **PCB2Blender_2_1**, but for v2.7 or newer.
|
||||
The content is the same, just using *2_1* instead of *2_7*
|
||||
|
||||
- `PCB2Blender_2_1_haschtl <https://github.com/haschtl/pcb2blender>`__: Similar to **PCB2Blender_2_1**, but for the
|
||||
experimental **haschtl** fork.
|
||||
|
||||
- Imports **PCB2Blender_2_1** and disables **_PCB2Blender_2_1**
|
||||
- **_PCB2Blender_tools_2_1_haschtl**: Pads, bounds and stack-up information. Disabled by default.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Parameters:
|
|||
|
||||
- **pcb3d** :index:`: <pair: output - blender_export - options; pcb3d>` [string|dict] Options to export the PCB to Blender.
|
||||
You can also specify the name of the output that generates the PCB3D file.
|
||||
See the `PCB2Blender_2_1` and `PCB2Blender_2_1_haschtl` templates.
|
||||
See the `PCB2Blender_2_1`, `PCB2Blender_2_7` and `PCB2Blender_2_1_haschtl` templates.
|
||||
|
||||
- Valid keys:
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ Parameters:
|
|||
- ``solder_paste_for_populated`` :index:`: <pair: output - blender_export - options - pcb3d; solder_paste_for_populated>` [boolean=true] Add solder paste only for the populated components.
|
||||
Populated components are the ones listed in `show_components`.
|
||||
- ``variant`` :index:`: <pair: output - blender_export - options - pcb3d; variant>` [string=''] Board variant to apply.
|
||||
- ``version`` :index:`: <pair: output - blender_export - options - pcb3d; version>` [string='2.1'] [2.1,2.1_haschtl] Variant of the format used.
|
||||
- ``version`` :index:`: <pair: output - blender_export - options - pcb3d; version>` [string='2.7'] [2.1,2.1_haschtl,2.7] Variant of the format used.
|
||||
|
||||
- **point_of_view** :index:`: <pair: output - blender_export - options; point_of_view>` [dict|list(dict)] How the object is viewed by the camera.
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,10 @@ Parameters:
|
|||
- ``pre_transform`` :index:`: <pair: output - pcb2blender_tools - options; pre_transform>` [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
|
||||
A short-cut to use for simple cases where a variant is an overkill.
|
||||
|
||||
- ``stackup_create`` :index:`: <pair: output - pcb2blender_tools - options; stackup_create>` [boolean=false] Create a JSON file containing the board stackup.
|
||||
- ``stackup_dir`` :index:`: <pair: output - pcb2blender_tools - options; stackup_dir>` [string='.'] Directory for the stackup file.
|
||||
- ``stackup_file`` :index:`: <pair: output - pcb2blender_tools - options; stackup_file>` [string='board.yaml'] Name for the stackup file.
|
||||
- ``stackup_create`` :index:`: <pair: output - pcb2blender_tools - options; stackup_create>` [boolean=false] Create a file containing the board stackup.
|
||||
- ``stackup_dir`` :index:`: <pair: output - pcb2blender_tools - options; stackup_dir>` [string='.'] Directory for the stackup file. Use 'layers' for 2.7+.
|
||||
- ``stackup_file`` :index:`: <pair: output - pcb2blender_tools - options; stackup_file>` [string='board.yaml'] Name for the stackup file. Use 'stackup' for 2.7+.
|
||||
- ``stackup_format`` :index:`: <pair: output - pcb2blender_tools - options; stackup_format>` [string='JSON'] [JSON,BIN] Format for the stackup file. Use 'BIN' for 2.7+.
|
||||
- ``sub_boards_bounds_file`` :index:`: <pair: output - pcb2blender_tools - options; sub_boards_bounds_file>` [string='bounds'] File name for the sub-PCBs bounds.
|
||||
- ``sub_boards_create`` :index:`: <pair: output - pcb2blender_tools - options; sub_boards_create>` [boolean=true] Extract sub-PCBs and their Z axis position.
|
||||
- ``sub_boards_dir`` :index:`: <pair: output - pcb2blender_tools - options; sub_boards_dir>` [string='boards'] Directory for the boards definitions.
|
||||
|
|
|
|||
|
|
@ -451,12 +451,12 @@ class Optionable(object):
|
|||
for color in names:
|
||||
self.validate_color(color)
|
||||
|
||||
def parse_one_color(self, color):
|
||||
def parse_one_color(self, color, scale=1/255.0):
|
||||
res = self._color_re_component.findall(color)
|
||||
alpha = 1.0
|
||||
if len(res) > 3:
|
||||
alpha = int(res[3], 16)/255.0
|
||||
return (int(res[0], 16)/255.0, int(res[1], 16)/255.0, int(res[2], 16)/255.0, alpha)
|
||||
alpha = int(res[3], 16)*scale
|
||||
return (int(res[0], 16)*scale, int(res[1], 16)*scale, int(res[2], 16)*scale, alpha)
|
||||
|
||||
def color_to_rgb(self, color):
|
||||
index = 4 if len(color) > 4 else 0
|
||||
|
|
|
|||
|
|
@ -248,8 +248,8 @@ class PCB3DExportOptions(Base3DOptionsWithHL):
|
|||
with document:
|
||||
self.output = GS.def_global_output
|
||||
""" Name for the generated PCB3D file (%i='blender_export' %x='pcb3d') """
|
||||
self.version = '2.1'
|
||||
""" [2.1,2.1_haschtl] Variant of the format used """
|
||||
self.version = '2.7'
|
||||
""" [2.1,2.1_haschtl,2.7] Variant of the format used """
|
||||
self.solder_paste_for_populated = True
|
||||
""" Add solder paste only for the populated components.
|
||||
Populated components are the ones listed in `show_components` """
|
||||
|
|
@ -307,7 +307,7 @@ class Blender_ExportOptions(BaseOptions):
|
|||
self.pcb3d = PCB3DExportOptions
|
||||
""" *[string|dict] Options to export the PCB to Blender.
|
||||
You can also specify the name of the output that generates the PCB3D file.
|
||||
See the `PCB2Blender_2_1` and `PCB2Blender_2_1_haschtl` templates """
|
||||
See the `PCB2Blender_2_1`, `PCB2Blender_2_7` and `PCB2Blender_2_1_haschtl` templates """
|
||||
self.pcb_import = PCB2BlenderOptions
|
||||
""" Options to configure how Blender imports the PCB.
|
||||
The default values are good for most cases """
|
||||
|
|
@ -461,11 +461,19 @@ class Blender_ExportOptions(BaseOptions):
|
|||
configure_and_run(tree, out_dir, ' - Creating SVG for layers ...')
|
||||
|
||||
def create_pads(self, dest_dir):
|
||||
options = {'stackup_create': False}
|
||||
if self.pcb3d.version == '2.1_haschtl':
|
||||
options['stackup_create'] = True
|
||||
elif self.pcb3d.version == '2.7':
|
||||
options['stackup_create'] = True
|
||||
options['stackup_file'] = 'stackup'
|
||||
options['stackup_dir'] = 'layers'
|
||||
options['stackup_format'] = 'BIN'
|
||||
tree = {'name': '_temporal_pcb3d_tools',
|
||||
'type': 'pcb2blender_tools',
|
||||
'comment': 'Internally created for the PCB3D',
|
||||
'dir': dest_dir,
|
||||
'options': {'stackup_create': self.pcb3d.version == '2.1_haschtl'}}
|
||||
'options': options}
|
||||
if self.pcb3d.solder_paste_for_populated:
|
||||
sc = 'all'
|
||||
if not self.pcb3d._show_all_components:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
# Project: KiBot (formerly KiPlot)
|
||||
# Some code is adapted from: https://github.com/30350n/pcb2blender
|
||||
from dataclasses import dataclass, field
|
||||
from enum import IntEnum
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
|
@ -37,6 +38,34 @@ class BoardDef:
|
|||
stacked_boards: List[StackedBoard] = field(default_factory=list)
|
||||
|
||||
|
||||
class KiCadColor(IntEnum):
|
||||
CUSTOM = 0
|
||||
GREEN = 1
|
||||
RED = 2
|
||||
BLUE = 3
|
||||
PURPLE = 4
|
||||
BLACK = 5
|
||||
WHITE = 6
|
||||
YELLOW = 7
|
||||
|
||||
|
||||
class SurfaceFinish(IntEnum):
|
||||
HASL = 0
|
||||
ENIG = 1
|
||||
NONE = 2
|
||||
|
||||
|
||||
SURFACE_FINISH_MAP = {
|
||||
"ENIG": SurfaceFinish.ENIG,
|
||||
"ENEPIG": SurfaceFinish.ENIG,
|
||||
"Hard gold": SurfaceFinish.ENIG,
|
||||
"ImAu": SurfaceFinish.ENIG,
|
||||
"Immersion Gold": SurfaceFinish.ENIG,
|
||||
"Immersion Au": SurfaceFinish.ENIG,
|
||||
"HT_OSP": SurfaceFinish.NONE,
|
||||
"OSP": SurfaceFinish.NONE}
|
||||
|
||||
|
||||
def sanitized(name):
|
||||
""" Replace character that aren't alphabetic by _ """
|
||||
return re.sub(r"[\W]+", "_", name)
|
||||
|
|
@ -59,11 +88,13 @@ class PCB2Blender_ToolsOptions(VariantOptions):
|
|||
self.pads_info_dir = 'pads'
|
||||
""" Sub-directory where the pads info files are stored """
|
||||
self.stackup_create = False
|
||||
""" Create a JSON file containing the board stackup """
|
||||
""" Create a file containing the board stackup """
|
||||
self.stackup_file = 'board.yaml'
|
||||
""" Name for the stackup file """
|
||||
""" Name for the stackup file. Use 'stackup' for 2.7+ """
|
||||
self.stackup_dir = '.'
|
||||
""" Directory for the stackup file """
|
||||
""" Directory for the stackup file. Use 'layers' for 2.7+ """
|
||||
self.stackup_format = 'JSON'
|
||||
""" [JSON,BIN] Format for the stackup file. Use 'BIN' for 2.7+ """
|
||||
self.sub_boards_create = True
|
||||
""" Extract sub-PCBs and their Z axis position """
|
||||
self.sub_boards_dir = 'boards'
|
||||
|
|
@ -146,30 +177,53 @@ class PCB2Blender_ToolsOptions(VariantOptions):
|
|||
pad.GetDrillShape(),
|
||||
*map(GS.to_mm, pad.GetDrillSize())))
|
||||
|
||||
def parse_kicad_color(self, string):
|
||||
if string[0] == "#":
|
||||
return KiCadColor.CUSTOM, self.parse_one_color(string, scale=1)[:3]
|
||||
else:
|
||||
return KiCadColor[string.upper()], (0, 0, 0)
|
||||
|
||||
def do_stackup(self, dir_name):
|
||||
if not self.stackup_create or (not GS.global_pcb_finish and not GS.stackup):
|
||||
return
|
||||
dir_name = os.path.join(dir_name, self.stackup_dir)
|
||||
os.makedirs(dir_name, exist_ok=True)
|
||||
fname = os.path.join(dir_name, self.stackup_file)
|
||||
# Create the board_info
|
||||
board_info = {}
|
||||
if GS.global_pcb_finish:
|
||||
board_info['copper_finish'] = GS.global_pcb_finish
|
||||
if GS.stackup:
|
||||
layers_parsed = []
|
||||
for la in GS.stackup:
|
||||
parsed_layer = {'name': la.name, 'type': la.type}
|
||||
if la.color is not None:
|
||||
parsed_layer['color'] = la.color
|
||||
if la.thickness is not None:
|
||||
parsed_layer['thickness'] = la.thickness/1000
|
||||
layers_parsed.append(parsed_layer)
|
||||
board_info['stackup'] = layers_parsed
|
||||
data = json.dumps(board_info, indent=3)
|
||||
logger.debug('Stackup: '+str(data))
|
||||
with open(fname, 'wt') as f:
|
||||
f.write(data)
|
||||
if self.stackup_format == 'JSON':
|
||||
# This is for the experimental "haschtl" fork
|
||||
# Create the board_info
|
||||
board_info = {}
|
||||
if GS.global_pcb_finish:
|
||||
board_info['copper_finish'] = GS.global_pcb_finish
|
||||
if GS.stackup:
|
||||
layers_parsed = []
|
||||
for la in GS.stackup:
|
||||
parsed_layer = {'name': la.name, 'type': la.type}
|
||||
if la.color is not None:
|
||||
parsed_layer['color'] = la.color
|
||||
if la.thickness is not None:
|
||||
parsed_layer['thickness'] = la.thickness/1000
|
||||
layers_parsed.append(parsed_layer)
|
||||
board_info['stackup'] = layers_parsed
|
||||
data = json.dumps(board_info, indent=3)
|
||||
logger.debug('Stackup: '+str(data))
|
||||
with open(fname, 'wt') as f:
|
||||
f.write(data)
|
||||
else: # self.stackup_format == 'BIN':
|
||||
# This is for 2.7+
|
||||
# Map the surface finish
|
||||
if GS.global_pcb_finish:
|
||||
surface_finish = SURFACE_FINISH_MAP.get(GS.global_pcb_finish, SurfaceFinish.HASL)
|
||||
else:
|
||||
surface_finish = SurfaceFinish.NONE
|
||||
ds = GS.board.GetDesignSettings()
|
||||
thickness_mm = GS.to_mm(ds.GetBoardThickness())
|
||||
mask_color, mask_color_custom = self.parse_kicad_color(GS.global_solder_mask_color.upper())
|
||||
silks_color, silks_color_custom = self.parse_kicad_color(GS.global_silk_screen_color.upper())
|
||||
logger.error(f"{mask_color} {mask_color_custom}")
|
||||
with open(fname, 'wb') as f:
|
||||
f.write(struct.pack("!fbBBBbBBBb", thickness_mm, mask_color, *mask_color_custom, silks_color,
|
||||
*silks_color_custom, surface_finish))
|
||||
|
||||
def get_boarddefs(self):
|
||||
""" Extract the sub-PCBs and their positions using texts.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
# PCB2Blender (PCB3D) format for plug-in v2.7
|
||||
# URL: https://github.com/30350n/pcb2blender
|
||||
kibot:
|
||||
version: 1
|
||||
|
||||
groups:
|
||||
- name: _PCB2Blender_elements_2_7
|
||||
outputs:
|
||||
- _PCB2Blender_tools_2_7
|
||||
- _PCB2Blender_layers_2_7
|
||||
- _PCB2Blender_vrml_2_7
|
||||
|
||||
outputs:
|
||||
- name: _PCB2Blender_tools_2_7
|
||||
comment: Pads information and board bounds for PCB3D 2.7
|
||||
type: pcb2blender_tools
|
||||
dir: '%f%v_pcb3d'
|
||||
run_by_default: false
|
||||
options:
|
||||
stackup_create: true
|
||||
stackup_file: stackup
|
||||
stackup_dir: layers
|
||||
stackup_format: BIN
|
||||
|
||||
- name: _PCB2Blender_layers_2_7
|
||||
comment: SVG files for the layers for PCB3D 2.7
|
||||
type: svg
|
||||
dir: '%f%v_pcb3d/layers'
|
||||
run_by_default: false
|
||||
options:
|
||||
output: "%i.%x"
|
||||
margin: 1
|
||||
limit_viewbox: true
|
||||
svg_precision: 6
|
||||
drill_marks: none
|
||||
layers:
|
||||
- F.Cu
|
||||
- B.Cu
|
||||
- F.Paste
|
||||
- B.Paste
|
||||
- layer: F.SilkS
|
||||
suffix: F_SilkS
|
||||
- layer: B.SilkS
|
||||
suffix: B_SilkS
|
||||
- F.Mask
|
||||
- B.Mask
|
||||
|
||||
- name: _PCB2Blender_vrml_2_7
|
||||
comment: VRML model for PCB3D 2.7
|
||||
type: vrml
|
||||
dir: '%f%v_pcb3d'
|
||||
run_by_default: false
|
||||
options:
|
||||
output: pcb.wrl
|
||||
dir_models: components
|
||||
use_pcb_center_as_ref: false
|
||||
model_units: meters
|
||||
|
||||
- name: _PCB2Blender_2_7
|
||||
comment: PCB3D model for pcb2blender plug-in
|
||||
type: compress
|
||||
options:
|
||||
output: '%f%v.pcb3d'
|
||||
format: ZIP
|
||||
files:
|
||||
- from_output: _PCB2Blender_tools_2_7
|
||||
from_output_dir: true
|
||||
- from_output: _PCB2Blender_layers_2_7
|
||||
dest: layers
|
||||
- from_output: _PCB2Blender_vrml_2_7
|
||||
from_output_dir: true
|
||||
|
|
@ -3,15 +3,15 @@ kibot:
|
|||
version: 1
|
||||
|
||||
import:
|
||||
- file: PCB2Blender_2_1
|
||||
- file: PCB2Blender_2_7
|
||||
|
||||
outputs:
|
||||
- name: '3d_export'
|
||||
comment: "Exports the PCB in blender format"
|
||||
type: blender_export
|
||||
disable_run_by_default: _PCB2Blender_2_1
|
||||
disable_run_by_default: _PCB2Blender_2_7
|
||||
options:
|
||||
pcb3d: _PCB2Blender_2_1
|
||||
pcb3d: _PCB2Blender_2_7
|
||||
# camera:
|
||||
# name: MyCamera
|
||||
# pos_x: 0.3
|
||||
|
|
|
|||
Loading…
Reference in New Issue