GDL
About building parametric objects with GDL.
SOLVED!

Hotspots automatically on polyline nodes from gdl

daniels
Booster

I script 2D gdl and use the POLY2_B{5} command and I can achieve most thing I wanted with it.

However, for hotspots on the nodes I need to write additional lines with the hotspot2 command and duplicate coordinate information in the script what is not ideal.

 

Is there a way to have hotspots automatically generated on each node of gdl polylines? (just pure hotspots for now).

1 ACCEPTED SOLUTION

Accepted Solutions
Solution

First of: Congrats for the courage to learn GDL! You will soon find it to be addicting.

 

Even if you do not need graphical editing the way the linked object works is worth to be examined. But I understand that dissecting code as a beginner is a hard task.

So to continue from my first post here:

In GDL you have the possibility to put data (only numbers, to be precise) onto the so called Stack. This is a kind of volatile data storage. This storage is FIFO (= First In, First Out), like a vending machine for numbers.

We utilize this to be able to quickly prepare masses of data for consumption in commands.

By the way: Do you really need version 5 of the poly2_b command? I work in 95% of all my objects with poly2_b alone.

 

To put data onto the stack, you literally just use "put" and the data afterwards, like this:

put 1.1, 2, 3

The stack now holds those three numbers. To retrieve them you can use "get" and "use".

The difference between them is how they alter the stack: "get" removes the data, "use" will leave it. This is crucial, not only for your example, but in general. Because a key concept of the stack is, that you can not discriminate the data. You will have to adhere to FIFO – so it's not like its an array, where you can use an index to grab some data.

Example:

get(1) gives us "1.1". The stack now looks "2, 3". use(1) will return "2", but the stack hasn't changed. This makes "use" in real life a bit useless, since the stack has no advancing pointer. So "use" just makes sense when you can consume the whole stack at once.

nsp gives us the current number of items on the stack.

 

With all of this info we can easily code the following example:

 

 

unID = 1
s = 1

put 0, 0, s
put A, 0, s
put A, B, s

poly2_b nsp/3, 1+2+4,
		1, 1,
		use(nsp)

for i=1 to nsp/3
	hotspot2 get(2), unID
	_dummy = get(1)
	unID = unID + 1
next i

 

 

Clean looking code. What can we learn here?

- "Use" (or "get") the entire stack at once for commands like poly2.

