Surface to mesh python

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?

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')

The syntax error in your Python script seems to be related to the use of an f-string, which is a feature introduced in Python 3.6. If you’re encountering a syntax error with the f-string, it could be due to running the script in an environment with a Python version earlier than 3.6.

To fix this, you can modify the string formatting to be compatible with older versions of Python

save_curves_as_dxf(curves, '{}.dxf'.format(filename))
convert_to_mesh_and_save_as_ply(objects, '{}.ply'.format(filename))

or

save_curves_as_dxf(curves, filename + '.dxf')
convert_to_mesh_and_save_as_ply(objects, filename + '.ply')
1 Like

Hi @장유경,

The openNURBS toolkit, on which Rhino3dm is based on, does not tesselate (mesh) surfaces or Breps.

More limitations of openNURBS:

Hope this helps.

– Dale

1 Like

So can’t I convert the surface to mesh in this code??

Hi @장유경,

Not using Rhino3dm. You’ll need full Rhino in order to do this, which can include Rhino.Inside and Rhino.Compute.

– Dale

1 Like