Set options for .xyz-import with script and path \\ only

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.

rhino returns this:
Command: _-RunPythonScript
C:\Users\admin\Desktop\LSH\Programmierung\xyz_swisstopo_api\py_modules\import_xyz.py
_-Import
c:\users\admin\desktop\lsh\programmierung\xyz_swisstopo_api\import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1249.xyz
_Delimiters=_Space
Successfully read file “c:\users\admin\desktop\lsh\programmierung\xyz_swisstopo_api\import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1249.xyz”
_CreatePointcloud=_Yes
Unknown command: _CreatePointcloud=_Yes

This works for me:
_-Import "<path>" _Delimiters=_Comma _CreatePointcloud=_Yes _Enter

Note that my XYZ file is comma separated.

In your script you might have to change

rs.Command("_-Import {0} {1} _Enter".format(fullpath, settings))

to

rs.Command("_-Import {} {} _Enter".format(fullpath, " ".join(settings)))

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 me, _CreatePointcloud=_Yes seems to work fine!

Can you print this: "_-Import {0} {1} _Enter".format(fullpath, settings)? And show what is output?

   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

Which version of Rhino are you on?

Rhino 6

What happens when you manually enter a command like this in Rhino?

_-Import c:/users/pierre/desktop/lasershare/programmierung/xyz_swisstopo_api/py_modules/../import_files\swissalti3d_0.5_xyz_chlv95_ln02_2680_1250.xyz _Delimiters=_Space _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

And without _CreatePointcloud=_Yes?

with or without its loading something but no points are appearing. when I just drag and drop it works fine…

Open one of your XYZ-files and verify whether they are really space separated!

Other than that it might be a path problem. Try to enclose it in " " when running the command.

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…

Thanks for your effort anyway.

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.

yes, I’m dowloading xyz. files from an API with a script and want to import them automaticaly…

Try this:

# 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()

1 Like

Hey, thank you very much - managed to solve it with your script!!!

That’s cool! Note that it currently only supports XYZ files. It would have to be extended for XYZRGB files (point clouds with color information).