Hello guys
1st: i’m wondering what’s the rigth wording to define the “delimiter = space” and activate the “create point cloud” option. I tried this and other stuff, but the points are never loaded when I run the script. It works of course when I import them normally.
2nd: The file is only found when the path is written with double-backslashes (“C:\\Users\\admin\…\\filename”) when I use the os.path or pathlib methods to get the full path I got a windows error in rhino when running the script. I tried every kind of path I could come up with, but nothing else seems to work. Thanks for helping!
for filename in os.listdir(targets_path):
delim = " _Delimiters=_Space "
pc = "_CreatePointcloud=_Yes"
settings = [delim, pc]
if filename.lower().endswith(".xyz"):
fullpath=os.path.join(targets_path,filename).lower()
rs.EnableRedraw(False)
rs.Command("_-Import {0} {1} _Enter".format(fullpath, settings))
rs.EnableRedraw(True)
the script follows another one to start rhino and is launched in vscode. I get the points but they are all in one place at 0,0,0.
Currently your command string looks something like this: "_-Import <path> ['_Delimiters=_Space', '_CreatePointcloud=_Yes'] _Enter"
You’re inserting the string representation of the settings list into the command string, instead of a correctly parsed string.
This is because the backslash character is used by Python and other programming languages internally, for instance as "\t" or "\n" in strings to define a tab or new line.
You thus need to escape it by doubling it up when you want to use the character in a string!
Thanks for helping but I always get the answer: Command _CreatePointCloud=_Yes does not exist.
Don’t know what it is though, CreatePointcloud, CreatePointCloud, PointCloud…nothing works.
for filename in os.listdir(targets_path):
if filename.lower().endswith(".xyz"):
fullpath=os.path.join(targets_path,filename).lower()
rs.EnableRedraw(False)
#Open file to convert
rs.Command("_-Import {0} _Delimiters=_Space _CreatePointcloud=_Yes _Enter".format(fullpath))
rs.EnableRedraw(True)
gives the same error:
Command: _-Import
Name of the file to import ( Browse ): c:/users/pierre/desktop/lasershare/programmierung/xyz_swisstopo_api/py_modules/…/import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1250.xyz
Delimiting character ( CreatePointCloud=Yes ): _Delimiters=_Space
Successfully read file “c:/users/pierre/desktop/lasershare/programmierung/xyz_swisstopo_api/py_modules/…/import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1250.xyz”
Command: _CreatePointcloud=_Yes
Unknown command: _CreatePointcloud=_Yes
same thing:Command: _-Import
Name of the file to import ( Browse ): c:/users/pierre/desktop/lasershare/programmierung/xyz_swisstopo_api/py_modules/…/import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1250.xyz
Delimiting character < > ( CreatePointCloud=Yes ): _Delimiters=_Space
Successfully read file “c:/users/pierre/desktop/lasershare/programmierung/xyz_swisstopo_api/py_modules/…/import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1250.xyz”
Command: _CreatePointcloud=_Yes
Unknown command: _CreatePointcloud=_Yes
2680000.25 1250999.75 493.44
2680000.75 1250999.75 493.56
2680001.25 1250999.75 493.98
2680001.75 1250999.75 494.22
2680002.25 1250999.75 494.43
2680002.75 1250999.75 494.65…this is how xyz looks. Funny thing is I’m doing it the same way (as mentioned at the beginning) for a dxf-import and it works fine…
What do you want the script exactly to do? Just read in points as single point clouds per file that was opened? I’m asking because I have some script for importing stuff that I can share.
# import_xyz.py : Imports a simple XZY-file as individual points or point cloud into Rhino
__author__ = "diff-arch (https://diff-arch.xyz)"
__version__ = "0.0.1 (2021-11-14)"
import Rhino.Geometry as rg
import scriptcontext as sc
import os
def read_lines(fpath, empty=True):
"""Reads the contents of a file line by line.
Args:
fpath (str): An absolute path to a file to read
empty (bool): By default True to remove empty lines
Raises:
OSError: '<fpath>' is not a valid file path
RuntimeError: Unable to read 'fname'
Returns:
The individual lines of data in a list."""
lines = []
if not os.path.exists(fpath) or not os.path.isfile(fpath):
raise OSError("'{}' is not a valid file path".format(fpath))
try:
with open(fpath) as f:
for line in f:
if empty and (line == '\n' or line == '\r\n'):
continue
lines.append(line)
except:
basedir, fname = os.path.split(fpath)
raise RuntimeError("Unable to read '{}'".format(fname))
return lines
def parse_xyz(fpath, delimiter=",", as_point_cloud=False, verbose=False):
"""Parses an XYZ-file to Rhino geometry types.
Args:
fpath (str): An absolute path to a XYZ-file to read
delimiter (str): Optional delimiter, by default a comma (",")
as_point_cloud (bool): Optionally True to return a Rhino.Geometry.PointCloud,
by default False to return a list of Rhino.Geometry.Point3d's instead
verbose (bool): Optionally True to output parsing information, by default False
Raises:
ValueError: The file '<os.path.basename(fpath)>' doesn't seem to a XYZ-file
RuntimeError: Unable to parse any points from file '<os.path.basename(fpath)>'
Returns:
The list of Rhino.Geometry.Point3d's or the Rhino.Geometry.PointCloud."""
fname = os.path.basename(fpath)
if os.path.splitext(fname)[-1].lower() != ".xyz":
raise ValueError("The file '{}' doesn't seem to a XYZ-file".format(fname))
data = read_lines(fpath, False)
points = []
for i, line in enumerate(data):
if line == '\n' or line == '\r\n':
continue # skip empty lines
line = line.strip('\n').strip('\r\n')
coords = []
for item in line.split(delimiter):
try:
num = float(item.strip())
coords.append(num)
except ValueError:
if verbose:
print "Line {}: non digit '{}' found and skipped".format(i+1, item.strip())
if len(coords) < 3:
if verbose:
print "Line {}: fewer than 3 coordinates found and skipped".format(i+1)
continue
elif len(coords) > 3:
if verbose:
print "Line {}: more than 3 coordinates found, only first 3 will be used".format(i+1)
x, y, z = coords[:3]
points.append(rg.Point3d(x, y, z))
if len(points) < 1:
raise RuntimeError("Unable to parse any points from file '{}'".format(fname))
if not as_point_cloud:
return points
pt_cloud = rg.PointCloud()
for pt in points:
pt_cloud.Add(pt)
return pt_cloud
if __name__ == "__main__":
result = parse_xyz("/your/path/to/file.xyz", delimiter=" ", as_point_cloud=True, verbose=True)
if isinstance(result, rg.PointCloud):
rc = sc.doc.Objects.AddPointCloud(result)
else:
rc = [sc.doc.Objects.AddPoint(pt) for pt in result]
sc.doc.Views.Redraw()