Arcs -- (poor man pt2)

continuing on from this adventure:

so i have 3-4 more other scripts i’d like to make… this one involves arcs… it’s going to require some conditionals but for now, i’ll leave out what exact functionality i need from the script (or else someone is just going to write it for me… i’d like to learn a little first. :wink: )

anyway, first question… i need to draw a vertical arc (vertical in perspective viewport) which sits 5.5" above the origin and has radius and height variables…

here’s what i have to accomplish that but i think there must be a better way (without the 3 plane manipulations)

import rhinoscriptsyntax as rs
import math

height=rs.GetReal("Height - Flat to top of template",66)
radius=rs.GetReal("Radius",90)


cang = math.acos((radius-height)/radius)
cangD = math.degrees(cang)

arcCP = 0.0,0.0,radius+5.5

plane = rs.WorldYZPlane()
plane = rs.MovePlane(plane,arcCP)
plane = rs.RotatePlane(plane, -90.0, plane.ZAxis)
rs.AddArc(plane, radius, cangD)

print cangD

so my first question is: if you had to draw that arc, how is the right way to write it?
thanks


[edit]
or would it be better to just use _Arc start,end, radius?

I can get those points with maths and could just use world coordinates but I wanted to try out the AddArc thing.

That looks as good as any method… For a little more sophistication perhaps:

import rhinoscriptsyntax as rs
import math

height=rs.GetReal("Height - Flat to top of template",66)
radius=rs.GetReal("Radius",90)

cang = math.acos((radius-height)/radius)
cangD = math.degrees(cang)

arcCP = rs.coerce3dpoint([0.0, 0.0, radius+5.5])
plane = rs.WorldYZPlane()
plane.Origin=arcCP
plane.Rotate(math.radians(-90.0), plane.ZAxis)
rs.AddArc(plane, radius, cangD)

print cangD

–Mitch

If you want to get rid of the plane manipulations you could construct the plane directly with PlaneFromNormal using the arc center point as origin and two vectors, one along the positive X axis (the plane normal) and one along the negative Z axis (the plane x-axis direction) :

import rhinoscriptsyntax as rs
import math

height=rs.GetReal("Height - Flat to top of template",66)
radius=rs.GetReal("Radius",90)

cang = math.acos((radius-height)/radius)
cangD = math.degrees(cang)

arcCP = rs.coerce3dpoint([0.0, 0.0, radius+5.5])
xVec=rs.coerce3dvector([1,0,0])
zVec=rs.coerce3dvector([0,0,-1])

plane=rs.PlaneFromNormal(arcCP,xVec,zVec)
rs.AddArc(plane, radius, cangD)

ah, ok… that seems better to me (or, it makes it easier for me to visualize what’s going to happen)

so the brackets [ ]
do those make a list of strings? (if my terminology is correct)

could I use them to do something like

a=[1,2,3]
b=[4,5,6]

then draw a line from a to b?

_line +str(a,b) ?
(sorry, typing on a phone… but hopefully the question is clear enough)


[edit] nvrmnd on those types of questions… just found the rhino python primer (was hesitant to check out general python stuff since i just want to draw things in rhino :wink: )… but it seems there are plenty of examples / tidbits to answer some of my questions.

who wrote the primer btw? seems like a wizard :sparkles:

i’m stuck again… i can’t figure out how to interpret the list from CurveCurveIntersection

here’s what i have:

import rhinoscriptsyntax as rs
import math


height=rs.GetReal("Height - Flat to top of template",66)
radius=rs.GetReal("Radius",90)


cang = math.acos((radius-height)/radius)
cangD = math.degrees(cang)

arcCP = rs.coerce3dpoint([0.0, 0.0, radius+5.5])
xVec=rs.coerce3dvector([1,0,0])
zVec=rs.coerce3dvector([0,0,-1])

plane= rs.PlaneFromNormal(arcCP,xVec,zVec)
arc1= rs.AddArc(plane, radius, cangD)

