Looking for help. I need to check if one node (in my case it's Line
) is inside another node (can be different shapes). In my case, I need to check if the Red Line
is inside Blue Node
.
My attempt: https://codesandbox.io/s/infallible-wing-xmy2pi
My goal is to check whether a separate node (in my case -> the Red Line
) is COMPLETELY inside (over) the Blue Node
. They are both separate nodes (Red Line
is not a child of the Blue Box
and vice versa).
The Blue Node
can be different shapes. Note that I can't check if only the first and last point of the Red Line
is inside the Blue Node
(see the image -> it should fail in such case because Red Line
is NOT completely over the Blue Node
).
TLDR: Solution in snippet below and at https://codepen.io/JEE42/pen/QWZEKYw. Dear the blue line around so it overlaps / is inside / is outside the polygon and click the 'test button.
Assuming that you know the x,y points of the polygon vertices:
Test #1 - does the line cross any edge?
If you think of the polygon edges as being a series of individual lines then you can tackle the first question via the line-line intersection test. There are plenty of solutions on the web, for example see solution for that at Jeffery Thompson.
So what you do is test each edge for collision with the line. Any collision means the line is not fully contained.
Test #2 - is the line inside or outside the shape?
We can use Konva's Shape.intersects(point) for this. Since we confirmed in test #1 that the line is either entirely inside or entirely outside the polygon, we can pick any point on the line and call shape.intersects(point) once - if the answer is false then the entire line is outside the polygon, if the answer is true then the line is entirely inside.
And here is the code from the solution
const stage = new Konva.Stage({
container: "container",
width: 1000,
height: 800,
draggable: true
}),
layer = new Konva.Layer({
draggable: false
}),
poly = new Konva.Line({
x: 100,
y: 100,
points: [23, 20, 23, 160, 70, 93, 150, 109, 290, 139, 270, 93],
stroke: 'black',
strokeWidth: 5,
closed: true,
draggable: true
}),
line = new Konva.Line({
x: 130, y: 140,
points: [0, 0, 100, 50],
stroke: 'blue',
strokeWidth: 8,
draggable: true
})
layer.add(poly, line);
stage.add(layer);
function test(line, polygon){
let hit = false;
// clear collsion marker
const circles = layer.find('.demoPt');
if (circles.length > 0){
for (const circle of circles){
circle.destroy()
}
}
// get the end-of-line points
const e1 = {
x: line.x() + line.points()[0],
y: line.y() + line.points()[1],
}
const e2 = {
x: line.x() + line.points()[2],
y: line.y() + line.points()[3],
}
// Process each edge of the polygon as a line
for (let i = 0; i < polygon.points().length; i = i + 2){
// get the line point
const v1 = {
x: poly.x() + polygon.points()[i],
y: poly.y() + polygon.points()[i + 1],
}
// for the other end we need the first point if we are on the last point
let v2
if (i === polygon.points().length - 2){
v2 = {
x: poly.x() + polygon.points()[0],
y: poly.y() + polygon.points()[1],
}
}
else {
v2 = {
x: poly.x() + polygon.points()[i+2],
y: poly.y() + polygon.points()[i + 3],
}
}
// Now run the line intersection check
const result = lineIntersection(v1.x, v1.y, v2.x, v2.y, e1.x, e1.y, e2.x, e2.y)
if (result){
// If we have a result then then lines DO interset -- add a circle to indicate
const c1 = new Konva.Circle({
name: 'demoPt',
x: result.x,
y: result.y,
fill: 'cyan',
radius: 10
})
layer.add(c1)
}
else {
// if we get to here then there are no line collisions.
// So check if line is outside of polygon
// we already know one end point of line in e1.
hit = polygon.intersects(e1)
// show the result
}
$('#result').html('line inside shape = ' + hit)
}
}
$('#test').on('click', function(){
test(line, poly)
})
function lineIntersection(x1, y1, x2, y2, x3, y3, x4, y4) {
// calculate the distance to intersection point
let denom = ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1))
let uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / denom;
let uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / denom;
// if uA and uB are between 0-1, lines are colliding
if (uA < 0 || uA > 1 || uB < 0 || uB > 1){
return null;
}
return {
x: x1 + (uA * (x2-x1)),
y: y1 + (uA * (y2-y1))};
}
body {
margin: 10px;
overflow: hidden;
background-color: #f0f0f0;
}
#container {
width: 1000px;
height: 1000px;
}
span {
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva@8/konva.min.js"></script>
<p id='info'>
<button id='test'>Test</button> <span id='result'>Is the line inside the shape?</span>
</p>
<div id="container" class='container'>