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.