[Render_3D] Added option to highlight components

This commit is contained in:
Salvador E. Tropea 2022-10-31 10:16:21 -03:00
parent 81ce2004d5
commit 6d3d2c37d0
9 changed files with 6229 additions and 2066 deletions

View File

@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Render_3D:
- Option to render only some components (like in PcbDraw)
- Option to auto-crop the resulting PNG
- Option to highlight components
- SVG:
- Option to control the *SVG precision* (units scale)

View File

@ -3105,6 +3105,9 @@ Notes:
- `dnf_filter`: [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.
- `height`: [number=720] Image height (aprox.).
- `highlight`: [list(string)=[]] List of components to highlight.
- `highlight_on_top`: [boolean=false] Highlight over the component (not under).
- `highlight_padding`: [number=1.5] [0,1000] How much the highlight extends around the component [mm].
- `kicad_3d_url`: [string='https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'] Base URL for the KiCad 3D models.
- `no_smd`: [boolean=false] Used to exclude 3D models for surface mount components.
- `no_tht`: [boolean=false] Used to exclude 3D models for through hole components.

View File

@ -1853,6 +1853,12 @@ outputs:
download: true
# [number=720] Image height (aprox.)
height: 720
# [list(string)=[]] List of components to highlight
highlight: []
# [boolean=false] Highlight over the component (not under)
highlight_on_top: false
# [number=1.5] [0,1000] How much the highlight extends around the component [mm]
highlight_padding: 1.5
# [string='https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'] Base URL for the KiCad 3D models
kicad_3d_url: 'https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'
# [number=0] Steps to move in the X axis, positive is to the right.

View File

@ -17,9 +17,10 @@ if not GS.kicad_version_n:
detect_kicad()
if GS.ki6:
# New name, no alias ...
from pcbnew import FP_SHAPE, wxPoint, LSET
from pcbnew import FP_SHAPE, wxPoint, LSET, FP_3DMODEL, ToMM
else:
from pcbnew import EDGE_MODULE, wxPoint, LSET
from pcbnew import EDGE_MODULE, wxPoint, LSET, MODULE_3D_SETTINGS, ToMM
FP_3DMODEL = MODULE_3D_SETTINGS
from .registrable import RegOutput
from .optionable import Optionable, BaseOptions
from .fil_base import BaseFilter, apply_fitted_filter, reset_filters, apply_pre_transform
@ -29,6 +30,26 @@ from .error import KiPlotConfigurationError
from . import log
logger = log.get_logger()
HIGHLIGHT_3D_WRL = """#VRML V2.0 utf8
#KiBot generated highlight
Shape {
appearance Appearance {
material DEF RED-01 Material {
ambientIntensity 0.494
diffuseColor 0.895 0.291 0.213
specularColor 0.047 0.055 0.109
emissiveColor 0.0 0.0 0.0
transparency 0.5
shininess 0.25
}
}
}
Shape {
geometry Box { size 1 1 1 }
appearance Appearance {material USE RED-01 }
}
"""
class BaseOutput(RegOutput):
@ -204,6 +225,8 @@ class VariantOptions(BaseOptions):
self._comps = None
self.undo_3d_models = {}
self.undo_3d_models_rep = {}
self._highlight_3D_file = None
self._highlighted_3D_components = None
def config(self, parent):
super().config(parent)
@ -584,7 +607,44 @@ class VariantOptions(BaseOptions):
if not matched and default is not None:
self.apply_list_of_3D_models(enable, slots, m, '_default_')
def filter_pcb_components(self, board, do_3D=False, do_2D=True):
def create_3D_highlight_file(self):
if self._highlight_3D_file:
return
with NamedTemporaryFile(mode='w', suffix='.wrl', delete=False) as f:
self._highlight_3D_file = f.name
logger.debug('Creating temporal highlight file '+f.name)
f.write(HIGHLIGHT_3D_WRL)
def highlight_3D_models(self, board, highlight):
if not highlight:
return
self.create_3D_highlight_file()
# TODO: Adjust? Configure?
z = (100.0 if self.highlight_on_top else 0.1)/2.54
for m in GS.get_modules_board(board):
if m.GetReference() not in highlight:
continue
models = m.Models()
bbox = m.GetBoundingBox()
# Create a new 3D model for the highlight
hl = FP_3DMODEL()
hl.m_Scale.x = ToMM(bbox.GetWidth()+self.highlight_padding)/2.54
hl.m_Scale.y = ToMM(bbox.GetHeight()+self.highlight_padding)/2.54
hl.m_Scale.z = z
hl.m_Filename = self._highlight_3D_file
models.push_back(hl)
self._highlighted_3D_components = highlight
def unhighlight_3D_models(self, board):
if not self._highlighted_3D_components:
return
for m in GS.get_modules_board(board):
if m.GetReference() not in self._highlighted_3D_components:
continue
m.Models().pop()
self._highlighted_3D_components = None
def filter_pcb_components(self, board, do_3D=False, do_2D=True, highlight=None):
if not self._comps:
return False
self.comps_hash = self.get_refs_hash()
@ -598,6 +658,8 @@ class VariantOptions(BaseOptions):
self.apply_3D_variant_aspect(board)
# Remove the 3D models for not fitted components (also rename)
self.remove_3D_models(board, self.comps_hash)
# Highlight selected components
self.highlight_3D_models(board, highlight)
return True
def unfilter_pcb_components(self, board, do_3D=False, do_2D=True):
@ -613,6 +675,14 @@ class VariantOptions(BaseOptions):
self.restore_3D_models(board, self.comps_hash)
# Re-enable the modules that aren't for this variant
self.apply_3D_variant_aspect(board, enable=True)
# Remove the highlight 3D object
self.unhighlight_3D_models(board)
def remove_highlight_3D_file(self):
# Remove the highlight 3D file if it was created
if self._highlight_3D_file:
os.remove(self._highlight_3D_file)
self._highlight_3D_file = None
def set_title(self, title, sch=False):
self.old_title = None

View File

@ -190,7 +190,7 @@ class Base3DOptions(VariantOptions):
models.add(full_name)
return list(models)
def filter_components(self):
def filter_components(self, highlight=None):
if not self._comps:
# No variant/filter to apply
if self.download_models():
@ -201,7 +201,7 @@ class Base3DOptions(VariantOptions):
self.undo_3d_models_rename(GS.board)
return ret
return GS.pcb_file
self.filter_pcb_components(GS.board, do_3D=True, do_2D=True)
self.filter_pcb_components(GS.board, do_3D=True, do_2D=True, highlight=highlight)
self.download_models()
fname = self.save_tmp_board()
self.unfilter_pcb_components(GS.board, do_3D=True, do_2D=True)

View File

@ -124,6 +124,12 @@ class Render3DOptions(Base3DOptions):
self.show_components = Optionable
""" *[list(string)|string=all] [none,all] List of components to draw, can be also a string for `none` or `all`.
Unlike the `pcbdraw` output, the default is `all` """
self.highlight = Optionable
""" [list(string)=[]] List of components to highlight """
self.highlight_padding = 1.5
""" [0,1000] How much the highlight extends around the component [mm] """
self.highlight_on_top = False
""" Highlight over the component (not under) """
self.auto_crop = False
""" When enabled the image will be post-processed to make the background transparent and then remove the
empty space around the image. In this mode the `background1` and `background2` colors are ignored """
@ -187,6 +193,11 @@ class Render3DOptions(Base3DOptions):
else: # a list
self.show_components = set(self.show_components)
self._expand_id += '_'+self._rviews.get(self.view)
# highlight
if isinstance(self.highlight, type):
self.highlight = set()
else:
self.highlight = set(self.highlight)
def add_step(self, cmd, steps, ops):
if steps:
@ -265,13 +276,14 @@ class Render3DOptions(Base3DOptions):
self.add_options(cmd)
# The board
self.apply_show_components()
board_name = self.filter_components()
board_name = self.filter_components(highlight=self.highlight)
cmd.extend([board_name, os.path.dirname(output)])
cmd, video_remove = add_extra_options(cmd)
# Execute it
ret = exec_with_retry(cmd)
# Remove the temporal PCB
self.remove_tmp_board(board_name)
self.remove_highlight_3D_file()
# Remove the downloaded 3D models
if self._tmp_dir:
rmtree(self._tmp_dir)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,5 +16,8 @@ outputs:
orthographic: true
zoom: 4
show_components: ["RV1", "RV2", "U1", "U2", "U3"]
highlight: ["RV1"]
# Looks ugly when rendered by software
# highlight_on_top: true
ray_tracing: true
auto_crop: true