You are not logged in.

Dear visitor, welcome to krpano.com Forum. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Friday, May 21st 2010, 9:50am

A Tutorial on Krpano Action Arguments (pt 1)

Hi ,
i try to understand this for a while but i get crazy with tha %1 etc thing..
what does that exactely mean?..
Hi Tuur,

Ah. I'd like to have an argument, please -- Michael Palin, The Argument Clinic

As you know krpano actions are of the form:

Source code

1
2
3
<action name="action_name">
	body
</action>

where body is the action code.

The actions may be called in the following manner:

Source code

1
action_name(arg1,arg2,arg3,...,argN);
or

Source code

1
action(action_name,arg1,arg2,arg3,...,argN);

where N is 99 or less. In other words, you may have up to 99 arguments (krpano versions less than 1.0.8.10 supported only 9 arguments).

krpano actions allow you to access arguments from within the body of your code via the %N reference, where N is a number from 1 to 99. %0 may be used to reference the name of the action from within the action's body.

In other words:
  • %0 is the name of the action that is being called
  • %1 is the first argument passed to that function, null if no first argument
  • %2 is the second argument passed to that action, null if no second argument
....
  • %9 is the ninth argument passed to that action, null if no ninth argument
For the new version 1.0.8.10 of krpano you can now have up to 99 arguments.
  • %10 is the tenth argument passed to that action, null if no tenth argument
  • %11 is the tenth argument passed to that action, null if no eleventh argument
....

First, a simple example:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />

<action name="hello">
	trace("hello ",%1);
</action>

<action name="main">
	hello(world);
	hello(kitty);
	hello(Klaus);
	hello();
</action>
</krpano>

produces:

Quoted

INFO: hello world
INFO: hello kitty
INFO: hello Klaus
INFO: hello null

This code snippet includes two actions: hello which prints the string hello followed by whatever the user passes in as the first argument, and main which calls the hello function four times with different arguments. Note that the fourth call passes no arguments: hello();. This produces the output INFO: hello null.

ARGUMENT SUBSTITUTION
Krpano's action language is different from other programming languages in that the arguments do not become local variables within the code body, rather arguments are substituted into the code prior to the execution of the code body. You can think of it as if you are using a text editor on the body of the code, and doing a search and replace for each argument, replacing all occurrences of %1 with the string that is the first argument, replacing all occurrences of %2 with the string that is the second argument, etc. If no argument has been provided for a given %N, then a global replace of null is performed for that particular %N.

This substitution occurs after the action is called, but before the action is executed. Consider this example:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />

<action name="test">
	trace("action ",%0," arg1 is ",%1,", arg2 is ",%2,", args 3 and 4 are %3%4");
</action>

