More Adaptive Curve Resample?

   1411   6   1
User Avatar
Member
1177 posts
Joined: 4月 2017
オフライン
Currently, if I resample a super high res curve, it spaces out each points by the exact same distance. Is there a way to have more points in complex areas? For example, if I resample a spiral curve, I end up with too many polygons on the outside and not enough points at the center.

In other words, is there an equivalent to Polyreduce but for curves?

-Olivier

Attachments:
Houdini_curve_resample_01.JPG (42.3 KB)

User Avatar
Member
654 posts
Joined: 8月 2014
オフライン
Look for Ramer-Douglas-Peucker (RDP) algorithm. Fabian Hirschmann made a Python implementation [github.com], which is easily portable to an HDA. It's not too fast, but it works very well.
Edited by ajz3d - 2025年5月8日 14:20:41
User Avatar
Member
654 posts
Joined: 8月 2014
オフライン
Here's a short video that I rendered years ago, which demonstrates how the algorithm performs geometry-wise. The number in parenthesis is the current number of points in the curve.
Edited by ajz3d - 2025年5月8日 14:33:28

Attachments:
rdp.webm (115.4 KB)

User Avatar
Member
1177 posts
Joined: 4月 2017
オフライン
Interesting method. I'll try it out. Thanks!
User Avatar
Member
173 posts
Joined: 8月 2017
オフライン
node = hou.pwd()
geo = node.geometry()


epsilon = 0.5


class Point:
    def __init__(self, index, pos):
        self.index = index
        self.pos = hou.Vector3(pos)


def douglas_peucker(points, epsilon):

    if len(points) < 3:
        return points

    start, end = points[0], points[-1]
    max_distance = 0.0
    index = 0

   
    for i in range(1, len(points) - 1):
        distance = point_line_distance(points[i], start, end)
        if distance > max_distance:
            max_distance = distance
            index = i

    
    if max_distance > epsilon:
        left = douglas_peucker(points[:index + 1], epsilon)
        right = douglas_peucker(points[index:], epsilon)
        
        return left[:-1] + right
    else:
        return [start, end]


def point_line_distance(point, start, end):
    if start.pos == end.pos:
        return (point.pos - start.pos).length()

    line_vec = (end.pos - start.pos).normalized()
    point_vec = point.pos - start.pos
    d = line_vec.dot(point_vec)
    projection = start.pos + line_vec * d
    dist = (point.pos - projection).length()
    
    return dist


points = []
index = 0
for pt in geo.points():
    points.append(Point(index, pt.position()))
    index += 1


simplified_points = douglas_peucker(points, epsilon)


result = []
for i in range(len(simplified_points)):
    result.append(simplified_points[i].index)


geo.addArrayAttrib(hou.attribType.Global, 'result', hou.attribData.Int, 1)
geo.setGlobalAttribValue('result', result)

int pts[] = detail(0, "result");

if(len(pts) > 0 && find(pts, @ptnum) < 0)
    removepoint(0, @ptnum);
Conservation of Momentum
User Avatar
Member
719 posts
Joined: 9月 2013
オンライン
The refine node reduces the number of points within a user-defined tolerance:
https://www.sidefx.com/docs/houdini/nodes/sop/refine.html [www.sidefx.com]

Labs offers resampling by density that can be set to curvature:
https://www.sidefx.com/docs/houdini/nodes/sop/labs--curve_resample_by_density-1.0.html [www.sidefx.com]

And for adaptive resampling I would accumulate the curvature along the curve and resample it.
Edited by Konstantin Magnus - 2025年5月10日 09:29:54

Attachments:
resample_adaptive.hip (202.6 KB)

https://procegen.konstantinmagnus.de/ [procegen.konstantinmagnus.de]
User Avatar
Member
392 posts
Joined: 8月 2018
オフライン
Konstantin, that adaptive resample is really impressive. I just wish I was clever enough to really understand what you did there : )
  • Quick Links