Python script from Windows to Mac


(Eggy) #1

Hello, scripters,

I have a problem. I switched from Windows to a Mac and we used to use a phython script on Rhino on Windows. Now the problem occurs that the script does not work on Mac. The script stops with the error:

AttributeError: ‘NoneType’ object has no attribute ‘Vertices’

I am no hero with scripting but I can understand solutions and we would really like it to work again.
Because I don’t understand how phython scripting is different compared to Mac.
Could anyone help us adjusting this script so that it works on Mac?


#2

It sounds likely that the script is using a method or function which is not yet implemented or is buggy on Mac Rhino. The function is failing (returning None) and looks like the script is not doing any error checking to see if it worked…

We would need to have the whole script in order to test and suggest possible fixes/workarounds…

–Mitch


(Eggy) #3

Hello Mitch,

Thank you for your reply. This is the script:

displacement 20170803.py (20.3 KB)


#4

Well, I don’t know exactly where it’s going wrong, I can’t run the script here (needs the configuration file and maybe something else…), but seems like somehow a mesh is not getting created by one of the calls to coercemesh() and so it can’t get the vertices, so it errors out… I would think a bit more error checking in the script might give you more clues.

So the same file works on Windows and not on Mac?

One thing I do notice that probably does not have anything to do with the problem, but should probably be changed for “good practice” - you have

import rhinoscriptsyntax as Rhino

As there is a module Rhino that exists which has all of the RhinoCommon functions, and by importing rhinoscriptsyntax as Rhino you may be disabling it… the popular convention is to use

import rhinoscriptsyntax as rs

–Mitch


(Eggy) #5

Thank you for looking into the script. It’s fully working on Windows. I will provide 2 files more to be able to test it. But indeed somehow it cannot create the mesh and I don’t know why… You will need this image below and the config which is a json file. I really appreciate your help.

configuration.json:

{
  "rings": [

    {"outerHeightfieldPath": "/Users/NAME/Bureaublad/displacement/Keyhole.jpg",
    "threeDmFilePath": "/Users/NAME/Bureaublad/testring.3dm",
    "ringModel": {
      "size": 55,
      "productionOrderReferenceNumber": "001",
      "productionArfefactReferenceNumber": "4",
      "profile": "B",
      "arfefactReferenceNumber": "A-1612345-200228",
      "material": "14WG",
      "width": 5
    },
    "stlFilePath": "/Users/NAME/Bureaublad/testring.stl",
    "innerHeightfieldPath": "/Users/NAME/Bureaublad/displacement/notnecessary.png"}

  ]
}

(qythium) #6

Looks like there are additional files needed to test the script - could you upload those as well?
Agreed that the rhinoscriptsyntax -> Rhino naming is confusing, but that shouldn’t affect anything due to the way Python namespaces work - unless it’s some quirk of Mono / IronPython on Mac …

I did a simple search-and-replace, see if that solves anything: displacement 20170803.py (19.9 KB)


#7

Except there is at least one “gotcha” in there:

rs.Rhino.RhinoApp.RunScript(macro, False) (3 instances)

Which used to read

Rhino.Rhino.RhinoApp.RunScript(macro, False)

but I’m not even sure that’s correct, I’m pretty sure should be:

Rhino.RhinoApp.RunScript(macro, False)

but you would also need to import Rhino at the top…

Haven’t got a Mac available here to test, and unfortunately I have a meeting tonight, so can’t test at home after…

–Mitch


(qythium) #8

Yeah, I noticed that as well - because the rhinoscript modules have Rhino imported as well, rs.Rhino should point to the same thing as if you had import Rhino at the top of the file.
Again, the more idiomatic syntax to use here would be

rs.Command(macro, False)

but I didn’t want to change anything else in the file.


(Eggy) #9

Thank you for your effort but the change of naming gave the same results, sadly enough.

It’s still unable to create the mesh and therefore it cannot select the vertices where it crashes.
Since Phython is still just Phython on Mac it shouldn’t be a naming problem I think since it works perfect on Windows.

Is Phython on mac limited in certain commands or something like that?
Are certain actions not available on Mac? Highly doubt it but could be, since the whole interface is different too on Mac for Rhino.


(qythium) #10

This might be a silly question but your script is looking for files located at

"outerHeightfieldPath": "/Users/NAME/Bureaublad/displacement/Keyhole.jpg",
"threeDmFilePath": "/Users/NAME/Bureaublad/testring.3dm"

according to the JSON config – Do those exact file paths exist on the computer you are running it on?
It could be that your script is failing to check these conditions and ends up trying to do things to a non-existent file, which blows up further down the line when you get a null mesh.

Without your test files to reproduce it with, it’s hard to say for sure.


(Eggy) #11

It’s not a silly question, you’re supposed to fill in your path to the image I included above in the posts.

So the first one is the path to the keyhole image. “/Users/Username/Desktop/Mapname/Keyhole.jpg”
Or wherever you want to place it. The 2nd one is not necessary to adjust because that line is supposed to save the ring as “testring” after rendering with the script so… WHEN it finally will work on Mac you will have to cancel the saving.

I hope those lines are clear enough. If you have questions don’t hesitate to ask me. I really appreciate your help.


(qythium) #12

Ah okay, so those other files are the outputs then? I ran the script and ended up with this intermediate geometry:


after which the script crashed with the traceback

Traceback (most recent call last):
  File ".../displacement 20170803.py", line 612, in <module>
    RhinoRendering(ring).createRing()
  File ".../displacement 20170803.py", line 574, in createRing
    self.closeSideMesh(sides[0], innerMesh, outerMesh)
  File ".../displacement 20170803.py", line 207, in closeSideMesh
    target = self.getClosestVertex(vertex, insideObj)
  File ".../displacement 20170803.py", line 223, in getClosestVertex
    targetFace = mesh.Faces[targetPoint.FaceIndex]