<action name="main">
	test(abc,def,123,456);
	test(krpano,is,#,1);
</action>
</krpano>

In the main action, the first call to test is test(abc,def,123,456);. When this line of the program is reached, then the arguments are substituted into the body of test. That is, before the test action is executed,
  • the name of the action "test" replaces all instances of %0
  • the first argument "abc" replaces all instances of %1
  • the second argument "def" replaces all instances of %2
  • the third argument "123" replaces all instances of %3
  • and the fourth argument"456" replaces all instances of %4
Thus the original test body code

Source code

1
trace("action ",%0," arg1 is ",%1,", arg2 is ",%2,", args 3 and 4 are %3%4");
becomes

Source code

1
trace("action ",test," arg1 is ",abc,", arg2 is ",def,", args 3 and 4 are 123456");
. After the substitution, the body is executed and produces the output:

Quoted

action test arg1 is abc, arg2 is def, args 3 and 4 are 123456
.
We then proceed to the next line in main where test is called again with different arguments: test(krpano,is,#,1). Here the action name "test" replaces %0, "krpano" replaces %1, "is" replaces %2, "#" replaces %3, and "1" replaces %4. Thus, before execution, the code body

Source code

1
trace("action ",%0," arg1 is ",%1,", arg2 is ",%2,", args 3 and 4 are %3%4");
is converted to

Source code

1
trace("action ",test," arg1 is ",krpano,", arg2 is ",is,", args 3 and 4 are #1");
Once executed, this produces the output

Quoted

action test arg1 is krpano, arg2 is is, args 3 and 4 are #1


One interesting thing to note, is that in this example, the replacement of arguments %3 and %4 occur within a quoted string. Krpano's handles argument through a simple substitution mechanism, without regard for syntax. The resulting code of course must be syntactically correct, but substitutions can occur within quoted strings, in or out of argument lists, in function names, really anywhere within the body of the code. In fact, entire code segments may be passed through the argument list as in the following example.

Suppose we want to add debugging code which is only executed when the global variable debug is set to true. We can create such an action, let's call it dbg, through which we can pass a code fragment that can be conditionally executed:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />

<action name="dbg">
	if (debug == true, %1);
</action>

<action name="main">
	set(a,123);
	set(b,345);
	dbg(
		trace("hello world");
		trace("a is ",get(a)," b is ",get(b));
	);
	set(debug,true);
	set(a,2000);
	set(b,1000);
	dbg(
		if (a GT b,
			trace("a is ",a);
		<!--else-->,
			trace("b is ",b);
		);
	);
</action>
</krpano>

When this is executed, what happens? The only output produced is:

Quoted

INFO: a is 2000
If we walk step by step through the main code, first we see the variable a is set to the value 123 and then the variable b is set to the value 345. The dbg action is then called with the argument

Source code

1
2
trace("hello world");
trace("a is ",get(a)," b is ",get(b));

This multi-line, multi command argument (complete with quoted strings) get's substituted into every %1 found in the body of dbg. Thus

Source code

1
if(debug == true, %1);
becomes

Source code

1
2
3
4
if(debug == true,
	trace("hello world");
	trace("a is ",get(a)," b is ",get(b));
);

When this is executed, the variable debug has not been set, so the if test fails and the traces do not get executed.

The next line in main sets the variable debug to true. Then the variable a is changed to 2000 and b is changed to 1000. The dbg action is called with the following argument:

Source code

1
2
3
4
5
if (a GT b,
	trace("a is ",a);
<!--else-->,
	trace("b is ",b);
);

This is substituted into the dbg function wherever there is a %1, thus

Source code

1
if(debug == true, %1);
is converted to

Source code

1
2
3
4
5
6
7
if(debug == true,
	if (a GT b,
		trace("a is ",a);
	<!--else-->,
		trace("b is ",b);
	);
);

This code now executes, and since debug has previously been set to true the nested if statement is executed where a is compared to b and is found to be greater resulting in the trace("a is ",a) code being executed which produces the (only) output a is 2000.

...more in Part 2

This post has been edited 1 times, last edit by "pinsane" (May 22nd 2010, 8:15am)


2

Friday, May 21st 2010, 9:51am

A Tutorial on Krpano Action Arguments (pt 2)

...continued from Part 1

USING VARIABLES AS ARGUMENTS

To use a variable's value as an argument, you must extract the value using the get() command. The get() command is one of the few krpano commands that returns a value, and it can only be used as an argument or (for version 1.0.8.10) in an index array.

Here's an example of using a variable as an argument:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />

<action name="test">
	trace("called %0(%1,%2,%3)");
</action>

<action name="main">

	<!--create 3 variables, a,b and c-->
	set(a,1);
	set(b,2);
	set(c,3);

	<!--call the test function -->
	test(a,b,c);
	test(get(a),get(b),get(c));
	test(100,200,300);
	test(d,get(d));
</action>
</krpano>

this produces the output

Quoted


INFO: called test(a,b,c);
INFO: called test(1,2,3);
INFO: called test(100,200,300);
INFO: called test(d,null,null);

In the main action, we first set a to 1, b to 2, and c to 3. We then call test(a,b,c) which prints called test(a,b,c). Note that we did not use the get function, so the value of the variables are not passed to the test action. In this case, we pass the strings "a" "b" and "c" rather than their values 1 2 and 3.

In the second call, test(get(a),get(b),get(c)); we dereference the variables a,b and c using the get() command. Thus in this case the values of the variables are passed through the arguments and the output is called test(1,2,3). It is important to note that the get function dereferences the variables before the argument substitutions are made. So the call

Source code

1
test(get(a),get(b),get(c));
first gets converted to

Source code

1
test(1,2,3);
next the argument substitions are made to the body of test causing

Source code

1
trace("called %0(%1,%2,%3)");
to be converted to

Source code

1
trace("called test(1,2,3)");
and lastly the body is executed producing the output

Quoted

INFO: called test(1,2,3);

In the third call, test(100,200,300);, we pass the scalar values 100, 200 and 300 as arguments and we get the predictable result called test(100,200,300).

In the fourth call, test(d,get(d)); we pass only two arguments. This means the third argument will be passed as null. The first argument d is passed as the string "d". The second argument is get(d). Since d is not a defined variable, this gets passed as null. So the output is called test(d,null,null).

RETURNING VALUES THROUGH ARGUMENT VARIABLES

krpano actions do not return values via a return(value); call. As such, the only way to pass values computed within an action back to the calling action is either through global variables (krpano does not support local variables) or "by reference" (through variables whose names are provided as arguments). While global variables would work, the use of globals is considered a bad programming practice and can lead to un-maintainable code. So it is preferable to pass values back through arguments.

Built in functions such as add, sub, etc use this argument passing method:

Source code

1
2
add(x,1,2);
trace("result is ",x);

produces:

Quoted


INFO: result is 3
Note here that the name of a variable, x is the first argument passed to add. The second and third arguments are the numbers to be added, 1 and 2. The add function sums 1 and 2 and sets the variable x to the result, in this case 3.
We can use variables with add in the following way:

Source code

1
2
3
set(a,10);
set(b,20);
add(sum,get(a),get(b));
Here we pass the variable name sum to the add function, but we pass the values of the addend variables a and b to the function. (Actually, add is one of only a handful functions that doesn't require the get() to extract the value of it's arguments. The other math functions, copy(), as well as trace() and the predicates for if statements automatically dereference variables passed to them. Nonetheless, user defined actions must always use get() to pass the values of variables.)

We can use the same approach as add uses to return values in a simple action of our own creation:

Source code

1
2
3
4
5
6
7
8
9
10
11
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />
<action name="coord_string">
	txtadd(%1,"(",get(view.hlookat),",",get(view.vlookat),")");
</action>

<action name="main">
	coord_string(xyz);
	trace("our current coordinates are =",xyz);
</action>
</krpano>
In this example we have an action named coord_string which takes one argument--the name of a variable that will be set to a string containing the coordinates. The action calls the txtadd function which composes a string in the format "(h,v)". The first argument is the variable name xyz, which means that the coord_string action sets the variable xyz to the string "(0,0)". Note that we do not use the get function on xyz because that would pass xyz's value, we want to pass its name so its value can be changed within the action.

In the following slightly more complicated example we calculate an (approximation) of the distance between two points.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />
<action name="abs">
	if (%1 LT 0,
		sub(%1,0,get(%1));
	);
</action>
<action name="dist">
	sub(xdiff,%2,%4);
	sub(ydiff,%3,%5);
	abs(xdiff);
	abs(ydiff);
	if (xdiff GT ydiff,
		mul(dist_tmp1,get(xdiff),0.941246);
		mul(dist_tmp2,get(ydiff),0.41);
	<!--else-->,
		mul(dist_tmp2,get(xdiff),0.41);
		mul(dist_tmp1,get(ydiff),0.941246);
	);
	add(%1,get(dist_tmp1),get(dist_tmp2));
	
</action>

<action name="main">
	dist(d,15,15,115,-115);
	trace("distance =",d);
</action>

First we look at the absolute value action abs. This function takes the name of a variable which contains a value, computes the absolute value and sets the variable to the result. Thus, it uses the only one argument both to provide input and return output. The action checks to see if the value for the variable is negative, and if so it subtracts the value from zero and writes the result back into the variable. If the value was positive, then the contents of the variable are unchanged.

The dist function uses the octagonal approximation to compute the distance between the two points. We use this approximation because krpano does not provide a square root function. The dist action takes five arguments, the first is the variable name into which to return the result, followed by the x y coordinates for the first point and finally the x and y coordinates for the second point. It computes the differences for the x's and y's and then applies the absolute value function to each difference. It then multiplies the greater of these two differences by the magic number 0.941246 and the lesser by 0.41. These are then added and the result is copied into the variable whose name was provided as the first argument.

AN IMPORTANT (SUBTLE) DIFFERENCE IN BEHAVIOR BETWEEN 1.0.8.10 AND PREVIOUS VERSIONS
Previous to krpano 1.0.8.10, the number of actions were limited to 9. With 1.0.8.10 the number of arguments was extended to 99. While this is a great improvement, it does create a small backward compatibility problem.

Consider the code:

Source code

1
2
3
4
5
6
7
8
9
10
<krpano version="1.0.8" onstart="showtext(press the 'o' key to see the output,infostyle);main()" >
<textstyle name="infostyle" origin="center" fontsize="20" showtime="2.0" fadetime="1.0" />

<action name="test">
	trace("%10");'
</action>

<action name="main">
	test(a,b,c,d,e,f,g,h,i,j);
</action>


Prior to 1.0.8.10 this code would produce the output: a0. With 1.0.8.10 the output would be j. This is because krpano now looks at two digits past the % rather than one, so in the pre 1.0.8.10 case it substitutes the first argument "a" for %1 and in the 1.0.8.10 case "j" is substituted for %10.

Hope this helps

steve
edited 5/30/10--corrected an error in the prose found by Michel, thanks Michel!

This post has been edited 2 times, last edit by "pinsane" (May 31st 2010, 3:00am)


Tuur

Sage

Posts: 3,822

Location: Netherlands

Occupation: Krpano custom coding / Virtual Tours / Photography / Musician / Recording engineer

  • Send private message

3

Friday, May 21st 2010, 10:26am

*love*

and then he writes... hope this helps *g*

YES!!!

very much..

So much time u put in it..
i'm sure a lot of people gonna like your "tut".

i understand now..
my next steps:

- try and error
- use it
- see where for to use it..

their must be tons of posibilities with it...

maybe it's nice to make some more examples that work in tours...
Let's see..
or get some examples from the field... that show us for what exactely we can use it... and for what not..

gonna check Klaus code from the new update in the examples...


Study time *wacko*

Steve
Thanx very much!

Tuur *thumbsup*

This post has been edited 1 times, last edit by "Tuur" (May 21st 2010, 10:56am)


4

Friday, May 21st 2010, 10:48am

Wahoou ! ! !

Great

Thanks a lot Pinsane *thumbsup*

Tuur

Sage

Posts: 3,822

Location: Netherlands

Occupation: Krpano custom coding / Virtual Tours / Photography / Musician / Recording engineer

  • Send private message

5

Friday, May 21st 2010, 10:55am

he is really insane *g*


"...some people say that he types his code with pints full of beer.."
" ...some people say that he drives with a heineken house draft on the lap.."

we better know him as THE Pinsane.


*thumbsup*

michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

6

Friday, May 21st 2010, 3:33pm

Hi all,

MUST READ TUTORIAL *thumbup* *attention*
I just rate this thread with 5 stars to help people to notice that there is something interesting inside...
Also read this from Klaus: How does dereferencing work in Krpano?

Great job Steve *thumbup* ...

7

Friday, May 21st 2010, 8:04pm

Great tutorial! I have been wishing for a clear explaination for a long time. Thank you for putting it in easy to understand terms.

Now onto putting it into use. *thumbsup*

Jarred

VN2009

Professional

Posts: 1,336

Location: Duluth MN

  • Send private message

8

Friday, May 21st 2010, 11:35pm

good Lord !!! Pinsane you are awsome. I am going to print this out and hang it near my workstation. thank you for this.

9

Saturday, May 22nd 2010, 9:15am

Thanks for the kind words guys!

I've made a few tweaks to the prose and formatting, and added a section on returning values through arguments. Good coding!

steve

10

Tuesday, May 25th 2010, 1:15pm

Hi Steve,

thanks for that great and good written tutorial!

best regards,
Klaus

Graydon

Professional

Posts: 614

Location: Texas

Occupation: Industrial gas turbine services.

  • Send private message

11

Thursday, May 27th 2010, 7:31am

"...some people say that he types his code with pints full of beer.."
" ...some people say that he drives with a heineken house draft on the lap.."

we better know him as THE Pinsane.


Somebody's been watching too much Top Gear *tongue*

Great tutorial.

Tuur

Sage

Posts: 3,822

Location: Netherlands

Occupation: Krpano custom coding / Virtual Tours / Photography / Musician / Recording engineer

  • Send private message

Shanti

Intermediate

Posts: 301

Location: Puerto Vallarta

Occupation: Web Developer

  • Send private message

13

Friday, May 28th 2010, 1:10am

Wow. very nice tutorial! on my favorites now :D

*thumbup* *thumbsup* *w00t*

nelk

Intermediate

Posts: 358

Location: Paris

  • Send private message

14

Friday, June 4th 2010, 6:08pm

Hi,

Is it possible to make multiple operation in one instance,

For example :

Source code

1
add(plugin[background].width, get(area.pixelwidth), mul(pano_bg_thick, 2) );


I've tried, but I'm not sure the operation can be combined ... thanks !
VideoStitch, a video stitching engine / blog sur les visites virtuelles ( french ).

15

Friday, June 4th 2010, 8:30pm

Hi,

Is it possible to make multiple operation in one instance,

For example :

Source code

1
add(plugin[background].width, get(area.pixelwidth), mul(pano_bg_thick, 2) );


I've tried, but I'm not sure the operation can be combined ... thanks !


Unfortunately, get() is the only function that returns a value in line, and thus can be used to pass a value into an argument list. Klaus recently introduced the ability to provide two arguments to a math function (as you did with mul in your example), but what this does is multiply the contents of the first variable argument by the second argument. The result is returned in the first variable argument.

Steve

nelk

Intermediate

Posts: 358

Location: Paris

  • Send private message

16

Saturday, June 5th 2010, 5:31pm

Thanks Steve for your answer.

Klaus, "recursive" calls could be great, and avoid unnecessary line of codes !
VideoStitch, a video stitching engine / blog sur les visites virtuelles ( french ).

17

Saturday, June 5th 2010, 6:20pm

Klaus, "recursive" calls could be great, and avoid unnecessary line of codes !
Hi Nelk,
Recursive calls are supported. Anytime you see someone doing anything that requires looping (resetting an attribute on every hotspot for instance) they are using recursion.

One limitation for recursion, is that Klaus prevents the call stack from getting too long, so if you're doing something that requires deep recursion (such as looping across a large number of plugins or traversing a large complex array) then you can get an action overflow error. I believe Klaus limits the number of single actions that can be called at any given time to 2000. You can get around this restriction by having your recursive function occasionally call wait(0); which internally breaks the action queue. Don't call wait(0); too many times however, as it will noticeably slow down the performance of your action.

steve

nelk

Intermediate

Posts: 358

Location: Paris

  • Send private message

18

Sunday, June 6th 2010, 11:08am

Hi Pinsane,

Recursive was probably not the good word, I didn't want to mean function like if/then or for(...) or switch /case.

The thing I'd like is, if a function like this is call :

Source code

1
add(plugin[background].width, get(area.pixelwidth), mul(pano_bg_thick, 2) );


then, the

Source code

1
mul(pano_bg_thick, 2)


return the computed value.

or maybe with something like

Source code

1
get(mul(pano_bg_thick, 2))
VideoStitch, a video stitching engine / blog sur les visites virtuelles ( french ).

jordi

Professional

Posts: 583

Location: Barcelona

Occupation: creating ideas & coding them

  • Send private message

19

Wednesday, March 9th 2011, 10:03am

Understanding the usage of those codes

Hi to everyone, this is one of my first post here, but the first of a big list I think,

I'm coming from flashpanoramas, so I know how the xml is working in order to configure the pano engine.

But with krpano, I have seen there are much more possibilities, and it seems to me that also there's much more performance, and so I have a lot of work to study the way of organizing files projects declaring actions, ...

Is there any post talking about the best architecture / workflow / files order....??

The other question would be, what this code would be used for in the real world ??

I have to build a similar project to this http://rcdespanyol.visita3d.com/en.html but in krpano, any suggestions ?? is better to have an xml file for every pano or is better to use scenes .....??

Any suugestion would be much aprecciated

thanks in advance
everpano.com step beyond 360

autiomaa

Beginner

Posts: 36

Location: Finland

Occupation: Photographer, Retoucher, Web Developer

  • Send private message

20

Wednesday, March 9th 2011, 12:20pm

RE: Understanding the usage of those codes


But with krpano, I have seen there are much more possibilities, and it seems to me that also there's much more performance, and so I have a lot of work to study the way of organizing files projects declaring actions, ...
Is there any post talking about the best architecture / workflow / files order....??
The other question would be, what this code would be used for in the real world ??
I have to build a similar project to this http://rcdespanyol.visita3d.com/en.html but in krpano, any suggestions ?? is better to have an xml file for every pano or is better to use scenes .....??

Quite impressive scenery in that RCD tour (but sadly the image quality is somewhat missing).

As for one file per panorama or using separate files for each panorama, it really depends on the amount of different panoramas you will have at the tour. If there's tens of scenes in the same file, it can really slow down loading time at least in some older iOS devices so dividing things to different files improves at least initial loading performance quite a bit. Also, have tried using bunch of scenes in multiple files but got to trouble with it. Depending on what you do with things (and how you handle navigation), you could actually use both separate files and bunch of scenes inside them.

Still, you have to note that even while krpano has quite bit of documentation, there are usage/implementation cases that aren't always as clear as they could be. Documentation is improving slowly but you should invest some of your time on browsing forum as there's quite bit of interesting ideas and tips around here. :) Welcome to the game.

This post has been edited 1 times, last edit by "autiomaa" (Mar 9th 2011, 12:32pm)