Note
3D floorplan graphics, and what can actually bind to them
A 3D floorplan is bought, not drawn in Workbench. The Niagara-side decisions are which file you ask for, whether anything on it can be bound, and what the controller pays to serve it.
- PX graphics
- JACE
- Workbench
Nobody draws the floorplan in Niagara
The long-running contractor threads on this are unanimous about the tooling and they never mention Niagara once. The work is done in Maya with V-Ray on GPU render cards, or in Blender, SketchUp, SweetHome3D, or traced into AutoCAD from a PDF when no CAD file exists. Turnaround from a specialist outfit runs to a couple of weeks, and the recurring conclusion is that doing it in house only pays if somebody is dedicated to it and the software subscriptions are already bought.
So the question that actually lands on the integrator is never "how do I model a building". It is three much smaller ones: what file do I ask the artist for, what on it can carry a live value, and what does the controller pay to serve it. Those have definite answers in the framework, and they are the reason the pretty version often cannot do the job it was bought for.
The format decides more than the look
Niagara's own type system draws a hard line between raster and vector.
BImage is documented as "a representation of a raster image", and
its byte-buffer factory says the buffer "should contain an image file in GIF,
PNG, or JPEG format". SVG is not a case of that: it is its own file type,
BSvgFile, serving the MIME type image/svg+xml.
What Workbench will actually open is narrower than what types exist. The image
viewer ships in the raster module and is registered as an agent on
exactly four file types — PNG, GIF, JPEG and SVG. WebP, BMP, APNG and ICO all
have first-class file types in the same package, and nothing is registered to
view them. A file the artist exported as WebP is a legitimate Niagara file with
no viewer.
"This image can not be displayed due to an invalid image format."
That exact sentence is a lexicon string in the raster module, and it is the
message behind most broken-graphic reports. The viewer is chosen by file
extension and then fails on the content, so it appears when a WebP or a TIFF has
been renamed to .png, or when a browser "Save image as" produced
something other than what the name claims. Check the bytes, not the name.
Which makes the artwork spec one line: PNG or JPEG for a photoreal render, SVG for anything line-based, nothing else, and a copy of the source project file for when a wall moves.
Tridium ships the same symbol set twice
There is no need to argue vector versus raster in the abstract, because both versions of the standard HVAC symbol library are in the install and can be measured against each other.
| Measure | Raster kit | SVG kit |
|---|---|---|
| Image files | 986 PNG + 87 GIF | 973 SVG |
| Jar on flash | 11.5 MB | 3.8 MB |
| Image bytes, stored | 11.17 MB | 3.47 MB |
| Image bytes, uncompressed | 11.25 MB | 10.9 MB |
The last two rows are the interesting pair. Uncompressed, the two libraries are the same size — the vector version is not inherently less data. It is text, so it compresses inside the jar by about 3:1 while the PNGs compress by almost nothing. On a controller what lands on flash is the jar, so the same symbol set costs a third as much for being vector, and scales cleanly to whatever pixel density the operator's screen has.
The libraries are close to a one-for-one swap: 681 of the SVG kit's 772 distinct
base names also exist in the raster kit, and the raster-only remainder is mostly
manufacturer-branded plant — specific actuator and boiler brands. Animation
survives the move too, differently: every one of the raster kit's 87 GIFs is an
_On state, multi-frame, while 48 of the SVG files carry their
animation inside the file as SMIL.
The exception is the 3D render itself. A photoreal image is photograph-shaped data, and tracing it into vector makes it bigger and worse. Render stays raster; everything drawn with lines should not be.
An image is not a bindable surface
This is the point the format argument is usually standing in front of. Look at
how Tridium's own SVG kit makes a boiler change state in its palette: the widget
is a ui:Picture, and the binding is on its image
property, through a boolean-to-simple converter holding two ORDs —
Boiler_Right_On.svg and Boiler_Right_Off.svg. Nothing
inside the SVG is being driven. A different file is being chosen.
That is the ceiling for artwork of any kind, 3D included. A bound image can be swapped, moved, rotated, shown or hidden. It cannot have one room in it change colour, because the framework has no handle on anything inside it.
What is bindable is geometry. The stock bajaui palette has
a Shape folder, and its ui:Polygon entry ships with three
properties that matter here: fill, stroke and
geom — a plain list of coordinate pairs, defaulted to a unit
square. Path, Rect, Ellipse and Line sit beside it. A zone outline is a list of
coordinate pairs, which is also exactly what a polyline in the CAD file already
is.
And the colour rule is stock as well. The SpectrumBinding in the
kitPx module is an agent on any bajaui:Widget; its
widgetProperty defaults to fill, and it maps a numeric
into a low / mid / high colour range — blue, white, red out of the box — with a
setpoint of 50 and an extent of 100. Values below setpoint minus half the extent
clamp to the low colour, above setpoint plus half the extent to the high colour,
and everything between is interpolated channel by channel.
A zone heat map is stock, not development. One polygon per zone
over the floor plan, fill bound with a spectrum binding, setpoint
and extent set to the comfort band. No module, no JavaScript, no purchase. The
only input it needs is the zone outlines as coordinates — which the CAD drawing
has and the render does not.
What 200 zone temperatures actually cost
Every value on the sheet is one Binding, resolved asynchronously
against a binder found by walking up the widget's parent tree. Two hundred
values is two hundred bindings whether the sheet is beautiful or hideous, so the
artwork is not where the cost is. In the Hx path the widget is handed a tree that
is already mounted in a component space with its bindings active and leased; the
subscription is live before anything is drawn.
Against that, a background image is nearly free. The web service's cache config
caches png,jpg,gif,svg by default specifically so those stop
revalidating on every request — the render is fetched once per operator and then
stops being a cost at all.
The cost that does scale badly is file count. A JavaScript file registered without a build id "will always be downloaded unminified", so a widget-heavy view can make the controller answer twenty-odd requests to draw one page, for every operator who opens it. That is the number to watch, not the size of the background.
Then there is the constraint no renderer solves: 200 values that have to be read are 200 pieces of legible text. The working rule the experienced graphics people use is one sheet per wing, or a dozen like rooms, sized by whatever keeps the font readable. A whole-building view that fits 200 labels is a view where none of them can be read, in 2D or 3D.
Where the thing runs, and why the profile matters
Niagara's runtime profiles say plainly what each environment is: rt
and ux are "Java 8 compact3", wb and se
are "Java 8 SE". The distribution file for the controller platform in this
install names its VM azul-zre-qnx71-compact3-arm32hf beside the QNX
7.1 ARMv7 core — so compact3 on the controller is in the shipped file, not an
inference.
That has one sharp consequence for images: BImage documents an
IllegalStateException when its buffer and pixel methods are called
from a compact3 VM, and again for the SVG path. Server-side image manipulation is
a Workbench and Supervisor activity. It does not stop a controller serving
graphics, because the controller never draws them — the operator's browser does,
and the controller only serves files and answers subscriptions.
The exception is Workbench itself. The image viewer module is built for the
wb profile: when you look at a graphic inside Workbench you are
looking at Workbench's own renderer and its embedded browser engine, which lags
the browser on the same desk. A ux widget drawing its own canvas or SVG can
therefore look right in Chrome and wrong in the PX editor, which is the usual
explanation for a graphic that "works for me".
Is a heavy 3D scene on a controller-served graphic a real constraint? Honestly: mostly no, and people worry about the wrong half. A static render is one cached file and costs the controller nothing after the first request. A live WebGL or canvas scene spends the operator's GPU, not the controller's CPU. What is genuinely a controller constraint is bytes and requests: a multi-megabyte texture set fetched by six concurrent operators, and a view that pulls twenty unbundled scripts. Size the artwork and count the files; do not reject 3D on the grounds that the controller has to render it, because it does not.
One sheet, twelve floors
The reuse instinct is right and it has a limit worth naming. Relative binding is what makes one plant sheet serve forty identically shaped air handlers, and it is covered properly in the note on one PX sheet for every AHU. It does not make one floor sheet serve twelve floors, because relativising fixes the ORDs, and what differs between floors is the geometry. Twelve floors with identical point structures still have twelve different outlines.
What is reusable across floors is everything except the outline. A
PxInclude embeds one PX file inside another and takes variables for
ORD substitution, so the zone-detail popup, the legend, the colour rule and the
header are made once and included on every floor with a different ORD passed in.
Per floor you own a background and a set of zone polygons. Everything else is
one file.
The coordinate system is worth setting up deliberately at the same time. A
CanvasPane has a viewSize — a logical drawing space,
100 by 100 by default — and a scale property that defaults to
none, with fit, fit-to-ratio and zoom modes available. Draw the plan
in the plan's own units and let the pane scale it, rather than drawing the same
floor three times for three screen sizes.
Is 3D the right answer?
For a view whose job is to show 200 zone temperatures: no. Three reasons, none of them aesthetic.
- An isometric view occludes. Rooms are hidden behind other rooms, and interior zones on a lower floor of a rendered block cannot be shown at all. A view that structurally cannot display part of its data set is the wrong view for that data set.
- It has one camera, so it has one scale. Zones far from the camera are smaller, and their labels are the ones that become unreadable first. Plan view gives every room the same treatment.
- The geometry is not addressable. The live layer has to be drawn on top as shapes anyway, and those shapes only line up from that one viewpoint. Move a wall and you are back with the artist rather than editing a coordinate list — which is precisely the maintenance worry raised in those threads, and it is well founded.
What 3D is genuinely good at is being looked at once by the person signing for the job. That is a real requirement, not vanity: the one who pays is impressed by the render in the presentation and then expects the delivered system to look like the demo. So buy the render, once, and spend it where it earns — the site landing view, the proposal, the handover pack.
The working views underneath it are plan-view and bound: a floor outline taken
from the CAD file, one polygon per zone, fill on a spectrum binding,
labels only where a number must actually be read, and detail behind a click.
That version is editable by your own engineers, survives a wall moving, and is
cheaper to build than the thing it replaces. The honest cost of insisting on 3D
everywhere is that every zone becomes artwork, and every layout change becomes a
purchase order.
The graphics question that arrives as "who makes 3D floorplans" is usually a standard-sheet question wearing a costume. Plant views built once and pointed at every unit are PX graphics and standard sheets; a view that has to be responsive, branded, or do something no stock widget does is a bajaux widget. The two notes behind this one cover relative ORDs, which decide how many sheets you maintain, and what actually runs on a JACE, which decides what the controller can afford to serve.
Related
Where this comes up in the work
PX graphics
Niagara PX graphics as a reusable template set: standard HVAC plant sheets, relative-ORD binding, navigation hierarchy and a written graphics standard.
bajaux widgets
Custom Niagara web widgets in bajaux and BajaScript: HTML5 BMS dashboards, HVAC plant views, navigation and charts, bound to live station ORDs and BQL.
More notes
Other things worth writing down
Pure Java, or it will not run on a JACE
A controller is an ARM host with a fraction of a server's memory. Native libraries, JNI and heavyweight dependencies do not survive the move from a PC.
- JACE
- Controllers
- Module development
One PX sheet for every AHU
The Px editor binds absolutely by default, which is why a graphic works for AHU-01 and nothing else. Relativised, one sheet serves the whole plant.
- PX graphics
- Standard sheets
- Reuse
JACE-8000 to JACE-9000: what the licence transfer does and does not do
The JACE 8000 to 9000 licence transfer, step by step: what it requires, what it does not include, and which parts cannot be undone.
- JACE
- Migration
- Licensing
Next step
Tell us the version, the hardware, and what it has to do.
You will get a written scope and a fixed price against it. If the honest answer is that you do not need us, you will get that instead.