Difference between revisions of "SHIP:Sail:towards"

From Serious Documentation
Jump to: navigation, search
(Created page with "__NOTOC__ {{SailFuncTableStart|}}<onlyinclude> |{{SailFunc|bytesToString}}||{{DataType|String}}||style="text-align:center;"|v5.0.207||Builds a string from the ASCII bytes of a...")
 
Line 1: Line 1:
 
__NOTOC__
 
__NOTOC__
 
{{SailFuncTableStart|}}<onlyinclude>
 
{{SailFuncTableStart|}}<onlyinclude>
|{{SailFunc|bytesToString}}||{{DataType|String}}||style="text-align:center;"|v5.0.207||Builds a string from the ASCII bytes of an  {{DataType|Integer}}, {{DataType|Short}}, or {{DataType|Byte}} until a <code>0x00</code> byte is encountered or the number of bytes of the size of the object are consumed. Optionally, non-printable characters can be replaced as-encountered. All byte orderings are supported.</onlyinclude>
+
|{{SailFunc|towards}}||{{DataType|Float}}/{{DataType|Integer}}||style="text-align:center;"|v5.0.207||Adjusts a number by a percentage in a range towards another number.</onlyinclude>
 
|}
 
|}
 
== See Also: ==
 
== See Also: ==
 
*[[SHIP:Sail|Sail Home]]
 
*[[SHIP:Sail|Sail Home]]
 
*[[SHIP:Sail:Functions|Sail Functions]]
 
*[[SHIP:Sail:Functions|Sail Functions]]
*[[SHIP:Sail:String Functions|Sail String Functions]]
+
*[[SHIP:Sail:Numeric Functions|Sail Numeric Functions]]
*{{SailFunc|charAt}}, {{SailFunc|codepointAt}}, {{SailFunc|codepointToString}},{{SailFunc|subStr}}, {{SailFunc|subString}}, {{SailFunc|toString}}
+
*{{SailFunc|mapRange}}
 
== Prototypes ==
 
== Prototypes ==
<code>{{DataType|String}} {{SailFunc|bytesToString}}({{DataType|Float}}/{{DataType|Integer}}/{{DataType|Short}}/{{DataType|Byte}} number, {{DataType|Byte}} nBytes);</code>
+
<code>{{DataType|Float}} {{SailFunc|towards}}({{DataType|Float}} percent, {{DataType|Float}} current, {{DataType|Float}} target, {{DataType|Float}} doneWithin);</code>
 
 
<code>{{DataType|String}} {{SailFunc|bytesToString}}({{DataType|Float}}/{{DataType|Integer}}/{{DataType|Short}}/{{DataType|Byte}} number, {{DataType|Byte}} nBytes, {{DataType|ByteOrder}} byteOrder);</code>
 
 
 
<code>{{DataType|String}} {{SailFunc|bytesToString}}({{DataType|Float}}/{{DataType|Integer}}/{{DataType|Short}}/{{DataType|Byte}} number, {{DataType|Byte}} nBytes, {{DataType|ByteOrder}} byteOrder, {{DataType|Codepoint}} replacement );</code>
 
  
 +
<code>{{DataType|Integer}} {{SailFunc|towards}}({{DataType|Float}} percent, {{DataType|Integer}} current, {{DataType|Integer}} target, {{DataType|Integer}} doneWithin);</code>
 
=== Parameters/Return Value ===
 
=== Parameters/Return Value ===
 
