Solibri API - Code Example
ClashDetectionRule Example
This example shows how to develop a simple rule that checks and visualized the clash between two different entities. User defines the checked components and the allowed tolerance between them.
This example shows also how to develop a simple UI Definition for this rule where the rule UI allows user to filter the selected components and and input a tolerance parameter represented in cubic meters.
You can download the examples project from here.
Table of Contents
- Implementing the Clash Detection Rule Example
- ClashDetectionRule.java
- Implementing the UI Definition
- ClashDetectionRuleUIDefinition.java
- ClashDetectionRule.properties
Implementing the Clash Detection Rule Example
ClashDetectionRule.java
package com.solibri.smc.api.examples.beginner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import com.solibri.smc.api.SMC;
import com.solibri.smc.api.checking.DoubleParameter;
import com.solibri.smc.api.checking.FilterParameter;
import com.solibri.smc.api.checking.OneByOneRule;
import com.solibri.smc.api.checking.Result;
import com.solibri.smc.api.checking.ResultFactory;
import com.solibri.smc.api.checking.RuleParameters;
import com.solibri.smc.api.filter.AABBIntersectionFilter;
import com.solibri.smc.api.filter.ComponentFilter;
import com.solibri.smc.api.intersection.Intersection;
import com.solibri.smc.api.model.Component;
import com.solibri.smc.api.model.PropertyType;
import com.solibri.smc.api.ui.UIContainer;
/**
* An example rule that checks all clashes between components. A tolerance
* parameter is included for specifying how much volume the clash must have to
* be considered an issue.
*/
public final class ClashDetectionRule extends OneByOneRule {
/**
* Constant strings are created to be used when creating different rule
* parameters. The declaration of constants keeps the code clean and
* reusable.
*/
private static final String COMPONENT_FILTER_PARAMETER_ID2 = "rpComponentFilter2";
private static final String ALLOWED_TOLERANCE_PARAMETER_ID = "rpAllowedTolerance";
/**
* Retrieve the rule parameters handler, used to define parameters for
* this rule.
*/
private final RuleParameters params = RuleParameters.of(this);
/**
* The default FilterParameter is used for source components, and a new one is
* created for target components. A DoubleParameter is created to state the
* allowed tolerance for components.
* Every component that passes the default filter filter is then forwarded to
* the check method.
*/
final FilterParameter rpComponentFilter = this.getDefaultFilterParameter();
final FilterParameter rpComponentFilter2 = params.createFilter(COMPONENT_FILTER_PARAMETER_ID2);
final DoubleParameter rpAllowedTolerance = params.createDouble(ALLOWED_TOLERANCE_PARAMETER_ID, PropertyType.VOLUME);
/**
* Add the UI definition from ClashDetectionRuleUIDefinition class.
*/
private final ClashDetectionRuleUIDefinition uiDefinition = new ClashDetectionRuleUIDefinition(this);
@Override
public Collection<Result> check(Component component, ResultFactory resultFactory) {
/*
* Get the values from the model using a geometric filter combined with the
* second filter from the UI. It is best to start the filter chains with
* a geometric filter to allow the use of optimized geometric queries.
*/
ComponentFilter secondFilter = rpComponentFilter2.getValue();
ComponentFilter targetComponentFilter = AABBIntersectionFilter.ofComponentBounds(component).and(secondFilter);
Collection<Component> targets = SMC.getModel().getComponents(targetComponentFilter);
/*
* Run the clash check for each component in the bounding box.
*/
Collection<Result> results = new ArrayList<>();
for (Component target : targets) {
results.addAll(clashCheck(component, target, resultFactory));
}
return results;
}
@Override
public UIContainer getParametersUIDefinition() {
return uiDefinition.getDefinitionContainer();
}
/**
* Checks for clashes between components and generates results.
*
* @param source the source component
* @param target the target component
*/
private Collection<Result> clashCheck(Component source, Component target, ResultFactory resultFactory) {
final double allowedTolerance = rpAllowedTolerance.getValue();
final double transparency = 0.5;
Collection<Result> results = new ArrayList<>();
Set<Intersection> intersections = source.getIntersections(target);
/*
* Loop through each intersection to find the involved components, create
* results, and visualize them.
*/
for (Intersection intersection : intersections) {
if (intersection.getVolume() < allowedTolerance) {
continue;
} else {
String name = source.getName() + " clashes with " + target.getName();
String description = "There is a clash between " + source.getName() + " and " + target.getName();
Result result = resultFactory
.create(name, description)
.withInvolvedComponent(target)
.withVisualization(visualization -> {
visualization.addComponent(source, transparency);
visualization.addComponent(target, transparency);
});
results.add(result);
}
}
return results;
}
}
ClashDetectionRuleUIDefinition.java
package com.solibri.smc.api.examples.beginner;
import com.solibri.smc.api.checking.RuleResources;
import com.solibri.smc.api.ui.BorderType;
import com.solibri.smc.api.ui.UIComponent;
import com.solibri.smc.api.ui.UIContainer;
import com.solibri.smc.api.ui.UIContainerVertical;
import com.solibri.smc.api.ui.UILabel;
import com.solibri.smc.api.ui.UIRuleParameter;
/**
* Class that provides the UI layout for Clash Detection Rule. The UI Consists
* of two component filters and one double values parameter field for length.
*/
class ClashDetectionRuleUIDefinition {
/**
* The Clash Detection Rule.
*/
private final ClashDetectionRule clashDetectionRule;
/**
* The UI definition container.
*/
private final UIContainer uiDefinition;
/**
* Basic constructor.
*
* @param clashDetectionRule the clash detection rule
*/
public ClashDetectionRuleUIDefinition(ClashDetectionRule clashDetectionRule) {
this.clashDetectionRule = clashDetectionRule;
this.uiDefinition = createUIDefinition();
}
/**
* Returns the UI definition of the rule.
*
* @return the UI definition container of the rule
*/
public UIContainer getDefinitionContainer() {
return uiDefinition;
}
/**
* Create the UI definition of the rule.
*
* @return the UI definition container of the rule
*/
private UIContainer createUIDefinition() {
/*
* Fetch the resources for this rule.
*/
RuleResources resources = RuleResources.of(clashDetectionRule);
/*
* Create the vertical component container.
*/
UIContainer uiContainer = UIContainerVertical.create(resources.getString("UI.ClashDetectionRule.TITLE"),
BorderType.LINE);
/*
* Add the description of the rule.
*/
uiContainer.addComponent(UILabel.create(resources.getString("UI.ClashDetectionRule.DESCRIPTION")));
/*
* Add the first filter for components to check.
*/
uiContainer.addComponent(createFirstComponentFilterUIDefinition());
/*
* Add the second filter for components to check.
*/
uiContainer.addComponent(createSecondComponentFilterUIDefinition());
/*
* Add the tolerance filter for clash of components.
*/
uiContainer.addComponent(createAllowedToleranceUIDefinition());
return uiContainer;
}
/**
* Create the UI definition of the first component filter.
*
* @return the UI definition container of the first component filter
*/
private UIComponent createFirstComponentFilterUIDefinition() {
UIContainer uiContainer = UIContainerVertical.create();
uiContainer.addComponent(UIRuleParameter.create(clashDetectionRule.rpComponentFilter));
return uiContainer;
}
/**
* Create the UI definition of the second component filter.
*
* @return the UI definition container of the second component filter
*/
private UIComponent createSecondComponentFilterUIDefinition() {
UIContainer uiContainer = UIContainerVertical.create();
uiContainer.addComponent(UIRuleParameter.create(clashDetectionRule.rpComponentFilter2));
return uiContainer;
}
/**
* Create the UI definition of the allowed tolerance.
*
* @return the UI definition container of the allowed tolerance
*/
private UIComponent createAllowedToleranceUIDefinition() {
UIContainer uiContainer = UIContainerVertical.create();
uiContainer.addComponent(UIRuleParameter.create(clashDetectionRule.rpAllowedTolerance));
return uiContainer;
}
}
ClashDetectionRule.properties
DEFAULT_NAME=Clash Detection Rule
DEFAULT_DESCRIPTION=This rule detects the clash between filtered components.
AUTHOR=Solibri, Inc.
AUTHOR_TAG=SOL
UID=EX4
VERSION=1.0
DATE=2019-8-15
rpComponentFilter.NAME=Source Components
rpComponentFilter.DESCRIPTION=This filter specifies the set of components to check.
rpComponentFilter2.NAME=Target Components
rpComponentFilter.DESCRIPTION=This filter specifies the set of components to check.
rpAllowedTolerance.NAME=Allowed Tolerance
rpAllowedTolerance.DESCRIPTION=Allowed tolerance before components clash. Represented as volume in cubic meters.
rpAllowedTolerance.DEFAULT_VALUE=0.01
UI.ClashDetectionRule.TITLE=Clash Detection Rule
UI.ClashDetectionRule.DESCRIPTION=This rule detects the clash between filtered components.