面積を比較しながら削減していくのでスケールに依存しないという点で便利。
処理の流れ
両隣のポイントと成す三角形の面積を比較して、小さいものから順に削除していく。削除したら前後のポイントの三角形の面積を再計算する。
三角形を視覚化したもの。
コード
初めに初期値として使う各ポイントの三角形の面積を計算する。外積の長さ=ベクトルの成す平行四辺形の面積、を利用する。
// Run Over: Primitives
int pts[] = primpoints(0, @primnum);
for(int i = 1; i < len(pts)-1; i++)
{
vector prev = point(0, "P", pts[i-1]);
vector next = point(0, "P", pts[(i+1)%len(pts)]);
vector pos = point(0, "P", pts[i]);
float area = length(cross(next-pos, prev-pos))/2;
setpointattrib(0, "area", pts[i], area);
}
このPythonコードではポイントを削除はせず、削除するべきポイントにフラグを振っている。
node = hou.pwd()
geo = node.geometry()
import math
class PT:
def __init__(self, index, pos, area):
self.index = index
self.pos = pos
self.area = area
pts = []
i = 0
#
for pt in geo.points():
pos = pt.position()
area = pt.floatAttribValue("area")
pts.append(PT(i, pos, area))
i = i+1
# 0-1
percent = `chs("../null1/percent")`
# 頂点が3つ以上を条件とする
if(len(pts) > 2):
# 最小頂点を2に設定する(直線)
num = (int)(len(pts) * percent)
if(num < 2):
num = 2
# 削減する目標までループ処理
while(len(pts) > num):
# 最大面積を調べる
maxArea = 0.0
for i in range(1, len(pts)-1):
if(pts[i].area > maxArea):
maxArea = pts[i].area
#print(maxArea)
# 最小面積のポイントを探す
minArea = maxArea
index = -1
for i in range(1, len(pts)-1):
if(pts[i].area <= minArea):
minArea = pts[i].area
index = i
#print('index:' + str(index))
prev = index-1
next = index+1
# 前後の頂点の面積値を更新する
if(prev > 0):
p0 = pts[prev-1].pos
p1 = pts[next].pos
v0 = p0 - pts[prev].pos
v1 = p1 - pts[prev].pos
area = hou.Vector3.cross(v0, v1)
area = hou.Vector3.length(area)/2
pts[prev].area = area
if(next < len(pts)-1):
p0 = pts[prev].pos
p1 = pts[next+1].pos
v0 = p0 - pts[next].pos
v1 = p1 - pts[next].pos
area = hou.Vector3.cross(v0, v1)
area = hou.Vector3.length(area)/2
pts[next].area = area
#print(index)
pts.pop(index)
result = []
for i in range(0, len(pts)):
result.append(pts[i].index)
# Detailに情報を保存
geo.addArrayAttrib(hou.attribType.Global, 'result', hou.attribData.Int, 1)
geo.setGlobalAttribValue('result', result)
フラグが立っているポイント以外を削除する
// Run Over: Points
int pts[] = detail(0, "result");
if(len(pts) > 0 && find(pts, @ptnum) < 0)
removepoint(0, @ptnum);