{| class="wikitable" style="margin: 1em 1em;"  
 
{| class="wikitable" style="margin: 1em 1em;"  
Line 21: Line 18:
 
! scope="col" style="text-align:left" | Description
 
! scope="col" style="text-align:left" | Description
 
|-
 
|-
|number||{{DataType|Float}}<br/>{{DataType|Integer}}<br/>{{DataType|Short}}<br/>{{DataType|Byte}}||Number to convert.<br/>The size of the source type drives the maximum number of bytes to convert; constants are assumed to have the least number of representation bytes.
+
|percent||{{DataType|Float}}||Percent to move ''current'' towards ''target''
 
|-
 
|-
|nBytes||{{DataType|Byte}}||Maximum number of bytes to process in the object. All values are promoted to signed {{DataType|Integer}} at runtime, but on a maximum of nBytes are processed in the byteOrder specified (or {{Reserved|BYTEORDER.BIG_ENDIAN}} if unspecified).
+
|current||{{DataType|Float}}<br/>{{DataType|Integer}}||Current value
 
|-
 
|-
|byteOrder||{{DataType|ByteOrder}}||Byte order to analyze the source number with; default is {{Reserved|BYTEORDER.BIG_ENDIAN}} (optional)
+
|target||{{DataType|Float}}<br/>{{DataType|Integer}}||Target ending value
 
|-
 
|-
|replacement||{{DataType|Codepoint}}||If a non-printable character (<code>0x01-0x1F</code>) is encountered, this UTF8 {{DataType|Codepoint}} is inserted into the string instead. <code>0x00</code> is permitted here and terminates the string upon encountering a non-printable byte. Any Unicode {{DataType|Codepoint}} is permitted.
+
|doneWithin||{{DataType|Float}}<br/>{{DataType|Integer}}||Target ending value
 
|-
 
|-
 
! scope="col" style="text-align:left" | Return
 
! scope="col" style="text-align:left" | Return
! scope="col" style="text-align:left" | {{DataType|String}}
+
! scope="col" style="text-align:left" | {{DataType|Float}}<br/>{{DataType|Integer}}
! scope="col" style="text-align:left" | Character string
+
! scope="col" style="text-align:left" | A new number "towards" the target
 
|}
 
|}
  
 
== Detailed Description ==
 
== Detailed Description ==
The {{SailFunc|bytesToString}}<code>()</code> function returns the character string representing the 8, 16, or 32-bit ASCII byte sequence held in the number specified.
+
The {{SailFunc|towards}} function moves a current numeric value ''towards'' a target value by a percentage.  
 
 
For example, the 32-bit integer <code>0x53484950</code> is a big endian order representation of "SHIP".
 
 
 
The most common use of this function is when receiving Modbus or other communications variables from a remote system that are encoding strings or character sequences.  For example, the remote end may pass {{DataType|Short}} variables with 2-letter codes describing the state of a machine; say <code>0x444F</code> or "<code>DO</code>" for Door Open. You may want to display these codes in your GUI, and so converting them to a {{DataType|String}} is desirable. One option in this example is
 
  
<code>{{DataType|String}} = {{SailFunc|codepointToString}}((x>>8)&0x0FF) + {{SailFunc|codepointToString}}(x&0x0FF);</code>
+
The function is very useful in moving objects, for example gauge needles, sliders, and boxes, in a fluid manner from their current positions to a target position. For example, when a slider needs to move from pixel position 55 to 85, rather than just assign the slider's position directly to 85 on a change, one can create a much more fluid movement using {{SailFunc|towards}}
  
But this technique gets cumbersome with {{DataType|Integer}} variables.  Further, what if the encoding in the number has non-printable characters you wish to replace, and/or you may encounter a string-ending <code>0x00</code> byte in the sequence?  The method above does not handle these cases.
+
The structure of this would use a timer with a "current" variable within the object (such as a slider box):
  
The {{SailFunc|bytesToString}}<code>()</code> function makes parsing these objects much simpler.
+
<code>
=== Size of Source Object ===
+
    variable DataType|Integer}} target
