Split BlenderBIM and other docs to not overwhelm users. Use Furo theme for Sphinx.

This commit is contained in:
Dion Moult
2022-05-04 13:06:39 +10:00
parent 6e55a04550
commit 8c3e29c351
38 changed files with 334 additions and 108 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 85 KiB

@@ -0,0 +1,95 @@
Georeferencing
==============
In the AEC industry, works in the built environment are split between vertical
construction (such as buildings and sites), and horizontal construction (such as
transit, transmission, and subterranean networks). Blender and the BlenderBIM
Add-on is only suitable for vertical construction.
IFC4 onwards supports georeferencing. The BlenderBIM Add-on has full support for
IFC georeferencing. Here are the potential scenarios you will encounter in the
wild for vertical construction.
1. Correctly georeferenced IFC4 with a map conversion transformation
2. Correctly georeferenced IFC4 with a map conversion without a transformation
3. Non-georeferenced IFC4
4. Non-georeferenced IFC2X3
The first scenario is desired for most disciplines, such as architects and all
engineers (except for civil). Typically, this results in small local engineering
coordinates, which work well in Blender.
Correct georeferencing requires a projected CRS and a map conversion.
Unfortunately, many users may be under the impression that their file is
correctly georeferenced, but this is rarely the case. You can check whether your
file is correctly georeferenced in the ``IFC Georeferencing`` scene panel. If
you see "Not Georeferenced", your file is not correctly georeferenced. If your
file is georeferenced, it is still no guarantee that the georeferencing data is
actually correct, but how to determine this is out of scope of this article.
For scenarios 2, 3, and 4, coordinates may be quite large. To present this data
in Blender, the BlenderBIM Add-on will automatically attempt to create a false
origin to preserve the precision of the model. The first coordinate greater than
1km will be detected and used as an offset coordinate. You can see the false
origin, if any, in the ``Blender Offset`` section of the ``IFC Georeferencing``
scene panel.
Instead of relying on an automatic false origin, you can also specify a custom
origin coordinate. To do this, choose ``Enable Advanced Mode`` when loading an
IFC project. Then enable the ``Import and Offset Model`` option and specify a
new coordinate to replace the origin's default of 0,0,0 in the ``Model Offset
Coordinates`` option.
Dealing with large coordinates
------------------------------
In scenarios 2, 3, and 4, a BIM vendor will typically choose from two possible
methods to offset their coordinates into large map coordinates.
The first method is to shift the origin point of objects in the model relative
to the global coordinate system. We call this the ``OBJECT_PLACEMENT`` method.
The second method is to shift the coordinates of geometry within the objects
themselves relative to the object placement. We call this the
``CARTESIAN_POINT`` method. Sometimes, BIM applications combine both of these
methods in a single IFC project. To see which workaround was used on an object,
check the "Blender Offset" property in the ``Transform`` object panel.
Sometimes, a model shifts their coordinates for some objects, but not all. For
example, the walls in a model may have their object placement or cartesian
points shifted to map coordinates, however, the object placement of the site is
still at 0, 0, 0. Since these coordinates are so far apart, this creates a
problem, because Blender needs to choose between displaying the walls accurately
and sacrificing precision at the site placement, or vice versa, but it is
impossible to satisfy both simultaneously in the same Blender session.
Many IFC viewers only show geometry, and don't show object placements. This may
give users the false impression that their coordinates in their IFC project do
not have such a large range. However, because the BlenderBIM Add-on is a full
authoring platform, we do need to show these placements and thus it is the users
responsibility to reconcile this inconsistency in their coordinates. Either the
user needs to fix their file to consistently offset all coordinates, or the user
needs to manually tell the BlenderBIM Add-on the coordinates of the desired
false origin. In the absence of manual intervention, the BlenderBIM Add-on will
make an intelligent guess, but it may be wrong.
Coordinates and precision limits
--------------------------------
Blender, and subsequently the BlenderBIM Add-on, is not designed for map
coordinate systems. Blender internally uses single precision floating point
calculations. A full description of the precision implications are described in
the `Blender working limits documentation
<https://docs.blender.org/manual/en/latest/advanced/limits.html>`__.
From a software perspective, lengths greater than 5,000 meters start to
accumulate precision errors that affect the nearest millimeter. Therefore, from
a software perspective, it is unwise to embark on a project with coordinates
ranging greater than +/- 5km.
However, if working in local engineering coordinates, a single transformation is
required to convert from local engineering coordinates to map coordinates. This
transformation includes a scale factor. The scale factor is only assumed to be
constant for small sites (defined approximately as less than 1km square). This
practical limit of georeferenced vertical construction is smaller than the
software limit, so this surveying convention is the actual limiting factor, not
the software.
+294
View File
@@ -0,0 +1,294 @@
Hello, world!
=============
The BlenderBIM Add-on takes a unique approach to authoring BIM data. Traditional
BIM authoring apps create features that are tailored for a single discipline's
paradigm, such as a 3D environment, or a spreadsheet view, and store their data
structure in a schema that is unique to their application. In order to
interoperate with others, there is an export or import process that translates
between their bespoke schema to and from open data standards. The most famous
ISO standard for BIM is IFC. After this translation, they then serialise it
typically into a format, which may be saved to disk.
The BlenderBIM Add-on does things differently.
The BlenderBIM Add-on does not have its own bespoke data structure and does not
import or export. The BlenderBIM Add-on uses ISO open data standards directly in
memory. Most commonly, this is IFC data. We will place a focus on IFC on this
guide, but the reader should be aware that the BlenderBIM Add-on also takes the
same approach to dealing with other open data standards, like Brickschema or
BCF. The same concepts will apply. We can call this Native OpenBIM authoring,
which is a paradigm shift from traditional BIM which relies on translated IFC
data.
.. image:: native-openbim.png
Every user operation reads or writes this data structure in memory, and the IFC
data becomes the source of truth for all data. There is no such thing as an
import or export. The data is always represented in IFC. When a BIM model is
opened or saved, it is simply a serialisation or deserialisation operation. This
also means that you are using Blender simply as an interface to interact with
IFC, and the ``.blend`` container is largely unnecessary, as nothing of
significance is stored in the Blender system, it is simply a snapshot of your
working session.
Due to this significant difference, hacking on the BlenderBIM Add-on requires
knowledge not just about how Blender works, but also how open data standards
like IFC works.
Just show me the code!
----------------------
Sometimes, the best way to learn how to hack on a project is to just start
hacking away. BIM authoring is a really big topic. As a result, the BlenderBIM
Add-on code is separated into modules. Each module focuses on a particular topic
of BIM. Most modules are self-contained, but sometimes they connect to one
another, just like how BIM works.
.. image:: module-architecture.png
Modules are not arbitrary divisions. They tend to reflect how portions of BIM
data are segregated in the IFC international standard. This allows us to
minimise the overlap between modules, so that developers can work on a single
portion of the code with relative certainty that their actions will not affects
other developers.
- `BlenderBIM Add-on modules <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/blenderbim/blenderbim/bim/module>`__
- `IFC modules <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/ifcopenshell-python/ifcopenshell/api>`__
The BlenderBIM Add-on comes with a secret **demo module** which is basically a
hello world coding tutorial which teaches you about all the moving parts. It's
far more interesting to read this code rather than 15 pages of abstract software
architecture flow charts and diagrams. The code and its comments will guide you
through the process.
Before playing with the demo module, you may want to switch to using a source
installation. See `blenderbim/installation <./installation.rst>`_ for details.
To see the demo module in action, you'll need to enable it. In
``src/blenderbim/blenderbim/bim/__init__.py``, uncomment the line for the demo
module. When you restart Blender, you will see a new demo panel in your scene
properties interface tab. Have fun!
.. image:: demo-module.png
Now you're ready to learn how to code! Here are all the files associated with
the demo module. Feel free to read them in any order. Each file is heavily
commented with explanations about what each line of code does. Change some of
the code, reload Blender, and see what happens!
::
src/blenderbim/blenderbim/bim/module/demo/__init__.py
src/blenderbim/blenderbim/bim/module/demo/operator.py
src/blenderbim/blenderbim/bim/module/demo/prop.py
src/blenderbim/blenderbim/bim/module/demo/ui.py
src/blenderbim/blenderbim/bim/module/demo/data.py
src/blenderbim/blenderbim/core/demo.py
src/blenderbim/blenderbim/tool/demo.py
Wow! That's a lot of files needed for a hello world! Don't worry, it's mostly
tutorial comments and it's there to teach you the basics from how Blender's
add-on system works, how interfaces work, to how the BlenderBIM Add-on works,
and how to test and structure it so that you can build incredibly complex
features in a maintainable way.
Tests for quality checking also exist. The system is designed so that you can
do "Test Driven Development". For reference on how to run these tests, see `blenderbim/running_tests <./running_tests.rst>`_
for details. You can find the tests here:
::
src/blenderbim/test/bim/feature/demo.feature
src/blenderbim/test/core/test_demo.py
src/blenderbim/test/tool/test_demo.py
Not all developers, especially those learning how to code, are familiar with
testing and how to write tests. That's OK! Feel free to ignore the tests at
first until you get a bit more comfortable with coding, and others can help
guide you when you're ready to make the leap. Don't let this stop you from
building things, others can also help write tests for you and clean your code.
It's a great way to learn!
Once you're through, you should be able to understand how most of the BlenderBIM
Add-on is built and where to find things.
There are many Blender Python tutorials out there. A good place to start is the
`Start coding for Blender
<https://wiki.osarch.org/index.php?title=Start_coding_for_Blender>`__ from the
OSArch Wiki. In addition, the Blender text editor comes with a menu called
``Templates > Python`` which gives you a whole list of example code of how to
create an add-on which creates objects, creates gizmos, new buttons, interfaces,
and so on. This is a great way to try out how to build different extensions.
Naturally, if you just want to tweak the BlenderBIM Add-on or build a small
feature just for yourself, you're free to ignore this advice, skip all the
tests, and just write half the code in a single file and it'll get the job done.
Software architecture
---------------------
If code isn't good enough for you and you want to learn more about why the code
is structured the way it is, here is a list of design principles we follow:
1. Big systems are hard to maintain. Break big systems into small systems.
2. Separate abstract code from concrete code. Start with abstract code, and
deal with the details later.
3. Good code reads like poetry. Every usecase should have a poem.
4. Separate UI code from domain logic. UI code should be as dumb as possible.
5. Follow the Unix philosophy. We're dealing with a big industry problem here.
Building a shared ecosystem of tools is better than one behemoth.
6. Everything should be testable. You should be able to test first.
7. Have different types of tests. Inversely correlate test speed and scope.
8. Community first. Allow beginner programmers to join in the fun! Code should
feel easy, not like a course in design pattern jargon.
9. Incremental change, not waterfall. Don't trash and rebuild. Refactor and
redesign one commit at a time. With each commit, ask if you're making the
code nicer.
10. Perfect is the enemy of the good. Half broken is better than completely
broken.
The rest of this contains nasty software architecture jargon. If that's not your
thing, stop reading now.
The BlenderBIM Add-on code may be understood in three separate layers: **Delivery**,
**Domain**, and **Data**. The BlenderBIM Add-on architecture separates these
three layers from one another. Because they are separate, they can be tested and
built separately.
.. image:: architecture.png
The **Delivery** mechanism is how the application is delivered to
the user and handles user interactions. It covers the interface and triggering
events as inputs into the application, and rendering responses.
As advertised in the name, the **Delivery** mechanism is based on **Blender**.
**Blender** is a well established 3D platform. Out of the box, it provides an
incredibly advanced interface to allow users to interact with geometry. The
delivery mechanism code extends Blender extensively, including new *Operations*
that users can perform, new *Properties* to store custom data, and new *UI*
layouts to display information.
When an event such as an *Operation* is triggered, the **Delivery** mechanism
executes the **Domain** layer through dependency injection. The **Domain** layer
will then decide how to process this input.
The **Domain** layer is divided into two halves: an abstract *Core* and concrete
*Tools*. The *Core* describes abstract, high-level application logic flow for
every single possible usecase in application. The *Tools* actually implement
this abstract logic, and figure out how things actually work, whether it is
manipulating the Blender scene, writing and reading files, building new IFC
graph relationships, and so on. The **Domain** layer also has interface classes
to describe what it needs.
Whenever the application needs to remember or store information, it does so
using a **Data** repository. The data ensures that stored information confirms
to a defined schema and is valid, and can be retrieved later. Some data is
stored in Blender, such as information about your working session and active
scene. Other data is stored in IFC, such as all the relationships in your BIM
model. We mention **Data** specifically because OpenBIM data authoring is such a
big aspect of the BlenderBIM Add-on. In fact, it's so big that most of it is
completely separated from the BlenderBIM Add-on code and lives elsewhere.
For example, all the code that handles IFC data, which you can think of as a
graph database, is in a completely separate codebase, even under a different
software license. You can find it in the IfcOpenShell-python API module. Many of
the various data processing functions are built as separate Unix-like utilities,
even with their own CLI. This **Data** layer isn't a single folder of code we
can point to, it's an ecosystem of libraries and utilities that we want to share
with the entire industry.
IfcOpenShell Architecture
-------------------------
A large part of the BlenderBIM Add-on is understanding how IFC data is modified.
This code is not technically part of the the BlenderBIM Add-on codebase, but it
is vital to understand. You will need to be familiar with the IfcOpenShell
Python module.
Manipulating IFC data is not simple. IFC may be serialised into multiple
formats, multiple schema versions must be supported, and geometry may be defined
in a highly parametric or implicit manner, which geometry kernels do not
natively support. All this heavy lifting is performed by the IfcOpenShell
library.
The IfcOpenShell library consists of a C++ based core. Its geometry processing
is done using OpenCascade, and optionally CGAL as an experimental option. By the
time the BlenderBIM Add-on interacts with IFC, it uses the IfcOpenShell Python
bindings, so all IFC data is already deserialised into Python objects. The inner
workings of the C++ base is out of scope.
.. image:: ifcopenshell-architecture.png
IfcOpenShell offers a core set of low-level functionality to read and write this
data. An example of the core functionality would be:
.. code-block:: python
import ifcopenshell
model = ifcopenshell.open("foo.ifc")
wall = model.create_entity("IfcWall")
wall.Name = "Foobar"
Core functions are simple read and write operations with no post processing.
Core functions also include geometry processing, which converts IFC geometry
into OpenCascade objects.
Sometimes, there are repetitive actions that need to be performed. These
functions are grouped into a ``util`` module. These include utility functions
for coordinate calculations, date conversions, filtering elements, unit
conversions, and more. Utility functions make no assumption about the context in
which they are used, and so perform highly specific tasks and nothing else.
Here's an example of utility functionality:
.. code-block:: python
import ifcopenshell
import ifcopenshell.util.date
import ifcopenshell.util.geolocation
start = ifcopenshell.util.date.ifc2datetime(task_time.ScheduleStart)
coordinates = ifcopenshell.util.geolocation.local2global(matrix, eastings, ...)
When authoring, core and utility functions are usually too low-level. To cater
for this, a high level API is provided. The API is divided into mostly isolated
modules, each module representing a distinct set of concepts in the IFC schema.
Unlike the util module, these API modules are highly context-sensitive, and
assume that you intend to be authoring native IFC.
This context-sensitive assumption means that the functions within the modules
are designed around typical usecases in an authoring environment. It performs
all the necessary manipulations to achieve a domain-specific usecase. Authoring
is complex and requires a deep knowledge of IFC to perform correctly and ensure
that the IFC graph state is well maintained. Typically, any authoring operation
that does not use the API is likely to contain mistakes.
Here's an example of it in action:
.. code-block:: python
import ifcopenshell.api
ifcopenshell.api.run("grid.create_grid_axis", model, ...)
ifcopenshell.api.run("structural.add_structural_load", model, ...)
Because the API performs all the IFC manipulations to achieve a usecase, no
further interaction is required in a typical native IFC authoring environment.
For this reason, the BlenderBIM Add-on only interacts with the API for its
authoring capabilities.
The code for IfcOpenShell's various systems can be found here:
- `ifcopenshell (core) <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/ifcopenshell-python/ifcopenshell>`__
- `ifcopenshell.util <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/ifcopenshell-python/ifcopenshell/util>`__
- `ifcopenshell.api <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/ifcopenshell-python/ifcopenshell/api>`__
Asking for help
---------------
It's no fun to code alone! It's encouraged to reach out if there are any issues,
if you'd like to code together with another developer, need a code review, or
need further testing. Here are some places to reach out:
- `Github issues <https://github.com/IfcOpenShell/IfcOpenShell/issues>`__
- `OSArch live chat <https://osarch.org/chat>`__
- `OSArch community forum <https://community.osarch.org>`__
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+212
View File
@@ -0,0 +1,212 @@
Installation
============
There are different methods of installation, depending on your situation.
1. **Unstable installation** is recommended for power users helping with testing.
2. **Building from source** is recommended for distributing a build from source.
3. **Live development environment** is recommended for developers who are actively coding.
4. **Distro installation** is recommended for those who use a Linux package manager.
Unstable installation
---------------------
**Unstable installation** is almost the same as **Stable installation**, except
that they are typically updated every day. Simply download a daily build from
the `Github releases page
<https://github.com/IfcOpenShell/IfcOpenShell/releases>`__, then follow the same
instructions as a packaged installation.
You will need to choose which build to download.
- If you are on Blender >=3.1, choose py310
- If you are on Blender >=2.93 and <3.1, choose py39
- If you are on Blender <2.93, choose py37
- Choose linux, macos, or win depending on your operating system
Sometimes, a build may be delayed, or contain broken code. We try to avoid this,
but it happens.
Building from source
--------------------
It is possible to run the latest bleeding edge version of BlenderBIM without
having to wait for an official release, since BlenderBIM is coded in Python and
doesn't require any compilation.
Note that the BlenderBIM Add-on does depend on IfcOpenShell, and IfcOpenShell
does require compilation. The following instructions will use a pre-built
IfcOpenShell (using an IfcOpenBot build) for convenience. Instructions on how to
compile IfcOpenShell is out of scope of this document.
You can create your own package by using the Makefile as shown below. You can
choose between a ``PLATFORM`` of ``linux``, ``macos``, and ``win``. You can
choose between a ``PYVERSION`` of ``py39``, ``py37``, or ``py310``.
::
$ cd src/blenderbim
$ make dist PLATFORM=linux PYVERSION=py310
$ ls dist/
This will give you a fully packaged Blender add-on zip that you can distribute
and install.
Live development environment
----------------------------
One option for developers who want to actively develop from source is to follow
the instructions from **Building from source**. However, creating a build,
uninstalling the old add-on, and installing a new build is a slow process.
Although it works, it is very slow, so we do not recommend it.
A more rapid approach is to follow the **Unstable installation** method, as this
provides all dependencies for you out of the box. Then, we can replace certain
Python files that tend to be updated frequently with those from the Git
repository. We're going to use symlinks (Windows users can use ``mklink``), so
we can code in our Git repository, and see the changes in our Blender
installation (you will need to restart Blender to see changes).
In addition, we're also going to replace the Python code of the IfcOpenShell
dependency with our Git repository, since most of the BlenderBIM Add-on
functionality is agnostic of Blender, and is actually part of IfcOpenShell.
Therefore, we need to keep this dependency highly updated as well.
The downside with this approach is that if a new dependency is added, or a
compiled dependency version requirement has changed, or the build system
changes, you'll need to fix your setup manually. But this is relatively rare.
::
$ git clone https://github.com/IfcOpenShell/IfcOpenShell.git
$ cd IfcOpenShell
# Remove the Blender add-on Python code
$ rm -r /path/to/blender/X.XX/scripts/addons/blenderbim/bim/
# Replace them with links to the Git repository
$ ln -s src/blenderbim/blenderbim/bim /path/to/blender/X.XX/scripts/addons/blenderbim/bim
# Remove the IfcOpenShell dependency Python code
$ rm -r /path/to/blender/X.XX/scripts/addons/blenderbim/libs/site/packages/ifcopenshell/api
$ rm -r /path/to/blender/X.XX/scripts/addons/blenderbim/libs/site/packages/ifcopenshell/util
# Replace them with links to the Git repository
$ ln -s src/ifcopenshell-python/ifcopenshell/api /path/to/blender/X.XX/scripts/addons/blenderbim/libs/site/packages/ifcopenshell/api
$ ln -s src/ifcopenshell-python/ifcopenshell/util /path/to/blender/X.XX/scripts/addons/blenderbim/libs/site/packages/ifcopenshell/util
On Windows:
::
$ git clone https://github.com/IfcOpenShell/IfcOpenShell.git
$ cd IfcOpenShell
# Remove the Blender add-on Python code
$ rd /S /Q "\path\to\blender\X.XX\scripts\addons\blenderbim\bim\"
# Replace them with links to the Git repository
$ mklink /D "\path\to\blender\X.XX\scripts\addons\blenderbim\bim" "src\blenderbim\blenderbim\bim"
# Remove the IfcOpenShell dependency Python code
$ rd \S \Q "\path\to\blender\X.XX\scripts\addons\blenderbim\libs\site\packages\ifcopenshell\api"
$ rd \S \Q "\path\to\blender\X.XX\scripts\addons\blenderbim\libs\site\packages\ifcopenshell\util"
# Replace them with links to the Git repository
$ mklink \D "\path\to\blender\X.XX\scripts\addons\blenderbim\libs\site\packages\ifcopenshell\api" "src\ifcopenshell-python\ifcopenshell\api"
$ mklink \D "\path\to\blender\X.XX\scripts\addons\blenderbim\libs\site\packages\ifcopenshell\util" "src\ifcopenshell-python\ifcopenshell\util"
After you modify your code in the Git repository, you will need to restart
Blender for the changes to take effect. In ``Edit > Preferences > Add-ons`` you
will see that the version number of the BlenderBIM Add-on has changed to
``0.0.999999``, which represents an un-versioned BlenderBIM Add-on.
There is a useful Blender Addon that adds a Reboot button in File menù.
In this way, it's possible to directly restart Blender and test the modified source code.
The add on is available `here <https://blenderartists.org/uploads/short-url/yto1sjw7pqDRVNQzpVLmn51PEDN.zip>`__
(check also the related forum discussion `here <https://blenderartists.org/t/reboot-blender-addon/640465/13>`__)
There is also a VS Code called `Blender Development <https://marketplace.visualstudio.com/items?itemName=JacquesLucke.blender-development>`__ that has a similar functionality.
Distro installation
-------------------
Those on Arch Linux can check out this `AUR package <https://aur.archlinux.org/packages/ifcopenshell-git/>`__.
Tips for package managers
-------------------------
If you are interested in packaging the BlenderBIM Add-on for a packaging
manager, read on.
The BlenderBIM Add-on is fully contained in the ``blenderbim/`` subfolder of the
Blender add-ons directory. This is typically distributed as a zipfile as per
Blender add-on conventions. Within this folder, you'll find the following file
structure:
::
bim/ (core code)
libs/ (dependencies)
__init__.py
This corresponds to the structure found in the source code `here
<https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/blenderbim/blenderbim>`__.
The BlenderBIM Add-on is complex, and requires many dependencies, including
Python modules, binaries, and static assets. When packaged for users, these
dependencies are bundled with the add-on for convenience.
If you choose to install the BlenderBIM Add-on and use your own system
dependencies, the source of truth for how dependencies are bundled are found in
the `Makefile
<https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/blenderbim/Makefile>`__.
Required Python modules to be stored in ``libs/site/packages/`` are:
::
ifcopenshell
bcf
ifcclash
bimtester
ifccobie
ifcdiff
ifccsv
ifcpatch
ifcp6
pystache
svgwrite
dateutil
isodate
networkx
deepdiff
jsonpickle
ordered_set
pyparsing
xmlschema
elementpath
six
lark-parser
hppfcl
behave
parse
parse_type
xlsxwriter
odfpy
defusedxml
boto3
botocore
jmespath
s3transfer
ifcjson
Notes:
1. ``ifcopenshell`` almost always requires the latest version due to the fast paced nature of the add-on development.
2. ``behave`` requires `patches <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.6.0/src/ifcbimtester/patch>`__.
3. ``ifcjson`` can be found `here <https://github.com/IFCJSON-Team/IFC2JSON_python/tree/master/file_converters>`__.
Required static assets are:
::
bim/data/gantt/jsgantt.js (from jsgantt-improved)
bim/data/gantt/jsgantt.css (from jsgantt-improved)
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@@ -0,0 +1,74 @@
.. _blenderbim/running_tests:
Running tests
=============
The BlenderBIM Add-on has three layers of tests for each of its three technology
layers. These roughly form a test pyramid, moving from many abstract domain
logic tests, to low-level concrete unit tests, to a minimal number of UI and
smoke tests. These tests use ``pytest`` as the test framework and runner.
All development is expected to use test driven development, and so we expect
test coverage to be 100% where it is technically possible to test.
When running tests, a Makefile target is provided for convenience so you can
type in a simple command without knowing the internals.
Because the BlenderBIM Add-on depends on IfcOpenShell, it is advised to also run
tests for IfcOpenShell and its Python bindings, which is not covered in this
document.
Core tests
----------
The core layer tests are pure Python unit tests with no dependencies on Blender
or other modules. They are designed to be fast and easy to run as they test
purely abstract domain logic.
Although they are vanilla Python tests, they do not use the Python Mock module.
Instead, a lightweight ``Prophecy`` mocker class is used, which allows tests to
be written in a highly concise, expressive manner. For those coming from a
BDD background in Ruby's RSpec, PHP's PHPSpec, and PHP's Prophecy, this is very
similar.
.. code-block:: bash
$ cd src/blenderbim/
$ make test-core
Tool tests
----------
The tool layer tests actual concrete functions. These have the following
dependencies:
* pytest-blender, accessible to your system's Python
* Blender executable, accessible to pytest-blender on your system's Python
(e.g. through the ``blender`` command in your path)
* pytest, accessible to your Blender Python
* pytest-bdd, accessible to your Blender Python
You can install the dependencies by running the ``scripts/setup_pytest.py``
script in Blender.
Then, run the tests. This will launch Blender headlessly and check the behaviour
of all concrete functions.
.. code-block:: bash
$ cd src/blenderbim/
$ make test-tool
BlenderBIM Add-on tests
-----------------------
The BIM layer acts as a full integration test. It is not possible to fully test
the UI, as we cannot reliable emit interface signals, nor read the interface as
a DOM of sorts. The best we can do is to call Blender operators as a smoke test,
and also check simple property and scene changes. It has the same dependencies
as the tool tests.
.. code-block:: bash
$ cd src/blenderbim/
$ make test-bim
+117
View File
@@ -0,0 +1,117 @@
Undo system
===========
Supporting undo and redo is quite a complex problem because the Blender undo
system only keeps track of changes occuring in the Blender system. However,
changes actually occur in two other locations that Blender doesn't know about:
the IFC dataset, and the BlenderBIM Add-on system that synchronises Blender and
the IFC dataset.
Let's see how undo works in a basic Blender add-on without IFC or the BlenderBIM
Add-on getting involved.
.. code-block:: python
:emphasize-lines: 4
class Foobar(bpy.types.Operator):
bl_idname = "foobar"
bl_label = "Foobar"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.name = "Foobar"
return {"FINISHED"}
This operation changes Blender data. The important line is ``bl_options =
{"REGISTER", "UNDO"}``, which tells Blender to keep track of it as a single
transaction in its undo history. When you press undo or redo, Blender figures
out all the changes automatically and you don't need to do anything.
If you have an operator that only manipulates (creates, removes, or edits)
Blender data, this solution is sufficient.
Now let's look at pure IfcOpenShell.
.. code-block:: python
:emphasize-lines: 3,5
import ifcopenshell
model = ifcopenshell.open("foo.ifc")
model.begin_transaction()
model.create_entity("IfcWall")
model.end_transaction()
model.undo()
model.redo()
Pure IfcOpenShell let's you start and stop recording transactions whenever you
want. Since IfcOpenShell has no interface, you manually run code like
``model.undo()`` and ``model.redo()`` to undo and redo.
This scenario where there is pure IfcOpenShell never occurs with the BlenderBIM
Add-on. Instead, stuff happens in Blender operators.
.. code-block:: python
:emphasize-lines: 6,7
class Foobar(bpy.types.Operator):
bl_idname = "foobar"
bl_label = "Foobar"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
ifcopenshell.api.run("foo.bar", IfcStore.get_file())
return {"FINISHED"}
When your operator manipulates (creates, removes, or edits) IFC data directly or
indirectly (i.e. through calling another operator), your operator must be
wrapped in an ``IfcStore.execute_ifc_operator`` call. This wrapper will:
1. Begin a BlenderBIM Add-on transaction
2. Begin an IfcOpenShell transaction
3. Runs your operator's ``_execute``.
4. Ends the IfcOpenShell transaction
5. Ends the BlenderBIM Add-on transaction
The IfcOpenShell transaction keeps track of IFC data changes, and the BlenderBIM
Add-on transaction keeps track of all other custom data changes, like changes in
the ``id_map`` and ``guid_map``. For the vast majority of operations, this
wrapper provides everything that you need.
If, however, your operator manipulates data that is not tracked by Blender, is
not tracked in the IFC data, and is not tracked in the element map, then you
will have to write your own rollback (undo) and commit (redo) code for your
operator. Here is an example.
.. code-block:: python
class Foobar(bpy.types.Operator):
bl_idname = "foobar"
bl_label = "Foobar"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
IfcStore.begin_transaction(operator)
old_value = Foo.bar
result = self._execute(context)
new_value = Foo.bar
self.transaction_data = {"old_value": old_value, "new_value": new_value}
IfcStore.add_transaction_operation(self)
IfcStore.end_transaction(operator)
return result
def _execute(self, context):
Foo.bar = "baz"
return {"FINISHED"}
def rollback(self, data):
Foo.baz = data["old_value"]
def commit(self, data):
Foo.baz = data["new_value"]
Note that there is still a distinction between ``execute`` and ``_execute``.
This recommended convention allows you to quickly discern undo state tracking
code from regular operation code.
+178
View File
@@ -0,0 +1,178 @@
User Experience and User Interface guidelines
=============================================
This is intended as a reference document for developers working on the BlenderBim addon.
Operators
^^^^^^^^^
BIM will by definition contain a (big) number of submodules or subschemas. Granting access to the features of these submodules to the users needs to be considered with several things in minds :
1. Ease of use : How do I achieve my goal with the minimal number of clicks ? How many different menu items do I have to go through to get to my goal ? How long do I have to scroll a menu to get to the specific thing I have in mind ?
2. Clarity : How long do I have to visually parse the interface to find the item or button I'm looking for ? Are the buttons correctly labeled and are the icons descriptive enough ? If something is forbidden, can I easily know why ? Can I know what a button does before clicking on it ?
3. Completeness : I need to have access to all the items that are related to the topic I'm interested in. If it is tied to another submodule, I need to have access to it.
* **Blender**
These considerations must be adapted to the Python API, to the general paradigm we have chosen to access, modify or create IFC data, and to the general philosophy of Blender. There are many ways and places where an add-on creator can choose to present information to the user. BlenderBim currently works that way :
- Information about the current context is displayed inside the properties editor. We leverage the fact that it is already built around displaying different types of information whether we are in the Scene, Material, Mesh, Object, Curve, Texture, etc. subpanels. It fits really well with the way things are already organized in the IFC classification.
- Tools to create, modify or delete items are in the dedicated Toolbar (The left one) in the 3D viewport
- Some Misc tools and informations are displayed in the N panel of the 3D viewport . They're shortcuts to things that are already present elsewhere in the UI, but are handy to have when modifying objects or geometry in the Viewport.
- Adding specific Import / Export IFC operators (arguably a bit misleading since BlenderBim does more than import / export in these operations)
* **Interface panels**
- The good : Every submodule is visually separated from each other. The user can customize its interface to only show what's relevant to them at any one point by folding in or out panels. Development / Debugging is facilitated because each submodule's interface is separated from the others.
- The bad : Having many interface panels clutters the interface, leading to an overwhelming experience for newcomers especially.
- Proposal : The addon should in the long run provide the user with dynamic UI depending on what's their usecase. Preferably accessed in the Addon Preferences interface, with pre-made options that dynamically enable or disable specific parts of the UI. It should also provide the option to selectively add or remove specific parts of the UI on top of that. Additionally, when it does not make sense to display a specific panel, it should be hidden from the UI. (eg if an object has no IFC Class, it can't be spatially contained, so the IFC Spatial Container panel should be hidden until the user sets the IFC class)
In the long term it could also be interesting to think about some kind of tutorial mode where more information is conveyed through the interface for new users.
* **Item Lists**
An item list should provide right off the bat a few features :
- Add a new item.
- Modify an item, whether by adding a button to each item in the list, or adding a button on the list header to modify the selected item.
- Delete an item, whether by adding a button to each item in the list, or adding a button on the list header to delete the selected item.
- Modify an item's name by double-clicking on the field if applicable
- The currently selected item should be highlighted
- There should be a search field to filter through specific items in the list, with buttons to invert selection, sort alphabetically and revert display. (Features that are provided by the `UIList` class)
* **Operators**
- Some buttons should be dynamically disabled (grayed out and impossible to click on) when the context to execute them does not make sense. It is important to note there should not be any heavy computation to determine this since this is executed several times per second for each button where it is implemented. It should only test for simple things and not rely on retrieving information from other modules too much. eg : `Is an item selected ?` `Is the z position of the selected object > 0 ?` or `Is the selected object an IfcOpeningElement ?` and **not** `Is there an IfcOpeningElement in the current file ?` or `How many different classes of IfcBeam are implemented in the file ?`
In Blender this is done in two ways :
- Directly in the operator `poll` method which is executed when the button is displayed in the interface. The drawback is that some operators rely on custom attributes which are provided only when the user clicks on the button, and cannot be test in the `poll` method. Note in V3.0 we can implement custom messages when the `poll` method fails, depending on the step where the context was not right.
- In the UI drawing code, where specific layout parts can be disabled.
- Some buttons or entire interface layout rows or columns may be disabled or hidden at once. It may be desirable when it relies on specific things or combinations of things not being met in the project. In order to avoid UI flicker or the user wondering where the button went, dynamically hiding UI elements should have a minimal interference with the rest of the UI by :
(1) Hiding the last row(s) of a panel
(2) Dynamically resizing the rest of the UI when it's not possible to (1)
The user should be advised why they are prevented to do things via either :
- A custom message using Blender's report system
- A label in the UI replacing the missing UI elements
- An helpful tooltip on an operator
Generally the context itself should be used to the best of its ability to convey why it's possible to do some things or not. The separation of concerns in multiple different dynamically hidden-or-shown sub-panels should help limit confusion.
- The user should be forbidden to click on buttons when its execution returns early and does nothing. If a button is clickable and the user clicks on it, there should always be some kind of feedback.
Icons
^^^^^
* .. image:: https://user-images.githubusercontent.com/25156105/137270452-bf6c03ea-2d3e-4ae3-8121-6799e8beb335.png
**Icon name** : `"CANCEL"`
**Use** : To disable the edition state of a particular item.
**Expected result** : A part of the interface showing the item attributes is either shrinked down or hidden. The button is usually replaced by a button to delete this item.
* .. image:: https://user-images.githubusercontent.com/25156105/137271575-dcae9e56-3c64-4d8b-89b0-6cf103b999f2.png
**Icon name** : `"X"`
**Use** : To delete a particular item, for instance an element of a list.
**Expected result** : The interface element referencing the deleted item is hidden from the interface. If the item was in a list, and the deleted element was selected, the next element becomes selected, or if there is no next element, no element is selected.
* .. image:: https://user-images.githubusercontent.com/25156105/137271601-e79012e5-fc61-402e-830c-b34b4ca757a0.png
**Icon name** : `"GREASEPENCIL"`
**Use** : To Enable the edition of a particular item.
**Behaviour** : Usually only one element of a particular context can be edited at a time.
**Expected result** : The interface should either expand or spawn new elements to display the chosen item's editable attributes. If the editem item is part of a list and its interface elements contained an operator to delete it, it is swapped for an operator to disable the edition of that item.
**Proposal** : Currently all the edition buttons are hidden from the interface when editing a particular item. This results on buttons jumping to the right slightly. My proposal is to instead show but disable the other buttons to prevent interface flicker.
**Current** : https://user-images.githubusercontent.com/25156105/137273603-f9ac39e5-7616-4fb9-89e2-4dae453e650a.gif
**Proposal** : https://user-images.githubusercontent.com/25156105/137273329-532d6d59-e39d-483e-980b-b8405062eaa8.gif
* .. image:: https://user-images.githubusercontent.com/25156105/137273981-26fa664a-a29e-402e-9d7e-67b8b71c2d5d.png
**Icon name** : `"ADD"`
**Use** : To add an item to a particular context, either initializing it (eg. adding a coordinate system) or adding an element to a list.
**Expected result** : The interface should either expand to display the new item or a new line should be shown if the item is added in a list.
**Proposal** : In some instances adding an element in a list automatically enables the edition of this item's attributes. (eg IFC Groups) but in other instances it does not (eg IFC strucural load cases). It is arguable but I do not think the user should expect a new item to be in editable state right off the bat when they add it to a list.
* .. image:: https://user-images.githubusercontent.com/25156105/137274869-0d0b876a-545c-4a58-a386-90f85764b7cc.png
**Icon name** : `"RESTRICT_SELECT_OFF"`
**Use** : To select all the instances related to a particular item.
**Expected result** : All the objects relating to a particular item should be selected in the 3D viewport and/or in the outline.
**Proposal** : Whether or not previously selected objects should be deselected beforehand is up for debate I think, because both behaviours can be desirable. It also raises the question of which object should be set to active. (Random ? First one ? Biggest one ?...)
* .. image:: https://user-images.githubusercontent.com/25156105/137275582-98c1dfcc-fc96-41d6-80dd-fdb82796e66e.png
**Icon name** : `"IMPORT"`
**Use** : to import a particular file from the user's computer's directory to the current context
**Expected result** : A new file browser window should open, with sufficient information provided to the user to know which file type should be loaded in (eg adding a file extension, adding information in the filebrowser UI). When the file is loaded, the interface should expand to show the attributes or informations or new context-sensitive operations provided by the imported file.
**Proposal** : Currently there are some instances where I don't know if the elements are supposed to require an external file, eg
.. image:: https://user-images.githubusercontent.com/25156105/137275887-e0f0b694-842b-422f-bc09-cdcefef64107.png
* .. image:: https://user-images.githubusercontent.com/25156105/137276333-4d083f6a-36b9-494f-b0de-ec1d321cbd3d.png
**Icon name** : `"EXPORT"`
**Use** : To export a particular file to the user's computer's directory
**Expected result** : A new file browser window should open, with sufficient information provided to the user to know which file type is going to be saved (eg adding a file extension, adding information in the filebrowser UI).
**Proposal** : When there is no actual file to be saved in the user's directory or the filepath is already set in another place in the UI :
.. image:: https://user-images.githubusercontent.com/25156105/137276840-3ceda0cd-87bd-45f5-8488-bfce86bf3d84.png
It may be better to use a save icon of some sort instead, eg
.. image:: https://user-images.githubusercontent.com/25156105/137276758-5d60f0ca-5a93-4af3-9c4f-30c5794e0657.png
* .. image:: https://user-images.githubusercontent.com/25156105/137277047-bd45df5b-3b47-4b2c-aa29-a340b0710345.png
**Icon name** : `"FILEBROWSER"`
**Use** : To Provide the current context with the path to a particular file or folder
**Expected result** : A new file browser window should open, with sufficient information provided to the user to know which file type is required (eg adding a file extension, adding information in the filebrowser UI). Upon file or folder selection, this should populate a field in the current interface context with the path to the selected file or folder, or at least let the user know that the required information is now correctly filled in.
* .. image:: https://user-images.githubusercontent.com/25156105/137277374-fa7ff310-0b41-49a9-98bd-7c4686da05fd.png
**Icon name** : `"EYEDROPPER"`
**Use** : To select a particular object in the interface to fill the field it is attached to
**Expected result** : The cursor should change to an eyedropper until the user clicks on the required item. The user should be made aware after selection if it was successful (associated field being filled) or unsuccessful (message ? or field staying empty)