在Three.js中切割平面后,如何对点进行分组

5
我找到了物体和平面之间的所有交点,就像这个很棒的示例中所示。但是现在我想将这些点连接起来(分成单独的数组),其中平面经过并再次连接它们。我尝试通过距离连接它们,但这并没有给出有效的结果。
//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。 有什么想法?例子?提前感谢您的回复!

1个回答

10

所以,是的,这个答案基于那个,并对其进行了扩展。解决方案还很粗糙,可以进行优化。

我使用了THREE.Vector3()的修改版.equals()方法(希望将来它或类似的东西成为核心的一部分,因为它是一个非常有用的功能),从这里获取:

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));
  }
}

在此输入图片描述

算法思路:

当我们获取到交点时,为每个交点添加信息,表示它属于哪个面。这意味着总是存在具有相同面索引的点对。

然后,我们递归地找到所有点形成的轮廓。

同时,将所有点标记为未检查状态 (.checked = false)。

  1. 找到第一个未检查的点,将其添加到当前轮廓数组中。

  2. 找到与其配对的点(具有相同的面索引),将其添加到当前轮廓的数组中。

  3. 查找最靠近上次找到的点的未检查点,并将其标记为已检查 .checked = true

  4. 找到与其配对的点(具有相同的面索引),并将其标记为已检查 .checked = true

  5. 检查最后找到的点是否等于(具有一定的容差)轮廓的起始点。

    5.1. 如果不是,则只需将最后找到的点添加到当前轮廓的数组中并转到步骤3

    5.2. 如果是,则克隆当前轮廓的第一个点,并将其添加到当前轮廓的数组中,将该轮廓添加到轮廓数组中。

  6. 检查是否已将所有点都标记为已检查。

    6.1. 如果没有,则转到步骤1

    6.2. 如果是,则完成。返回轮廓数组。

修改后的设置交点函数:

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);
  };
}

如何获取轮廓并绘制它们:

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);
  });

在哪里

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例子r87。


很酷。非常感谢!由于这是一次性计算,在加载时,我认为这是一个好的解决方案和好的解释^^ 这对我有效。再次感谢。 - Mr.Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接