rotCP = rs.coerce3dpoint([0.0, 48.0, 24.0])
rotVec = rs.coerce3dvector([1.0, 0.0, 0.0])
arc2= rs.RotateObject (arc1, rotCP, 180, axis=rotVec, copy=True)

intlist= rs.CurveCurveIntersection (arc1, arc2)
for intersection in intlist:
    intPT1=intersection[1]
    intPT2=intersection[2]
    intPT3=intersection[3]
    intPT4=intersection[4]

print intPT1
print intPT2
print intPT3
print intPT4

they all give me the same intersection point

0,69.7101353382048,38.5746363109627
0,69.7101353382048,38.5746363109627
0,69.7101353382048,38.5746363109627
0,69.7101353382048,38.5746363109627

but the point i want is the other one: (the lower of the two intersections)

0,26.2898646617952,9.42536368903734

OK, I was just about to answer the question on lists. As a résumé:

Lists are ordered collections of things, they are one of the workhorses of Python - or any programming languages, actually, where they may be called something else like “arrays”.

You can put any different kinds of variables into a Python list - strings, numbers, True/False values, etc. You can even have lists that have different types in the same list.

The most important thing about lists is that they are ordered and you can address/access the items in the list by their index (from left to right). Indexes in programming always start at 0 (something to get used to). Python has marvelous tools for working with lists - too long to go into here, but the Python online documentation is really good for this. If you prefer books, there are several good ones out there.

To answer your question on CurveCurveIntersection: intersection methods are among the hardest to program because the results are complex. The output is a multi-level (nested) list, that is to say a list of lists. The first level will be the number of intersections found. The next level is the details on the type and location.

So, if you know in this case that you only have 2 intersections:

All the info about the first intersection will be contained under result[0]. You will have

result[0][0] which will tell you whether the intersection is a point or a curve (overlap)

if it’s a point, result[0][1] - result[0][4] will all be the same point.

To get the second intersection, you need to use

result[1][n]

result[1][1] - result[1][4] will all contain the same point which will be your second intersection point.

I need to run now, but will be back later…

HTH, --Mitch

great. i see it now… i was looking at the example in the index:

for intersection in intersection_list:
        if intersection[0] == 1:
            print "Point"
            print "Intersection point on first curve: ", intersection[1]
            print "Intersection point on second curve: ", intersection[3]
            print "First curve parameter: ", intersection[5]
            print "Second curve parameter: ", intersection[7]
        else:
            print "Overlap"
            print "Intersection start point on first curve: ", intersection[1]
            print "Intersection end point on first curve: ", intersection[2]

and if i used it like that, it would work… i couldn’t figure out why it needed if/then but now i get what’s happening… it’s saying if [0] is True then print [1] … or [0] [1] instead of just [1]
:eyeglasses:
thank you!


:sigh: i thought it clicked when i read your post but i still can’t get the point to where it will act like

thatPoint = ([x,y,z])

…or, i can’t figure out how to put a Point object on the lower intersection (not that i need the point in the model… just that i couldn’t do it with rs.AddPoint if i had to)

gottta sleep now though.

OK, here’s some more info that might help in general…

The first thing is that Python (unlike vb script) is a completely object oriented programming language (OOP). That sounds scary and technical - actually it is somewhat - but it’s also what makes it very cool and powerful to work with. Rhinoscriptsyntax in Python is simply a set of “scripts” that emulate the existing vb Rhinoscript functions - which themselves are designed to make it easier to program Rhino by encapsulating a series of lower-level operations into easily understandable functions for the “average” scripter (like AddPoint).

So, EVERYTHING in Python is an “object”. Not a physical object, sure, but a programming object. Objects are not static things, they have specific characteristics, notably Properties and Methods. Properties are things that are intrinsic to the object - if the object was an apple, it might be color, size, weight, etc. Methods are actions that one can do with an object - again if it’s an apple it could be eat, peel, bake, throw, etc. - that normally produce some kind of result.

So, what does this have to do with your questions?