Numeric operands in SHIP are always promoted to 32-bit signed numbers during mathematical manipulation and assignment. Since all number types in SHIP are signed, all 32-bit values used in math are signed {{DataType|Integer}} values.  When a smaller {{Node|variable}} or {{Node|const}} objects (i.e. ({{DataType|Byte}} or {{DataType|Short}}) are supplied in expressions, they will be sign extended to the full 32-bits. For example, a {{Node|const}} such as <code>0x99</code> will always be sign extended to <code>0xFFFFFF99</code> during use.
 
  
With the {{SailFunc|bytesToString}} function, this can cause some interesting side effects. Consider {{SailFunc|bytesToString}}<code>(0x81)</code> which would, ideally, should return "&#153;". However, because of sign extension and 32-bit promotion, the <code>0x99</code> will be promoted to <code>0xFFFFFF99</code> and the full return from the {{SailFunc|bytesToString}}<code>(0x99)</code> would be "&#255;&#255;&#255;&#153;". This is rarely the desirable outcome.
+
    box
 +
        timer oneshot=true value=1 period=1 autoreload=true enabled=false
 +
            listener listeningto=timer.alarm condition=timer.alarm
 +
                script
 +
                    box.ol        = towards(0.33f, box.ol, target, 1);
 +
                    timer.alarm  = false;
 +
                    timer.enabled = (target != box.ol);
 +
            listener target
 +
                    timer.enabled = (target != box.ol);
  
Therefore there is an additional mandatory parameter, <code>nBytes</code>,  which helps address this issue. Note the byte ordering (see below) is performed in advance of the characters being processed.
+
=== The ''doneWithin'' Parameter ===
 +
There is a floating point and an integer version of this function, and since rounding can play a role in the integer version as well as asymptotic behavior in the floating point version, the ''doneWithin'' parameter says that when the ''current'' is within that distance, it is adjusted to the ''target''.  For example, continuously moving 25% towards a target number using floating point values:
 +
<code>
 +
Float f = 1.0f;
  
You still need to take care that you're processing the bytes you truly desire. For example, if a single byte is desired to be processed from the lowest byte position of a 32-bit value, using {{SailFunc|bytesToString}}<code>(0x99,1)</code> will not generate the expected "&#153;" because the default byte ordering is big Endian, and the first byte processed (of the 1 allowed by the <code>nBytes</code> parameter) is a sign-extended <code>0xFF</code>.  To get the correct result, one should specify in this case {{SailFunc|bytesToString}}<code>(0x99,1,</code>{{Reserved|BYTEORDER.LITTLE_ENDIAN}}<code>);</code>.
+
(repeated) f = </code>{{SailFunc|towards}}<code>(0.25f, f, 5.0f, 0.1f);
 
+
</code>
=== Byte Ordering ===
+
Will, upon repetition of the formula, adjust f by 25% towards the target of 5.0 until is within 0.1 of 5.0, at which point 5.0 will be returned. Typically, the integer function will be supplied a <code>1</code> for the ''doneWithin'' parameter.
Often the bytes in the number object are not in the same order. Often communications {{DataType|Integer}} values come in big Endian, but other times you may have all sorts of needs for the 4 different byte orderings of a 32-bit value (or 2 for a 16-bit value).
 
 
 
The optional parameter allows you to manipulate the byte ordering that the object is processed in. The {{DataType|ByteOrder}} value is similar to that supported in {{Node|linkset}} nodes to convert incoming data, and a typical value might be {{Reserved|BYTEORDER.SWAP8}} to swap pairs of 8-bit values in a 16- or 32-bit number.
 
  
 
== Examples ==
 
== Examples ==
Line 66: Line 66:
 
! scope="col" style="text-align:left" | Notes
 
! scope="col" style="text-align:left" | Notes
 
|-
 
|-
|<code>bytesToString(0x53,1);</code> || "" || The bytes are sign extended to <code>0x00000053</code>, and processed by default in big Endian order, so the first byte encountered is a <code>0x00</code> which ends the string.
+
|<code>towards(0.25f,0,4,1);</code> || 1 || 25% from 0 to 4 is 1.
|-
 
|<code>bytesToString(0x53,1,</code>{{Reserved|BYTEORDER.LITTLE_ENDIAN}}<code>);</code> || "S" ||
 
|-
 
|<code>bytesToString(0x53484950,4);</code> || "SHIP" ||
 
|-
 
|<code>bytesToString(0x53484900,4);</code> || "SHI" ||  
 
|-
 
|<code>bytesToString(0x53480050,4);</code> || "SH" || Early terminated when <code>0x00</code> encountered in 3rd byte.
 
|-
 
|<code>bytesToString(0x53484950,4,</code>{{Reserved|BYTEORDER.LITTLE_ENDIAN}}<code>);</code> || "PIHS" || All 4 bytes endian flipped.
 
 
|-
 
|-
|<code>bytesToString(0x53484950,4,</code>{{Reserved|BYTEORDER.BIG_ENDIAN}}<code>,0x3F);</code> || "SHIP" || All bytes are printable, so the replacement character <code>3F</code> ('?') is unused.
+
|<code>towards(0.25f,4,0,1);</code> || 3 || 25% from 4 to 0 is 3.
 
|-
 
|-
|<code>bytesToString(0x53480350,4,</code>{{Reserved|BYTEORDER.BIG_ENDIAN}}<code>,0x3F);</code> || "SH?P" || The third byte, <code>0x03</code> is unprintable, so it is replaced with the replacement character <code>3F</code> ('?').
+
|<code>towards(0.25f,-4,4,1);</code> || -2 || 25% from -4 to +4 is 2.
 
|-
 
|-
|<code>bytesToString(0x53480350,4,</code>{{Reserved|BYTEORDER.BIG_ENDIAN}}<code>,0x2573);</code> || "SH╳P" || The third byte, <code>0x03</code> is unprintable, so it is replaced with the extended UTF8 replacement character <code>0x2573</code>, the diagonal cross ('╳'). Note for this to be visible in your GUI this character must be present in your font.
+
|<code>towards(0.25f,3,4,1);</code> || 4 || 25% from 3 to 4 is 3.25, which is within 1 of 4, so 4 is returned.
 
|}
 
|}
  
 
== References ==
 
== References ==
* [http://www.asciitable.com A handy 8-bit ASCII table]
 
* [http://lwp.interglacial.com/appf_01.htm A good codepoint table], courtesy of Sean M. Burke
 

Revision as of 07:34, 8 June 2015

Function Returns Introduced Description
towards Float/Integer v5.0.207 Adjusts a number by a percentage in a range towards another number.

See Also:

Prototypes

Float towards(Float percent, Float current, Float target, Float doneWithin);

Integer towards(Float percent, Integer current, Integer target, Integer doneWithin);

Parameters/Return Value

Parameter Data Type Description
percent Float Percent to move current towards target
current Float
Integer
Current value
target Float
Integer
Target ending value
doneWithin Float
Integer
Target ending value
Return Float
Integer
A new number "towards" the target

Detailed Description

The towards function moves a current numeric value towards a target value by a percentage.

The function is very useful in moving objects, for example gauge needles, sliders, and boxes, in a fluid manner from their current positions to a target position. For example, when a slider needs to move from pixel position 55 to 85, rather than just assign the slider's position directly to 85 on a change, one can create a much more fluid movement using towards.

The structure of this would use a timer with a "current" variable within the object (such as a slider box):

   variable DataType|Integer}} target
   box
       timer oneshot=true value=1 period=1 autoreload=true enabled=false
           listener listeningto=timer.alarm condition=timer.alarm
               script
                   box.ol        = towards(0.33f, box.ol, target, 1);
                   timer.alarm   = false;
                   timer.enabled = (target != box.ol);
           listener target
                   timer.enabled = (target != box.ol);

The doneWithin Parameter

There is a floating point and an integer version of this function, and since rounding can play a role in the integer version as well as asymptotic behavior in the floating point version, the doneWithin parameter says that when the current is within that distance, it is adjusted to the target. For example, continuously moving 25% towards a target number using floating point values: <code> Float f = 1.0f;

(repeated) f = towards(0.25f, f, 5.0f, 0.1f); Will, upon repetition of the formula, adjust f by 25% towards the target of 5.0 until is within 0.1 of 5.0, at which point 5.0 will be returned. Typically, the integer function will be supplied a 1 for the doneWithin parameter.

Examples

Example Result Notes
towards(0.25f,0,4,1); 1 25% from 0 to 4 is 1.
towards(0.25f,4,0,1); 3 25% from 4 to 0 is 3.
towards(0.25f,-4,4,1); -2 25% from -4 to +4 is 2.
towards(0.25f,3,4,1); 4 25% from 3 to 4 is 3.25, which is within 1 of 4, so 4 is returned.

References