~/satyajit

KOLC+ puts Gaussian splats inside BIM/CIM: how each feature has to work, and how I would build one

mdjsonmcp

2026-10-06 · 38 min · 3d · gaussian-splatting · point-cloud · lidar · slam

Why read this

Notabletop 60%

Works out what splat volumes, sections and alignment must compute inside a closed BIM tool, then lays out an open, licence-checked pipeline to build one.

  • A guide you can follow today
  • Original analysis
  • A lasting reference

3D & spatialAPI onlyProprietaryPractitioner guide

How this was scored
Is it new?
1 of 3: An incremental tweak
Can I trust it?
2 of 3: Measures key facts from files, code or configs
Can I run it?
1 of 3: API-only, gated or restrictive licence
Will I understand it?
2 of 3: Mechanism from first principles with figures
Can I act on it?
3 of 3: A decision guide a practitioner can follow today
Will it last?
2 of 3: A reference for a year or more
Does it affect many?
1 of 3: A specialist community
Only here?
2 of 3: A teardown or measurement few others did

Score 63 of 100, ranked 183 of 445 rated articles. Each question is answered 0–3 by hand, and a 3 is rare. How articles are scored

On 6 October 2026 KOLG Inc. (株式会社コルク, Tokyo) announced that the "integrated app" of its BIM/CIM cloud, KOLC+, now takes 3D Gaussian Splatting scenes into the same space as BIM/CIM models, point clouds, terrain and 2D drawings, and that its earthwork, section, placement, annotation and 4D tools work on them (press release, in Japanese). The motivation it gives is concrete: sites have been buying XGRIDS scanners, and someone has to do something with the .lcc files they produce.

A splat next to a Revit model is a nice picture. A splat that a quantity surveyor signs an earthwork volume off is a different object, and the release does not say which one KOLC+ is. It is closed, and no accuracy figure is published anywhere I could find. So this piece reads what KOLG shows (the release, its screenshots, three product pages), works out what each feature has to compute when the input is anisotropic Gaussians rather than a surface, and then builds the same thing from open parts on the stack I would use: a 360 camera, Spirula Studio, gsplat, Revit.

Labels, as everywhere on this site: reported is KOLG's or a project's own claim; measured is something I read off a file, a screenshot or a spec; reasoned is my arithmetic on the other two.

Promotional card: on the left a Gaussian-splat scene of a plaza with an elevated walkway, trees and a yellow excavator model, overlaid by a white BIM building model; on the right, on black, the text KOLC+, 3DGS in large yellow letters, and BIM統合/土量計算 (BIM integration / earthwork volumes).
The announcement card: a Gaussian-splat scan with a BIM building and an excavator model placed in it. The Japanese reads 'BIM integration / earthwork volume calculation' (KOLG Inc. press release, 6 October 2026, image 1).

What was announced

The feature list in the release, translated, with what each item has to compute once the input is a splat. Everything in the first two columns is reported.

KOLC+ feature (release)What it showsWhat it has to compute on splats
Integration with BIM/CIM, point clouds, terrain, 2D drawings, measurement data, GNSSRevit model over an XGRIDS splata common coordinate frame and a shared depth buffer
Alignment, 3-point matchingmove/rotate gizmo; public-coordinate data placed automaticallya similarity transform from three correspondences
Earthwork volume (BIM vs splat, or two epochs of splats)"surface determination from 3DGS alone"a height field from something that is not a surface
Sections: auto-trace, manual trace, DXF outstair profile traced as a polylinethe intersection of a plane with millions of Gaussians
Section box (6 faces), slicesBIM-vs-splat clash checkclipping splats by planes in the renderer
Measurement: coordinates, distance, angle, areacoordinates in metres to three decimalsa 3D point under the cursor
Spatial notes, markuplabels pinned in the scenethe same picking
Placement planning: scaffolding, hoarding, sandbags, conesexcavator and fence placed on the plazaground height under a dragged object
4D timeline, walkthrough, saved viewsnone showntime-indexed visibility; camera paths
"Point-cloud mode" toggle for 3DGSsplat centres as coloured pointsthe Gaussians' means, drawn as points

Formats and money, also reported: the integrated app reads LCC (.lcc) only, exported by XGRIDS' free LCC Studio; "LCC2, PLY, SPZ and others" are "under consideration". That is narrower than KOLC+'s separate 3DGS viewer, whose product page lists PLY (compressed and uncompressed), SPZ, SPLAT, KSPLAT and SOG with LoD streaming, says PLY is converted to "1/8" of its size for delivery, and until this release said the integrated app could only show a splat in a split screen beside the model (3DGS viewer page). The price is ¥50,000 a month before tax for 100 GB, 100 users and the integrated app on two sites, with no setup fee. The pricing page shows where that comes from: the ¥30,000 3D plan plus the integrated-app add-on at ¥10,000 per site, minimum two (reasoned: 30,000 + 2 x 10,000 = 50,000). KOLC+ is also registered as an information-sharing system (ASP) for MLIT work and reports 500+ companies using it. KOLG shows it at Construction Technology Expo 2026 Kanto, 20-21 October, Sunshine City in Ikebukuro, booth B-61.

A street-level view inside a Gaussian-splat scan of a plaza: a concrete elevated walkway on columns at left, dense trees at right, and a flat-shaded white Revit model of a multi-storey office building standing in the middle of the scene, with a yellow excavator model in front of it.
A Revit model integrated into a Gaussian splat scanned and generated with XGRIDS. Splat courtesy of Kobe Seiko; Revit model from the Revit User Group (KOLG Inc. press release, image 2).
An oblique view of a six-faced section box cutting both a splat and a BIM model: the splat's plaza, trees, staircase and walkway are clipped to the box, and the BIM building's floors are exposed where the box cuts through it.
A six-face section box used to check where the BIM model and the splat interfere; IFC, Navisworks and SketchUp models can be integrated the same way (KOLG Inc. press release, image 3).

A splat is not a surface

Everything hard in that table comes from one fact. Each Gaussian is a mean μi\mu_i, a covariance Σi=RiSi2Ri⊤\Sigma_i = R_i S_i^2 R_i^\top, an opacity αi\alpha_i and a colour, and the optimiser was paid to make images match, not to put mass on surfaces. Most mass ends up near surfaces anyway. Some does not: floaters in front of glass, haze in the sky, flat Gaussians painting a road's texture a few centimetres off the asphalt, a shell around foliage. So every geometric query must answer "where is the surface along this ray?", three ways:

KOLG's release says its measurement and annotation tools use "an in-house hit-detection logic" that makes raycasting fast and coordinate detection precise, and that the point-cloud mode lets you "check the state of the hit detection". The viewer page adds that its distance tool judges "the contact point between the Gaussian-distribution mesh and the mouse cursor" (reported, my translation). That reads like the first option: a proxy mesh of ellipsoids at a fixed sigma, ray-cast on the CPU or with a BVH. It is the fast answer. I cannot see the opacity floor or the sigma, so I cannot say how it treats floaters.

The same plaza and staircase shown as a sparse field of coloured points on a dark background, with red measurement lines labelled 6.765 m, 3.921 m and 6.55 m, numbered markers A1 to A5, and a coordinate readout: X -8349.312, Y 60322.814, Z 10.819, units metres.
Point-cloud mode: the splat drawn as its Gaussians' centres, used to check what the hit detection is hitting. Note the coordinate readout in metres, X -8349.312, Y 60322.814, Z 10.819 (KOLG Inc. press release, image 9).

The point-cloud mode is honest about the representation: sparse on flat ground, dense on edges and texture, because a splat's centre density follows image gradients where LiDAR's follows range and incidence. The centres are not samples of the surface; they are the centres of blobs whose extent you are throwing away.

What splat geometry is worth, measured by other people

No one has published accuracy for KOLC+. Several groups have published it for splats against survey references, and the pattern is consistent (all reported, each paper's own tables):

StudyCaptureReferenceResult
McNally et al., ISPRS Annals 2026phone on a gimbal, two building exteriorstotal station + TLStargets picked in the splat: 0.8-1.9 cm RMSE; Gaussian centres as a cloud: 3.6-13.6 cm mean distance, decimetres RMS from floaters
Clini et al., ISPRS Archives 2024Insta360 X4, church interiorLeica RTC360splat mean error 6 mm, but standard deviation 25.8 cm
Suwardhi et al., ISPRS Archives 2026GoPro MAX 360 video, heritage buildingLeica BLK360control residual 12.5 cm RMS; cloud-to-cloud mean 15.2 cm
Haitz et al., ISPRS Annals 2024nadir aerial, about 2 cm pixelsairborne LiDARsplat centres 0.28-0.40 m RMSE; COLMAP MVS 0.07-0.09 m
LI-GStwo Hesai XT32 + an Insta360the rig's own LiDARLiDAR-constrained surfels 4.51 cm; image-only 2DGS, GOF, PGSR 14.8-16.6 cm

Read it as three statements. A splat built on a well-controlled SfM solve keeps the solve's geometry: McNally's targets moved less than 8 mm between the SfM input and the splat. Reading the Gaussians as a point cloud is several times worse than that, mostly because of floaters. And a 360 camera alone sits at decimetres, while LiDAR constraints bring a splat to about 5 cm, measured against the same LiDAR. I found no peer-reviewed study that validates an earthwork or stockpile volume computed from splats.

A splat view of a wide outdoor staircase with markup: a hand-drawn red circle and arrow on the handrail, numbered pins A1 to A5, measurement lines of 6.765 m up a column, 3.921 m and 6.55 m along the base of the stairs, and a coordinate box reading X -8349.312, Y 60322.814, Z 10.819.
Spatial notes, markup and measurements drawn directly on the splat and saved as a shared view (KOLG Inc. press release, image 8).

Earthwork volumes from two epochs

What KOLC+ computes

KOLC+'s earthwork page is specific (reported, translated): volumes are computed by the point-height method (one-point method) in MLIT's civil-works quantity rules (土木工事数量算出要領), which "computes the elevation difference at the mesh intersections"; the rules call for a mesh of "50 cm or less", KOLC+ lets you set any size; and a "median" mode reduces point-cloud noise. The reference and comparison surfaces can be a TIN drawn in the viewer, BIM/CIM, LandXML, FBX/OBJ, point clouds, GSI terrain, or all models together. The release adds two epochs of 3DGS to that list, and says the surface determination runs "on 3DGS alone".

The one-point method is the simplest volume integral there is. On a grid of cell area a=s2a = s^2:

Vfill=a∑kmax⁡(0, z2(k)−z1(k)),Vcut=a∑kmax⁡(0, z1(k)−z2(k))V_\text{fill} = a \sum_{k} \max(0,\ z_2(k) - z_1(k)), \qquad V_\text{cut} = a \sum_{k} \max(0,\ z_1(k) - z_2(k))

where z1z_1 and z2z_2 are the reference and comparison heights sampled at grid node kk. All the difficulty is in z1(k)z_1(k) and z2(k)z_2(k).

An oblique view of a splat staircase with a polygon drawn around it and the area filled with columns on a grid: orange columns for fill rising over the stairs, blue cells for cut at the base. A table reads: fill 217.328 m³, cut 2.218 m³, difference 215.110 m³, grid count 698, grid width 0.5 m, and a label reads 219.546 m³.
Earthwork volume on a splat: not only against a BIM model, but between two epochs of 3DGS files, with 'surface determination on 3DGS alone' (KOLG Inc. press release, image 4).

Read off the screenshot (measured): fill 217.328 m³, cut 2.218 m³, difference 215.110 m³, 698 cells of 0.5 m, and a label of 219.546 m³, which is fill plus cut. So the area is 174.5 m² and the net averages 1.23 m (reasoned). The fill columns rise over a staircase: this measures the stairs above some reference surface the release does not name. It demonstrates the tool; it is not a validated quantity.

Turning a splat into a height field

There are four ways to get z(k)z(k) from a splat, in increasing order of effort.

  1. Centres as points, filtered. Drop Gaussians below an opacity floor and above a size limit, then take the lowest, median or highest centre per cell. Fast, and what a "point-cloud mode" plus the median option would naturally do. It is also biased: at object scale, Petrovska and Jutzi found every radiance-field method's points sat inside a statue's surface on average, by 1.6 to 3.5 mm in the clear scene, while MVS sat 0.16 mm outside (reported). Scaled up to a stockpile, a surface that sits inside reads as missing volume.
  2. Depth renders from above. An orthographic median-depth map straight down, per epoch, is a DEM directly. Overhangs and canopy go into it.
  3. A surface-trained model. Train with a method that puts Gaussians on surfaces: 2DGS flattens each Gaussian into a disc with a normal; Gaussian Opacity Fields (GOF) and PGSR add depth-normal consistency and extract a mesh. Then rasterise the mesh. More training work, much better geometry. The 2DGS paper's own ablation on DTU shows the order: 3DGS centres meshed with Poisson 1.65 mm Chamfer, 2DGS expected-depth fusion 0.88, median-depth fusion 0.80 (reported). Fused depth beats centres; median beats mean.
  4. Do not use the splat for geometry. An XGRIDS export ships a LAS beside the splat. Boring, and for a payment quantity, right.

Whichever route, the errors are the same:

How registration error becomes volume error

Let epoch 2 be registered to epoch 1 with a small vertical offset δz\delta z and a small tilt θ\theta about a horizontal axis through the point p0p_0. To first order the height error at horizontal position xx is δz+θ (x−p0)⋅u^\delta z + \theta\,(x - p_0)\cdot \hat u, where u^\hat u is the horizontal direction perpendicular to the tilt axis. Integrate over a region of area AA with centroid xˉ\bar x:

ΔVnet=A (δz+θ (xˉ−p0)⋅u^)\Delta V_\text{net} = A\,\big(\delta z + \theta\,(\bar x - p_0)\cdot \hat u\big)

Two consequences (reasoned):

A tilt comes from the targets you aligned on. One target 2 cm off vertically on a 30 m baseline tilts the fit by about 0.67 mrad (0.038°), which is 1.3 cm of height 20 m from the pivot (reasoned). Two centimetres is an ordinary RTK fix; a thin lift is not much more.

The widget runs the one-point method on a synthetic 40 m x 30 m site, where epoch 2 adds a pit (cut) and a stockpile (fill).

two-epoch cut and fill, point-height methodsynthetic site
■ cut (lower in epoch 2)40 m x 30 m■ fill (higher)
m³truthmeasured
cut198.5198.5
fill112.9112.9
net-85.6-85.6
net error0.0

A dz of 0 cm over 1200 m² is 0.0 m³ of net error by itself. Tilt about the centre nets to zero but still inflates cut and fill separately.

On the 0.5 m grid (reasoned, synthetic): the truth is 198.5 m³ cut and 112.9 m³ fill. A 5 cm offset over 1,200 m² moves the net from -85.6 to -25.6 m³, exactly 60 m³. A 0.10° tilt about the centre leaves the net at -85.6 but raises cut to 208.8 and fill to 123.2. Floaters add fill; the 3x3 median takes almost all of it back.

Would it count?

In Japan the question has a precise answer, because MLIT writes the test down. The March 2026 edition of its as-built control rules for 3D measurement (「3次元計測技術を用いた出来形管理要領(案)」, PDF) sets the same accuracy classes for earthwork surfaces whether the instrument is a UAV camera, a terrestrial scanner, a mobile scanner or ground photogrammetry (measured, read in the text):

PurposeAccuracy, vertical and horizontalPoint densityGround pixel size (photo methods)
Pre-construction survey, rock line±100 mm1 per 0.25 m² (0.5 m mesh)20 mm/px or finer
Interim payment quantities±200 mm1 per 0.25 m²30 mm/px or finer
As-built±50 mm1 per 0.01 m² to measure, 1 per m² to evaluate10 mm/px or finer

Accuracy is proven per site on check points against known coordinates, and the record is submitted; the pixel rule can be relaxed if that check passes. Deliverables are the point cloud (CSV, LandXML or LAS) and TIN surfaces as LandXML. A .lcc or .ply is not on the list, though methods the rules do not describe may be agreed with the client site by site.

So, on my reading, a splat volume counts only if the geometry under it passes the ±50 mm or ±200 mm check-point test and is delivered as points and a TIN, or the client agrees for that site. KOLG claims neither. For a 360 camera, the pixel rule is arithmetic (reasoned): an 8K ERP spreads 7,680 px over 2π, so a pixel covers 2πr/76802\pi r / 7680, reaching 10 mm at about 12.2 m. Against the published numbers above (12.5-25.8 cm for 360-only captures), ±50 mm needs LiDAR or very good control.

Sections and DXF from Gaussians

Slicing a Gaussian with a plane

KOLC+'s section tool traces a profile automatically between two picked points, lets you edit the traced vertices, and exports DXF as 3D lines in public coordinates or flattened to the XY plane, with one layer per model (reported, section tool page). On a point cloud you take the points within a slab around the plane and trace them. On splats there is a closed form.

Take the plane through p0p_0 with unit normal nn, and an orthonormal basis B=[ a b ]B = [\,a\ b\,] (3×23\times 2) for it, so a point on the plane is p0+Btp_0 + Bt with t∈R2t \in \mathbb{R}^2. Write δ=μ−p0\delta = \mu - p_0 and d=n⊤δd = n^\top \delta, the signed distance from the Gaussian's mean to the plane. The Gaussian's density along the plane is

G(t)∝exp⁡ ⁣(−12(Bt−δ)⊤Σ−1(Bt−δ)).G(t) \propto \exp\!\Big(-\tfrac12 (Bt-\delta)^\top \Sigma^{-1} (Bt-\delta)\Big).

The exponent is a quadratic in tt, so the slice is a 2D Gaussian. Completing the square:

M=B⊤Σ−1B,c=M−1B⊤Σ−1δ,σn2=n⊤Σ n,M = B^\top \Sigma^{-1} B, \qquad c = M^{-1} B^\top \Sigma^{-1} \delta, \qquad \sigma_n^2 = n^\top \Sigma\, n, (Bt−δ)⊤Σ−1(Bt−δ)=(t−c)⊤M (t−c)+d2σn2.(Bt-\delta)^\top \Sigma^{-1} (Bt-\delta) = (t-c)^\top M\, (t-c) + \frac{d^2}{\sigma_n^2}.

The last term is the minimum of the Mahalanobis distance over the plane, a standard result for conditioning a Gaussian on a linear constraint. Three things fall out:

A section is then an image: splat every surviving Gaussian's 2D slice onto a raster in plane coordinates, each with its weight, and you have an opacity field on the section plane. The profile is the 0.5 contour of accumulated opacity (marching squares), or the ridge of the density. That polyline goes out through ezdxf as an LWPOLYLINE in the plane's 2D frame or a 3D POLYLINE mapped back through p0+Btp_0 + Bt into site coordinates. For the "public coordinates" option, keep the coordinates in float64 all the way to the file; the next section shows why float32 is not enough.

A side view of a splat staircase rising to a landing and continuing up, with a purple polyline of closely spaced vertices tracing the stairs' underside profile from ground level to the upper landing.
A staircase auto-traced from the splat. The traced lines can be re-edited on screen and exported as DXF (3D CAD) (KOLG Inc. press release, image 5).

The section box is the same test, ∣d∣≤kσn|d| \le k\sigma_n, against six faces, plus a per-fragment test so a straddling Gaussian is cut along the plane rather than popping in and out whole.

Registration: three points, and why that is a minimum

KOLC+ offers a manual move-and-rotate tool, "3-point matching" to a BIM model, and automatic placement for data already in public coordinates (reported).

An oblique view of a splat of the plaza and staircase with a transform gizmo: red, green and blue axis lines crossing at a yellow handle in the middle of the scene.
A frame from the release's animation of the alignment tool: the splat is moved and rotated with a gizmo; 3-point matching aligns it to a BIM model (KOLG Inc. press release, alignment animation, frame 28 of 42).

Three-point matching is a similarity transform y=cRx+ty = cRx + t: rotation (3 parameters), translation (3) and scale (1). Seven unknowns. Each correspondence gives three equations. Two points give six, and leave the rotation about the line through them free. Three non-collinear points give nine, two more than needed. The least-squares solution is Umeyama's (1991): with centroids xˉ,yˉ\bar x, \bar y, variance σx2\sigma_x^2 of the source points and cross-covariance Σxy=1n∑i(yi−yˉ)(xi−xˉ)⊤=UDV⊤\Sigma_{xy} = \frac1n\sum_i (y_i-\bar y)(x_i-\bar x)^\top = UDV^\top,

R=USV⊤,S=diag(1,1,det⁡Udet⁡V),c=tr⁡(DS)σx2,t=yˉ−cRxˉ.R = U S V^\top,\quad S = \mathrm{diag}(1, 1, \det U \det V),\quad c = \frac{\operatorname{tr}(DS)}{\sigma_x^2},\quad t = \bar y - cR\bar x .

SS guards against a reflection; fix c=1c = 1 for a rigid fit. COLMAP's model_aligner does the same from camera centres and needs "at least 3 images".

Three points is the minimum to solve, not to check. With exactly three, every point is fitted and the residuals tell you nothing; with five, two of them are independent check points, and their residual is the honest number. Geometry matters as much as count. Points that are nearly collinear leave the rotation about their line weakly determined, and Spirula Studio's LiDAR notes measured exactly that: a centres-only Umeyama fit was 1.9° off the anchors' own rotations "on the FJD walk, which is nearly a line -- the rotation about it is free"; fitting rotations first, from the anchors' poses, gave 0.16° (reported, docs/notes/lidar-alignment.md). Points on one plane, say all on the ground, leave tilt determined by their vertical errors over their spread, which is the 0.038° from the previous section.

Layout matters more than count. I simulated it (measured, 4,000 Monte Carlo trials of an Umeyama fit, 2 cm noise per axis on both the picked and the surveyed coordinates, a 100 m square site). The vertical error at the centre and at the far corner: three corners, 2.0 and 5.0 cm; four corners, 1.4 and 2.4 cm; four targets clustered in one 20 m corner, 7.9 and 17.6 cm. Targets have to surround what you measure. Better still, put them into the bundle adjustment as control, so the poses themselves are in the survey frame and the solve's own bending is corrected, which no seven-parameter fit afterwards can do.

Then refine. Point-to-plane ICP against a LiDAR scan, or against the BIM model's own floor and wall faces where the as-built is expected to match, takes out the residual tilt and scale that the targets leave. It needs a starting point inside its basin: Spirula measured convergence from about 5° and 10% scale, failure at about 10° (reported). Three points get you there; ICP finishes it.

The LCC container

KOLC+'s integrated app reads only .lcc (Lixel CyberColor). XGRIDS publishes the layout in an LCC white paper (read at b38c2eb). A scene is a folder: meta.lcc (JSON), Index.bin, Data.bin, and optionally Shcoef.bin (higher-order SH), Environment.bin (far background) and Collision.lci (a mesh with a serialised BVH).

A schematic: a horizontal grid of cells labelled Level, and above one cell a vertical stack of four blocks labelled Node at the bottom, with the whole stack labelled Unit.
LCC's organisation: the scene is a horizontal grid; each grid cell (a Unit) holds one Node per LOD level (XGRIDS, LCC Data Organization Format White Paper, Figure 1).

It is a 2D tiling with a LOD pyramid per tile: a Unit is a grid cell (x and y packed into a uint32), a Node is that cell at one level, and Index.bin gives each node's splat count, offset and size in Data.bin, so a viewer streams the right level per tile. The base record is 32 bytes (measured, white paper table):

A table of the Data.bin record: Position X, Y, Z as 4-byte floats; Color RGBA as a uint32; Scale X, Y, Z as uint16 each; Rotation xyzw as one uint32; Normal X, Y, Z as uint16 each.
One splat in Data.bin: float32 position, RGBA8 colour, 16-bit quantised scale and normal, and a 32-bit packed rotation, 32 bytes in all (XGRIDS, LCC Data Organization Format White Paper, Data.bin table).

Position is three unquantised float32 (12 bytes), colour RGBA8 with opacity in alpha (4), scale three uint16 dequantised between per-scene bounds (6), rotation one uint32 in smallest-three 10-10-10-2 packing, the trick SOG and SPZ also use (4), and a normal as three uint16 (6). The Portable profile stops there. Quality adds 64 bytes in Shcoef.bin, the degree-1 to 3 coefficients as fifteen RGB triples packed 11-10-11. So 96 bytes a splat against 248 for a float32 PLY at SH3, 2.6x smaller before any LOD (reasoned).

The LOD is not free. The white paper's example meta.lcc lists nine levels with 2,890,271 splats at LOD0 and roughly 0.47x fewer at each level down; summed, all levels hold 5,440,665 splats, 1.88x the finest level (measured from the example). If every level is stored, a Quality LCC is about 96 x 1.88, roughly 181 bytes per finest-level splat, only 1.4x smaller than the PLY (reasoned). The example does not add up, either: its totalSplats says 3,678,719 "include all lods", and its indexDataSize of 86 bytes does not match the 4 + 9 x 16 = 148 the index table implies for nine levels (measured). Do not use it as a test vector.

Two details matter for construction. First, float32 positions in public coordinates lose millimetres. A float32 has a 24-bit significand; at the Y = 60,322.814 m in the KOLC+ screenshot, adjacent representable values are 2^-8 m, about 3.9 mm, apart (reasoned). That is why the metadata carries a global offset, shift, scale and epsg: store local coordinates, keep the georeference in float64 beside them. A pipeline that writes public coordinates straight into a float32 file quantises its own survey. Second, the licence is conditional: a visible "Data Organization Format originated from XGRIDS" attribution in your product, derivatives under terms "no less open", no use of the format to train AI models that compete with XGRIDS, and arbitration in Shenzhen under PRC law (reported, white paper sections 4-5). Reading .lcc is easy; building a product on it is a contract.

The open formats, and the one I would pick

You do not need LCC to leave XGRIDS' world. PlayCanvas's MIT-licensed splat-transform reads .lcc and .lcc2 and writes PLY, SPZ, SOG, streamed SOG and glTF (reported, README). Spirula Studio v2026.10.6 opens an LCC Studio developer_data/ export directly: its raw/ and perspective/ folders are COLMAP datasets in the frame of the scanner's LAS (reported, docs/notes/lidar-alignment.md).

FormatOwner, licencePositionsCompressionLOD / tilingRead by
PLY (3DGS layout)Inria reference layout, de facto openfloat32none; 248 B a splat at SH3noneeverything
SPZNiantic, MIT24-bit fixed point, 12 fractional bits by defaultquantised + zstd (v4)noneSpark, PlayCanvas (via splat-transform), Niantic tools, KOLC+ viewer
SOG / streamed SOGPlayCanvas, MIT16-bit, log domain per axisWebP images, codebooks; 18x on the bicycle scenestreamed SOG: chunked LOD (lod-meta.json)PlayCanvas engine, SuperSplat, Spark, KOLC+ viewer
glTF + KHR_gaussian_splattingKhronos, ratifiedfloat or normalised ints on a point primitivenone in the base extensionvia 3D Tiles (glTF content)CesiumJS and the Khronos ecosystem
LCCXGRIDS, white-paper licence with conditionsfloat32 + global offset/EPSG32 B (Portable) or 96 B (Quality)2D grid of units, LOD pyramid per unitXGRIDS tools, KOLC+ integrated app, splat-transform (read)

Two reasoned consequences. SPZ's 12 fractional bits on a 24-bit integer give a 0.24 mm step over plus or minus 2,048 m, so a public coordinate like 60,322 m needs a local origin. SOG's log-domain 16 bits spend precision near the origin, so put the origin mid-site, not at a monument a kilometre away.

KHR_gaussian_splatting is now "Complete, Ratified by the Khronos Group" (measured, its README; the status changed on 3 September 2026). Splats are attributes on a glTF point primitive, which degrades to a point cloud in a viewer that does not know them, and since 3D Tiles content is glTF, it is the path to splats in a geospatial tileset. Compression is left to follow-on extensions, the SPZ one still an open proposal.

My pick for a web viewer that overlays IFC: streamed SOG on the PlayCanvas engine. MIT end to end, LOD streaming already there, a converter that reads everything above including .lcc, and files small enough to ship an epoch a week. The IFC goes through That Open's web-ifc (MPL-2.0), or is converted to glTF into the same scene; one renderer and one depth buffer is the requirement, not the library. If the deliverable is a georeferenced tileset over terrain, glTF splats in 3D Tiles on CesiumJS is the standards answer, with bigger files for now.

Building a KOLC+-like pipeline from open parts

KOLC+ starts after capture and SfM: the splat arrives from XGRIDS trained and posed. A pipeline you own has to do those too. Here is the one I would build around a 360 camera. Licences are as I read them in each repository's LICENSE, COPYING or README this week; an engineer's reading, not legal advice.

splat + BIM from open partslicences as read in each repo
pick
DJI Osmo 360 or Insta360 X5, 8K equirectangular video; printed AprilTags plus surveyed targets
or
a LiDAR + camera rig (XGRIDS-style) where the earthwork tolerance demands it
in → out
.OSV / .insv → ERP .mp4, GCP list in the site CRS
licence
hardware; GCPs shot with RTK GNSS or a total station
KOLC+
KOLC+ does not capture. The press release says customers scan with XGRIDS and export .lcc from LCC Studio.

Put at least five targets around the perimeter and at two heights. Three is the minimum for a similarity; the extra ones are your check points.

stage 1 of 8

1. Capture

A DJI Osmo 360 or Insta360 X5, walked or flown, recorded at 8K. Stitch to equirectangular (ERP) in DJI Studio or Insta360 Studio before SfM, for the reason the capture-pipeline piece established: a dual-fisheye file makes the solver discover the rig, and on long captures it fails to. Turn in-camera horizon levelling off if you mask the stitch seam.

The camera's GPS is a phone's, pushed over Bluetooth, good to metres. Put out five or more targets around the perimeter and at two heights and shoot their centres with RTK GNSS or a total station: three for the fit, the rest as check points. Where the tolerance is tight, add a LiDAR scan.

2. Poses: Spirula Studio, or COLMAP

Spirula Studio solves the ERP as one spherical camera, takes GPS as a weak per-frame prior with a Huber loss, and since v2026.10.6 takes a laser scan as an input next to photos and videos: E57, LAS 1.0-1.4 (uncompressed; LAZ is refused) or PLY (reported, docs/notes/lidar-alignment.md). SfM still runs; then a similarity fit (rotation from anchor images, RANSAC scale and translation, point-to-plane ICP) moves the model into the scan's metric frame, the scan thinned to 500k points seeds the Gaussians, and depth and normal maps rendered from it replace the monocular ones. It is marked experimental. As the update to the Spirula piece found in the code, the depth loss is off by default and is a scale-blind Pearson correlation when on, so the metric accuracy comes from the alignment and the seeds, not from a depth loss.

Its own measurements are the best public evidence I have seen for 360 video plus LiDAR (reported, the project's note, 4 October 2026):

CaptureAnchor fitAfter ICP
FJD Trion P2 E57 (51 panoramas) + Insta360 X5 video (224 frames)0.16° / 3.5 cm1.3 cm to the surface
Same LAS without photos + the same X5 video0.16° / 1.1 cm0.8 cm
ETH3D courtyard, DSLR + FARO scan0.14° / 2.0 cm3.0 cm / 0.11° vs ground truth
Oxford Spires, 525 handheld images + 19 RTC360 scans0.59° / 36 cm12.8 cm

The last row is the useful one: when photographs and scan barely overlap, it says so with a big number. Spirula is GPLv3: fine as a separate process, a conversation with a lawyer if you link it into a product.

The permissive alternative is COLMAP (BSD-3-Clause): EXIF GPS becomes pose priors for its pose_prior_mapper, GLOMAP is now its "global" mapper, panorama_sfm.py turns 360° images into a virtual pinhole rig, and model_aligner fits the similarity to GCPs (reported, COLMAP docs). Feed-forward pose models are improving fast (the first and second roundups), but read the weights' licences: MASt3R is CC BY-NC-SA 4.0, and of VGGT's checkpoints only the gated VGGT-1B-Commercial allows commercial use.

3. Training: gsplat for licence, 2DGS for geometry

For appearance any trainer works. For a pipeline that measures, two constraints decide it.

Licence. The reference code for 3DGS, 2DGS and Gaussian Opacity Fields carries Inria's licence: "THE USER CANNOT USE, EXPLOIT OR DISTRIBUTE THE SOFTWARE FOR COMMERCIAL PURPOSES" (measured, each LICENSE.md); PGSR's is "educational, research and non-profit purposes only". gsplat is Apache-2.0 and ships its own 2DGS rasteriser, the commercial-safe route to surfel geometry; mesh it with your own median-depth TSDF. LichtFeld Studio and Spirula are GPLv3.

Geometry. Train one appearance model and, if you need measured surfaces, one surface model, or use the LiDAR for geometry outright. The trained splat is for the viewer; the DEM and the sections come from the scan or the 2DGS mesh. Mixing the two roles is how floaters end up in a payment quantity. Spirula's new region-of-interest editor keeps the training budget on the site without cropping the scene: densification outside the region is weighted by 1e-4 (reported, the Spirula update).

4. Georeferencing

Fit the similarity from the GCPs (Umeyama, above), report residuals on the check points, then ICP against the scan. If there is no scan, ICP against the BIM's floor slabs and core walls in areas you expect to be as designed. Choose the target CRS once. In Japan that is a JGD2011 plane rectangular zone; everywhere, keep the coordinates as float64 offsets from a site origin and the origin plus EPSG code as metadata.

5. Revit to the same frame

This is where splat-plus-BIM demos quietly cheat, by dragging the model until it looks right. Revit has three points:

The georeference that matters is the survey point plus the true-north angle: the site's shared coordinates. Acquire them from a georeferenced site model or specify them at a surveyed point, and check against a monument before exporting anything. In Japan, check the height datum too: the JGD2024 survey results that took effect on 1 April 2025 changed only heights, by up to tens of centimetres on control points, so a design surface and a new scan can disagree vertically before anyone has moved any earth (reported, GSI).

Then export IFC with Autodesk's open-source exporter (revit-ifc, LGPLv2). Its coordinate bases are the SiteTransformBasis enum: Shared, Site, Project, Internal, ProjectInTN, InternalInTN (measured, CommonEnum.cs). Export IFC4 with an EPSG code set and it writes an IfcMapConversion with eastings, northings, height and the true-north rotation, leaving the world coordinate system at zero; IFC2x3, or no EPSG code, bakes the offsets into the placement instead (measured, Exporter.cs: "In IFC4 onward and EPSG has value (IfcMapConversion will be created), the wcs will be (0,0,0)"). The first is what you want: the geometry stays local and the reader applies the conversion in float64.

One more trap, reasoned: a projected CRS has a scale factor. In a JGD2011 plane rectangular zone the grid scale is 0.9999 at the origin meridian, so grid distances and ground distances differ by about 1 cm per 100 m there, and differently elsewhere in the zone. A splat georeferenced from GNSS sits in grid coordinates; a Revit model built at true size sits at ground scale. IfcMapConversion has a Scale attribute for exactly this. On a 200 m building it is a 2 cm misfit at the far end, invisible in a demo and very visible in a deviation map.

For the element link, the IFC already has what you need. The exporter fills each element's Tag with its Revit ElementId by default, and its GlobalId from the element's IfcGUID parameter when present, with an option to store the generated one back into Revit so it stays stable between exports (measured, NamingUtil.cs and GUIDUtil.cs). IfcOpenShell (LGPL-3.0) iterates the geometry into per-element meshes keyed by GlobalId, with the category (IfcWall, IfcSlab, …) and property sets alongside. Autodesk Platform Services' Model Derivative API is the paid cloud alternative, and can itself produce IFC from an RVT.

With elements in the splat's frame, the useful construction queries are per element:

6. Earthwork

Per epoch: classify ground in PDAL (filters.smrf or filters.csf) on the LiDAR or the fused splat surface, rasterise with writers.gdal at 0.5 m, difference with rasterio and numpy, and sum with the one-point formula. The design surface is LandXML or the IFC on the same grid. Print the error budget beside the number: A δzA\,\delta z from the check-point bias, 3ε3\varepsilon from scale. For MLIT deliverables, export the points and a LandXML TIN as well.

7. Sections and DXF

On the LiDAR or the mesh, a section is trimesh.section; on the splat, the slicing above. ezdxf (MIT) writes the polylines in 3D site coordinates, one layer per source and per IFC category, plus a 2D copy in the section plane.

8. Delivery and the viewer

splat-transform converts each epoch's PLY to streamed SOG with LOD chunks (its defaults: about 512K Gaussians or 16 m per chunk). A small JSON manifest lists epochs by date, each pointing at its lod-meta.json, plus the IFC version current at that date; the 4D slider is a pick from that list. KOLC+'s placement tools (scaffolding, hoarding, cones) are glTF models dropped on the picked ground height and exported back as DXF.

An oblique view of the splat plaza with planning objects placed in it: a purple excavator model, a white temporary hoarding fence with measured runs of 10.645 m, 5.916 m and 10.043 m, a line of red traffic cones along a yellow rope labelled 20 pieces, and a cyan grid of scaffolding against the walkway.
Placement planning on a splat: scaffolding, hoarding, cones and an excavator placed 'like in PowerPoint', exportable as DXF (KOLG Inc. press release, image 6).
A top-down view of the same splat with the planning objects: the yellow excavator from above, the hoarding as white measured lines of 10.645 m, 5.916 m and 10.043 m, and the cone line as a yellow polyline with red vertices labelled 20 pieces.
The same plan in the 2D view, editable like a plan drawing (KOLG Inc. press release, image 7).

What you would still have to write

Everything above exists. The parts that do not, and that KOLC+ is selling, are:

KOLC+ also ships something the open pipeline does not: an MLIT-registered information-sharing system with 500+ companies on it. That is not a rendering feature, and it is what ¥50,000 a month buys.

What it costs to run

All reasoned, from figures this site has already measured or reported:

Who else puts splats next to BIM

All reported, from vendor pages and trade coverage, none of it tested by me:

The pattern: everyone who measures on splats either measures on a point cloud underneath, or declines to offer volumes. KOLC+ offers volumes on the splat itself. That is the most ambitious claim in the set, and the least documented.

What I could not check

Related: Gaussian-splat capture in practice for the 360-camera half; SOG for the format I would deliver in; Spirula Studio for the SfM; Carveout for labelling a splat's objects, the first step to linking them to BIM elements; for how construction SLAM is graded against surveyed marks rather than another estimator, the Hilti SLAM datasets; and for the LiDAR side of the same site, FAR-LIO, GTSAM 4.3 for the factor graphs behind GPS-prior bundle adjustment, and the Kalman filter.

Cite this article

For attribution, please use the following reference or BibTeX:

Satyajit Ghana, "KOLC+ puts Gaussian splats inside BIM/CIM: how each feature has to work, and how I would build one", ai.thesatyajit.com, October 2026.

bibtex
@misc{ghana2026kolc3dgsbim,
  author = {Satyajit Ghana},
  title  = {KOLC+ puts Gaussian splats inside BIM/CIM: how each feature has to work, and how I would build one},
  url    = {https://ai.thesatyajit.com/articles/kolc-3dgs-bim},
  year   = {2026}
}
share