/** * Initialize an Action that move the cell of a given space delta, which can be expressed in percent of the cell's diameter or in absolute. * If the cell has diameter 0, the only way to express delta is absolute. * There's no way to decide the direction of the cell by this {@link Action}. This is inferred by the polarization vector contained in the cell. * * @param environment the {@link Environment} * @param node the {@link Node} in which the {@link Action} is contained. This can be only a CellNode. * @param inPercent a boolean parameter which set the way of expressing delta: if is true the cell movement will be (delta * cellDiameter), otherwise will be simply delta. If cellDiameter is zero, this {@link Action} will in both cases behave like inPercent == false. * @param delta the distance at which the cell will be moved. */ public CellMove(final Environment<Double> environment, final Node<Double> node, final boolean inPercent, final double delta) { super(environment, node); this.inPer = inPercent; if (node instanceof CellNode) { if (inPercent) { if (node instanceof CellWithCircularArea && ((CellWithCircularArea) node).getRadius() != 0) { this.delta = ((CellWithCircularArea) node).getDiameter() * delta; } else { throw new IllegalArgumentException("Can't set distance in percent of the cell's diameter if cell has not a diameter"); } } else { this.delta = delta; } } else { throw new UnsupportedOperationException("CellMove can be setted only in cells."); } }
@Override public boolean isValid() { final CircularDeformableCell thisNode = (CircularDeformableCell) getNode(); return env.getNodesWithinRange(thisNode, env.getMaxDiameterAmongCircularDeformableCells()).stream() .parallel() .flatMap(n -> n instanceof CellWithCircularArea ? Stream.of((CellWithCircularArea) n) : Stream.empty()) .filter(n -> { final double maxDN = thisNode.getMaxRadius(); if (n instanceof CircularDeformableCell) { return env.getDistanceBetweenNodes(n, thisNode) < (maxDN + ((CircularDeformableCell) n).getMaxRadius()); } else { return env.getDistanceBetweenNodes(n, thisNode) < (maxDN + n.getRadius()); } }) .findAny() .isPresent(); }
private double getDiameterFromCell(final Optional<? extends CellWithCircularArea> biggest) { return biggest .transform(n -> n instanceof CircularDeformableCell ? ((CircularDeformableCell) n).getMaxDiameter() : n.getDiameter()) .or(0d); } }
minRn = cell.getRadius(); } else { maxRn = n.getRadius(); minRn = maxRn;
@Override protected void nodeAdded(final Node<Double> node, final Position position, final Neighborhood<Double> neighborhood) { super.nodeAdded(node, position, neighborhood); if (node instanceof CellWithCircularArea) { final CellWithCircularArea cell = (CellWithCircularArea) node; if (cell.getDiameter() > getMaxDiameterAmongCellWithCircularShape()) { biggestCellWithCircularArea = Optional.of(cell); } } if (node instanceof CircularDeformableCell) { final CircularDeformableCell cell = (CircularDeformableCell) node; if (cell.getMaxDiameter() > getMaxDiameterAmongCircularDeformableCells()) { biggestCircularDeformableCell = Optional.of(cell); } } }
@Override protected boolean nodeShouldBeAdded(final Node<Double> node, final Position p) { final boolean isWithinLimits = super.nodeShouldBeAdded(node, p); if (isWithinLimits) { if (node instanceof CellWithCircularArea) { final CellWithCircularArea thisNode = (CellWithCircularArea) node; double range = getMaxDiameterAmongCellWithCircularShape(); if (thisNode.getDiameter() > range) { range = thisNode.getDiameter(); } final double nodeRadius = thisNode.getRadius(); return isWithinLimits && (range <= 0 || !getNodesWithinRange(p, range).stream() .filter(n -> n instanceof CellWithCircularArea) .map(n -> (CellWithCircularArea) n) .filter(n -> getPosition(n).getDistanceTo(p) < nodeRadius + n.getRadius()) .findFirst() .isPresent()); } else { return true; } } else { return false; } }
return requestedPos; final double distanceToScan = distanceToReq + nodeToMove.getRadius() + (maxDiameter / 2); final double halfDistance = (distanceToScan / 2); .parallel() .filter(n -> n instanceof CellWithCircularArea) .mapToDouble(n -> ((CellWithCircularArea) n).getDiameter()) .max() .orElse(0); final double newDistanceToScan = distanceToReq + nodeToMove.getRadius() + newMaxDiameter / 2; final double newHalfDistance = newDistanceToScan / 2; final Position vecToMid2 = new Continuous2DEuclidean(xVer * newHalfDistance, yVer * newHalfDistance);
private boolean selectNodes(final CellWithCircularArea node, final CellWithCircularArea nodeToMove, final Position origin, final Position requestedPos, final double xVer, final double yVer) { // testing if node is between requested position and original position final Position nodePos = getPosition(node); final Position nodeOrientationFromOrigin = new Continuous2DEuclidean(nodePos.getCoordinate(0) - origin.getCoordinate(0), nodePos.getCoordinate(1) - origin.getCoordinate(1)); final double scalarProductResult1 = xVer * nodeOrientationFromOrigin.getCoordinate(0) + yVer * nodeOrientationFromOrigin.getCoordinate(1); // testing if node is near enough to requested position to be an obstacle final Position oppositeVersor = new Continuous2DEuclidean(-xVer, -yVer); final Position nodeOrientationFromReq = new Continuous2DEuclidean(nodePos.getCoordinate(0) - requestedPos.getCoordinate(0), nodePos.getCoordinate(1) - requestedPos.getCoordinate(1)); final double scalarProductResult2 = oppositeVersor.getCoordinate(0) * nodeOrientationFromReq.getCoordinate(0) + oppositeVersor.getCoordinate(1) * nodeOrientationFromReq.getCoordinate(1); if (scalarProductResult2 <= 0) { return (nodePos.getDistanceTo(requestedPos) < node.getRadius() + nodeToMove.getRadius()) && scalarProductResult1 >= 0; } return scalarProductResult1 >= 0; }