How to make pointclouds from NURBS

I want to extract point clouds from NURBS. However, it doesnโ€™t seem to have that function within Rino.
Do I have to convert to mesh and use a program like MeshLab? However, in this case, polyline is omitted. Is there any extension that includes polyline and mesh together?

1 Like

Itโ€™s possible with Rhino 8 but Iโ€™m pretty sure youโ€™ll have to convert the NURBS to a mesh first no matter whatโ€ฆ

2 Likes

Yes, you will have to mesh the object(s) first with the desired density, you can then just run ExtractPt on the selected mesh(es) and polyline(s) with the CreatePointCloud option set to Yes.

I think you can run ExtractPt on the NURBS object directly, but in that case I believe you will only get the control points, which may not be dense enough for your point cloud.

4 Likes

The control points will not be on the surface in general.

2 Likes

Yep, youโ€™re absolutely right, I was thinking of the SolidEdit pointsโ€ฆ I actually donโ€™t know what ExtractPt does on polysurfaces, not where I can test right now.

2 Likes

increase isocurve density (no idea if that is scriptable) then ExtractIsocurve with options both and all then Intersect.

2 Likes

Divide command to place points along a curve.
PointCloud command to create a point cloud.

2 Likes
import math
import rhino3dm
import rhino3dm as rh
import ezdxf
from ezdxf.math import BSpline
import numpy as np
from plyfile import PlyData, PlyElement
import os


# ๊ณก์„ ์„ DXF ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜
def save_curves_as_dxf(curves, filename):
    doc = ezdxf.new('R2010')
    msp = doc.modelspace()

    for curve in curves:
        if isinstance(curve, rh.LineCurve):  # ์ง์„  ๊ณก์„ 
            start = curve.PointAtStart
            end = curve.PointAtEnd
            msp.add_line((start.X, start.Y, start.Z), (end.X, end.Y, end.Z))
        elif isinstance(curve, rh.ArcCurve):
            arc = curve.Arc
            # ์•„ํฌ์˜ ์ค‘์‹ฌ, ๋ฐ˜์ง€๋ฆ„, ์‹œ์ž‘ ๊ฐ๋„, ๋ ๊ฐ๋„๋ฅผ ์‚ฌ์šฉ
            msp.add_arc(
                center=(arc.Center.X, arc.Center.Y, arc.Center.Z),
                radius=arc.Radius,
                start_angle=math.degrees(arc.StartAngle),
                end_angle=math.degrees(arc.EndAngle),
                is_counter_clockwise=True
            )

        elif isinstance(curve, rh.NurbsCurve):
            # ๊ณก์„ ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฒ”์œ„๋ฅผ ์–ป์Œ
            t0 = curve.Domain.T0  # ์‹œ์ž‘ ํŒŒ๋ผ๋ฏธํ„ฐ
            t1 = curve.Domain.T1  # ๋ ํŒŒ๋ผ๋ฏธํ„ฐ
            point_count = max(100, len(curve.Points) * 2)  # ์ถฉ๋ถ„ํ•œ ๋ถ„ํ•ด๋Šฅ์„ ์œ„ํ•ด ์ ์˜ ๊ฐœ์ˆ˜ ์กฐ์ •
            points = []

            # ๊ณก์„ ์„ ์—ฌ๋Ÿฌ ์ ๋“ค๋กœ ์ด์‚ฐํ™”
            for i in range(point_count + 1):
                t = t0 + (t1 - t0) * i / point_count
                pt = curve.PointAt(t)
                points.append((pt.X, pt.Y, pt.Z))

            # ํด๋ฆฌ๋ผ์ธ์œผ๋กœ ๋ณ€ํ™˜๋œ ์ ๋“ค์„ DXF ํŒŒ์ผ์— ์ถ”๊ฐ€
            msp.add_lwpolyline(points)


        elif isinstance(curve, rh.PolylineCurve):
            polyline = curve.ToPolyline()  # PolylineCurve๋ฅผ Polyline ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜
            points = [(pt.X, pt.Y, pt.Z) for pt in polyline]  # Polyline์˜ ์ ๋“ค์„ ๊ฐ€์ ธ์˜ด
            msp.add_lwpolyline(points)


    doc.saveas(filename)


def explode_brep_to_surfaces(brep):
    return [brep.Faces[i].UnderlyingSurface() for i in range(len(brep.Faces))]

