THREE.JS:寻找边缘,算法优化

时间:2017-05-25 12:16:32

标签: algorithm optimization 3d three.js edge

我有直接的函数来识别THREE.Geometry()中的边。

var edges = []; 

for(var i = 0, l = geometry.faces.length; i < l; i++) {  findAdjacentFaces(i, edges, geometry); }


function findAdjacentFaces(face_, edges_, geometry_){

    var adjacentFaces = [];

    if(face_ >= 0 && face_ < geometry_.faces.length){

            for(var i = 0, l = geometry_.faces.length; i < l; i++){

                if(i != face_){

                    if(checkAdjacent(geometry_.faces[face_], geometry_.faces[i]) == true ){

                            adjacentFaces.push(i);

                    }

                }

                if(adjacentFaces.length > 2) { break; }

            }

    }

    if(adjacentFaces.length == 2){

        edges_.push(setEdge(face_, adjacentFaces[0], adjacentFaces[1], geometry_));

    }

}

function checkAdjacent(faceA_, faceB_){

    var values = [faceA_.a, faceA_.b, faceA_.c, faceB_.a, faceB_.b, faceB_.c].sort();

    var counter = 0;
    var duplicates = {}; 

    values.forEach(function(x) { duplicates[x] = (duplicates[x] || 0) + 1; if(duplicates[x] > 1) { counter++; } });

    if(counter == 2) { return true; } else { return false; }

}

function setEdge(faceA_, faceB_, faceC_, geometry_){

    var vertices = [], peak, tmpA, tmpB;
    var values =  [ geometry_.faces[faceA_].a, geometry_.faces[faceA_].b, geometry_.faces[faceA_].c, 
                    geometry_.faces[faceB_].a, geometry_.faces[faceB_].b, geometry_.faces[faceB_].c, 
                    geometry_.faces[faceC_].a, geometry_.faces[faceC_].b, geometry_.faces[faceC_].c ].sort();

    var sideA = [geometry_.faces[faceA_].a, geometry_.faces[faceA_].b, geometry_.faces[faceA_].c];
    var sideB = [geometry_.faces[faceB_].a, geometry_.faces[faceB_].b, geometry_.faces[faceB_].c];
    var sideC = [geometry_.faces[faceC_].a, geometry_.faces[faceC_].b, geometry_.faces[faceC_].c];

    var counter = 0;
    var duplicates = {}; 

    values.forEach(function(x) { duplicates[x] = (duplicates[x] || 0) + 1; });

    for (const key of Object.keys(duplicates)) { 

        if(duplicates[key] == 2) { vertices.push(key); } 
        else if(duplicates[key] == 3) { peak = key; } 

    }

    return  [ Number(vertices[0]), Number(vertices[1]) ];

}

它返回几何边缘上的所有顶点索引。工作正常,但很慢。 什么可以优化加快速度?

3 个答案:

答案 0 :(得分:2)

问题的初始代码检查每个几何面的所有几何面,以确定一对相邻面和相应的边。虽然这提取了所有非边界边缘,但这导致几何/网格的面数的二次算法复杂度(并且因此边缘或顶点的数量的二次复杂度)。可以删除一些额外的实际开销(例如setEdge()函数)。

这是一个提取网格的所有边缘(这使用网格中面数的顺序的额外工作空间)的提议,具有拟线性时间复杂度(由于边缘排序,N log N)并且可能减少开销:

  • 从网格面中提取所有未定向的边(作为两个顶点索引的有序对),
  • 丢弃所有独特的无定向边缘,仅保留属于至少两个面的无定向边缘。

以下是一个可能的实现示例:

// A cube
var faces = [
  {a: 0, b: 1, c: 2}, {a: 2, b: 3, c: 0}, // Front
  {a: 1, b: 5, c: 6}, {a: 6, b: 2, c: 1}, // Right
  {a: 5, b: 4, c: 7}, {a: 7, b: 6, c: 5}, // Back
  {a: 4, b: 0, c: 3}, {a: 3, b: 7, c: 4}, // Left
  {a: 3, b: 2, c: 6}, {a: 6, b: 7, c: 3}, // Top
  {a: 4, b: 5, c: 1}, {a: 1, b: 0, c: 4}, // Bottom
];

function compareEdges(edge1, edge2) {
  var i1 = edge1[0];
  var i2 = edge2[0];

  if (i1 != i2)
    return i1 < i2 ? -1 : 1;

  var j1 = edge1[1];
  var j2 = edge2[1];

  if (j1 != j2)
    return j1 < j2 ? -1 : 1;

  return 0;
}

function discardUniqueEdges(edges) {
  var i, j, n;
  var count;

  edges.sort(compareEdges);

  count = 0;
  j = 0; // The range [0, j[ of the array stores duplicated edges

  for (i = 0, n = edges.length; i < n; i++) {
    if (!count) {
      count = 1;
      continue;
    }

    if (!compareEdges(edges[i - 1], edges[i])) {
      ++count;
      continue;
    }

    // edges[i - 1] != edges[i]
    if (count <= 1)
      continue;

    // edges[i - 1] != edges[i] && count > 1
    edges[j][0] = edges[i - 1][0];
    edges[j][1] = edges[i - 1][1];
    j += 1;
    count = 1;
  }

  if (count > 1) {
    edges[j][0] = edges[i - 1][0];
    edges[j][1] = edges[i - 1][1];
    j += 1;
  }

  edges.length = j;

  return edges;
}

function extractEdges(faces) {
  var edges = [];
  var face;
  var i, n;

  // Store all edges
  for (i = 0, n = faces.length; i < n; i++) {
    face = faces[i];
    edges.push([face.a, face.b].sort());
    edges.push([face.b, face.c].sort());
    edges.push([face.c, face.a].sort());
  }

  return discardUniqueEdges(edges);
}

var edges = extractEdges(faces);
console.log(edges.length)
console.log(edges)

答案 1 :(得分:0)

    props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
    props.put(Context.PROVIDER_URL, "mq://localhost:7676");
    props.put("connectionFactoryNames" , "TestQueueConnectionFactory");
    props.put("queue." + "TestQueue", "TestQueue");
    InitialContext ic = new InitialContext(props);
    ConnectionFactory qFactory = (ConnectionFactory) ic.lookup("TestQueueConnectionFactory");
    Queue  queue  = (Queue ) ic.lookup("TestQueue");

我尝试添加另一个参数[2]作为重复计数器,并在您的extractEdges()函数之后对边缘进行排序,以捕获那些没有副本的内容。

答案 2 :(得分:0)

function discardUniqueEdges(edges) {

var hash = {};

for(var i = 0, l = edges.length; i < l; i++){

    var ab = [edges[i][0], edges[i][1]];

    if (!(ab in hash)) { hash[ab] = 1; }

    if((ab in hash)) { hash[ab]++; }

}

var sorted = [];

Object.keys(hash).forEach(function(key) {
  if (hash[key] == 2) { sorted.push(key.split(",")); }
});

return sorted;

}

除@ user3146587提案外,此方法也很有用。