Well a point in Rhino/Python is not just a list of 3 coordinates, it’s a “point3d” object. As with any object, it has both methods and properties. Point object methods are things like Add, Subtract, Multiply and Divide (yes, you can do that with points) but also things like DistanceTo() and CompareTo(); Properties would be things like its X, Y, and Z coordinates (things that are intrinsic to a point object).

Methods are called on an object with parentheses afterwards - i.e. object.Method() , whereas properties are accessed without parentheses - i.e. object.Property. Methods can take arguments (inputs) which are put in the parentheses, but not all methods require them.

So, you’ve already seen something like this for getting the properties of a 3d point:

a=my_point.X

a will then contain a number that is the X coordinate of your point. In addition to “Get”-ing properties, in most cases you can also “Set” them by inverting the order:

my_point.X=a

Assuming a had a number stored in it, it will change the X coordinate of your point to the value of a. (if a has any other type of data in it, say a string, it will error out).

An example of a 3dpoint object method might be:

dist=ptA.DistanceTo(ptB)

In vb Rhinoscript, which is not object oriented, an array (list) of 3 numbers is the equivalent of a 3d point. For compatibility reasons, most python rhinoscriptsyntax methods have been engineered to accept lists or tuples of 3 numbers and interpret them as 3d points - even if they are not real 3d point objects. These methods do so by calling coerce3dpoint() behind the scenes; coerce3dpoint() is a function which attempts to interpret diverse data (even strings!) as a point if possible. You can also call it expressly outside of any other method, which you see me do in one of the examples above.

So, finally, with all that said, I can answer your question:

rs.AddPoint([x,y,z]) works because it is designed to convert the [x,y,z] into a 3d point behind the scenes without you having to explicitly do so. However:

thatPoint = ([x,y,z]) doesn’t work because it’s not actually creating a 3d point - you haven’t asked it to do so. All you’ve done there is create a list…

To get a 3dpoint object, you would need:

thatPoint=rs.coerce3dpoint([x,y,z])

So now maybe some of the code in my previous examples will now make more sense… at least I hope so.

Gotta go out again now, hope you had a good sleep and that all the above rambling actually helps clear up some of the confusion and not add to it…

–Mitch

1 Like

Oh, and what I wanted to say also… sometimes, it’s easier to simply call rs.Command("_Intersect") with the selected objects and get the returned results. If you know they are supposed to be points - you can check with rs.IsPoint() - you can then get the point coordinates with rs.PointCoordinates(ptID). You will have to do some cleanup afterwards, though, i.e. have your script delete the actual Rhino objects that Intersect has added to the document. once you have gotten their coordinates.

–Mitch

wow… thanks so much for the detailed info

i wouldn’t say it’s completely sunk in yet but enough to where i can make this work for now… can you see if what i did on line24 is right or if i just got lucky (and line 27, where i needed only the Y)

further down in the _Polyline, i feel like i should of been able to use the info obtained from the intersect but i couldn’t figure out how to get it out of object form and back into list… (but what i really wanted to do was just draw the polyline with 6 point objects if that’s possible)… instead i had to do maths to get certain locations when the info i need is already in the script… [EDIT]hmm… actually, no it’s not… the intersection point isn’t the same point where my needed arc stops… so, nevermind on that bit [/Edit]

anyway, this script is about 1/3 done right now… it needs some things to handle radii over ~11’ and under ~6’… (over 11 needs bigger plywood… under ~7’ will have the arc centerpoint moving along Y)…
but even exactly as is, this will save me so much time on the jobsite… (well, 15 minutes here&there… but on site, that’s valuable time :wink: )

import rhinoscriptsyntax as rs
import math


height=rs.GetReal("Height - Flat to top of template",66)
radius=rs.GetReal("Radius",90)


cang = math.acos((radius-height)/radius)
cangD = math.degrees(cang)

arcCP = rs.coerce3dpoint([0.0, 0.0, radius+5.5])
xVec=rs.coerce3dvector([1,0,0])
zVec=rs.coerce3dvector([0,0,-1])

