SOLIBRI SDK · JAVA

Eigene Solibri-Regeln

Eigene Prüfregeln, die Solibri nicht eingebaut hat - entwickelt mit dem Solibri Java SDK (Maven).

Set-Connectivity-Prüfung

Problem

Im Modulbau werden Bauteile über eine IFC-Eigenschaft zu „Sets" gruppiert. Ein Set ist nur gültig, wenn seine Mitglieder tatsächlich verbunden sind - ein loses Teil stört Montage und QS. Solibri bietet keine eingebaute Prüfung der Konnektivität innerhalb eines Sets.

Ansatz

Eine eigene Java-Regel, die Bauteile nach der Set-Eigenschaft gruppiert und sich berührende Mitglieder per Union-Find zu Clustern zusammenführt. Ein Paar gilt als verbunden, wenn die echte Geometrie innerhalb der Toleranz liegt - oder bei eingebetteten Teilen (z. B. eine in die Wand eingelassene Stütze), wenn sich die Boxen durchdringen und der Spalt innerhalb des Einbettungsabstands liegt.

Parameter

Bauteilewas geprüft wird
Set-EigenschaftIFC-Eigenschaft, die die Set-Zugehörigkeit festlegt
Abstandstoleranzgrößter Spalt, der noch als Berührung gilt (0,01 m)
EinbettungsabstandToleranz für eingebettete Mitglieder (0,05 m)

Ergebnis

Der größte Cluster ist die Hauptgruppe; jeder andere Cluster wird einmal gemeldet - mit Größe, nächstem Mitglied der Hauptgruppe und Abstand dazu. Auf einem Modell mit 56.000 Bauteilen brauchte die erste, erschöpfende Version rund vier Stunden - bei einem voll verbundenen Set mit 200 Mitgliedern senkt Union-Find die exakten Abstandsberechnungen von 19.900 auf 199.

Wie der Code funktioniert

if (touch) {
    dsu.union(i, j);
    if (dsu.getClusterCount() == 1) {
        break scan; // everything is connected - no disconnected cluster can exist
    }
}

// Union-find with path halving: members already in one cluster
// never need the expensive exact distance test again.
int find(int x) {
    while (parent[x] != x) {
        parent[x] = parent[parent[x]];
        x = parent[x];
    }
    return x;
}
  • Broad phaseDer Bounding-Box-Abstand ist eine untere Schranke für den echten Abstand - weit entfernte Paare werden günstig verworfen, bevor Geometrie berechnet wird.
  • Narrow phaseComponent.distance() ist der echte Oberflächenabstand der Körper - der teuerste Aufruf der Regel.
  • Union-Find statt BFSPaare, die schon im selben Cluster liegen, werden übersprungen, und die Suche endet, sobald das ganze Set verbunden ist. Die Cluster sind identisch mit der erschöpfenden Version - eingespart wird nur sicher überflüssige Arbeit.
Set-Connectivity-Prüfung

Duplikat-Prüfung

Problem

Die eingebaute Schnittregel von Solibri listet jedes Duplikat ohne Filtermöglichkeit - dabei sind manche Duplikate legitim: Objekte am selben Ort, die sich in Typ oder Untertyp unterscheiden. Koordinatoren arbeiten sich durch Hunderte Fehlalarme.

Ansatz

Eine eigene Java-Regel, die nur meldet, wenn ALLE gewählten Unterscheidungs-Eigenschaften übereinstimmen. Eigenschaften werden vor der Geometrie verglichen: Eine Eigenschaft zu lesen ist ein Tabellenzugriff, ein Schnitttest muss Körper verschneiden.

Parameter

BauteileMenge, in der Duplikate gesucht werden
Unterscheidungs-Eigenschaft 1..4ein Unterschied macht das Duplikat legitim

Ergebnis

Ein Ergebnis je Paar mit den verglichenen Eigenschaften und ihren Werten. Existiert eine gewählte Eigenschaft nirgends im Modell, meldet die Regel das deutlich - statt still „keine Fehler" zu liefern.

Wie der Code funktioniert

for (Component target : SMC.getModel().getComponents(candidateFilter)) {
    // Look at each pair once, from its lower-GUID member.
    if (component.getGUID().compareTo(target.getGUID()) >= 0) {
        continue;
    }
    // Properties before geometry: a lookup is cheap, intersecting solids is not.
    if (!PropertyMatcher.allMatch(ownValues, valuesOf(target))) {
        continue;
    }
    if (!isDuplicatePair(component, target)) {
        continue;
    }
    results.add(createResult(component, target, ownValues, resultFactory));
}
  • Jedes Paar einmalDas Paar wird nur vom Mitglied mit der kleineren GUID betrachtet - das halbiert die Arbeit und schließt den Vergleich eines Bauteils mit sich selbst aus.
  • Günstiger Test zuerstEin Paar, das sich in einer Eigenschaft unterscheidet, ist kein Fehler und wird verworfen, ohne die Geometrie anzufassen.
  • Solibri entscheidet „Duplikat"Das geometrische Kriterium bleibt bei Intersection.isDuplicate() - die Regel verhält sich wie die eingebaute, nur ohne die legitimen Fälle.

Mittig-zwischen-Prüfung

Problem

„Dieses Fenster muss mittig zwischen den Balken links und rechts sitzen." Die eingebauten Solibri-Regeln messen den Abstand zu EINEM Objekt - „in der Mitte" lässt sich so nicht ausdrücken, denn es geht gerade um den Vergleich zweier Abstände.

Ansatz

Für jedes Objekt sucht die Regel das nächste Referenzobjekt nach echter Geometrie, nimmt die Richtung dorthin und sucht dann das nächste Referenzobjekt auf der Gegenseite innerhalb einer Winkeltoleranz - und vergleicht die beiden Abstände. Sie arbeitet mit einem Richtungsvektor statt mit Koordinatenachsen: Ein beliebig gedrehtes Modell liefert dasselbe Ergebnis.

Parameter

Bauteile / Referenzbauteilez. B. Fenster / Balken
Suchradiusdarüber hinaus wird nicht gesucht (2,0 m)
Abstandstoleranzwie weit die Abstände abweichen dürfen (5 mm)
Gegenrichtungs-ToleranzAbweichung von exakt gegenüber, in Grad

Ergebnis

Außermittige Objekte werden mit BEIDEN Referenzobjekten und beiden Abständen gemeldet. Fehlt das Gegenstück, ist auch das ein Fehler - ein ungeprüftes Objekt darf nicht wie geprüft aussehen.

Wie der Code funktioniert

static boolean isOpposite(Candidate reference, Candidate candidate, double toleranceDegrees) {
    double referenceLength = reference.offsetLength();
    double candidateLength = candidate.offsetLength();
    if (referenceLength == 0.0 || candidateLength == 0.0) {
        return false;
    }
    double dot = reference.dx * candidate.dx
        + reference.dy * candidate.dy
        + reference.dz * candidate.dz;
    double cosine = dot / (referenceLength * candidateLength);

    double tolerance = Math.min(Math.max(toleranceDegrees, 0.0), MAX_TOLERANCE_DEGREES);
    return cosine <= -Math.cos(Math.toRadians(tolerance));
}
  • Richtung statt AchsenDie erste Version wählte X, Y oder Z - und scheiterte an einer Wand unter 37 Grad, wo die „Hauptachse" zum Münzwurf wurde. Ein Skalarprodukt zwischen Richtungsvektoren ist drehungsinvariant.
  • Box vs. KugelKandidaten kommen aus einem Bounding-Box-Filter und werden dann über den echten Abstand reduziert - eine Box wächst als Würfel, der Suchradius ist eine Kugel.
  • Begrenzte ToleranzÜber 90 Grad würde „gegenüber" Objekte auf derselben Seite durchlassen - deshalb wird die Toleranz begrenzt statt übernommen.

Modellübergreifender Vergleich

Problem

Unser Modell und das Modell des Herstellers müssen im Kleinen übereinstimmen - Bohrungen, Schrauben, Bolzen, Öffnungen. Ein paar Millimeter Versatz zeigen sich erst auf der Baustelle, und nichts in Solibri ordnet „unserer Bohrung" „ihre Bohrung" zu und misst die Abweichung.

Ansatz

Die Regel ordnet jedem unserer Objekte sein Gegenstück im Herstellermodell zu und misst, wie weit die Mittelpunkte versetzt sind und wie sich die Abmessungen unterscheiden. Die Zuordnung ist gierig nach Abstand: Das nächste Paar wird zuerst festgelegt, beide Mitglieder scheiden aus. Objekte ohne Partner werden von beiden Seiten gemeldet.

Parameter

Referenz- / Vergleichsbauteileunsere Objekte / die des Herstellers
Suchradiusdarüber hinaus wird kein Partner gesucht (50 mm)
Toleranzeine Toleranz für Versatz und Größe (2 mm)

Ergebnis

Genau ein Ergebnis je abweichendem Paar, mit Versatz und Größenunterschied auf eine Nachkommastelle - dazu „kein Gegenstück" und „zusätzliches Objekt" für Unzugeordnete. Auf einem realen Fachmodell-Verbund bestätigt.

Wie der Code funktioniert

public static Matching match(List<Box> reference, List<Box> compared, double radius) {
    int[] comparedForReference = new int[reference.size()];
    int[] referenceForCompared = new int[compared.size()];
    Arrays.fill(comparedForReference, -1);
    Arrays.fill(referenceForCompared, -1);

    List<Candidate> candidates = collectCandidates(reference, compared, radius);
    sortByDistanceThenId(candidates, reference, compared);

    for (Candidate candidate : candidates) {
        if (comparedForReference[candidate.referenceIndex] != -1
                || referenceForCompared[candidate.comparedIndex] != -1) {
            continue; // one of the two is already taken by a closer pair
        }
        comparedForReference[candidate.referenceIndex] = candidate.comparedIndex;
        referenceForCompared[candidate.comparedIndex] = candidate.referenceIndex;
    }
    return new Matching(comparedForReference, referenceForCompared);
}
  • Sweep statt n×mDie Vergleichsboxen werden einmal nach X sortiert; jede Referenzbox betrachtet per Binärsuche nur den Streifen innerhalb des Radius - danach reduziert der echte Abstand den Streifen auf eine Kugel.
  • Bewusst gierigNicht „jeder nimmt seinen nächsten" - in einer Lochreihe würden zwei unserer Bohrungen dieselbe des Herstellers greifen. Auch nicht der Ungarische Algorithmus - er minimiert die Summe und schiebt die Schuld von der wirklich versetzten Bohrung auf ihre Nachbarn.
  • Ein Befund statt zweiDer erste reale Lauf zeigte: Lage- und Größenfehler sind ein physischer Sachverhalt - wächst eine Bohrung auf einer Seite um d, wandert ihr Mittelpunkt um d/2. Deshalb werden sie gemeinsam gemeldet.

Modellübergreifender Eigenschaftsabgleich

Problem

Eine Fassade wird abschnittsweise gestrichen, und die Farbe der Holzrahmung um jede Platte wird im Herstellermodell von Hand vergeben - ein manueller Schritt, in dem Fehler passieren. Eine 1:1-Zuordnung gibt es nicht: Eine Platte kann von mehreren Rahmenteilen umgeben sein.

Ansatz

Für jedes Objekt unseres Modells findet die Regel alle Nachbarn aus dem Herstellermodell im Suchradius und vergleicht eine gewählte Eigenschaft auf beiden Seiten - Zahlen mit Epsilon, Text ohne Groß-/Kleinschreibung. Entitätswerte (Gebäude, Geschoss) werden auf ihren Namen aufgelöst, das von Solibri ergänzte Modellpräfix wird entfernt.

Parameter

Bauteil A / Bauteil Bz. B. unsere Bekleidung / Rahmung des Herstellers
Eigenschaft an A / an Bmeist auf jeder Seite anders benannt
Suchradiusdarüber hinaus wird kein Nachbar geprüft (10 mm)
Ergebnisse gruppieren nachunter A oder unter B sammeln

Ergebnis

Abweichungen tragen die WERTE im Titel und beide Objekte in der Beschreibung und werden rot gegen blau dargestellt - auch für Farbenblinde unterscheidbar. Ein fehlender Wert ist nie eine Übereinstimmung - sonst ließe ein Tippfehler im Eigenschaftsnamen jedes Paar still durch.

Wie der Code funktioniert

static Outcome compare(Optional<String> valueA, Optional<String> valueB) {
    if (valueA.isEmpty() && valueB.isEmpty()) {
        return Outcome.MISSING_BOTH;   // not a match - a typo must not pass silently
    }
    if (valueA.isEmpty()) {
        return Outcome.MISSING_A;
    }
    if (valueB.isEmpty()) {
        return Outcome.MISSING_B;
    }
    return valuesEqual(valueA.get(), valueB.get()) ? Outcome.MATCH : Outcome.MISMATCH;
}

// Numbers within EPSILON = 1e-3, otherwise case-insensitive text.
  • Am realen Modell gelerntDer erste Lauf ergab 4.282 Abweichungen bei 4.282 Paaren: Solibri lieferte die Gebäude-Entität selbst, deren toString eine je Modell eindeutige interne ID ist. Der Wert wird jetzt über getName() aufgelöst.
  • Präfixe im VerbundIm Fachmodell-Verbund stellt Solibri Namen das Modellkürzel voran - dasselbe Gebäude hieß „(B) …" gegen „(A) …". Das Präfix wird am tragenden Bauteil abgelesen und entfernt.
  • Lesbare Ergebnisse4.282 Ergebnisse über 142 Nachbarn waren nicht lesbar. Der Parameter „Ergebnisse gruppieren nach" fasst sie je Objekt A oder je Nachbar B zusammen.