Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grouping points after cut plane three js

Tags:

three.js

I found all intersection points between the object and plane, as in this great example. But now I want to connect these points between themselves (dividing into separate arrays) where the plane passes and connect them again. I tried to connect them by distance, but this does not give an effective result

//SORT POINTS DISTANCE
var pointsArray = []; //point after intersection
var sortedPoints = [];
var sortedPointsDis = [];

sortedPoints.push( pointsArray.pop() );

while( pointsArray.length ) {
  var distance = sortedPoints[sortedPoints.length - 1].distanceTo( pointsArray[0] );
  var index = 0;
  for(var i = 1; i < pointsArray.length; i++) {
      var tempDistance = sortedPoints[sortedPoints.length - 1].distanceTo( pointsArray[i] );
      if( tempDistance < distance ) {
          distance = tempDistance;
          index = i;
      }
  }
  sortedPoints.push( pointsArray.splice(index, 1)[0] );
  sortedPointsDis.push( distance );
 }

 //GROUP POINTS
 var result = [[]];

 for(var i = 0; i < sortedPoints.length; i++) {
  var lastArr = result[result.length - 1];
  if( lastArr.length < 3 ) {
      lastArr.push( sortedPoints[i] );
  } else {
      var distance = lastArr[0].distanceTo( sortedPoints[i] );
      if( distance < sortedPointsDis[i - 1] ) {
          result.push([]);
          lastArr = result[result.length - 1];
      }
      lastArr.push(sortedPoints[i]);
  }
}

JSfiddle. Ideas? Examples? Thank in advance for your replies!

like image 495
Mr.Andrew Avatar asked Jan 04 '23 08:01

Mr.Andrew


1 Answers

So, yes, this answer based on that one and extends it. The solution is rough and can be optimized.

I've used modified .equals() method of THREE.Vector3() (I hope it (or something similar) will be a part of the core one day as it's a very useful feature), taken from here:

THREE.Vector3.prototype.equals = function(v, tolerance) {
  if (tolerance === undefined) {
    return ((v.x === this.x) && (v.y === this.y) && (v.z === this.z));
  } else {
    return ((Math.abs(v.x - this.x) < tolerance) && (Math.abs(v.y - this.y) < tolerance) && (Math.abs(v.z - this.z) < tolerance));
  }
}

enter image description here

The idea:

When we're getting points of intersection, to each point we add information about which face a point belongs to. It means that there are always pairs of points with the same face index.

Then, we recursively find all the contours our points form.

Also, all points mark as unchecked (.checked = false).

  1. Find first unchecked point. Add it to the array of the current contour.

  2. Find its pair point (with the same face index). Add it to the array of the current contour.

  3. Find an unchecked point, the closest one to the point found last. Makr it as checked .checked = true.

  4. Find its pair point (with the same face index). Mark it as checked .checked = true.

  5. Check, if the last found point equals (with some tolerance) to the first found point (the beginning of the contour)

    5.1. If no, then just add the last found point in the array of the current contour and go to step 3.

    5.2. If yes, then clone the first point of the current contour and add it to the array of the current contour, add the contour to the array of contours.

  6. Check, if we have have all points marked as checked.

    6.1. If no, then go to step 1.

    6.2. If yes, we finished. Return the array of contours.

Modified function of setting a point of intersection:

function setPointOfIntersection(line, plane, faceIdx) {
  pointOfIntersection = plane.intersectLine(line);
  if (pointOfIntersection) {
    let p = pointOfIntersection.clone();
    p.faceIndex = faceIdx;
    p.checked = false;
    pointsOfIntersection.vertices.push(p);
  };
}

How to get contours and how to draw them:

var contours = getContours(pointsOfIntersection.vertices, [], true);

contours.forEach(cntr => {
    let cntrGeom = new THREE.Geometry();
    cntrGeom.vertices = cntr;
    let contour = new THREE.Line(cntrGeom, new THREE.LineBasicMaterial({
      color: Math.random() * 0xffffff
    }));
    scene.add(contour);
  });

Where

function getContours(points, contours, firstRun) {
  console.log("firstRun:", firstRun);

  let contour = [];

  // find first line for the contour
  let firstPointIndex = 0;
  let secondPointIndex = 0;
  let firsPoint, secondPoint;
  for (let i = 0; i < points.length; i++) {
    if (points[i].checked == true) continue;
    firstPointIndex = i;
    firstPoint = points[firstPointIndex];
    firstPoint.checked = true;
    secondPointIndex = getPairIndex(firstPoint, firstPointIndex, points);
    secondPoint = points[secondPointIndex];
    secondPoint.checked = true;
    contour.push(firstPoint.clone());
    contour.push(secondPoint.clone());
    break;
  }

  contour = getContour(secondPoint, points, contour);
  contours.push(contour);
  let allChecked = 0;
  points.forEach(p => { allChecked += p.checked == true ? 1 : 0; });
  console.log("allChecked: ", allChecked == points.length);
  if (allChecked != points.length) { return getContours(points, contours, false); }
  return contours;
}

function getContour(currentPoint, points, contour){
  let p1Index = getNearestPointIndex(currentPoint, points);
  let p1 = points[p1Index];
  p1.checked = true;
  let p2Index = getPairIndex(p1, p1Index, points);
  let p2 = points[p2Index]; 
  p2.checked = true;
  let isClosed = p2.equals(contour[0], tolerance);
  if (!isClosed) {
    contour.push(p2.clone());
    return getContour(p2, points, contour);
  } else {
    contour.push(contour[0].clone());
    return contour;
  }
}

function getNearestPointIndex(point, points){
  let index = 0;
  for (let i = 0; i < points.length; i++){
    let p = points[i];
    if (p.checked == false && p.equals(point, tolerance)){ 
      index = i;
      break;
    }
  }
  return index;
}

function getPairIndex(point, pointIndex, points) {
  let index = 0;
  for (let i = 0; i < points.length; i++) {
    let p = points[i];
    if (i != pointIndex && p.checked == false && p.faceIndex == point.faceIndex) {
      index = i;
      break;
    }
  }
  return index;
}

jsfiddle example r87.

like image 178
prisoner849 Avatar answered Mar 16 '23 21:03

prisoner849