gpt4 book ai didi

javascript - 朴素表面网络算法的工作流程

转载 作者:行者123 更新时间:2023-12-03 04:52:06 25 4
gpt4 key购买 nike

我目前正在研究等值面提取算法。我找到了introduction在这里使用有效的 Javascript 代码。我必须注意,我不是 Javascript 编码员。我主要使用 Java 和 F#,但我能够将代码移植到 F#。

毕竟我目前的问题是理解表面网络算法的实现原理。 (下面提供了链接)。它是由博客/简介的作者制作的。

197 行(169 sloc)6.38 KB,来自 here

// The MIT License (MIT)
//
// Copyright (c) 2012-2013 Mikola Lysenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/**
* SurfaceNets in JavaScript
*
* Written by Mikola Lysenko (C) 2012
*
* MIT License
*
* Based on: S.F. Gibson, "Constrained Elastic Surface Nets". (1998) MERL Tech Report.
*/
var SurfaceNets = (function() {
"use strict";

//Precompute edge table, like Paul Bourke does.
// This saves a bit of time when computing the centroid of each boundary cell
var cube_edges = new Int32Array(24)
, edge_table = new Int32Array(256);
(function() {

//Initialize the cube_edges table
// This is just the vertex number of each cube
var k = 0;
for(var i=0; i<8; ++i) {
for(var j=1; j<=4; j<<=1) {
var p = i^j;
if(i <= p) {
cube_edges[k++] = i;
cube_edges[k++] = p;
}
}
}

//Initialize the intersection table.
// This is a 2^(cube configuration) -> 2^(edge configuration) map
// There is one entry for each possible cube configuration, and the output is a 12-bit vector enumerating all edges crossing the 0-level.
for(var i=0; i<256; ++i) {
var em = 0;
for(var j=0; j<24; j+=2) {
var a = !!(i & (1<<cube_edges[j]))
, b = !!(i & (1<<cube_edges[j+1]));
em |= a !== b ? (1 << (j >> 1)) : 0;
}
edge_table[i] = em;
}
})();

//Internal buffer, this may get resized at run time
var buffer = new Int32Array(4096);

return function(data, dims) {

var vertices = []
, faces = []
, n = 0
, x = new Int32Array(3)
, R = new Int32Array([1, (dims[0]+1), (dims[0]+1)*(dims[1]+1)])
, grid = new Float32Array(8)
, buf_no = 1;

//Resize buffer if necessary
if(R[2] * 2 > buffer.length) {
buffer = new Int32Array(R[2] * 2);
}

//March over the voxel grid
for(x[2]=0; x[2]<dims[2]-1; ++x[2], n+=dims[0], buf_no ^= 1, R[2]=-R[2]) {

//m is the pointer into the buffer we are going to use.
//This is slightly obtuse because javascript does not have good support for packed data structures, so we must use typed arrays :(
//The contents of the buffer will be the indices of the vertices on the previous x/y slice of the volume
var m = 1 + (dims[0]+1) * (1 + buf_no * (dims[1]+1));

for(x[1]=0; x[1]<dims[1]-1; ++x[1], ++n, m+=2)
for(x[0]=0; x[0]<dims[0]-1; ++x[0], ++n, ++m) {

//Read in 8 field values around this vertex and store them in an array
//Also calculate 8-bit mask, like in marching cubes, so we can speed up sign checks later
var mask = 0, g = 0, idx = n;
for(var k=0; k<2; ++k, idx += dims[0]*(dims[1]-2))
for(var j=0; j<2; ++j, idx += dims[0]-2)
for(var i=0; i<2; ++i, ++g, ++idx) {
var p = data[idx];
grid[g] = p;
mask |= (p < 0) ? (1<<g) : 0;
}

//Check for early termination if cell does not intersect boundary
if(mask === 0 || mask === 0xff) {
continue;
}

//Sum up edge intersections
var edge_mask = edge_table[mask]
, v = [0.0,0.0,0.0]
, e_count = 0;

//For every edge of the cube...
for(var i=0; i<12; ++i) {

//Use edge mask to check if it is crossed
if(!(edge_mask & (1<<i))) {
continue;
}

//If it did, increment number of edge crossings
++e_count;

//Now find the point of intersection
var e0 = cube_edges[ i<<1 ] //Unpack vertices
, e1 = cube_edges[(i<<1)+1]
, g0 = grid[e0] //Unpack grid values
, g1 = grid[e1]
, t = g0 - g1; //Compute point of intersection
if(Math.abs(t) > 1e-6) {
t = g0 / t;
} else {
continue;
}

//Interpolate vertices and add up intersections (this can be done without multiplying)
for(var j=0, k=1; j<3; ++j, k<<=1) {
var a = e0 & k
, b = e1 & k;
if(a !== b) {
v[j] += a ? 1.0 - t : t;
} else {
v[j] += a ? 1.0 : 0;
}
}
}

//Now we just average the edge intersections and add them to coordinate
var s = 1.0 / e_count;
for(var i=0; i<3; ++i) {
v[i] = x[i] + s * v[i];
}

//Add vertex to buffer, store pointer to vertex index in buffer
buffer[m] = vertices.length;
vertices.push(v);

//Now we need to add faces together, to do this we just loop over 3 basis components
for(var i=0; i<3; ++i) {
//The first three entries of the edge_mask count the crossings along the edge
if(!(edge_mask & (1<<i)) ) {
continue;
}

// i = axes we are point along. iu, iv = orthogonal axes
var iu = (i+1)%3
, iv = (i+2)%3;

//If we are on a boundary, skip it
if(x[iu] === 0 || x[iv] === 0) {
continue;
}

//Otherwise, look up adjacent edges in buffer
var du = R[iu]
, dv = R[iv];

//Remember to flip orientation depending on the sign of the corner.
if(mask & 1) {
faces.push([buffer[m], buffer[m-du], buffer[m-du-dv], buffer[m-dv]]);
} else {
faces.push([buffer[m], buffer[m-dv], buffer[m-du-dv], buffer[m-du]]);
}
}
}
}

//All done! Return the result
return { vertices: vertices, faces: faces };
};
})();

我将在这里写下我所理解和不清楚的内容:

我如何理解算法:

  1. 制作一个cube_edges(或者更确切地说是顶点列表)组合列表和一个边列表(查找表)

  2. 迭代整个网格,根据当前单元/立方体中每个顶点的拓扑(依赖于边列表)插入浮点值。

  3. 推回顶点并设置面。

我不清楚的是:

  1. 我已经在互联网上搜索了生成edges_table的算法,但我还没有找到。有人能给我解释一下吗?
  2. 这些面是如何相互连接的。最后一个片段中的面孔发生了什么?

我愿意改进我的问题以符合规则。

最佳答案

我没有阅读您引用的代码,但回答您的问题:

  1. Edges_table 算法非常简单,它遵循将立方体的顶点和边映射到特定数字的约定。请参阅Paul Bourke's Implementation了解详情。

  2. 在匹配框算法中,交点通常是通过每个顶点值的线性插值来计算的:

P = P1 + (isovalue - V1) (P2 - P1) / (V2 - V1)

相邻立方体的共享边将始终在相同位置具有交点,因此相邻立方体的生成面将始终完美契合。

关于javascript - 朴素表面网络算法的工作流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42607740/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com