[Render_3D] Added option to highlight components
This commit is contained in:
parent
81ce2004d5
commit
6d3d2c37d0
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue