OptionalclassificationsOptionaldescriptionOptionalmaterialsThe entity's resolved material NAMES. Missing from this projection
entirely before, so a re-specified element (measured: Soil1 ->
topsoil on an infrastructure pair) read as unchanged in every channel.
Names, never entity references — an IfcMaterial's express id is
reassigned on every save, so comparing references flags every re-exported
element. Same argument that keeps TypeAssignmentInput.globalId
out of the hash, and a material is not even an IfcRoot, so its id is
the only thing a reference comparison could see.
Resolve through every indirection before supplying this: the usage /
set / list wrappers (IfcMaterialLayerSetUsage, IfcMaterialLayerSet,
IfcMaterialProfileSet, IfcMaterialConstituentSet, IfcMaterialList,
and their layer/profile/constituent members), down to IfcMaterial.Name
at the leaf. The shipped viewer adapter does this via
extractAllMaterialsOnDemand + lensMaterialNames; reading only a
directly attached IfcMaterial silently under-reports on any layered
element. Order is irrelevant (sorted here), and an empty array is
identical to omitting the field: both say "no material named".
OptionalnameOptionalobjectOptionalpredefinedOptionalpropertyOptionalquantityOptionaltagThe entity's Tag, and only for a type object (issue #2021).
A type object carries no geometry hash, so its data fingerprint is the
whole of the evidence a content match has about it. That was not enough on
real files: Duplex has eight IfcFurnitureType entities all named
'800 mm', identical in every other attribute this hashes and separable
only by Tag ('157200', '157607', …), so they landed in one bucket and
the engine correctly abstained on all of them. Hashing Tag gives that
bucket the discriminator it was missing.
An occurrence's Tag must NOT be supplied here, and the shipped adapters
do not. IfcElement.Tag is the authoring tool's own element id (Revit
writes its ElementId). It is not a property of the design, it is a property
of the file's producer — so two tools exporting one design disagree on it
for every element, and dataHash is the bucket key, which means an
occurrence whose Tag moved cannot content-match at all. That is exactly
the re-export scenario matchUnpairedByContent exists for, and an
occurrence has a geometry hash to be separated by anyway. The same argument
is why the assigned type's GlobalId is not hashed; see
TypeAssignmentInput.globalId.
The blast radius is contained to the type object itself: type assignments project only TypeAssignmentInput.name and TypeAssignmentInput.type, so re-tagging a type does not move the fingerprint of a single element assigned to it.
Optionaltype
The entity's resolved classification references, each projected to a single string (e.g.
system:identification). Same reasoning as materials: missing from this projection entirely was the prior state, so a re-classified element (re-coded from one Uniclass group to another, geometry and every property untouched) read as unchanged everywhere — a classification edit touches none ofpropertySets,quantitySetsormaterials. Resolve through the fullIfcRelAssociatesClassification->IfcClassificationReferencechain before supplying this; order is irrelevant, and[]== omitted.