use of com.ait.lienzo.client.core.shape.MultiPath in project lienzo-core by ahome-it.
the class ShapeControlUtils method checkForAndApplyLineSplice.
public static boolean checkForAndApplyLineSplice(final WiresManager wiresManager, final WiresShape shape) {
if (!wiresManager.isSpliceEnabled() || (shape.getMagnets() == null)) {
// cannot connect to a shape with no magnets.
return true;
}
boolean accept = true;
for (final WiresConnector c : wiresManager.getConnectorList()) {
final Point2DArray linePoints = ((OrthogonalPolyLine) c.getLine()).getComputedPoint2DArray();
final MultiPath path = shape.getPath();
Point2DArray intersectPoints = null;
final Point2D absLoc = path.getComputedLocation();
intersectPoints = getIntersections(linePoints, path, intersectPoints, absLoc);
if (((c.getHeadConnection().getMagnet() != null) && (c.getHeadConnection().getMagnet().getMagnets().getWiresShape() == shape)) || ((c.getTailConnection().getMagnet() != null) && (c.getTailConnection().getMagnet().getMagnets().getWiresShape() == shape))) {
// don't split yourself
return accept;
}
if (intersectPoints != null) {
final WiresConnection headCon = c.getHeadConnection();
final WiresConnection tailCon = c.getTailConnection();
if (intersectPoints.size() == 1) {
// one arrow end is enclosed in the shape, we can only splice/connect if that connection is not already connected.
final BoundingBox bbox = shape.getContainer().getComputedBoundingPoints().getBoundingBox();
if (bbox.contains(headCon.getPoint()) && (headCon.getMagnet() != null)) {
return accept;
} else if (bbox.contains(tailCon.getPoint()) && (headCon.getMagnet() != null)) {
return accept;
} else {
throw new RuntimeException("Defensive programming: should not be possible if there is a single intersection.");
}
}
c.getWiresConnectorHandler().getControl().hideControlPoints();
final Point2DArray oldPoints = c.getLine().getPoint2DArray();
int firstSegmentIndex = Integer.MAX_VALUE;
int lastSegmentIndex = 0;
for (final Point2D p : intersectPoints) {
final double x = p.getX() + absLoc.getX();
final double y = p.getY() + absLoc.getY();
// get first and last segment, this can happen if shape straddles multiple segments of the line
final int pointIndex = WiresConnectorControlImpl.getIndexForSelectedSegment(c, (int) x, (int) y, oldPoints);
if (pointIndex < firstSegmentIndex) {
firstSegmentIndex = pointIndex;
}
if (pointIndex > lastSegmentIndex) {
lastSegmentIndex = pointIndex;
}
}
WiresConnector c2 = null;
// record these, as they may need restoring later.
double tailXOffset = 0;
double tailYOffset = 0;
boolean tailAutoConnection = false;
Point2D tailPoint = null;
WiresMagnet tailMagnet = null;
if (tailCon != null) {
tailXOffset = tailCon.getXOffset();
tailYOffset = tailCon.getYOffset();
tailAutoConnection = tailCon.isAutoConnection();
tailMagnet = tailCon.getMagnet();
tailPoint = tailCon.getPoint();
}
if (firstSegmentIndex > 0) {
final Point2DArray newPoints1 = new Point2DArray();
final Point2DArray newPoints2 = new Point2DArray();
newPoints1.push(oldPoints.get(0));
for (int i = 1; i < firstSegmentIndex; i++) {
newPoints1.push(oldPoints.get(i));
}
final WiresMagnet cmagnet = shape.getMagnets().getMagnet(1);
// check if isAllowed
WiresConnectionControlImpl.allowedMagnetAndUpdateAutoConnections(headCon, true, shape, cmagnet, false);
accept = accept && WiresConnectionControlImpl.allowedMagnetAndUpdateAutoConnections(tailCon, false, shape, cmagnet, false);
if (!accept) {
return accept;
}
if (intersectPoints.size() > 1) {
final Point2D startPoint = new Point2D(cmagnet.getControl().getX(), cmagnet.getControl().getY());
newPoints2.push(startPoint);
// will skip any segments between first and last. this happens if a shape straddles multiple segments.
for (int i = lastSegmentIndex; i < oldPoints.size(); i++) {
newPoints2.push(oldPoints.get(i));
}
final AbstractDirectionalMultiPointShape<?> line = c.getLine().copy();
line.setPoint2DArray(newPoints2);
c2 = new WiresConnector(line, c.getHeadDecorator().copy(), c.getTailDecorator().copy());
wiresManager.register(c2);
final WiresConnection headCon2 = c2.getHeadConnection();
headCon2.setAutoConnection(true);
// reset, if not already 0
headCon2.setXOffset(0);
headCon2.setYOffset(0);
final WiresConnection tailCon2 = c2.getTailConnection();
// preserve tail auto connection
tailCon2.setAutoConnection(tailCon.isAutoConnection());
tailCon2.setMagnet(tailCon.getMagnet());
// reset, if not already 0
tailCon2.setXOffset(tailCon.getXOffset());
tailCon2.setYOffset(tailCon.getYOffset());
tailCon2.setPoint(tailCon.getPoint());
accept = accept && WiresConnectionControlImpl.allowedMagnetAndUpdateAutoConnections(headCon2, true, shape, cmagnet, true);
if (!accept) {
// we already checked isAllowed before mutation, so this in theory should not be needed. Adding for future proofing and completeness - in
// case a future version doesn't require identical behavioural logic for allowed and accept.
tailCon2.setMagnet(null);
wiresManager.deregister(c2);
return accept;
}
}
// this is done after the potential newPoitns2, as it reads values from the original connector.
final Point2D endPoint = new Point2D(cmagnet.getControl().getX(), cmagnet.getControl().getY());
newPoints1.push(endPoint);
tailCon.setAutoConnection(true);
// reset, if not already 0
tailCon.setXOffset(0);
tailCon.setYOffset(0);
tailCon.setPoint(endPoint);
c.getLine().setPoint2DArray(newPoints1);
accept = accept && WiresConnectionControlImpl.allowedMagnetAndUpdateAutoConnections(tailCon, false, shape, cmagnet, true);
if (!accept) {
// case a future version doesn't require identical behavioural logic for allowed and accept.
if (c2 != null) {
c2.getTailConnection().setMagnet(null);
c2.getHeadConnection().setMagnet(null);
wiresManager.deregister(c2);
}
tailCon.setAutoConnection(tailAutoConnection);
// reset, if not already 0
tailCon.setXOffset(tailXOffset);
tailCon.setYOffset(tailYOffset);
tailCon.setMagnet(tailMagnet);
tailCon.setPoint(tailPoint);
return accept;
}
}
}
}
return accept;
}
use of com.ait.lienzo.client.core.shape.MultiPath in project lienzo-core by ahome-it.
the class SelectionManager method getItemsInBoundingBox.
public void getItemsInBoundingBox(final BoundingBox selectionBox) {
m_selected.setSelectionGroup(true);
final BoundingBox box = m_selected.getBoundingBox();
BoundingBox nodeBox = null;
final List<WiresShape> shapesList = new ArrayList<>();
final List<WiresShape> toBeRemoved = new ArrayList<>();
final Map<String, WiresShape> shapesMap = new HashMap<>();
final Map<String, BoundingBox> uuidMap = new HashMap<>();
// first build a map of all shapes that intersect with teh selection rectangle. Nested shapes will be used later.
for (final WiresShape shape : m_wiresManager.getShapesMap().values()) {
if (shape.getDockedTo() != null) {
// docked items cannot be added to a selection, only their parent they are docked to
continue;
}
nodeBox = shape.getContainer().getComputedBoundingPoints().getBoundingBox();
if (selectionBox.intersects(nodeBox)) {
shapesList.add(shape);
shapesMap.put(shape.getContainer().uuid(), shape);
uuidMap.put(shape.getContainer().uuid(), nodeBox);
}
}
// add to removal list any shape whose parent is also in the selection
for (final WiresShape shape : shapesMap.values()) {
if ((null != shape.getParent()) && shapesMap.containsKey(shape.getParent().getContainer().uuid())) {
// can't remove yet, as it may have selected children itself, which will also need to be removed
toBeRemoved.add(shape);
}
}
// now the list is built, safely remove the shapes
for (final WiresShape shape : toBeRemoved) {
shapesMap.remove(shape.getContainer().uuid());
}
for (final WiresShape shape : shapesMap.values()) {
nodeBox = uuidMap.get(shape.getContainer().uuid());
m_selected.add(shape);
box.add(nodeBox);
}
for (final WiresConnector connector : m_wiresManager.getConnectorList()) {
final boolean externallyConnected = isExternallyConnected(connector);
final Point2DArray points = new Point2DArray();
final Point2D loc = getSelectionShape().getLocation();
final BoundingBox boundingBox = getSelectionShape().getBoundingBox();
points.push(loc.getX(), loc.getY());
points.push(loc.getX() + boundingBox.getWidth(), loc.getY());
points.push(loc.getX() + boundingBox.getWidth(), loc.getY() + boundingBox.getHeight());
points.push(loc.getX(), loc.getY() + boundingBox.getHeight());
nodeBox = connector.getGroup().getComputedBoundingPoints().getBoundingBox();
if (selectionBox.contains(nodeBox)) {
addConnector(connector, externallyConnected, box, nodeBox);
} else {
Point2DArray intersections = Geometry.getIntersectPolyLinePath(points, connector.getLine().getPathPartList(), true);
if ((intersections != null) && (intersections.size() > 0)) {
addConnector(connector, externallyConnected, box, nodeBox);
} else {
// the above checked the line, also check the head and tail.
// head is rotated around an offset with also set. The reverse of this must be applied to the
// selection rectangle, to ensure thinsg are all in the same space, for intersection to work
MultiPath path = connector.getHead();
Transform xfrm = new Transform();
xfrm.translate(path.getOffset().getX(), path.getOffset().getY());
xfrm.rotate(0 - path.getRotation());
xfrm.translate(0 - path.getX(), 0 - path.getY());
xfrm.translate(0 - path.getOffset().getX(), 0 - path.getOffset().getY());
Point2DArray transformedPoints = points.copy();
for (final Point2D p : transformedPoints) {
xfrm.transform(p, p);
}
intersections = Geometry.getIntersectPolyLinePath(transformedPoints, connector.getHead().getActualPathPartListArray().get(0), true);
if ((intersections != null) && (intersections.size() > 0)) {
addConnector(connector, externallyConnected, box, nodeBox);
} else {
// tail is rotated around an offset with also set. The reverse of this must be applied to the
// selection rectangle, to ensure thinsg are all in the same space, for intersection to work
path = connector.getTail();
xfrm = new Transform();
xfrm.translate(path.getOffset().getX(), path.getOffset().getY());
xfrm.rotate(0 - path.getRotation());
xfrm.translate(0 - path.getX(), 0 - path.getY());
xfrm.translate(0 - path.getOffset().getX(), 0 - path.getOffset().getY());
transformedPoints = points.copy();
for (final Point2D p : transformedPoints) {
xfrm.transform(p, p);
}
intersections = Geometry.getIntersectPolyLinePath(transformedPoints, connector.getTail().getActualPathPartListArray().get(0), true);
if ((intersections != null) && (intersections.size() > 0)) {
addConnector(connector, externallyConnected, box, nodeBox);
}
}
}
}
}
}
use of com.ait.lienzo.client.core.shape.MultiPath in project kie-wb-common by kiegroup.
the class WiresConnectorViewExtTest method setup.
@Before
@SuppressWarnings("unchecked")
public void setup() throws Exception {
HEAD_DECORATOR = new MultiPathDecorator(new MultiPath().rect(0, 0, 10, 10));
TAIL_DECORATOR = new MultiPathDecorator(new MultiPath().rect(0, 0, 10, 10));
POINTS = new Point2DArray(new Point2D(0, 10), new Point2D(10, 10), new Point2D(20, 20), new Point2D(30, 30), new Point2D(40, 40));
line = new PolyLine(POINTS);
layer = spy(new Layer());
doAnswer(invocation -> {
((Consumer) invocation.getArguments()[0]).accept(labelText);
return label;
}).when(label).configure(any(Consumer.class));
tested = spy(new WiresConnectorViewExt(ShapeViewSupportedEvents.DESKTOP_CONNECTOR_EVENT_TYPES, line, HEAD_DECORATOR, TAIL_DECORATOR) {
@Override
protected Optional<WiresConnectorLabel> createLabel(String title) {
return Optional.of(WiresConnectorViewExtTest.this.label);
}
});
tested.setControl(connectorControl);
layer.add(tested.getGroup());
}
use of com.ait.lienzo.client.core.shape.MultiPath in project kie-wb-common by kiegroup.
the class AbstractConnectorView method createLine.
static Object[] createLine(LineConnectorFactory lineFactory, ConnectorShapeDef.Direction direction, final double... points) {
// The head decorator must be not visible, as connectors are unidirectional.
final MultiPath head = BOTH.equals(direction) ? getArrowMultiPath() : new MultiPath();
final MultiPath tail = BOTH.equals(direction) || ONE.equals(direction) ? getArrowMultiPath() : new MultiPath();
final AbstractDirectionalMultiPointShape<?> line = lineFactory.createLine(Point2DArray.fromArrayOfDouble(points));
line.setDraggable(true);
line.setSelectionStrokeOffset(SELECTION_OFFSET);
line.setHeadOffset(head.getBoundingBox().getHeight());
line.setTailOffset(tail.getBoundingBox().getHeight());
final MultiPathDecorator headDecorator = new MultiPathDecorator(head);
final MultiPathDecorator tailDecorator = new MultiPathDecorator(tail);
return new Object[] { line, headDecorator, tailDecorator };
}
use of com.ait.lienzo.client.core.shape.MultiPath in project kie-wb-common by kiegroup.
the class AuthorityRequirementView method createLine.
private static Object[] createLine(final double x1, final double y1, final double x2, final double y2) {
final MultiPath head = new MultiPath();
final MultiPath tail = new MultiPath().M(DECORATOR_RADIUS, -DECORATOR_RADIUS).circle(DECORATOR_RADIUS).setFillColor(ColorName.BLACK).setFillAlpha(1);
final DirectionalLine line = new DirectionalLine(x1, y1, x2, y2);
line.setDashArray(new DashArray(4, 4));
line.setDraggable(true);
line.setSelectionStrokeOffset(SELECTION_OFFSET);
line.setHeadOffset(head.getBoundingBox().getHeight());
line.setTailOffset(tail.getBoundingBox().getHeight());
final MultiPathDecorator headDecorator = new MultiPathDecorator(head);
final MultiPathDecorator tailDecorator = new MultiPathDecorator(tail);
return new Object[] { line, headDecorator, tailDecorator };
}
Aggregations