plane= rs.PlaneFromNormal(arcCP,xVec,zVec)
arc1= rs.AddArc(plane, radius, cangD)

rotCP = rs.coerce3dpoint([0.0, 48.0, 24.0])
rotVec = rs.coerce3dvector([1.0, 0.0, 0.0])
arc2= rs.RotateObject (arc1, rotCP, 180, axis=rotVec, copy=True)

intlist= rs.CurveCurveIntersection (arc1, arc2)
intPT=rs.coerce3dpoint(intlist[1][1])

#central angle & arc length from start point to furthest intersection point
cang2 = math.asin(intPT[1]/radius)
arclen2 = radius*cang2
#find the nearest length to the intersection point which is divisible by 8" while no longer intersecting.. this is the cutline for the lower template.
lowArcLen = 8*(math.floor(arclen2/8))

lowCang = lowArcLen/radius
lowCangD = math.degrees(lowCang)

lowArc= rs.AddArc(plane, radius, lowCangD)
lowArc2= rs.RotateObject (lowArc, rotCP, 180, axis=rotVec, copy=True)
rs.DeleteObject(arc1)
rs.DeleteObject(arc2)

#draw 4x8ply for reference.. take this out later.
#recPlane= rs.WorldYZPlane()
#rs.AddRectangle (recPlane, 96.0, 48.0)

lpl2=math.sin(lowCang)*radius
lpl3=(radius+5.5)-(math.cos(lowCang)*radius)
lpl5=math.sin(lowCang)*(radius+5.5)
lpl6=(radius+5.5)-(math.cos(lowCang)*(radius+5.5))

lowPL= rs.Command("Polyline w0,"+str(lpl2)+","+str(lpl3)+" w0,"+str(lpl5)+","+str(lpl6)+" w0,96,"+str(lpl6)+" w0,96,0 w0,0,0 w0,0,5.5 _Enter")
lowPL1= rs.LastCreatedObjects()
lowPL2= rs.RotateObject (lowPL1, rotCP, 180, axis=rotVec, copy=True)

[what it’s doing is drawing arcs with lengths divisible by 8" while letting two of these things fit on one sheet of plywood (8" is the framing layout… there’s a top&bottom section and i like the seam to be on layout or else you end up with either a wonky layout of 4-2x6s crammed in the seam section)

I’m going to write some more of this script in a couple hours and need to add some conditions(?).

it will basically be - if this happens then a whole bunch of stuff is different than if that happens.

will I use def? like-

if boolean is true:
def1
else:
def2

(can’t get it to indent on my phone but I know there are some indent ions there)

is that how that works? and if so, do the defs have to be in a certain place in the script… before or after the if/then statement?


or for example… a few places in this script, there’s ‘radius+5.5’…
but I’ll have a GetBoolean at the beginning which lets me either run the arc to the ground or have it start 5.5 above the ground.
for many of the calculations, I could just do-
if ground is true: radius = R
else radius = R+5.5
and I think it would work out… however, the poly line at the end will need to be different too (if true it has 4 lines… if false it will need a 5th vertical line) so I think I might have to have two separate polyline options and need to know how to steer the script to the right one.


edit-
found this:
http://code.algorithmicdesign.net/Introduction-To-Python

seems pretty good for me… short and sweet with lots of examples :wink:

Yep, you’ve pretty much got it…


if a:
    #do something
elif b:
    #do something else
else:
    #do some default thing if neither condition a nor condition b is met...

When a condition is met, the script proceeds to the indented block just below the query, and will execute all of the following code until the next “outdent”. The tricky part is keeping the indents to the correct level if you have nested conditionals. You can have as many “elif’s” as you want or none (just if-else)…

–Mitch

found out rs.AddPolyline does this:

Duplicate, consecutive points found in the array will be removed. 

pretty sweet feature for what i need in certain parts of this script.



is it possible to make these kind of dialogs via python?

or-- 1) is it possible? 2) if possible, is it a lot of work/learning to make?