Remove the point outside of draw plane

Hello, everybody

I have worked on this topic for a while, now I have the last question (I hope) …
I tried to use the following function to determin whether the points are in the polygon,

function pointIsInPoly(p, polygon) {
        var isInside = false;
        var minX = polygon[0].x,
            maxX = polygon[0].x;
        var minY = polygon[0].y,
            maxY = polygon[0].y;
        for (var n = 1; n < polygon.length; n++) {
            var q = polygon[n];
            minX = Math.min(q.x, minX);
            maxX = Math.max(q.x, maxX);
            minY = Math.min(q.y, minY);
            maxY = Math.max(q.y, maxY);
        }

        if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) {
            return false;
        }

        var i = 0,
            j = polygon.length - 1;
        for (i, j; i < polygon.length; j = i++) {
            if ((polygon[i].y > p.y) != (polygon[j].y > p.y) &&
                p.x < (polygon[j].x - polygon[i].x) * (p.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x) {
                isInside = !isInside;
            }
        }

        return isInside;
    }

but the points in the polygon count is 0, therefore I would like to ask whether there is a way in three.js that I can determin the plane and point overlap, if overlap then keep, rest of points can be remove.

image

Thanks and hope someone can kindly guide me.

What exactly do you mean by overlap? (Taking into consideration it’s a 3D space.)

on the visual perspective, I would like to only high-light the points within the white plane region.

In that case you should be able to just raycast the point against the polygon:

const raycaster = new Raycaster();

const isWithinPolygon = (camera, point, polygon) => {
  raycaster.setFromCamera(camera, point);

  return raycaster.intersectObject(polygon, true).length > 0;
};
  1. If you have a lot of points, regardless of how you’d try to determine whether they are within the polygon or not, consider bundling them up by distance (so if one point from that specific region is visible - assume all points within some range around it are also visible. It’ll limit the amount of raycasting / calculations.

  2. Unlike the bounding box calculations with min/max values - when using the raycaster you can also test points against shapes more complex than just a plane, since raycaster does see polygons and faces.

Thanks for your replay! This is exactly what I need I think, but just don’t know why there is no any point intersect.

The parameter point I give a vector2, the camera is gave current using camera(PerspectiveCamera), the ploygon is the plane

var point = new THREE.Vector2(dot.x, dot.y);
var selected_plane = geneScene.scene.getObjectByName("selectionPlane");

function isPointwithinPolygon(point, camera, selected_plane ){
        raycaster_p.setFromCamera(point, camera);
        return raycaster_p.intersectObject(selected_plane , true).length > 0;
    }

do I miss anything?

My bad - setFromCamera does indeed only work with Vector2. Use Raycaster.set instead:

raycaster.set(point, camera.position); // NOTE Make sure point is a Vector3 here

If there’s still no intersections, you can increase raycaster.near / raycaster.far values - they work the same as they do for cameras.

1 Like

Thank you for so helpful guidance. I think getting closer and closer.
I don’t get any intersections after using .set, but I trying something based on your tips.

Please correct me if this thinking is incorrect.
I am trying to that the ray direction, such as

raycaster_p.set(point, new THREE.Vector3(0, 0, 5))
raycaster_p.set(point, new THREE.Vector3(0, 0, 3))
raycaster_p.set(point, new THREE.Vector3(0, 0, 1))

I am not sure whether my thinking is correct since the plane is on top of the points(z value is greater than point’s z), so could be making ray direction to positive till intersected the plan from the point position.

This is how the plan and points located, look from side

  1. Make sure the plane is visible from the direction you’re casting the ray from (or just set DoubleSide for the plane material.)
  2. If the points aren’t around centre of the scene that camera.position was indeed likely not the best idea. You can calculate the direction from point to camera by just subtracting their positions and normalising the result:
// NOTE Camera-to-Point Ray
const direction = new THREE.Vector3();
direction.copy(camera.position).sub(point).normalize();

raycaster.set(point, direction);

// NOTE Or alternatively Point-to-Camera ray:
const direction = new THREE.Vector3();
direction.copy(point).sub(camera.position).normalize();

raycaster.set(camera.position, direction);
  1. If the points are nested within Groups (or just aren’t direct scene children / don’t use world coordinates), be sure to first convert all raycasted values to world-space using either Object3D.getWorldPosition or Object3D.localToWorld.

Here’s a small demo with plane + sphere.

1 Like

Yes, I am sure the plane is visible status.
The polygon I use for detecting intersection is not in a group.

function isPointwithinPolygon(point, camera, polygon) {
        //2D
        //raycaster_p.setFromCamera(point, camera);
        //raycaster_p.set(point, camera.position);

        //3D
        const direction = new THREE.Vector3();
        direction.copy(camera.position).sub(point).normalize();

        raycaster_p.set(camera.position, direction);
        return raycaster_p.intersectObject(polygon).length > 0;
    }

I would like to clarify my understanding, please kindly correct me if it is wrong

for this statement,
direction.copy(camera.position).sub(point).normalize();
Do I understand correctly that the statement is to set up the direction from point to camera position which should be included with plane in between? If this is correct, I don’t understand why I don’t get any intersection length

My purpose of this implementation is to remove those points that are not included selection area, I would like to exclude them in the array.

Use the arrow keys on keyboard to move the dot.
_P_In_Polygon.html (2.9 KB)

Function p_in_poly(p) returns 1 if p is within and 0 for not.

1 Like

Thank you for providing the solution, I will switch to 2D in order to achieve my task, so the page you provide is definitely helpful!

I draw lines according to the points cover by frustum, and then using vector3 direction as you guided me to determine whether the line and plane are intersected, the plane and line seem not intersection, raycaster_p.intersectObject(polygon).length return 0, do I miss something?

//3D
        var point_2 = { x: point.x, y: point.y, z: point.z + 0.05 };
        raycaster_p.set(point, point_2);
        const direction = new THREE.Vector3();

        direction.copy(point).sub(point_2).normalize();
        raycaster_p.set(point_2, direction);

        line_g.name = "line_group";
        measurement.points = [];
        measurement.points.push(point);
        measurement.points.push(point_2);
        measurement.geometry = new THREE.BufferGeometry().setFromPoints(measurement.points);
        measurement.material = new THREE.LineBasicMaterial({
            color: color,
            opacity: 0.1,
            linewidth: 0.1
        })
        measurement.line = new THREE.Line(measurement.geometry, measurement.material);
        measurement.line.name = "distance";
        line_g.add(measurement.line);

        if (raycaster_p.intersectObject(polygon).length > 0) {
            console.info("selected point: " + point.x + ", " + point.y);
            return true;
        } else {
            return false;
        }

the line should be excludsived, but seems all do not intersection…

I finally found a path getting closer to the goal. I use raycaster to get intersect point coordinations and collecting them in an array, and then go through each point to verfiy whether the point is within the draw area. This works!

And then I have a further question,
can I get a coordinate even the mouse does not intersecte an object? I oberserved the raycaster object, raycaster.ray.origin values are all the same even mosue is moving.

Finally, I found a path arriving at the end line. I would like to share this idea if someone also needs it. The raycaster function is a solution to achieve free-hand point selection.

The idea is like this :

  1. Collect the coordinates that the mouse intersected while it’s moving.
  2. Using collecting array to draw shapes using THREE.Shape(); ← so it looks like drawing a close circle. This function is attached to mousemove event.
if ($(".gene_interactive:checked").val() === "freehand" && isPressed) {

        if (genes.raycaster_points.length === 0) { return false; }

        genes.freehand.drawToCollect.push(genes.raycaster_points[0].point);

        if (genes.freehand.drawToCollect.length < 2) { return false; }

        genes.raycaster_shape = new THREE.Shape();
        genes.raycaster_shape.autoClose = true;

        genes.raycaster_shape.moveTo(genes.freehand.drawToCollect[0].x, genes.freehand.drawToCollect[0].y);

        for (let i = 0; i < genes.freehand.drawToCollect.length; i++) {
            genes.raycaster_shape.lineTo(genes.freehand.drawToCollect[i].x, genes.freehand.drawToCollect[i].y);
        }

        var raycaster_plane = rois_class.drawLineClass(
            genes.raycaster_shape,
            new THREE.Color("rgb(255, 213, 0)"),
            0,
            0,
            "",
            1);

        raycaster_plane.name = "raycasterCover";
        raycaster_plane.position.z = 0.001;
        geneScene.scene.add(raycaster_plane);

    }
  1. While the mouse pointer-up event is triggered, the following function can determine whether the point is in or out of the polygon.
//Stackoverflow
//https://stackoverflow.com/questions/217578/how-can-i-determine-whether-a-2d-point-is-within-a-polygon/17490923#17490923
function isPointInPoly(p, polygon) {
    var isInside = false;
    var minX = polygon[0].x,
        maxX = polygon[0].x;
    var minY = polygon[0].y,
        maxY = polygon[0].y;
    for (var n = 1; n < polygon.length; n++) {
        var q = polygon[n];
        minX = Math.min(q.x, minX);
        maxX = Math.max(q.x, maxX);
        minY = Math.min(q.y, minY);
        maxY = Math.max(q.y, maxY);
    }

    if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) {
        return false;
    }

    var i = 0,
        j = polygon.length - 1;
    for (i, j; i < polygon.length; j = i++) {
        if ((polygon[i].y > p.y) != (polygon[j].y > p.y) &&
            p.x < (polygon[j].x - polygon[i].x) * (p.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x) {
            isInside = !isInside;
        }
    }

    return isInside;
}

The raycaster function have been used for other purpose, but I have never thought the free-hand selection can be achive by this function.

Thanks again for @mjurczyk helps.