diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e6a0cfe..dace7ee4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.5.2] - Unreleased
### Fixed
+- New output:
+ - `vrml` export the 3D model in Virtual Reality Modeling Language (#349)
- PCB_Print:
- Images not showing in custom frames. (#352)
diff --git a/README.md b/README.md
index fad538aa..b5ac1a40 100644
--- a/README.md
+++ b/README.md
@@ -94,7 +94,7 @@ For example, it's common that you might want for each board rev:
* Gerbers, drills and drill maps for a fab in their favourite format
* Fab docs for the assembler, including the BoM (Bill of Materials), costs spreadsheet and board view
* Pick and place files
-* PCB 3D model in STEP format
+* PCB 3D model in STEP and VRML format
* PCB 3D render in PNG format
* Compare PCB/SCHs
* Panelization
@@ -137,8 +137,8 @@ Notes:
[**Requests**](https://pypi.org/project/Requests/) [](https://pypi.org/project/Requests/) [](https://pypi.org/project/Requests/) [](https://packages.debian.org/bullseye/python3-requests)
- Mandatory
-[**KiCad Automation tools**](https://github.com/INTI-CMNB/KiAuto) v2.0.4 [](https://github.com/INTI-CMNB/KiAuto) 
-- Mandatory for: `gencad`, `netlist`, `pdf_pcb_print`, `pdf_sch_print`, `render_3d`, `run_drc`, `run_erc`, `step`, `svg_pcb_print`, `svg_sch_print`, `update_xml`
+[**KiCad Automation tools**](https://github.com/INTI-CMNB/KiAuto) v2.1.0 [](https://github.com/INTI-CMNB/KiAuto) 
+- Mandatory for: `gencad`, `netlist`, `pdf_pcb_print`, `pdf_sch_print`, `render_3d`, `run_drc`, `run_erc`, `step`, `svg_pcb_print`, `svg_sch_print`, `update_xml`, `vrml`
- Optional to:
- Compare schematics for `diff` (v2.0.0)
- Show KiAuto installation information for `info` (v2.0.0)
@@ -1260,6 +1260,7 @@ The available values for *type* are:
- `kicost` BoM in XLSX format with costs generated by [KiCost](https://github.com/INTI-CMNB/KiCost)
- 3D model:
- `step` *Standard for the Exchange of Product Data* for the PCB
+ - `vrml` *Virtual Reality Modeling Language* for the PCB
- `render_3d` PCB render, from the KiCad's 3D Viewer (broken in KiCad 6.0.0)
- Web pages:
- `populate` To create step-by-step assembly instructions.
@@ -3977,6 +3978,47 @@ Notes:
Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
- `run_by_default`: [boolean=true] When enabled this output will be created when no specific outputs are requested.
+* VRML (Virtual Reality Modeling Language)
+ * Type: `vrml`
+ * Description: Exports the PCB as a 3D model (WRL file).
+ This is intended for rendering, unlike STEP which is intended to be
+ an exact mechanic model
+ * Valid keys:
+ - **`comment`**: [string=''] A comment for documentation purposes.
+ - **`dir`**: [string='./'] Output directory for the generated files.
+ If it starts with `+` the rest is concatenated to the default dir.
+ - **`name`**: [string=''] Used to identify this particular output definition.
+ - **`options`**: [dict] Options for the `vrml` output.
+ * Valid keys:
+ - **`download`**: [boolean=true] Downloads missing 3D models from KiCad git. Only applies to models in KISYS3DMOD.
+ - **`no_virtual`**: [boolean=false] Used to exclude 3D models for components with 'virtual' attribute.
+ - **`output`**: [string='%f-%i%I%v.%x'] Filename for the output (%i=vrml, %x=wrl). Affected by global options.
+ - `dir_models`: [string='shapes3D'] Subdirectory used to store the 3D models for the components.
+ If you want to create a monolithic file just use '' here.
+ Note that the WRL file will contain relative paths to the models.
+ - `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.
+ - `kicad_3d_url`: [string='https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'] Base URL for the KiCad 3D models.
+ - `model_units`: [string='millimeters'] [millimeters,meters,deciinches,inches] Units used for the VRML (1 deciinch = 0.1 inches).
+ - `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.
+ - `ref_units`: [string='millimeters'] [millimeters,inches'] Units for `ref_x` and `ref_y`.
+ - `ref_x`: [number=0] X coordinate to use as reference when `use_pcb_center_as_ref` is disabled.
+ - `ref_y`: [number=0] Y coordinate to use as reference when `use_pcb_center_as_ref` is disabled.
+ - `use_pcb_center_as_ref`: [boolean=true] The center of the PCB will be used as reference point.
+ When disabled the `ref_x`, `ref_y` and `ref_units` will be used.
+ - `variant`: [string=''] Board variant to apply.
+ - `category`: [string|list(string)=''] The category for this output. If not specified an internally defined category is used.
+ Categories looks like file system paths, i.e. PCB/fabrication/gerber.
+ - `disable_run_by_default`: [string|boolean] Use it to disable the `run_by_default` status of other output.
+ Useful when this output extends another and you don't want to generate the original.
+ Use the boolean true value to disable the output you are extending.
+ - `extends`: [string=''] Copy the `options` section from the indicated output.
+ - `output_id`: [string=''] Text to use for the %I expansion content. To differentiate variations of this output.
+ - `priority`: [number=50] [0,100] Priority for this output. High priority outputs are created first.
+ Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
+ - `run_by_default`: [boolean=true] When enabled this output will be created when no specific outputs are requested.
+
#### Consolidating BoMs
diff --git a/docs/README.in b/docs/README.in
index 9f5323d7..521a7236 100644
--- a/docs/README.in
+++ b/docs/README.in
@@ -93,7 +93,7 @@ For example, it's common that you might want for each board rev:
* Gerbers, drills and drill maps for a fab in their favourite format
* Fab docs for the assembler, including the BoM (Bill of Materials), costs spreadsheet and board view
* Pick and place files
-* PCB 3D model in STEP format
+* PCB 3D model in STEP and VRML format
* PCB 3D render in PNG format
* Compare PCB/SCHs
* Panelization
@@ -737,6 +737,7 @@ The available values for *type* are:
- `kicost` BoM in XLSX format with costs generated by [KiCost](https://github.com/INTI-CMNB/KiCost)
- 3D model:
- `step` *Standard for the Exchange of Product Data* for the PCB
+ - `vrml` *Virtual Reality Modeling Language* for the PCB
- `render_3d` PCB render, from the KiCad's 3D Viewer (broken in KiCad 6.0.0)
- Web pages:
- `populate` To create step-by-step assembly instructions.
diff --git a/docs/images/icon_sources/file_wrl.svg b/docs/images/icon_sources/file_wrl.svg
new file mode 100644
index 00000000..301af5bf
--- /dev/null
+++ b/docs/images/icon_sources/file_wrl.svg
@@ -0,0 +1,213 @@
+
+
diff --git a/docs/samples/generic_plot.kibot.yaml b/docs/samples/generic_plot.kibot.yaml
index 1dd61100..6a5d748f 100644
--- a/docs/samples/generic_plot.kibot.yaml
+++ b/docs/samples/generic_plot.kibot.yaml
@@ -2850,3 +2850,42 @@ outputs:
# [string=''] Board variant to apply.
# Not fitted components are crossed
variant: ''
+ # VRML (Virtual Reality Modeling Language):
+ # This is intended for rendering, unlike STEP which is intended to be
+ # an exact mechanic model
+ - name: 'vrml_example'
+ comment: 'Exports the PCB as a 3D model (WRL file).'
+ type: 'vrml'
+ dir: 'Example/vrml_dir'
+ options:
+ # [string='shapes3D'] Subdirectory used to store the 3D models for the components.
+ # If you want to create a monolithic file just use '' here.
+ # Note that the WRL file will contain relative paths to the models
+ dir_models: 'shapes3D'
+ # [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
+ dnf_filter: '_none'
+ # [boolean=true] Downloads missing 3D models from KiCad git. Only applies to models in KISYS3DMOD
+ download: true
+ # [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/'
+ # [string='millimeters'] [millimeters,meters,deciinches,inches] Units used for the VRML (1 deciinch = 0.1 inches)
+ model_units: 'millimeters'
+ # [boolean=false] Used to exclude 3D models for components with 'virtual' attribute
+ no_virtual: false
+ # [string='%f-%i%I%v.%x'] Filename for the output (%i=vrml, %x=wrl). Affected by global options
+ output: '%f-%i%I%v.%x'
+ # [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
+ pre_transform: '_none'
+ # [string='millimeters'] [millimeters,inches'] Units for `ref_x` and `ref_y`
+ ref_units: 'millimeters'
+ # [number=0] X coordinate to use as reference when `use_pcb_center_as_ref` is disabled
+ ref_x: 0
+ # [number=0] Y coordinate to use as reference when `use_pcb_center_as_ref` is disabled
+ ref_y: 0
+ # [boolean=true] The center of the PCB will be used as reference point.
+ # When disabled the `ref_x`, `ref_y` and `ref_units` will be used
+ use_pcb_center_as_ref: true
+ # [string=''] Board variant to apply
+ variant: ''
diff --git a/kibot/out_navigate_results.py b/kibot/out_navigate_results.py
index 6bb113cf..e0e02806 100644
--- a/kibot/out_navigate_results.py
+++ b/kibot/out_navigate_results.py
@@ -78,6 +78,7 @@ EXT_IMAGE = {'gbr': 'file_gbr',
'stl': 'file_stl',
'step': 'file_stp',
'stp': 'file_stp',
+ 'wrl': 'file_wrl',
'html': 'file_html',
'css': 'file_css',
'xml': 'file_xml',
diff --git a/kibot/out_vrml.py b/kibot/out_vrml.py
new file mode 100644
index 00000000..4fddfa72
--- /dev/null
+++ b/kibot/out_vrml.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2022 Salvador E. Tropea
+# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
+# License: GPL-3.0
+# Project: KiBot (formerly KiPlot)
+"""
+Dependencies:
+ - from: KiAuto
+ role: mandatory
+ version: 2.1.0
+"""
+import os
+from .gs import GS
+from .out_base_3d import Base3DOptions, Base3D
+from .misc import FAILED_EXECUTE
+from .kiplot import exec_with_retry, add_extra_options
+from .macros import macros, document, output_class # noqa: F401
+from . import log
+
+logger = log.get_logger()
+
+
+class VRMLOptions(Base3DOptions):
+ def __init__(self):
+ with document:
+ self.output = GS.def_global_output
+ """ *Filename for the output (%i=vrml, %x=wrl) """
+ self.dir_models = 'shapes3D'
+ """ Subdirectory used to store the 3D models for the components.
+ If you want to create a monolithic file just use '' here.
+ Note that the WRL file will contain relative paths to the models """
+ self.use_pcb_center_as_ref = True
+ """ The center of the PCB will be used as reference point.
+ When disabled the `ref_x`, `ref_y` and `ref_units` will be used """
+ self.ref_x = 0
+ """ X coordinate to use as reference when `use_pcb_center_as_ref` is disabled """
+ self.ref_y = 0
+ """ Y coordinate to use as reference when `use_pcb_center_as_ref` is disabled """
+ self.ref_units = 'millimeters'
+ """ [millimeters,inches'] Units for `ref_x` and `ref_y` """
+ self.model_units = 'millimeters'
+ """ [millimeters,meters,deciinches,inches] Units used for the VRML (1 deciinch = 0.1 inches) """
+ super().__init__()
+ self._expand_id = 'vrml'
+ self._expand_ext = 'wrl'
+
+ def get_targets(self, out_dir):
+ targets = [self._parent.expand_filename(out_dir, self.output)]
+ if self.dir_models:
+ # We will also generate the models
+ dir = os.path.join(out_dir, self.dir_models)
+ filtered = {os.path.join(dir, os.path.basename(m)) for m in self.list_models() if m.endswith('.wrl')}
+ targets.extend(list(filtered))
+ return targets
+
+ def get_pcb_center(self):
+ center = GS.board.ComputeBoundingBox(True).Centre()
+ return self.to_mm(center.x), self.to_mm(center.y)
+
+ def run(self, name):
+ command = self.ensure_tool('KiAuto')
+ super().run(name)
+ board_name = self.filter_components()
+ cmd = [command, 'export_vrml', '--output_name', os.path.basename(name), '-U', self.model_units]
+ if self.dir_models:
+ cmd.extend(['--dir_models', self.dir_models])
+ if not self.use_pcb_center_as_ref or GS.ki5:
+ # KiCad 5 doesn't support using the center, we emulate it
+ if self.use_pcb_center_as_ref and GS.ki5:
+ x, y = self.get_pcb_center()
+ units = 'millimeters'
+ else:
+ x = self.ref_x
+ self.ref_y
+ units = self.ref_units
+ cmd.extend(['-x', str(x), '-y', str(x), '-u', units])
+ cmd.extend([board_name, os.path.dirname(name)])
+ cmd, video_remove = add_extra_options(cmd)
+ # Execute it
+ try:
+ ret = exec_with_retry(cmd)
+ finally:
+ self.remove_tmp_board(board_name)
+ if ret:
+ logger.error(command+' returned %d', ret)
+ exit(FAILED_EXECUTE)
+ if video_remove:
+ video_name = os.path.join(self.expand_filename_pcb(GS.out_dir), 'pcbnew_export_vrml_screencast.ogv')
+ if os.path.isfile(video_name):
+ os.remove(video_name)
+
+
+@output_class
+class VRML(BaseOutput): # noqa: F821
+ """ VRML (Virtual Reality Modeling Language)
+ Exports the PCB as a 3D model (WRL file).
+ This is intended for rendering, unlike STEP which is intended to be
+ an exact mechanic model """
+ def __init__(self):
+ super().__init__()
+ self._category = 'PCB/3D'
+ with document:
+ self.options = VRMLOptions
+ """ *[dict] Options for the `vrml` output """
+
+ @staticmethod
+ def get_conf_examples(name, layers, templates):
+ return Base3D.simple_conf_examples(name, 'PCB in VRML format', '3D')
diff --git a/kibot/resources/images/file_wrl.svg b/kibot/resources/images/file_wrl.svg
new file mode 100644
index 00000000..b1d1786d
--- /dev/null
+++ b/kibot/resources/images/file_wrl.svg
@@ -0,0 +1,179 @@
+
+
diff --git a/src/kibot-check b/src/kibot-check
index 2ec288e9..6a01f8f5 100755
--- a/src/kibot-check
+++ b/src/kibot-check
@@ -300,7 +300,7 @@ deps = '{\
"extra_arch": null,\
"extra_deb": null,\
"help_option": "--version",\
- "importance": 110003,\
+ "importance": 120003,\
"in_debian": false,\
"is_kicad_plugin": false,\
"is_python": false,\
@@ -432,6 +432,17 @@ deps = '{\
0\
]\
},\
+ {\
+ "desc": null,\
+ "mandatory": true,\
+ "max_version": null,\
+ "output": "vrml",\
+ "version": [\
+ 2,\
+ 1,\
+ 0\
+ ]\
+ },\
{\
"desc": null,\
"mandatory": true,\
diff --git a/tests/yaml_samples/vrml_1.kibot.yaml b/tests/yaml_samples/vrml_1.kibot.yaml
new file mode 100644
index 00000000..ba1cec8d
--- /dev/null
+++ b/tests/yaml_samples/vrml_1.kibot.yaml
@@ -0,0 +1,8 @@
+# Example KiBot config file
+kibot:
+ version: 1
+
+outputs:
+ - name: 'VRML export Test'
+ comment: "Example of VRML export"
+ type: vrml