AttributeError: 'NoneType' object has no attribute 'FaceIndex'

Is this the same as what you see? The twisted mesh ring has 1000000+ vertices and some glitchy looking long triangles which don’t look quite right, does this occur on the Windows computer as well? Maybe check what the document tolerances are on both sides-


(Eggy) #13

No I receive another error: AttributeError: ‘NoneType’ object has no attribute ‘Vertices’
but it seems it comes a multiple steps further then mine…
These are my results of running the script:

Command: _None
Command: _SelNone
Command: _-Heightfield
Full path to image file/Gebruikers/Ilona/Bureaublad/displacement/keyhole.png
1 curve added to selection.
1 curve added to selection.
Object ID to select_Circle
Center of circle ( Deformable Vertical 2Point 3Point Tangent AroundCurve FitPoints )0,0,2.57
Radius <10.624> ( Diameter Orientation Circumference Area )_R
Radius <10.624> ( Diameter Orientation Circumference Area )10.6235218701
Radius <10.624> ( Diameter Orientation Circumference Area )_Enter
1 curve added to selection.
1 curve added to selection.
Unknown command: _R
Traceback (most recent call last):
  File "/Users/Ilona/Desktop/displacement/displacement 20170803.py", line 610, in <module>
    RhinoRendering(ring).createRing()
  File "/Users/Ilona/Desktop/displacement/displacement 20170803.py", line 563, in createRing
    self.closeRingMesh(outerMesh)
  File "/Users/Ilona/Desktop/displacement/displacement 20170803.py", line 182, in closeRingMesh
    vertices = meshObj.Vertices

It also shows errors in different lines… I’m really at loss what’s wrong with it. It still works just fine on Windows.


(qythium) #14

hmm… that’s the error I got when there was no input image file- are you sure the path in your JSON file is correct?

Maybe you’re missing a /Users at the beginning of that path or some other typo– you can always use (menu bar)Edit -> Copy as Pathname in the Finder to get the path of a file.

PS. I would usually use the rs.OpenFileName() GUI instead to avoid these sort of errors, and have error checking conditions before proceeding, eg.:

if not os.path.isfile(heightfieldPath):
    raise Exception("Not a valid file")

(qythium) #15

Okay I did some more messing around with the code to try and get it running- it turns out there is a difference in the Mac version when it came to creating text objects (line 394 and 441)

        cmd = "_-TextObject "
        cmd = cmd + "_GroupOutput=_Yes "
        cmd = cmd + "_FontName=script  "
        cmd = cmd + "_Italic=_No "
        cmd = cmd + "_Bold=_No "
        cmd = cmd + "_Height=1 "
        cmd = cmd + "_Output=_Solids "
        cmd = cmd + "_Thickness=0.75 "
        cmd = cmd + "_Addspacing=_Yes "
        cmd = cmd + "_Spacing=0.25 "
        cmd = cmd + str(self.ringConfig.productionOrderReferenceNumber) + "-" + str(int(self.ringConfig.productionArfefactReferenceNumber) + 0) + " "
        cmd = cmd + "_AllowOpenCurves=_No "
        cmd = cmd + "3,-0.5,0 "
        rs.Command(cmd)

Firstly, I don’t have a installed font named “script”, so I changed that to Arial and ended up with this work of art :smile::

Apparently the TextObject command on a Mac takes in fewer options than it does in Windows, leading it to interpret “_Italic=No” as the text.


Do you have a reference screenshot of what the end result is supposed to look like?


(Eggy) #16

Thanks I indeed used dutch language but it had to be in English as I noticed in the log.
Now I’m getting the same results as you…


#17

Also, there is a MAJOR difference in _TextObject command strings between Windows V5 and V6, so watch out…


(qythium) #18

Ouch, I expect that would break many command string-centric scripts like this one, but then again a string-based approach is inherently more fragile to API changes.
@Eggy Maybe consider using rs.AddText() instead?


(Eggy) #19

It looks already a lot better. Actually the “wheel” that’s created on it can be removed from the script since we already don’t use them anymore. Maybe that helps with solving the text problem. It’s the weird spider looking thing.

We’re producing rings it’s very number related and the results should exactly be the same as on windows. This is the result on a windows computer after running the script:


Without the “wheel”:



#20

Yep, _TextObject is the most outrageous example I found for V6, but anywhere they have added or changed a command-line option could potentially break command string based operations. Unfortunately _TextObject has no rhinoscript or RhinoCommon equivalent.

One thing that is also ESSENTIAL here (IMO) is that all the command-line options in the string are spelled out explicitly (i.e. not abbreviated by their shortcut letters as they are in the script above). The reason is that those letters are not hard coded, and can also change if a command line option is added or changed. There is a thread somewhere concerning this… Spelling the options out adds a measure of robustness and readability, at the expense of some line length…

Here is a sample command string comparison for V5/V6 _TextObject:

    if RHV6():
        comm_1='! _-TextObject _Height={} _Rotation=0 _Font "Arial"'
        comm_1+=' _Italic=_No _Bold=_No _CreateGeometry=_Curves _GroupOutput=_Yes'
        comm_1+=' _AllowSingleStrokeFonts=_Yes _LowerCaseAsSmallCaps=_No'
        comm_1+=' _AddSpacing=_No _UseTextCenterToPosition=_No "{}" {}'
    else:
        comm_1='! _-TextObject _GroupOutput=_Yes _FontName='
        comm_1+='"Arial" _Italic=_No _Bold=_No _Height={}'
        comm_1+=' _Output=_Curves _AllowOpenCurves=_Yes "{}" {}'

(the {} get substituted for values later on)

–Mitch