def convert_to_mesh_and_save_as_ply(objects, filename):
    vertices = []  # ๋ฉ”์‹œ์˜ ์ •์ ๋“ค์„ ์ €์žฅํ•  ๋ฆฌ์ŠคํŠธ
    faces = []     # ๋ฉ”์‹œ์˜ ๋ฉด๋“ค์„ ์ €์žฅํ•  ๋ฆฌ์ŠคํŠธ

    for obj in objects:
        surfaces = []

        if isinstance(obj, rh.Brep):
            # Brep์„ ๊ฐœ๋ณ„ ์„œํ”ผ์Šค๋กœ ๋ถ„ํ•ด
            surfaces.extend(explode_brep_to_surfaces(obj))
        elif isinstance(obj, rh.Surface):
            # ์„œํ”ผ์Šค ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
            surfaces.append(obj)

        for surface in surfaces:
            mesh = rh.Mesh.CreateFromSurface(surface)
            if mesh:
                start_index = len(vertices)
                vertices.extend([v for v in mesh.Vertices])
                faces.extend([[v + start_index for v in f] for f in mesh.Faces])

    # ์ •์ ๊ณผ ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ PlyElement ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
    vertex_element = np.array(vertices, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
    face_element = np.array(faces, dtype=[('vertex_indices', 'i4', (3,))])

    ply_data = PlyData([PlyElement.describe(vertex_element, 'vertex'),
                        PlyElement.describe(face_element, 'face')], text=True)
    ply_data.write(filename)
    pass

# ํŒŒ์ผ์—์„œ ํฌ์ธํŠธ ํด๋ผ์šฐ๋“œ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜
def extract_pointcloud_from_file(filename):
    # ํŒŒ์ผ ํ˜•์‹์— ๋”ฐ๋ฅธ ํฌ์ธํŠธ ํด๋ผ์šฐ๋“œ ์ถ”์ถœ ๋กœ์ง ํ•„์š”
    return np.random.rand(100, 3)  # ์˜ˆ์‹œ: ๋žœ๋ค ํฌ์ธํŠธ ํด๋ผ์šฐ๋“œ ์ƒ์„ฑ

# ๋‘ ํฌ์ธํŠธ ํด๋ผ์šฐ๋“œ๋ฅผ ๋ณ‘ํ•ฉํ•˜์—ฌ PLY ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜
def merge_and_save_pointclouds_as_ply(pointcloud1, pointcloud2, filename):
    merged_pointcloud = np.vstack((pointcloud1, pointcloud2))
    # PLY ํŒŒ์ผ ์ €์žฅ ๋กœ์ง ๊ตฌํ˜„ ํ•„์š”
    pass

# Rhino 3dm ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
model = rh.File3dm.Read('C:/Users/jjang/Desktop/YG2/nurbs_file/1113.3dm')

# ๊ฐ์ฒด ๋ถ„๋ฅ˜
curves = [obj.Geometry for obj in model.Objects if obj.Geometry.ObjectType == rh.ObjectType.Curve]
objects = [obj.Geometry for obj in model.Objects if obj.Geometry.ObjectType in [rh.ObjectType.Brep, rh.ObjectType.Surface]]

# ํŒŒ์ผ ์ด๋ฆ„ ์ถ”์ถœ (ํ™•์žฅ์ž ์ œ์™ธ)
filename = os.path.splitext('C:/Users/jjang/Desktop/YG2/nurbs_file/1113.3dm')[0]

# DXF ๋ฐ PLY ํŒŒ์ผ ์ €์žฅ
save_curves_as_dxf(curves, f'{filename}.dxf')
convert_to_mesh_and_save_as_ply(objects, f'{filename}.ply')

# ํฌ์ธํŠธ ํด๋ผ์šฐ๋“œ ์ถ”์ถœ ๋ฐ ๋ณ‘ํ•ฉ
#pointcloud_dxf = extract_pointcloud_from_file(f'{filename}.ply')
#pointcloud_ply = extract_pointcloud_from_file(f'{filename}.ply')
#merge_and_save_pointclouds_as_ply(pointcloud_dxf, pointcloud_ply, f'{filename}_merged.ply')

First Iโ€™m working on a code that converts files and generates a mesh. An error occurs while converting surface to mesh.

Traceback (most recent call last):
File โ€œC:\Users\jjang\Desktop\YG2\nurbs_file\convert_file.pyโ€, line 113, in
convert_to_mesh_and_save_as_ply(objects, fโ€™{filename}.plyโ€™)
File โ€œC:\Users\jjang\Desktop\YG2\nurbs_file\convert_file.pyโ€, line 75, in convert_to_mesh_and_save_as_ply
mesh = rh.Mesh.CreateFromSurface(surface)
AttributeError: type object โ€˜rhino3dm._rhino3dm.Meshโ€™ has no attribute โ€˜CreateFromSurfaceโ€™

Is there any other good way to generate mesh on surface?

Hello- โ€˜import Rhino as rhโ€™ at the top, rather than rhino3dm .

-Pascal

Import โ€œRhinoโ€ could not be resolved

Do you know what I need to install?

Hi @์žฅ์œ ๊ฒฝ,

Can you explain in detail what you are trying to do and why? Why do you want or need a point cloud from a NURBS surface?

Thanks,

โ€“ Dale