[Blender Export] Now can be used as renderer
- Tested with kikit_present and populate - Also added `auto_crop`
This commit is contained in:
parent
fce9a2d581
commit
e16086ca70
|
|
@ -201,6 +201,7 @@ Notes:
|
||||||
|
|
||||||
[**ImageMagick**](https://imagemagick.org/) [](https://imagemagick.org/) [](https://packages.debian.org/bullseye/imagemagick) 
|
[**ImageMagick**](https://imagemagick.org/) [](https://imagemagick.org/) [](https://packages.debian.org/bullseye/imagemagick) 
|
||||||
- Optional to:
|
- Optional to:
|
||||||
|
- Automatically crop images for `blender_export`
|
||||||
- Create outputs preview for `navigate_results`
|
- Create outputs preview for `navigate_results`
|
||||||
- Create monochrome prints and scaled PNG files for `pcb_print`
|
- Create monochrome prints and scaled PNG files for `pcb_print`
|
||||||
- Create JPG and BMP images for `pcbdraw`
|
- Create JPG and BMP images for `pcbdraw`
|
||||||
|
|
@ -1608,10 +1609,14 @@ Notes:
|
||||||
- **`samples`**: [number=10] How many samples we create. Each sample is a raytracing render.
|
- **`samples`**: [number=10] How many samples we create. Each sample is a raytracing render.
|
||||||
Use 1 for a raw preview, 10 for a draft and 100 or more for the final render.
|
Use 1 for a raw preview, 10 for a draft and 100 or more for the final render.
|
||||||
- **`transparent_background`**: [boolean=false] Make the background transparent.
|
- **`transparent_background`**: [boolean=false] Make the background transparent.
|
||||||
|
- `auto_crop`: [boolean=false] When enabled the image will be post-processed to remove the empty space around the image.
|
||||||
|
In this mode the `background2` is changed to be the same as `background1`.
|
||||||
- `background1`: [string='#66667F'] First color for the background gradient.
|
- `background1`: [string='#66667F'] First color for the background gradient.
|
||||||
- `background2`: [string='#CCCCE5'] Second color for the background gradient.
|
- `background2`: [string='#CCCCE5'] Second color for the background gradient.
|
||||||
|
- *height*: Alias for resolution_y.
|
||||||
- `resolution_x`: [number=1280] Width of the image.
|
- `resolution_x`: [number=1280] Width of the image.
|
||||||
- `resolution_y`: [number=720] Height of the image.
|
- `resolution_y`: [number=720] Height of the image.
|
||||||
|
- *width*: Alias for resolution_x.
|
||||||
- `add_default_light`: [boolean=true] Add a default light when none specified.
|
- `add_default_light`: [boolean=true] Add a default light when none specified.
|
||||||
The default light is located at (-size*3.33, size*3.33, size*5) where size is max(width, height) of the PCB.
|
The default light is located at (-size*3.33, size*3.33, size*5) where size is max(width, height) of the PCB.
|
||||||
- `camera`: [dict] Options for the camera.
|
- `camera`: [dict] Options for the camera.
|
||||||
|
|
|
||||||
|
|
@ -209,10 +209,14 @@ outputs:
|
||||||
view: 'top'
|
view: 'top'
|
||||||
# [dict] Controls how the render is done for the `render` output type
|
# [dict] Controls how the render is done for the `render` output type
|
||||||
render_options:
|
render_options:
|
||||||
|
# [boolean=false] When enabled the image will be post-processed to remove the empty space around the image.
|
||||||
|
# In this mode the `background2` is changed to be the same as `background1`
|
||||||
|
auto_crop: false
|
||||||
# [string='#66667F'] First color for the background gradient
|
# [string='#66667F'] First color for the background gradient
|
||||||
background1: '#66667F'
|
background1: '#66667F'
|
||||||
# [string='#CCCCE5'] Second color for the background gradient
|
# [string='#CCCCE5'] Second color for the background gradient
|
||||||
background2: '#CCCCE5'
|
background2: '#CCCCE5'
|
||||||
|
# `height` is an alias for `resolution_y`
|
||||||
# [number=1280] Width of the image
|
# [number=1280] Width of the image
|
||||||
resolution_x: 1280
|
resolution_x: 1280
|
||||||
# [number=720] Height of the image
|
# [number=720] Height of the image
|
||||||
|
|
@ -222,6 +226,7 @@ outputs:
|
||||||
samples: 10
|
samples: 10
|
||||||
# [boolean=false] Make the background transparent
|
# [boolean=false] Make the background transparent
|
||||||
transparent_background: false
|
transparent_background: false
|
||||||
|
# `width` is an alias for `resolution_x`
|
||||||
# BoardView:
|
# BoardView:
|
||||||
# This format allows simple pads and connections navigation, mainly for circuit debug.
|
# This format allows simple pads and connections navigation, mainly for circuit debug.
|
||||||
# The output can be loaded using Open Board View (https://openboardview.org/)
|
# The output can be loaded using Open Board View (https://openboardview.org/)
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ KICAD5_SVG_SCALE = 116930/297002200
|
||||||
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'
|
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'
|
||||||
# Text used to disable 3D models
|
# Text used to disable 3D models
|
||||||
DISABLE_3D_MODEL_TEXT = '_Disabled_by_KiBot'
|
DISABLE_3D_MODEL_TEXT = '_Disabled_by_KiBot'
|
||||||
RENDERERS = ['pcbdraw', 'render_3d']
|
RENDERERS = ['pcbdraw', 'render_3d', 'blender_export']
|
||||||
PCB_GENERATORS = ['pcb_variant', 'panelize']
|
PCB_GENERATORS = ['pcb_variant', 'panelize']
|
||||||
KIKIT_UNIT_ALIASES = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'}
|
KIKIT_UNIT_ALIASES = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -468,38 +468,6 @@ class Optionable(object):
|
||||||
def color_str_to_rgb(self, color):
|
def color_str_to_rgb(self, color):
|
||||||
return self.color_to_rgb(self.parse_one_color(color))
|
return self.color_to_rgb(self.parse_one_color(color))
|
||||||
|
|
||||||
def save_renderer_options(self):
|
|
||||||
""" Save the current renderer settings """
|
|
||||||
options = self._renderer.options
|
|
||||||
self.old_filters_to_expand = options._filters_to_expand
|
|
||||||
self.old_show_components = options.show_components
|
|
||||||
self.old_highlight = options.highlight
|
|
||||||
self.old_output = options.output
|
|
||||||
self.old_dir = self._renderer.dir
|
|
||||||
self.old_done = self._renderer._done
|
|
||||||
if self._renderer_is_pcbdraw:
|
|
||||||
self.old_bottom = options.bottom
|
|
||||||
self.old_add_to_variant = options.add_to_variant
|
|
||||||
else: # render_3D
|
|
||||||
self.old_view = options.view
|
|
||||||
self.old_show_all_components = options._show_all_components
|
|
||||||
|
|
||||||
def restore_renderer_options(self):
|
|
||||||
""" Restore the renderer settings """
|
|
||||||
options = self._renderer.options
|
|
||||||
options._filters_to_expand = self.old_filters_to_expand
|
|
||||||
options.show_components = self.old_show_components
|
|
||||||
options.highlight = self.old_highlight
|
|
||||||
options.output = self.old_output
|
|
||||||
self._renderer.dir = self.old_dir
|
|
||||||
self._renderer._done = self.old_done
|
|
||||||
if self._renderer_is_pcbdraw:
|
|
||||||
options.bottom = self.old_bottom
|
|
||||||
options.add_to_variant = self.old_add_to_variant
|
|
||||||
else: # render_3D
|
|
||||||
options.view = self.old_view
|
|
||||||
options._show_all_components = self.old_show_all_components
|
|
||||||
|
|
||||||
|
|
||||||
class BaseOptions(Optionable):
|
class BaseOptions(Optionable):
|
||||||
""" A class to validate and hold output options.
|
""" A class to validate and hold output options.
|
||||||
|
|
|
||||||
|
|
@ -990,6 +990,32 @@ class VariantOptions(BaseOptions):
|
||||||
self._sub_pcb = self.variant._sub_pcb
|
self._sub_pcb = self.variant._sub_pcb
|
||||||
self._comps = comps
|
self._comps = comps
|
||||||
|
|
||||||
|
# The following 3 members are used by 2D and 3D renderers
|
||||||
|
def setup_renderer(self, components, active_components):
|
||||||
|
""" Setup the options to use it as a renderer """
|
||||||
|
self._show_all_components = False
|
||||||
|
self._filters_to_expand = False
|
||||||
|
self.highlight = self.solve_kf_filters([c for c in active_components if c])
|
||||||
|
self.show_components = [c for c in components if c]
|
||||||
|
if self.show_components:
|
||||||
|
self.show_components = self.solve_kf_filters(self.show_components)
|
||||||
|
|
||||||
|
def save_renderer_options(self):
|
||||||
|
""" Save the current renderer settings """
|
||||||
|
self.old_filters_to_expand = self._filters_to_expand
|
||||||
|
self.old_show_components = self.show_components
|
||||||
|
self.old_highlight = self.highlight
|
||||||
|
self.old_dir = self._parent.dir
|
||||||
|
self.old_done = self._parent._done
|
||||||
|
|
||||||
|
def restore_renderer_options(self):
|
||||||
|
""" Restore the renderer settings """
|
||||||
|
self._filters_to_expand = self.old_filters_to_expand
|
||||||
|
self.show_components = self.old_show_components
|
||||||
|
self.highlight = self.old_highlight
|
||||||
|
self._parent.dir = self.old_dir
|
||||||
|
self._parent._done = self.old_done
|
||||||
|
|
||||||
|
|
||||||
class PcbMargin(Optionable):
|
class PcbMargin(Optionable):
|
||||||
""" To adjust each margin """
|
""" To adjust each margin """
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ Dependencies:
|
||||||
- from: Blender
|
- from: Blender
|
||||||
role: mandatory
|
role: mandatory
|
||||||
version: 3.4.0
|
version: 3.4.0
|
||||||
|
- from: ImageMagick
|
||||||
|
role: Automatically crop images
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
@ -122,14 +124,21 @@ class BlenderRenderOptions(Optionable):
|
||||||
Use 1 for a raw preview, 10 for a draft and 100 or more for the final render """
|
Use 1 for a raw preview, 10 for a draft and 100 or more for the final render """
|
||||||
self.resolution_x = 1280
|
self.resolution_x = 1280
|
||||||
""" Width of the image """
|
""" Width of the image """
|
||||||
|
self.width = None
|
||||||
|
""" {resolution_x} """
|
||||||
self.resolution_y = 720
|
self.resolution_y = 720
|
||||||
""" Height of the image """
|
""" Height of the image """
|
||||||
|
self.height = None
|
||||||
|
""" {resolution_y} """
|
||||||
self.transparent_background = False
|
self.transparent_background = False
|
||||||
""" *Make the background transparent """
|
""" *Make the background transparent """
|
||||||
self.background1 = "#66667F"
|
self.background1 = "#66667F"
|
||||||
""" First color for the background gradient """
|
""" First color for the background gradient """
|
||||||
self.background2 = "#CCCCE5"
|
self.background2 = "#CCCCE5"
|
||||||
""" Second color for the background gradient """
|
""" Second color for the background gradient """
|
||||||
|
self.auto_crop = False
|
||||||
|
""" When enabled the image will be post-processed to remove the empty space around the image.
|
||||||
|
In this mode the `background2` is changed to be the same as `background1` """
|
||||||
self._unkown_is_error = True
|
self._unkown_is_error = True
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -154,6 +163,7 @@ class BlenderPointOfViewOptions(Optionable):
|
||||||
""" String to diferentiate the name of this view.
|
""" String to diferentiate the name of this view.
|
||||||
When empty we use the `view` """
|
When empty we use the `view` """
|
||||||
self._unkown_is_error = True
|
self._unkown_is_error = True
|
||||||
|
self._file_id = ''
|
||||||
|
|
||||||
def config(self, parent):
|
def config(self, parent):
|
||||||
super().config(parent)
|
super().config(parent)
|
||||||
|
|
@ -190,6 +200,38 @@ class PCB3DExportOptions(Base3DOptionsWithHL):
|
||||||
p._expand_ext = cur_ext
|
p._expand_ext = cur_ext
|
||||||
return out_name
|
return out_name
|
||||||
|
|
||||||
|
def setup_renderer(self, components, active_components, bottom, name):
|
||||||
|
super().setup_renderer(components, active_components)
|
||||||
|
self._pov.view = 'Z' if bottom else 'z'
|
||||||
|
# Expand the name using .PNG
|
||||||
|
cur_ext = self._expand_ext
|
||||||
|
self._expand_ext = 'png'
|
||||||
|
o_name = self.expand_filename_both(name, is_sch=False)
|
||||||
|
self._expand_ext = cur_ext
|
||||||
|
self._out.output = o_name
|
||||||
|
return o_name
|
||||||
|
|
||||||
|
def save_renderer_options(self):
|
||||||
|
""" Save the current renderer settings """
|
||||||
|
p = self._parent
|
||||||
|
# We are an option inside another option
|
||||||
|
self._parent = self._parent._parent
|
||||||
|
super().save_renderer_options()
|
||||||
|
self._parent = p
|
||||||
|
self.old_show_all_components = self._show_all_components
|
||||||
|
self.old_view = self._pov.view
|
||||||
|
self.old_output = self._out.output
|
||||||
|
|
||||||
|
def restore_renderer_options(self):
|
||||||
|
""" Restore the renderer settings """
|
||||||
|
p = self._parent
|
||||||
|
self._parent = self._parent._parent
|
||||||
|
super().restore_renderer_options()
|
||||||
|
self._parent = p
|
||||||
|
self._show_all_components = self.old_show_all_components
|
||||||
|
self._pov.view = self.old_view
|
||||||
|
self._out.output = self.old_output
|
||||||
|
|
||||||
|
|
||||||
class Blender_ExportOptions(BaseOptions):
|
class Blender_ExportOptions(BaseOptions):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -222,9 +264,12 @@ class Blender_ExportOptions(BaseOptions):
|
||||||
def config(self, parent):
|
def config(self, parent):
|
||||||
super().config(parent)
|
super().config(parent)
|
||||||
# Check we at least have a name for the source output
|
# Check we at least have a name for the source output
|
||||||
if isinstance(self.pcb3d, type) or (isinstance(self.pcb3d, str) and not self.pcb3d):
|
if isinstance(self.pcb3d, str) and not self.pcb3d:
|
||||||
raise KiPlotConfigurationError('You must specify the name of the output that'
|
raise KiPlotConfigurationError('You must specify the name of the output that'
|
||||||
' generates the PCB3D file or its options')
|
' generates the PCB3D file or its options')
|
||||||
|
if isinstance(self.pcb3d, type):
|
||||||
|
self.pcb3d = PCB3DExportOptions()
|
||||||
|
self.pcb3d.config(self)
|
||||||
# Do we have outputs?
|
# Do we have outputs?
|
||||||
if isinstance(self.outputs, type):
|
if isinstance(self.outputs, type):
|
||||||
self.outputs = []
|
self.outputs = []
|
||||||
|
|
@ -409,6 +454,10 @@ class Blender_ExportOptions(BaseOptions):
|
||||||
return
|
return
|
||||||
# Make sure Blender is available
|
# Make sure Blender is available
|
||||||
command = self._pcb3d.ensure_tool('Blender')
|
command = self._pcb3d.ensure_tool('Blender')
|
||||||
|
if self.render_options.auto_crop:
|
||||||
|
# Avoid a gradient
|
||||||
|
self.render_options.background2 = self.render_options.background1
|
||||||
|
convert_command = self.ensure_tool('ImageMagick')
|
||||||
# Create a JSON with the scene information
|
# Create a JSON with the scene information
|
||||||
with NamedTemporaryFile(mode='w', suffix='.json') as f:
|
with NamedTemporaryFile(mode='w', suffix='.json') as f:
|
||||||
scene = {}
|
scene = {}
|
||||||
|
|
@ -473,6 +522,13 @@ class Blender_ExportOptions(BaseOptions):
|
||||||
cmd.append(pcb3d_file)
|
cmd.append(pcb3d_file)
|
||||||
# Execute the command
|
# Execute the command
|
||||||
run_command(cmd)
|
run_command(cmd)
|
||||||
|
if self.render_options.auto_crop:
|
||||||
|
for pov in self.point_of_view:
|
||||||
|
for o in self.outputs:
|
||||||
|
if o.type != 'render':
|
||||||
|
continue
|
||||||
|
name = self.get_output_filename(o, self._parent.output_dir, pov)
|
||||||
|
run_command([convert_command, name, '-trim', '+repage', '-trim', '+repage', name])
|
||||||
|
|
||||||
|
|
||||||
@output_class
|
@output_class
|
||||||
|
|
@ -501,6 +557,25 @@ class Blender_Export(Base3D):
|
||||||
files.extend(self.options.pcb3d.list_models())
|
files.extend(self.options.pcb3d.list_models())
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
def get_renderer_options(self):
|
||||||
|
""" Where are the options for this output when used as a 'renderer' """
|
||||||
|
ops = self.options
|
||||||
|
out = next(filter(lambda x: x.type == 'render', ops.outputs), None)
|
||||||
|
res = None
|
||||||
|
if out is not None:
|
||||||
|
if isinstance(ops.pcb3d, str):
|
||||||
|
# We can't configure it
|
||||||
|
out = None
|
||||||
|
else:
|
||||||
|
res = ops.pcb3d
|
||||||
|
res._pov = ops.point_of_view[0]
|
||||||
|
res._out = out
|
||||||
|
return res if out is not None else None
|
||||||
|
|
||||||
|
def get_extension(self):
|
||||||
|
# Used when we are a renderer
|
||||||
|
return 'png'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_conf_examples(name, layers, templates):
|
def get_conf_examples(name, layers, templates):
|
||||||
if not GS.check_tool(name, 'Blender'):
|
if not GS.check_tool(name, 'Blender'):
|
||||||
|
|
|
||||||
|
|
@ -122,23 +122,19 @@ class PresentBoards(Optionable):
|
||||||
return self.name, self.comment, self.pcb_file, self.front_image, self.back_image, self.gerbers
|
return self.name, self.comment, self.pcb_file, self.front_image, self.back_image, self.gerbers
|
||||||
|
|
||||||
def generate_image(self, back, tmp_name):
|
def generate_image(self, back, tmp_name):
|
||||||
self.save_renderer_options()
|
options = self._renderer.get_renderer_options()
|
||||||
options = self._renderer.options
|
if options is None:
|
||||||
|
raise KiPlotConfigurationError('No suitable renderer ({})'.format(self._renderer))
|
||||||
|
# Memorize the current options
|
||||||
|
options.save_renderer_options()
|
||||||
logger.debug('Starting renderer with back: {}, name: {}'.format(back, tmp_name))
|
logger.debug('Starting renderer with back: {}, name: {}'.format(back, tmp_name))
|
||||||
# Configure it according to our needs
|
# Configure it according to our needs
|
||||||
options._filters_to_expand = False
|
options.setup_renderer([], [], back, tmp_name)
|
||||||
options.show_components = None if self._renderer_is_pcbdraw else []
|
self._renderer.dir = self._parent._parent.dir
|
||||||
options.highlight = []
|
|
||||||
options.output = tmp_name
|
|
||||||
self._renderer._done = False
|
self._renderer._done = False
|
||||||
if self._renderer_is_pcbdraw:
|
|
||||||
options.add_to_variant = False
|
|
||||||
options.bottom = back
|
|
||||||
else: # render_3D
|
|
||||||
options.view = 'Z' if back else 'z'
|
|
||||||
options._show_all_components = False
|
|
||||||
run_output(self._renderer)
|
run_output(self._renderer)
|
||||||
self.restore_renderer_options()
|
# Restore the options
|
||||||
|
options.restore_renderer_options()
|
||||||
|
|
||||||
def do_compress(self, tmp_name, out):
|
def do_compress(self, tmp_name, out):
|
||||||
tree = {'name': '_temporal_compress_gerbers',
|
tree = {'name': '_temporal_compress_gerbers',
|
||||||
|
|
@ -202,7 +198,6 @@ class PresentBoards(Optionable):
|
||||||
format(out, RENDERERS))
|
format(out, RENDERERS))
|
||||||
config_output(out)
|
config_output(out)
|
||||||
self._renderer = out
|
self._renderer = out
|
||||||
self._renderer_is_pcbdraw = out.type == 'pcbdraw'
|
|
||||||
tmp_name = _get_tmp_name(out.get_extension())
|
tmp_name = _get_tmp_name(out.get_extension())
|
||||||
self.temporals.append(tmp_name)
|
self.temporals.append(tmp_name)
|
||||||
self.generate_image(back, tmp_name)
|
self.generate_image(back, tmp_name)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2020-2022 Salvador E. Tropea
|
# Copyright (c) 2020-2023 Salvador E. Tropea
|
||||||
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
|
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
|
||||||
# License: GPL-3.0
|
# License: GPL-3.0
|
||||||
# Project: KiBot (formerly KiPlot)
|
# Project: KiBot (formerly KiPlot)
|
||||||
"""
|
"""
|
||||||
|
|
@ -322,6 +322,29 @@ class PcbDrawOptions(VariantOptions):
|
||||||
self._expand_id = 'bottom' if self.bottom else 'top'
|
self._expand_id = 'bottom' if self.bottom else 'top'
|
||||||
self._expand_ext = self.format
|
self._expand_ext = self.format
|
||||||
|
|
||||||
|
def setup_renderer(self, components, active_components, bottom, name):
|
||||||
|
super().setup_renderer(components, active_components)
|
||||||
|
self.add_to_variant = False
|
||||||
|
self.bottom = bottom
|
||||||
|
self.output = name
|
||||||
|
if not self.show_components:
|
||||||
|
self.show_components = None
|
||||||
|
return self.expand_filename_both(name, is_sch=False)
|
||||||
|
|
||||||
|
def save_renderer_options(self):
|
||||||
|
""" Save the current renderer settings """
|
||||||
|
super().save_renderer_options()
|
||||||
|
self.old_bottom = self.bottom
|
||||||
|
self.old_add_to_variant = self.add_to_variant
|
||||||
|
self.old_output = self.output
|
||||||
|
|
||||||
|
def restore_renderer_options(self):
|
||||||
|
""" Restore the renderer settings """
|
||||||
|
super().restore_renderer_options()
|
||||||
|
self.bottom = self.old_bottom
|
||||||
|
self.add_to_variant = self.old_add_to_variant
|
||||||
|
self.output = self.old_output
|
||||||
|
|
||||||
def expand_filtered_components(self, components):
|
def expand_filtered_components(self, components):
|
||||||
""" Expands references to filters in show_components """
|
""" Expands references to filters in show_components """
|
||||||
if not components or not self._filters_to_expand:
|
if not components or not self._filters_to_expand:
|
||||||
|
|
@ -530,6 +553,10 @@ class PcbDraw(BaseOutput): # noqa: F821
|
||||||
files.append(self.options.style)
|
files.append(self.options.style)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
def get_renderer_options(self):
|
||||||
|
""" Where are the options for this output when used as a 'renderer' """
|
||||||
|
return self.options
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_conf_examples(name, layers, templates):
|
def get_conf_examples(name, layers, templates):
|
||||||
outs = []
|
outs = []
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2022 Salvador E. Tropea
|
# Copyright (c) 2022-2023 Salvador E. Tropea
|
||||||
# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
|
# Copyright (c) 2022-2023 Instituto Nacional de Tecnología Industrial
|
||||||
# License: GPL-3.0
|
# License: GPL-3.0
|
||||||
# Project: KiBot (formerly KiPlot)
|
# Project: KiBot (formerly KiPlot)
|
||||||
"""
|
"""
|
||||||
|
|
@ -82,33 +82,22 @@ class PopulateOptions(VariantOptions):
|
||||||
img_dir = os.path.dirname(self._parent.expand_filename(out_dir, self.imgname))
|
img_dir = os.path.dirname(self._parent.expand_filename(out_dir, self.imgname))
|
||||||
return [self._parent.expand_filename(out_dir, self.get_out_file_name()), img_dir]
|
return [self._parent.expand_filename(out_dir, self.get_out_file_name()), img_dir]
|
||||||
|
|
||||||
def generate_image(self, side, components, active_components, name):
|
def generate_image(self, side, components, active_components, name, options):
|
||||||
options = self._renderer.options
|
|
||||||
logger.debug('Starting renderer with side: {}, components: {}, high: {}, image: {}'.
|
logger.debug('Starting renderer with side: {}, components: {}, high: {}, image: {}'.
|
||||||
format(side, components, active_components, name))
|
format(side, components, active_components, name))
|
||||||
# Configure it according to our needs
|
# Configure it according to our needs
|
||||||
options._filters_to_expand = False
|
o_name = options.setup_renderer(components, active_components, side.startswith("back"), name)
|
||||||
options.show_components = [c for c in components if c]
|
|
||||||
if not options.show_components:
|
|
||||||
options.show_components = None if self._renderer_is_pcbdraw else []
|
|
||||||
else:
|
|
||||||
options.show_components = options.solve_kf_filters(options.show_components)
|
|
||||||
options.highlight = options.solve_kf_filters([c for c in active_components if c])
|
|
||||||
options.output = name
|
|
||||||
self._renderer.dir = self._parent.dir
|
self._renderer.dir = self._parent.dir
|
||||||
self._renderer._done = False
|
self._renderer._done = False
|
||||||
if self._renderer_is_pcbdraw:
|
|
||||||
options.add_to_variant = False
|
|
||||||
options.bottom = side.startswith("back")
|
|
||||||
else: # render_3D
|
|
||||||
options.view = 'Z' if side.startswith("back") else 'z'
|
|
||||||
options._show_all_components = False
|
|
||||||
run_output(self._renderer)
|
run_output(self._renderer)
|
||||||
return options.expand_filename_both(name, is_sch=False)
|
return o_name
|
||||||
|
|
||||||
def generate_images(self, dir_name, content):
|
def generate_images(self, dir_name, content):
|
||||||
|
options = self._renderer.get_renderer_options()
|
||||||
|
if options is None:
|
||||||
|
raise KiPlotConfigurationError('No suitable renderer ({})'.format(self._renderer))
|
||||||
# Memorize the current options
|
# Memorize the current options
|
||||||
self.save_renderer_options()
|
options.save_renderer_options()
|
||||||
dir = os.path.dirname(os.path.join(dir_name, self.imgname))
|
dir = os.path.dirname(os.path.join(dir_name, self.imgname))
|
||||||
if not os.path.exists(dir):
|
if not os.path.exists(dir):
|
||||||
os.makedirs(dir)
|
os.makedirs(dir)
|
||||||
|
|
@ -119,9 +108,9 @@ class PopulateOptions(VariantOptions):
|
||||||
for x in item["steps"]:
|
for x in item["steps"]:
|
||||||
counter += 1
|
counter += 1
|
||||||
filename = self.imgname.replace('%d', str(counter))
|
filename = self.imgname.replace('%d', str(counter))
|
||||||
x["img"] = self.generate_image(x["side"], x["components"], x["active_components"], filename)
|
x["img"] = self.generate_image(x["side"], x["components"], x["active_components"], filename, options)
|
||||||
# Restore the options
|
# Restore the options
|
||||||
self.restore_renderer_options()
|
options.restore_renderer_options()
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def run(self, dir_name):
|
def run(self, dir_name):
|
||||||
|
|
@ -140,7 +129,6 @@ class PopulateOptions(VariantOptions):
|
||||||
if out.type not in RENDERERS:
|
if out.type not in RENDERERS:
|
||||||
raise KiPlotConfigurationError('The `renderer` must be {} type, not {}'.format(RENDERERS, out.type))
|
raise KiPlotConfigurationError('The `renderer` must be {} type, not {}'.format(RENDERERS, out.type))
|
||||||
self._renderer = out
|
self._renderer = out
|
||||||
self._renderer_is_pcbdraw = out.type == 'pcbdraw'
|
|
||||||
# Load the input content
|
# Load the input content
|
||||||
try:
|
try:
|
||||||
_, content = load_content(self.input)
|
_, content = load_content(self.input)
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,26 @@ class Render3DOptions(Base3DOptionsWithHL):
|
||||||
self.view = view
|
self.view = view
|
||||||
self._expand_id += '_'+self._rviews.get(self.view)
|
self._expand_id += '_'+self._rviews.get(self.view)
|
||||||
|
|
||||||
|
def setup_renderer(self, components, active_components, bottom, name):
|
||||||
|
super().setup_renderer(components, active_components)
|
||||||
|
self.view = 'Z' if bottom else 'z'
|
||||||
|
self.output = name
|
||||||
|
return self.expand_filename_both(name, is_sch=False)
|
||||||
|
|
||||||
|
def save_renderer_options(self):
|
||||||
|
""" Save the current renderer settings """
|
||||||
|
super().save_renderer_options()
|
||||||
|
self.old_show_all_components = self._show_all_components
|
||||||
|
self.old_view = self.view
|
||||||
|
self.old_output = self.output
|
||||||
|
|
||||||
|
def restore_renderer_options(self):
|
||||||
|
""" Restore the renderer settings """
|
||||||
|
super().restore_renderer_options()
|
||||||
|
self._show_all_components = self.old_show_all_components
|
||||||
|
self.view = self.old_view
|
||||||
|
self.output = self.old_output
|
||||||
|
|
||||||
def add_step(self, cmd, steps, ops):
|
def add_step(self, cmd, steps, ops):
|
||||||
if steps:
|
if steps:
|
||||||
cmd.extend([ops, str(steps)])
|
cmd.extend([ops, str(steps)])
|
||||||
|
|
@ -265,6 +285,10 @@ class Render_3D(Base3D): # noqa: F821
|
||||||
""" *[dict] Options for the `render_3d` output """
|
""" *[dict] Options for the `render_3d` output """
|
||||||
self._category = 'PCB/3D'
|
self._category = 'PCB/3D'
|
||||||
|
|
||||||
|
def get_renderer_options(self):
|
||||||
|
""" Where are the options for this output when used as a 'renderer' """
|
||||||
|
return self.options
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_conf_examples(name, layers, templates):
|
def get_conf_examples(name, layers, templates):
|
||||||
outs = []
|
outs = []
|
||||||
|
|
|
||||||
|
|
@ -250,17 +250,24 @@ deps = '{\
|
||||||
],\
|
],\
|
||||||
"extra_deb": null,\
|
"extra_deb": null,\
|
||||||
"help_option": "--version",\
|
"help_option": "--version",\
|
||||||
"importance": 4,\
|
"importance": 5,\
|
||||||
"in_debian": true,\
|
"in_debian": true,\
|
||||||
"is_kicad_plugin": false,\
|
"is_kicad_plugin": false,\
|
||||||
"is_python": false,\
|
"is_python": false,\
|
||||||
"name": "ImageMagick",\
|
"name": "ImageMagick",\
|
||||||
"no_cmd_line_version": false,\
|
"no_cmd_line_version": false,\
|
||||||
"no_cmd_line_version_old": false,\
|
"no_cmd_line_version_old": false,\
|
||||||
"output": "navigate_results",\
|
"output": "blender_export",\
|
||||||
"plugin_dirs": null,\
|
"plugin_dirs": null,\
|
||||||
"pypi_name": "ImageMagick",\
|
"pypi_name": "ImageMagick",\
|
||||||
"roles": [\
|
"roles": [\
|
||||||
|
{\
|
||||||
|
"desc": "Automatically crop images",\
|
||||||
|
"mandatory": false,\
|
||||||
|
"max_version": null,\
|
||||||
|
"output": "blender_export",\
|
||||||
|
"version": null\
|
||||||
|
},\
|
||||||
{\
|
{\
|
||||||
"desc": "Create outputs preview",\
|
"desc": "Create outputs preview",\
|
||||||
"mandatory": false,\
|
"mandatory": false,\
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ outputs:
|
||||||
mode: local
|
mode: local
|
||||||
comment: This is a comment
|
comment: This is a comment
|
||||||
name: Light control
|
name: Light control
|
||||||
back_image: Raytraced
|
# back_image: Raytraced
|
||||||
|
back_image: Blender
|
||||||
repository: 'https://github.com/INTI-CMNB/KiBot/'
|
repository: 'https://github.com/INTI-CMNB/KiBot/'
|
||||||
|
|
||||||
- name: PcbDraw
|
- name: PcbDraw
|
||||||
|
|
@ -37,6 +38,18 @@ outputs:
|
||||||
rotate_z: -2
|
rotate_z: -2
|
||||||
ray_tracing: true
|
ray_tracing: true
|
||||||
|
|
||||||
|
- name: Blender
|
||||||
|
type: blender_export
|
||||||
|
run_by_default: false
|
||||||
|
options:
|
||||||
|
outputs:
|
||||||
|
- type: render
|
||||||
|
render_options:
|
||||||
|
transparent_background: true
|
||||||
|
auto_crop: true
|
||||||
|
# width: 640
|
||||||
|
# height: 480
|
||||||
|
|
||||||
- name: 'gerbers'
|
- name: 'gerbers'
|
||||||
comment: "Gerbers for the Gerber god"
|
comment: "Gerbers for the Gerber god"
|
||||||
type: gerber
|
type: gerber
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue