Skip to content

Commit

Permalink
Enhancement: Consider Node Ancestry in Proto Type Restrictions (#6574)
Browse files Browse the repository at this point in the history
* allow programatic determination of base node model ancestry

Signed-off-by: CoolSpy3 <[email protected]>

* consider node ancestry in proto type restrictions

Signed-off-by: CoolSpy3 <[email protected]>

* update documentation

* update test suite

* run clang-format

Signed-off-by: CoolSpy3 <[email protected]>

* workaround Transform edge case

* fix spacing in documentation

* update changelog

* initialize mParentModel in constructor

* fix typo

* fix DerivedAppearanceProto file extension

* add proto_allowed_mf_field_value test

* fix DerivedAppearanceProto filename

* fix test suite

* fix test suite

* create WbFieldValueRestriction

* add parsing of '=' syntax to reenable old behavior

* keep track of proto parents

* update field validation checks

* switch to '+' syntax

* check if old field validation behavior should be used

* fix parsing of '+'

* update tests

* clarify error messages to indicate whether subtypes are allowed

* more tests

* bug fixes

* update docs

* documentation clarification

* update changelog

* clarify function name

* run clang-format

* improve node insertion validity api

* bug fixes

* fix file formatting

* additional documentation

* fix isAllowedToInsert

* address comments from PR

Co-authored-by: Olivier Michel <[email protected]>

---------

Signed-off-by: CoolSpy3 <[email protected]>
Co-authored-by: Olivier Michel <[email protected]>
  • Loading branch information
CoolSpy3 and omichel authored Jul 11, 2024
1 parent ece474f commit 7ddffc6
Show file tree
Hide file tree
Showing 80 changed files with 606 additions and 119 deletions.
2 changes: 1 addition & 1 deletion docs/reference/changelog-r2024.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
Released on December **th, 2023.
- New Features
- **Change the name of the web scene format from `X3D` to `W3D` ([#6280](https://github.com/cyberbotics/webots/pull/6280)).**
- Added a method to include all subtypes of a node type in a PROTO field restriction ([#6574](https://github.com/cyberbotics/webots/pull/6574)).
- Enhancements
- Improved the image range of the rotating [Lidar](lidar.md) ([#6324](https://github.com/cyberbotics/webots/pull/6324)).
- Cleanup
Expand All @@ -12,4 +13,3 @@ Released on December **th, 2023.
- Fixed error message on Windows when `libssl-3-x64.dll` was added to `PATH` ([#6553](https://github.com/cyberbotics/webots/pull/6553)).
- Fixed length of arrays returned by `getPose()` in Java ([#6556](https://github.com/cyberbotics/webots/pull/6556)).
- Fixed length of arrays returned by `CameraRecognitionObject.getColors()` in Java ([#6564](https://github.com/cyberbotics/webots/pull/6564))

8 changes: 6 additions & 2 deletions docs/reference/proto-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ PROTO MyProto [
field SFString name "my proto"
field SFColor{0 0 0, 0.5 0.5 0.5, 1 1 1} color 0.5 0.5 0.5
field SFNode physics NULL
field MFNode{Solid{}, Pose{}} extensionSlot []
field MFNode{Solid{}+, Pose{}} extensionSlot []
]
```

In this example, the `color` field value can only be `0 0 0`, `0.5 0.5 0.5` or `1 1 1` and the `extensionSlot` field can only accept [Solid](../reference/solid.md) and [Pose](../reference/pose.md) nodes.
For `SFNode`/`MFNode` fields, the `<NodeType>{}+` syntax allows the field to also accept nodes which derive from a specific node type.

In this example, the `color` field value can only be `0 0 0`, `0.5 0.5 0.5` or `1 1 1`, and the `extensionSlot` field can only accept [Pose](pose.md) nodes, PROTOs whose base type is [Pose](pose.md), [Solid](solid.md) nodes, nodes derived from [Solid](solid.md), and PROTOs derived from [Solid](solid.md) or a type that inherits from [Solid](../reference/solid.md). Note that because `Pose{}` is not followed by a `+`, `extensionSlot` does not accept nodes that derive from [Pose](pose.md) (e.g. [Transform](transform.md) or [Fluid](fluid.md)) or PROTOs whose base type is not [Pose](pose.md).

Because [Solid](solid.md) derives from [Pose](pose.md), we could have allowed all the same node types by using `MFNode{Pose{}+}`, but this would also allow other descendants of [Pose](pose.md) such as [Transform](transform.md) or [Fluid](fluid.md).

### IS Statements

Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Accelerometer.wrl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# simulation. The acceleration is measured along the 3 axes (X, Y and Z) and is
# expressed in m/s^2. It is mostly used to measure the direction of the
# gravity, but can be used for many other purposes.
# parent: Solid

Accelerometer {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Altimeter.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The Altimeter node can be used to determine the global altitude of a robot or of a robot part.
# parent: Solid

Altimeter {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/BallJoint.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# A BallJoint node can be used to simulate a rotating motion with 3 DOF (ball and socket).
# parent: Hinge2Joint

BallJoint {
field SFNode jointParameters NULL # BallJointParameters specifying the joint anchor and spring and damper constants, minStop, maxStop related to the first axis
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/BallJointParameters.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The BallJointParamaters node defines the parameters of a BallJoint node.
# parent: JointParameters

BallJointParameters {
field SFFloat position 0 # current position (rad)
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Billboard.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# A Billboard node contains children nodes that rotate and translate automatically to face the viewpoint.
# It is otherwise similar to a Group node.
# parent: Group

Billboard {
#field that inherits from the Group node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Camera.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The Camera node is used to model an on-board camera.
# parent: Solid

Camera {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Charger.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The Charger node is used to model a special kind of battery charger for the robots.
# When a robot gets close to a Charger, the robot's battery gets recharged.
# parent: Solid

Charger {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Compass.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# A Compass node can be used to simulate 1, 2 and 3-axis digital compasses.
# It indicates the direction of the simulated magnetic north which is specified in the WorldInfo node.
# parent: Solid

Compass {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Connector.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Connector nodes are used to simulate mechanical docking systems, or any other type of device that
# can dynamically create a rigid link with a similar device.
# The physical connection between two Connectors can be created and destroyed at run time by the robot controller program.
# parent: Solid

Connector {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Display.wrl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# It can model an embedded screen or it can display any graphical
# information such as graphs, text, robot trajectory, filtered camera
# images and so on.
# parent: Solid

Display {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/DistanceSensor.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The DistanceSensor node can be used to model an ultrasound sonar, an infra-red sensor,
# a single-ray laser or any type of device that measures the distance to objects.
# To model a Lidar sensor, you should rather use a Lidar node.
# parent: Solid

DistanceSensor {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Emitter.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The Emitter node is used to model a radio, or infra-red emitter.
# It can be used to send data packets to Receiver nodes (onboard other robots).
# An Emitter cannot receive data: bidirectional communication requires two Emitter/Receiver pairs.
# parent: Solid

Emitter {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Fluid.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# A Fluid node can be used to represent a collection of fluid volumes where hydrostatic and hydrodynamic forces apply.
# parent: Pose

Fluid {
#fields that inherit from the Pose node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/GPS.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The GPS node can be used to determine the global position of a robot or of a robot part.
# parent: Solid

GPS {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Gyro.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# A Gyro node measures the angular velocity about 3 orthogonal axes (X, Y and Z).
# The output is in rad/s. The Gyro node is mostly used for balance control.
# parent: Solid

Gyro {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Hinge2Joint.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# A Hinge2Joint can be used to simulate a combination of two rotating motions along axes which intersect.
# It is equivalent to two HingeJoint nodes but it spares the creation of an intermediate solid and is therefore more stable.
# Spring and damping behavior can be specified.
# parent: HingeJoint

Hinge2Joint {
field SFNode jointParameters NULL # HingeJointParameters specifying anchor, axis, spring and damper constants, minStop, maxStop, suspension
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/HingeJointParameters.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# A HingeJointParameters defines the parameters of a HingeJoint node.
# parent: JointParameters

HingeJointParameters {
field SFFloat position 0 # current position (m or rad)
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/InertialUnit.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The InertialUnit node simulates an Inertial Measurement Unit (IMU).
# The InertialUnit node computes and returns the roll, pitch and yaw angles of the
# robot with respect to the global coordinate system defined in the WorldInfo node.
# parent: Solid

InertialUnit {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/LED.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The LED node can be used to model a light emitting diode (LED) that can be controlled by the robot.
# parent: Solid

LED {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Lidar.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The Lidar node is used to model an on-board lidar.
# A lidar is used to measure the distance to obstacles.
# parent: Solid

Lidar {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/LightSensor.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# A LightSensor node can be used to model a phototransistor, a photodiode or any type
# of device that measures the irradiance of light on its surface.
# A LightSensor node detects the light emitted by PointLight, SpotLight and DirectionalLight nodes.
# parent: Solid

LightSensor {
# fields inherited from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Microphone.wrl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# parent: Solid
Microphone {
# fields that inherit from the Solid node:
w3dField SFVec3f translation 0 0 0
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Pen.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# A Pen node can be used to model a pen attached to a mobile robot.
# It can draw the trajectory of the robot on a textured ground.
# parent: Solid

Pen {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Pose.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The Pose node is a grouping node that defines a coordinate system for its children that is
# relative to the coordinate system of its parent.
# parent: Group

Pose {
#fields specific to the AbstractPose node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/PositionSensor.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# A PositionSensor allows a robot controller to read the position of a joint with respect to its main axis.
# parent: Solid

PositionSensor {
field SFString name "position sensor" # used by wb_robot_get_device()
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Propeller.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The Propeller node is used to model a motorized helix propeller.
# It can be used to propel underwater robots, flying robots, floating robots or even wheeled robots.
# parent: Solid

Propeller {
field SFVec3f shaftAxis 1 0 0 # thrust direction (m)
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Radar.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The Radar node is used to model a radar device, commonly found in automobiles.
# parent: Solid

Radar {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Radio.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Experimental Radio node.
# parent: Solid

Radio {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/RangeFinder.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The RangeFinder node is used to model an on-board range finder.
# A range finder is used to measure the distance to obstacles.
# parent: Solid

RangeFinder {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Receiver.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# A Receiver node models a radio or infra-red receiver.
# It can be used to receive data packets emitted by Emitter nodes (onboard other robots).
# A Receiver cannot emit data: bidirectional communication requires two Emitter/Receiver pairs.
# parent: Solid

Receiver {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Robot.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The Robot node is a generic type of robot.
# parent: Solid

Robot {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Solid.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# A Solid node can be used to represent objects in the simulated environment (e.g. obstacles, walls, ground, robot parts, etc.).
# Solid nodes can be collision detected (boundingObject) and therefore can prevent objects from intersecting.
# In addition, Solid nodes can have an optional Physics node that allow them to be simulated with the physics engine.
# parent: Pose

Solid {
#fields that inherit from the Pose node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Speaker.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The Speaker node is used to model a loudspeaker device.
# It can be used to playback wav sound files as well as text-to-speech.
# The sounds are localized in the 3D space and rendered at the main viewpoint in stereo.
# parent: Solid

Speaker {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/TouchSensor.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# A TouchSensor can be used to measure contact force ("force", "force-3d") or simply detect collisions ("bumper").
# It is critical that 'boundingObject' of a TouchSensor is defined and placed appropriately.
# Refer to the Webots reference manual for more information on this.
# parent: Solid

TouchSensor { #models a bumper, button, cat whisker, force sensor etc.
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Track.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The Track node can be used to simulate tracks of tank robots or conveyor belts.
# parent: Solid

Track {
#fields that inherit from the Solid node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/TrackWheel.wrl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# A TrackWheel node can be used to simulate a wheel that it is part of a track system.
# parent: Group

TrackWheel {
#fields specific to the TrackWheel node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/Transform.wrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The Transform node is a grouping node that defines a coordinate system for its children that is
# relative to the coordinate system of its parent.
# The 'scale' field of a Transform node can be adjusted only in a graphical context and not in a 'boundingObject' context.
# parent: Pose

Transform {
#fields specific to the AbstractTransform node:
Expand Down
1 change: 1 addition & 0 deletions resources/nodes/VacuumGripper.wrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# VacuumGripper nodes are used to simulate vacuum suction systems.
# The physical connection with a Solid can be created and destroyed at run time by the robot controller program.
# parent: Solid

VacuumGripper {
#fields that inherit from the Solid node:
Expand Down
3 changes: 3 additions & 0 deletions scripts/packaging/generate_proto_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def __init__(self, path, name):
self.path = path.replace('\\', '/') # use cross-platform forward slashes
self.proto_type = None # direct node type, ex: for RoadSegment is Road
self.base_type = None # lowest node type, ex: for RoadSegment is Solid
self.parents = [] # all proto types this type extends, ex: for Road Segment is [Road]
self.license = None
self.license_url = None
self.description = ''
Expand Down Expand Up @@ -154,6 +155,7 @@ def generate_proto_list(current_tag=None, silent=False):
if info.base_type not in protos: # the current proto depends on a sub-proto: iterate until a base node is reached
raise RuntimeError(f'Error: "{info.base_type}" proto node does not exist. Either it was skipped or the regex '
'that retrieves the proto_type is incorrect.')
info.parents.append(info.base_type)
sub_proto = protos[info.base_type]
info.base_type = sub_proto.proto_type

Expand Down Expand Up @@ -201,6 +203,7 @@ def generate_proto_list(current_tag=None, silent=False):
proto_element = ET.SubElement(root, 'proto')
ET.SubElement(proto_element, 'name').text = info.name
ET.SubElement(proto_element, 'base-type').text = info.base_type
ET.SubElement(proto_element, 'parents').text = ','.join(info.parents)
ET.SubElement(proto_element, 'url').text = info.path.replace(WEBOTS_HOME + '/', prefix)

if info.license is not None:
Expand Down
1 change: 1 addition & 0 deletions src/webots/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ QT_SOURCES = WbAboutBox.cpp \
WbFieldIntSpinBox.cpp \
WbFieldLineEdit.cpp \
WbFindReplaceDialog.cpp \
WbFieldValueRestriction.cpp \
WbFluid.cpp \
WbFocus.cpp \
WbFog.cpp \
Expand Down
18 changes: 7 additions & 11 deletions src/webots/nodes/utils/WbDictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ bool WbDictionary::updateDef(WbBaseNode *&node, WbSFNode *sfNode, WbMFNode *mfNo
definitionNode = static_cast<WbBaseNode *>(defNodes[defIndex]);
QString error;
assert(node->parentField() && node->parentNode());
typeMatch = WbNodeUtilities::isAllowedToInsert(node->parentField(), definitionNode->nodeModelName(), node->parentNode(),
error, nodeUse, QString(), QStringList(definitionNode->nodeModelName()));
typeMatch = WbNodeUtilities::isAllowedToInsert(node->parentField(), node->parentNode(), error, nodeUse, QString(),
definitionNode);
match = typeMatch && !definitionNode->isAnAncestorOf(node);
}

Expand All @@ -137,9 +137,8 @@ bool WbDictionary::updateDef(WbBaseNode *&node, WbSFNode *sfNode, WbMFNode *mfNo
definitionNode = static_cast<WbBaseNode *>(matchingNode->defNode());
QString error;
assert(node->parentField() && node->parentNode());
typeMatch =
WbNodeUtilities::isAllowedToInsert(node->parentField(), definitionNode->nodeModelName(), node->parentNode(), error,
nodeUse, QString(), QStringList(definitionNode->nodeModelName()));
typeMatch = WbNodeUtilities::isAllowedToInsert(node->parentField(), node->parentNode(), error, nodeUse, QString(),
definitionNode);
}
}

Expand Down Expand Up @@ -464,8 +463,7 @@ bool WbDictionary::checkBoundingObjectConstraints(const WbBaseNode *defNode, QSt
if (sfnode) {
const WbNode *const n = sfnode->value();
if (n) {
if (!WbNodeUtilities::isAllowedToInsert(fields[i], n->nodeModelName(), parentNode, errorMessage, nodeUse, QString(),
QStringList(n->nodeModelName()), false))
if (!WbNodeUtilities::isAllowedToInsert(fields[i], parentNode, errorMessage, nodeUse, QString(), n, false))
return false;
subNodes << n;
}
Expand All @@ -476,8 +474,7 @@ bool WbDictionary::checkBoundingObjectConstraints(const WbBaseNode *defNode, QSt
for (int j = 0; j < size; ++j) {
const WbNode *const n = mfnode->item(j);
if (n) {
if (!WbNodeUtilities::isAllowedToInsert(fields[i], n->nodeModelName(), parentNode, errorMessage, nodeUse,
QString(), QStringList(n->nodeModelName()), false))
if (!WbNodeUtilities::isAllowedToInsert(fields[i], parentNode, errorMessage, nodeUse, QString(), n, false))
return false;

subNodes << n;
Expand Down Expand Up @@ -535,8 +532,7 @@ bool WbDictionary::isSuitable(const WbNode *defNode, const QString &type) const
assert(mTargetField);
QString errorMessage;
const WbNode::NodeUse targetNodeUse = static_cast<WbBaseNode *>(mTargetNode)->nodeUse();
if (!WbNodeUtilities::isAllowedToInsert(mTargetField, defNode->nodeModelName(), mTargetNode, errorMessage, targetNodeUse,
type, QStringList(defNode->nodeModelName()), true))
if (!WbNodeUtilities::isAllowedToInsert(mTargetField, mTargetNode, errorMessage, targetNodeUse, type, defNode, true))
return false;

const WbBaseNode *defBaseNode = dynamic_cast<const WbBaseNode *>(defNode);
Expand Down
5 changes: 2 additions & 3 deletions src/webots/nodes/utils/WbNodeOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,8 @@ WbNodeOperations::OperationResult WbNodeOperations::importNode(WbNode *parentNod
foreach (WbNode *node, nodes) {
childNode = static_cast<WbBaseNode *>(node);
QString errorMessage;
if (WbNodeUtilities::isAllowedToInsert(field, childNode->nodeModelName(), parentNode, errorMessage, nodeUse,
WbNodeUtilities::slotType(childNode),
QStringList() << childNode->nodeModelName() << childNode->modelName(), false)) {
if (WbNodeUtilities::isAllowedToInsert(field, parentNode, errorMessage, nodeUse, WbNodeUtilities::slotType(childNode),
childNode, false)) {
if (avoidIntersections)
tryToAvoidIntersections(childNode);
const OperationResult result = initNewNode(childNode, parentNode, field, nodeIndex, true);
Expand Down
Loading

0 comments on commit 7ddffc6

Please sign in to comment.