- Variables that hold numbers can be put on the stack as well (here: "s" as status code for the poly2_b command.

- "NSP" is just a number, so it can be part of arithmetics – which is a must here, since the loop should only be running 3 times, once for every ordinate pair.

- We can use "get" and assign it to an unused dummy variable, which discards the item from the stack, so we can advance in the next loop run.

- After the final loop the stack is exhausted, meaning its empty. "NSP" would yield zero.

 

Lucas Becker | AC 27 on Mac | Graphisoft Insider Panelist | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text | My List of AC shortcomings & bugs | I Will Piledrive You If You Mention AI Again |

POSIWID – The Purpose Of a System Is What It Does /// «Furthermore, I consider that Carth... yearly releases must be destroyed»

View solution in original post

10 REPLIES 10
runxel
Legend

Two possibilities for you:

  • You either store it in an array before hand, or
  • Directly use "put" once, then get it back via "use" before the final "get".

The hotspots should be done in a loop.

Lucas Becker | AC 27 on Mac | Graphisoft Insider Panelist | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text | My List of AC shortcomings & bugs | I Will Piledrive You If You Mention AI Again |

POSIWID – The Purpose Of a System Is What It Does /// «Furthermore, I consider that Carth... yearly releases must be destroyed»

Thank you for the suggestion.

I looked for these commands on the gdl site and to be honest I didn't really get how to start with them, how to extract the certain values of coordinates I need. An example would be vey helpful to see how should I go further. I attached a sample object where I would like to add the hotspots on each node. I would be very grateful if you could show me on this how to proceed.

runxel
Legend

Okay, so it looks like you're a beginner with GDL, right?

You might have already now took a deep dive into a hard topic. 😄

Look at the glorious object of sinceV6 – that is the best example you can get. But beware: GDL is verbose; there is no single command to just achieve what you want. And the example might be very hard to grok if you are not already comfortable in GDL.

Lucas Becker | AC 27 on Mac | Graphisoft Insider Panelist | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text | My List of AC shortcomings & bugs | I Will Piledrive You If You Mention AI Again |

POSIWID – The Purpose Of a System Is What It Does /// «Furthermore, I consider that Carth... yearly releases must be destroyed»

Hi runxel, yes very beginner 🙂 Just started a few weeks ago doing only 2D basic linework and fill stuff, just to replace our practice's current method of saving one-off 2D Objects.

The glorious object looks very interesting I will dive into its script, but as you mentioned, quite deep for me yet.

At the moment I don't need graphical editing possibility with the purple diamond hotspots, only adding simple black hotspots to the nodes for snapping purposes. Currently I write a lot of lines with the hotspot2 command and looking for the possibility to have these coming from the coordinate pairs of the poly2_b{5} command.

Solution

First of: Congrats for the courage to learn GDL! You will soon find it to be addicting.

 

Even if you do not need graphical editing the way the linked object works is worth to be examined. But I understand that dissecting code as a beginner is a hard task.

So to continue from my first post here:

In GDL you have the possibility to put data (only numbers, to be precise) onto the so called Stack. This is a kind of volatile data storage. This storage is FIFO (= First In, First Out), like a vending machine for numbers.

We utilize this to be able to quickly prepare masses of data for consumption in commands.

By the way: Do you really need version 5 of the poly2_b command? I work in 95% of all my objects with poly2_b alone.

 

To put data onto the stack, you literally just use "put" and the data afterwards, like this:

put 1.1, 2, 3

The stack now holds those three numbers. To retrieve them you can use "get" and "use".

The difference between them is how they alter the stack: "get" removes the data, "use" will leave it. This is crucial, not only for your example, but in general. Because a key concept of the stack is, that you can not discriminate the data. You will have to adhere to FIFO – so it's not like its an array, where you can use an index to grab some data.

Example:

get(1) gives us "1.1". The stack now looks "2, 3". use(1) will return "2", but the stack hasn't changed. This makes "use" in real life a bit useless, since the stack has no advancing pointer. So "use" just makes sense when you can consume the whole stack at once.

nsp gives us the current number of items on the stack.

 

With all of this info we can easily code the following example:

 

 

unID = 1
s = 1

put 0, 0, s
put A, 0, s
put A, B, s

poly2_b nsp/3, 1+2+4,
		1, 1,
		use(nsp)

for i=1 to nsp/3
	hotspot2 get(2), unID
	_dummy = get(1)
	unID = unID + 1
next i

 

 

Clean looking code. What can we learn here?

- "Use" (or "get") the entire stack at once for commands like poly2.

- Variables that hold numbers can be put on the stack as well (here: "s" as status code for the poly2_b command.

- "NSP" is just a number, so it can be part of arithmetics – which is a must here, since the loop should only be running 3 times, once for every ordinate pair.

- We can use "get" and assign it to an unused dummy variable, which discards the item from the stack, so we can advance in the next loop run.

- After the final loop the stack is exhausted, meaning its empty. "NSP" would yield zero.

 

Lucas Becker | AC 27 on Mac | Graphisoft Insider Panelist | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text | My List of AC shortcomings & bugs | I Will Piledrive You If You Mention AI Again |

POSIWID – The Purpose Of a System Is What It Does /// «Furthermore, I consider that Carth... yearly releases must be destroyed»

Hi runxel,

 

Amazingly well written and easy to understand description. Thank you!

It would have been very hard to reach this from the gdl reference guide's complex NSP example.

 

I originally used the version 5 of the poly2_b command because it is the one generated by Archicad when you save an object. Then I was worried if they will remove older commands in the future (does that happen?), but moreover I found that it has a separate 'fillcategory' parameter which seemed cleaner in the script. However, it is indeed a bit disturbing to have so many unused distortion and fill origin parameters, so I will probably go with your recommendation.

 

A few other questions:

 

I see you used status code 1 where I used 33. I wanted to express that the next segment is contour line. Is it actually the case, that 33 is only needed once in case you switch back from inner lines to contour lines? No other benefit of 33? And in the same manner is 17 status code needed only once when you switch to inner line and then you can continue with '1'-s until you are creating more inner lines?

 

As I understand, we could write anything instead of _dummy (except command or parameter names) - is that right?

 

I tried your script without unID and worked. Is there a practical reason to have it?

 

I developed my test object with your recommendation and it works nicely - see attached DS-04.gsm

 

There is one issue however if there are curves - hotspots will be generated with the angle values as well.

 

I would like to include an exclusion in the hotspot loop, like below. But it does not work how I wrote it. Would there be a way to script this?

 

for i=1 to nsp/3
hotspot2 get(2), unID
IF get(1) = 900 THEN _dummy = get(4) ELSE _dummy = get(1)
unID = unID + 1
next i


Amazingly well written and easy to understand description. Thank you!

You're welcome! I'm glad you could learn something from this.

 

I originally used the version 5 of the poly2_b command because it is the one generated by Archicad when you save an object. Then I was worried if they will remove older commands in the future (does that happen?),

No, this has never been the case. It's fully future-compatible (well, except when they slashed some commands for usage in the parameter script, but thats another story for another day). They will even leave all bugs in, as well! Instead GS just makes new versions of the same command....

So don't worry.

 

I see you used status code 1 where I used 33. I wanted to express that the next segment is contour line. Is it actually the case, that 33 is only needed once in case you switch back from inner lines to contour lines? No other benefit of 33? And in the same manner is 17 status code needed only once when you switch to inner line and then you can continue with '1'-s until you are creating more inner lines?

I rarely use that. The status is basically like the LINE_PROPERTY attribute, just with a fine grained control, since you can decide on every edge.

The only benefit I see ist that the object will then react to the view option that conture lines should be fat. But that's just for display. So basically that's visual sugar for the user, but no one else (since it won't be visible in physical plan). Also if you explode an object the line categories will be set right, but yeah, I do not care too much about this.

 

As I understand, we could write anything instead of _dummy (except command or parameter names) - is that right?

Yes. What 99% of all GDL coders don't know: Even just the underscore itself is enough.

 

I tried your script without unID and worked. Is there a practical reason to have it?

Yes, there is. The whole concept of scripted Hotspots was added later in GDL, so they made it optional to use the unique ID (again, for backwards compatibility). However, starting with 26 we could see that there was an internal change in how objects with hotspots who are not uniquely numbered are handled: The ID comes into play when you dimension the object. The dimension will be associated. But with unnumbered hotspots there will be problems tho. My tip: Treat the unID as obligatory now.

 

There is one issue however if there are curves - hotspots will be generated with the angle values as well.

 

I would like to include an exclusion in the hotspot loop, like below. But it does not work how I wrote it. Would there be a way to script this?

 

for i=1 to nsp/3
hotspot2 get(2), unID
IF get(1) = 900 THEN _dummy = get(4) ELSE _dummy = get(1)
unID = unID + 1
next i


Okay, that needs to have a different strategy. It was already well observed and smart to just disregard any data that is not an ordinate pair, but has some other status set.

I would it do like this:

for i=1 to nsp/3
	_x = get(1)
	_y = get(1)
	_s = get(1)
	if _s # 900 then
		hotspot _x, _y, unID
		unID = unID + 1
	endif
next i

 

Lucas Becker | AC 27 on Mac | Graphisoft Insider Panelist | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text | My List of AC shortcomings & bugs | I Will Piledrive You If You Mention AI Again |

POSIWID – The Purpose Of a System Is What It Does /// «Furthermore, I consider that Carth... yearly releases must be destroyed»

Thank you again,

Might be strange, but I find it kind of a beauty when a script becomes smarter and smarter. Addictive as you said.

I attached the new version (DS-05), it works nicely now, the only thing I realized that the lines with the status codes referring to the arcs themselves need to be omitted, so changed the line to

if _s < 1000 then

 

One last thing to make my exercise "perfect" - especially as I understand now the importance of hotspots' ID-s, is the possibility of skip hotspot creation when there is one in the same place already.

 

Something like:

for i=1 to nsp/3
	_x = get(1)
	_y = get(1)
	_s = get(1)
	if (_s < 1000 and "no hotspot2 in the script yet where (x =_x and y=_y)") then
		hotspot2 _x, _y, unID
		unID = unID + 1
	endif
next i

Is it scriptable?


@daniels wrote:

One last thing to make my exercise "perfect" - especially as I understand now the importance of hotspots' ID-s, is the possibility of skip hotspot creation when there is one in the same place already.

Is it scriptable?


First I was asking myself, why that would be, but I guess if you have multiple fills in the object then they probably share some vertices and you want to omit any doubles.

So is it scriptable? Of course, but this is left as an exercise for the reader 😉

Jokes aside, that would need to have an entire different code structure and you would work with arrays then. The computational overhead would be big, too. In my opinion not worth the hassle.

Lucas Becker | AC 27 on Mac | Graphisoft Insider Panelist | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text | My List of AC shortcomings & bugs | I Will Piledrive You If You Mention AI Again |

POSIWID – The Purpose Of a System Is What It Does /// «Furthermore, I consider that Carth... yearly releases must be destroyed»