Help up the garden path

Discussion in 'AutoCAD' started by Jonathan Parsons, Mar 3, 2005.

  1. I have R14 and wanted to give Autolisp a try so I started looking at the
    garden path tutorial.

    I can just about cope with the maths concepts but can't grasp the (defun
    drow (pd offset).....

    Where do the values for "pd" and "offset" come from? I can get a value for
    things like "pfirst" with !pfirst but !pd just returns nil.

    I understand how the other points, distances and angles are set with "setq"
    or calculations using such "setq" values. How does the line (setq pfirst
    (polar sp pangle pd)) work when no value is given or calculated for "pd"?

    Hope I'm being stupid and a word of explanation will sort me out.

    Thanks
    Jon
     
    Jonathan Parsons, Mar 3, 2005
    #1
  2. Post the code so we can see it.
     
    Michael Bulatovich, Mar 3, 2005
    #2
  3. The code is below. I've left out dtr.lsp which converts degrees to radians.

    The part where I lose it is

    "(defun drow (pd offset)
    (setq pfirst (polar sp pangle pd))
    (setq pctile (polar pfirst angp90 offset))".

    As I say I can't understand how pd and offset can be used without having
    been assigned a value with setq or being previously calculated. What are
    their values and where are they assigned?

    It works of course (it comes with Acad 14 as the tutorial) but the notes in
    the help file don't explain it in enough detail.

    Thanks for the interest Michael

    Jon








    ; Draw outline of path
    (defun drawout ()
    (command "pline"
    (setq p (polar sp angm90 hwidth))
    (setq p (polar p pangle plength))
    (setq p (polar p angp90 width))
    (polar p (+ pangle (dtr 180)) plength)
    "close"
    )

    )
    ; Place one row of tiles the given distance along path
    ; and possibly offset it






    (defun drow (pd offset)
    (setq pfirst (polar sp pangle pd))
    (setq pctile (polar pfirst angp90 offset))







    (setq p1tile pctile)
    (while (< (distance pfirst p1tile) (- hwidth trad))
    (command "circle" p1tile trad)
    (setq p1tile
    (polar p1tile angp90 (+ tspac trad trad)))
    )
    (setq p1tile (polar pctile angm90 (+ tspac trad trad)))
    (while (< (distance pfirst p1tile) (- hwidth trad))

    (command "circle" p1tile trad)
    (setq p1tile
    (polar p1tile angm90 (+ tspac trad trad)))
    )
    )

    ; Draw the rows of tiles
    (defun drawtiles ()
    (setq pdist (+ trad tspac))
    (setq off 0.0)
    (while (<= pdist (- plength trad))
    (drow pdist off)
    (setq pdist
    (+ pdist (* (+ tspac trad trad) (sin (dtr 60)))))
    (if (= off 0.0)
    (setq off (* (+ tspac trad trad) (cos (dtr 60))))
    (setq off 0.0)
    )
    )

    )
     
    Jonathan Parsons, Mar 3, 2005
    #3
  4. Jonathan Parsons

    Paul Turvill Guest

    The symbols pd and offset are arguments required by the draw function; it is
    called with
    (draw val1 val1)
    where val1 and val2 contain the values to be assigned to pd and offset,
    respectively. They can be variables (symbols with values assigned), or
    actual numbers.
    ___
     
    Paul Turvill, Mar 3, 2005
    #4
  5. You've got to post all of it. If memory serves, the tutorial was a group of
    functions working together.

    The values are probably coming from another function.
     
    Michael Bulatovich, Mar 3, 2005
    #5
  6. OK here's the full tutorial. Except the diagrams which don't show much more
    than what you get.
    The bit I'm stuck on is described below as : "The function drow draws a row
    of tiles at a given distance along the path specified by its first argument,
    offsetting the row perpendicular to the path by a distance given by its
    second argument."
    My problem is about the "given distance"s - where are they given? They don't
    seem to be, they are just used!

    pd must be (+ tspac trad) both of which are set with getdist. I just don't
    see where it says so.

    Ah ha!!!!!!!!!!!!!

    It just clicked!

    pd and offset are just unnecessarily obscure names to show that drow takes 2
    arguments! They could have been elephant and mouse or a &b.

    When drow is called latter pdist and off are substituted and they actually
    mean something!!!!!

    Is that right?

    Thanks Paul (you were right) and Michael for your replys
    Jon




    You will develop this application from the inside out (or from the bottom
    up), and you will frequently use angles. AutoLISP specifies angles in
    radians. Radians measure angles from 0 to 2 * p (pi). Because most users
    think of angles in terms of degrees, you will define a function that
    converts degrees to radians. Using your text editor, create a file called
    gp.lsp. Enter the following program:

    ; Convert angle in degrees to radians
    (defun dtr (a)
    (* pi (/ a 180.0))

    )

    Now consider what this does. You are defining a function by using the defun
    function. The function is called dtr (short for degrees to radians). It
    takes one argument, a, the angle in degrees. Its result is this expression:

    p * (a / 180.0)

    The function is expressed in LISP notation that you can read as the product
    of PI multiplied by the quotient of A divided by 180.0. p is predefined by
    AutoLISP as 3.14159.... The line beginning with a semicolon is a comment;
    AutoLISP ignores all text on a line after a semicolon.
    Save the file to a disk, and then bring up AutoCAD on a new drawing. (The
    name doesn't matter, because you won't be saving the drawing.) At the
    Command prompt, load the function by entering

    Command: (load "gp")

    DTR

    AutoLISP loads your function, echoing its name DTR (if gp.lsp is in the
    AutoCAD search path). From now on, start AutoCAD and load the program refers
    to the sequence just described.
    Now test the function by executing it with various values. Based on the
    definition of radians, 0 degrees should equal 0 radians. So enter this:

    Command: (dtr 0)

    Entering a line that begins with a left parenthesis makes AutoCAD pass the
    line to AutoLISP for evaluation. In this case, you are evaluating the dtr
    function that was just defined, and you are passing it an argument of 0.
    After evaluating the function, AutoCAD displays the result, so that the
    input should generate this reply:

    0.0

    Now try 180 degrees. Enter the following

    Command: (dtr 180)

    You then see this response:

    3.14159

    This indicates that 180 degrees is equal to p radians. If you examine the
    function, you see that this is how it was defined.
    At this point you should quit AutoCAD and return to your text editor.

    The "garden path" command asks the user where to draw the path, how wide to
    make it, how large the concrete tiles are, and how closely to space them.
    You will define a function that asks the user for all of these items and
    then computes various numbers to use in the rest of the command.
    Using your text editor, add the following lines to gp.lsp.

    ; Acquire information for garden path
    (defun gpuser ()
    (setq sp (getpoint "\nStart point of path: "))
    (setq ep (getpoint "\nEndpoint of path: "))
    (setq hwidth (getdist "\nHalf width of path: " sp))
    (setq trad (getdist "\nRadius of tiles: " sp))
    (setq tspac (getdist "\nSpacing between tiles: " sp))
    (setq pangle (angle sp ep))
    (setq plength (distance sp ep))
    (setq width (* 2 hwidth))
    (setq angp90 (+ pangle (dtr 90))) ; Path angle + 90 deg
    (setq angm90 (- pangle (dtr 90))) ; Path angle - 90 deg

    )

    It isn't necessary to indent the expressions that constitute your functions.
    However, indentation and line breaks make the structure of the program
    clearer. Also, lining up the starting and ending parentheses of major
    expressions helps to ensure that your parentheses balance properly. It is
    recommended that you use spaces instead of tabs to indent lines. This
    ensures that the indentation remains consistent between edit sessions and
    word processors.
    Here you have defined a function called gpuser. It takes no arguments and
    asks the user for all of the desired items. The setq function sets an
    AutoLISP variable to a specific value. The first setq sets variable sp
    (start point) to the result of the getpoint function, which obtains a point
    from the user. A string specifies the prompt that AutoCAD uses to obtain the
    point. You use the getdist function to obtain the half width of the path,
    the tile radius, and the spacing between the tiles. The second argument to
    the getdist function, sp, specifies the base point for the distance. This
    makes the distance, if specified by a point in AutoCAD, relative to the
    starting point of the path, and attaches a rubber-band line to that point.

    The function computes several commonly used variables after obtaining input
    from the user. The pangle variable is set to the angle from the start point
    to the endpoint of the path. The angle function returns this angle given two
    points. The plength variable is set to the length of the path. The distance
    function calculates a distance based on two points. Since you specified the
    half width of the path, you calculate the width as twice this distance.
    Finally, you calculate and save the angle of the path plus and minus 90
    degrees in angp90 and angm90, respectively. (Because angles within AutoLISP
    are in radians, you used the dtr function to convert degrees to radians
    before calculating these measurements.)

    The following illustration shows how the variables obtained by gpuser
    specify the dimensions of the path.

    Save this updated program to a disk. Then start AutoCAD and load it. Now
    test this input function to make sure it is working properly. Activate the
    function by entering

    Command: (gpuser)

    Respond to the prompts as follows:

    Start point of path: 2,2
    Endpoint of path: 9,8
    Half width of path: 2
    Radius of tiles: .2

    Spacing between tiles: .1

    The gpuser function uses your replies to compute the additional variables it
    needs, and then displays the result of its last computation (in this
    case, -0.86217, the value of angm90 in radians). You can dump out all the
    variables set by the gpuser function by entering their names preceded by an
    exclamation point (!). This causes AutoCAD to evaluate the variable and
    print the result. If you enter the following commands, you should receive
    the results shown in parentheses.

    Command: !sp
    (2.0 2.0 0.0)
    Command: !ep
    (9.0 8.0 0.0)
    Command: !hwidth
    2.0
    Command: !width
    4.0
    Command: !trad
    0.2
    Command: !tspac
    0.1
    Command: !pangle
    0.708626
    Command: !plength
    9.21954
    Command: !angp90
    2.27942
    Command: !angm90

    -0.86217

    The sp and ep variables are returned as 3D points (X, Y, and Z); ignore the
    Z component in this exercise.
    Also, pangle, angp90, and angm90 are represented in radians. After verifying
    these values, quit AutoCAD and return to your text editor on gp.lsp.

    Now that you have asked the user for the location of the path, you can draw
    its outline. Add the following lines to your gp.lsp file.

    ; Draw outline of path
    (defun drawout ()
    (command "pline"
    (setq p (polar sp angm90 hwidth))
    (setq p (polar p pangle plength))
    (setq p (polar p angp90 width))
    (polar p (+ pangle (dtr 180)) plength)
    "close"
    )

    )

    This addition defines a function called drawout. This function uses the
    starting point, angle, and length of the path obtained by the gpuser
    function, and draws the outline of the path as a polyline. The drawout
    function uses the command function to submit commands and data to AutoCAD.
    The command function takes any number of arguments and submits each one to
    AutoCAD.
    In this case, you feed the PLINE command to AutoCAD and then supply the
    four corners of the path. The function locates each corner with the polar
    function, and then stores their coordinates in the temporary variable p.
    The polar function takes a point as its first argument, and an angle and
    distance supplied by its second and third arguments, and returns a point the
    specified distance and angle from the original point. In this case you
    calculate the four points bounding the path geometrically from the start
    point of the path. You complete the command by sending the string close to
    the PLINE command, which causes it to draw the fourth side of the path and
    return to the Command prompt.

    To test this function, save the updated gp.lsp, start AutoCAD on a new
    drawing, and load the AutoLISP file as before. Activate the user input
    function as before.

    Command: (gpuser)

    Supply the values as you did in the preceding step. Then test the new
    drawout function by invoking it.

    Command: (drawout)

    Your function supplies the commands to AutoCAD to draw the border for the
    path, and the border appears on the screen. After testing the function, quit
    AutoCAD.

    Now that you have developed and tested the user input function and the
    function that draws the border, you are ready to fill the path with the
    circular tiles. This requires some geometry. Bring up your text editor, and
    add the following code:

    ; Place one row of tiles the given distance along path
    ; and possibly offset it
    (defun drow (pd offset)
    (setq pfirst (polar sp pangle pd))
    (setq pctile (polar pfirst angp90 offset))
    (setq p1tile pctile)
    (while (< (distance pfirst p1tile) (- hwidth trad))
    (command "circle" p1tile trad)
    (setq p1tile
    (polar p1tile angp90 (+ tspac trad trad)))
    )
    (setq p1tile (polar pctile angm90 (+ tspac trad trad)))
    (while (< (distance pfirst p1tile) (- hwidth trad))

    (command "circle" p1tile trad)
    (setq p1tile
    (polar p1tile angm90 (+ tspac trad trad)))
    )
    )

    ; Draw the rows of tiles
    (defun drawtiles ()
    (setq pdist (+ trad tspac))
    (setq off 0.0)
    (while (<= pdist (- plength trad))
    (drow pdist off)
    (setq pdist
    (+ pdist (* (+ tspac trad trad) (sin (dtr 60)))))
    (if (= off 0.0)
    (setq off (* (+ tspac trad trad) (cos (dtr 60))))
    (setq off 0.0)
    )
    )

    )

    To understand how these functions work, refer to the following illustration.
    The function drow draws a row of tiles at a given distance along the path
    specified by its first argument, offsetting the row perpendicular to the
    path by a distance given by its second argument. You want to offset the
    tiles on alternate rows to cover more space and to make a more pleasing
    arrangement.

    The drow function finds the location for the first tile in the row by using
    polar to move along the path by the distance given by the first argument. It
    then uses polar again to move perpendicularly to the path for the offset.
    The drow function uses the while function to continue to draw circles until
    the edge of the path is encountered. The setq at the end of the while loop
    moves on to the next tile location by spacing a distance of two tile radii
    and one intertile spacing. A second while loop then draws the tiles in the
    row in the other direction until the other edge of the path is encountered.

    The drawtiles function calls drow repeatedly to draw all the rows of tiles.
    Its while loop steps along the path, calling drow for each row. Tiles in
    adjacent rows form equilateral triangles, as shown in the illustration. The
    edges of these triangles are equal to twice the tile radius plus the spacing
    between the tiles. Therefore, by trigonometry, the distance along the path
    between rows is the sine of 60 degrees multiplied by this quantity, and the
    offset for odd rows is the cosine of 60 degrees multiplied by this quantity.

    The if function is used in drawtiles to offset every other row. The if
    function tests its first argument and executes the second argument if it is
    true and the third argument otherwise. In this case, if OFF is equal to 0,
    set it to the spacing between the centers of tiles multiplied by the cosine
    of 60 degrees as explained earlier. If OFF is not 0, set it to 0. This
    alternates the offset on the rows as you want.
    To test this function, save the file. Then start AutoCAD and load the
    program. Enter the following:

    Command: (gpuser)

    Supply the path information as before. Enter the following:

    Command: (drawout)

    The outline should be drawn as before. Finally, enter the following:

    Command: (drawtiles)

    All of the tiles should be drawn within the border.
     
    Jonathan Parsons, Mar 3, 2005
    #6
  7. pd and offset ARE the arguments to the function DROW.
    They must be passed with the call to the function.
    When the call to drow was made like this:

    (drow pdist off)

    the value of pdist becomes pd in the function, and that of off becomes
    offset.

    Head hurt yet?
     
    Michael Bulatovich, Mar 3, 2005
    #7
  8. After a night's sleep I think I can think again.

    Thanks
    Jon
     
    Jonathan Parsons, Mar 4, 2005
    #8
  9. When I started poking around with lisp I did what you did, and checked out
    the tutorial. But then, I did what I usually do. I gave up on the program
    and devised for myself a project which could be divided up into several
    discreet stages, but which, when added together, would give me a useful tool
    at the end of it. After some success with that, I quickly started
    recognizing all kinds of productivity enhancing opportunities for lisp which
    were within my tenuous grip on the language.

    Some routines were larger projects with meager payback, and others were
    quite quick with huge payback. I'm not sure if I ever managed an error
    handler, but it didn't matter. They all made me faster. You can see a
    collection on my site.

    When it comes to elegance, my routines aren't the place. I am the King of
    Kludge. I often resort to long English names for variables and functions and
    I do heavily annotate them while I developed them. I usually leave the
    annotation in the code to remind me of how they work when I revisit them.
    You might find that it makes them easier to follow for you as well.
     
    Michael Bulatovich, Mar 4, 2005
    #9
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.