How to get start/end point of a dm-script line annotation (Component)? - annotations

I want to use:
Component NewLineAnnotation( Number top, Number left, Number bottom, Number right )
The problem is that the line always runs in the direction from the top-left to the bottom-right.
However, I need the line to go from bottom-right to top-left.
And I also need to be able to get the accurate direction from an existing one.
It seems silly that the command is not:
Component NewLineAnnotation( Number start_x, Number start_y, Number end_x, Number end_y )
but surely there is a way to get the direction of the line annotation?
void ComponentGetRect( Component comp, NumberVariable top, NumberVariable left, NumberVariable bottom, NumberVariable right )
does not have such a detail.

Given the details in earlier great answer I looked more and found this to be the situation - I am using GMS 3.
The command for creating a line as a component via:
NewLineAnnotation( Number top, Number left, Number bottom, Number right )
could be described better as:
NewLineAnnotation( Number sX, Number sY, Number eX, Number eY )
But there is another source of potential confusion. When looking for the Get() command for the coordinates, these commands are listed:
void ComponentGetBoundingRect( Component comp, NumberVariable t, NumberVariable l, NumberVariable b, NumberVariable r )
void ComponentGetRect( Component comp, NumberVariable top, NumberVariable left, NumberVariable bottom, NumberVariable right )
void ComponentGetRectInView( Component comp, NumberVariable top, NumberVariable left, NumberVariable bottom, NumberVariable right )
All 3 commands claim the order: top, left, bottom, right, but only the first and the last commands do. The second command could again be better described by
ComponentGetRect(Number sX, Number sY, Number eX, Number eY)
I had mixed up the command NewLineAnnotation() with ComponentGetBoundingRect() and that caused some real issues. I feel a better description in the manual might help avoid such issues.
As a summary, here is some code I used to demonstrate the different functionalities to myself.
image front := CreateFloatImage("", 800, 800)
front.setZoom(.4)
front.ShowImage()
component frontComponent = front.ImageGetImageDisplay(0)
component solid_Line_orange = NewLineAnnotation(700, 10, 500, 200);
frontComponent.ComponentAddChildAtEnd(solid_Line_orange)
solid_Line_orange.ComponentSetForegroundColor(1,.66,0);
component solid_Line_white = NewLineAnnotation(500, 10, 700, 200);
frontComponent.ComponentAddChildAtEnd(solid_Line_white)
number sx, sy, ex, ey
number l_top, l_left, l_buttom, l_right
solid_Line_orange.ComponentGetRect( l_top, l_left, l_buttom, l_right );
Result("\n\n")
Result("using: ComponentGetRectangle();\t actual convention: (start_x, start_y, end_x, end_y)\n")
Result("orange line set at: \t(700, 10, 500, 200);\n")
Result("orange line found at: \t(" + l_top + ", " + l_left + ", " + l_buttom + ", " + l_right + ")\n")
solid_Line_white.ComponentGetRect( l_top, l_left, l_buttom, l_right )
Result("white line set at: \t(500, 10, 700, 200); \n")
Result("white line found at: \t(" + l_top + ", " + l_left + ", " + l_buttom + ", " + l_right + ")\n")
Result("using: ComponentGetBoundingRectangle();\t actual convention: (top, left, bottom, right)\n")
solid_Line_orange.ComponentGetBoundingRect( l_top, l_left, l_buttom, l_right );
Result("orange line found at: \t(" + l_top + ", " + l_left + ", " + l_buttom + ", " + l_right + ")\n")
solid_Line_white.ComponentGetBoundingRect( l_top, l_left, l_buttom, l_right );
Result("white line found at: \t(" + l_top + ", " + l_left + ", " + l_buttom + ", " + l_right + ")\n")
Result("using: ComponentGetBoundingRectInView();\t actual convention: (top, left, bottom, right)\n")
solid_Line_orange.ComponentGetBoundingRectInView( l_top, l_left, l_buttom, l_right );
Result("orange line found at: \t(" + l_top + ", " + l_left + ", " + l_buttom + ", " + l_right + ")\n")
solid_Line_white.ComponentGetBoundingRectInView( l_top, l_left, l_buttom, l_right );
Result("white line found at: \t(" + l_top + ", " + l_left + ", " + l_buttom + ", " + l_right + ")\n")
This solves the problem for me. Hope this helps somebody else as well. And maybe a better description in the manual could help as well.

This is an interestings question!
I think the behavior of ComponentGetRect() is doing correct thing but mislabeling the variables names in the documentation. While it says that it returns you a rectangle as top-left to bottom-right coordinates, it actually returns you the Y/X start coordinate and the Y/X end coordiante pair of the Annotation. (For other types of annoations, this then is [TLBR] ). Note that it is Y/X not X/Y! This is confusing, but to keep it in line with the more general "component" object.
Similarly, the signature variables names for NewLineAnnotation() are wrong, as they are obvisoulsy giving a start to end direction, as you can easily try out when using arrow-annotations instead. (See example script below.)
You can defenitly set the direction of a created line or arrow annotation using:
Component NewLineAnnotation( Number StartY, Number StartX, Number EndY, Number EndX )
Component NewArrowAnnotation( Number StartY, Number StartX, Number EndY, Number EndX )
Similarly, you should use for reading the postions:
ComponentGetRect( NumberVariable StartY, NumberVariable StartX, NumberVariable EndY, NumberVariable EndX )
Now, and alternative way of getting start and end coordinates would be the control point of the component, and the F1 help documention explicitly lists the control point ID values:
So, the presumably correct way would be to ask the componet of the coordinates of the specified control point using:
Boolean ComponentGetControlPoint( Component comp, Number loc, NumberVariable x, NumberVariable y )
However, giving this a test (see script below) it does not actually work for the control point ID values 1 and 2. It seems that the two control points for start/end of a line have not been implemented with the command.
But, you can use the "Top/Left" control point 4 for getting the start value and the "Bottom/Right" control point 7 for getting the end value. Again, this just matches the same somewhat irregular mapping of "line/arrow" annotations on the regular components.
Alternatvive way of getting a start point XY:
Boolean ComponentGetControlPoint( Component comp, 4, NumberVariable x, NumberVariable y )
Alternatvive way of getting a end point XY:
Boolean ComponentGetControlPoint( Component comp, 7, NumberVariable x, NumberVariable y )
Test script used
// Control Point constants. See F1 help documentaton ("Component Object" Overview)
number kLineStart = 1 // = start point of line
number kLineEnd = 2 // = end point of line
number kTopLeft = 4 // = top-left for rect, or start point for line
number kBottomRight = 7 // = bottom-right for rect, or end point for line
number sx = 50
number sy = 30
number ex = 400
number ey = 200
number sizeX = 500
number sizeY = 500
void PrintAnnoInfo( component anno )
{
if ( !anno.ComponentIsValid() ) return
number t,l,b,r
anno.ComponentGetRect( t, l, b, r )
// note that it is return StartY, StartX, EndY, EndX into TLBR!
number type = anno.ComponentGetType()
Result( "\n\n Component of type " + type + ":" )
Result( "\n\t Position rect: " + t + " / " + l + " / "+ b + " / "+ r )
Result( "\n\t\t { TOP / LEFT / BOTTOM / RIGHT }" )
number sx, sy, ex, ey
if ( !anno.ComponentGetControlPoint( kLineStart, sx, sy ) )
Result( "\n INVALID Control point for annotation type. ( " + kLineStart + " ) " )
else
Result( "\n\t Start point (X/Y): " + sx + " / " + sy )
if ( !anno.ComponentGetControlPoint( kLineEnd, ex, ey ) )
Result( "\n INVALID Control point for annotation type. ( " + kLineEnd + " ) " )
else
Result( "\n\t End point (X/Y) : " + ex + " / " + ey )
if ( !anno.ComponentGetControlPoint( kTopLeft, sx, sy ) )
Result( "\n INVALID Control point for annotation type. ( " + kLineStart + " ) " )
else
Result( "\n\t Start point (X/Y): " + sx + " / " + sy )
if ( !anno.ComponentGetControlPoint( kBottomRight, ex, ey ) )
Result( "\n INVALID Control point for annotation type. ( " + kLineEnd + " ) " )
else
Result( "\n\t End point (X/Y) : " + ex + " / " + ey )
Result( "\n\n" )
}
// clear workspace and created dummy
EGUPerformActionWithAllShownImages( "Delete" )
ClearResults()
Result( "Component direction test:\n\n" )
image img := Realimage( "Test", 4, sizeX, sizeY )
img.ShowImage()
imageDisplay disp = img.ImageGetImageDisplay(0)
// Creating and adding line-Annotation
number UseArrow
useArrow = TwoButtonDialog( "In this test use", "Arrows", "Lines" )
string msg
msg = "\nAdding " + (useArrow?"arrow":"line") + ":"
msg += "\n from (" + sx + " / " + sy + ") to (" + ex + " / " + ey + ")"
msg += "\n { from (Ex/Ey) to (Sx/Sy) }"
Result( msg )
OKdialog( msg )
Component anno
if ( useArrow )
anno = NewArrowAnnotation( sy, sx, ey, ex ) // note that it is YX!
else
anno = NewLineAnnotation( sy, sx, ey, ex ) // note that it is YX!
anno.ComponentSetForegroundcolor(1,0,0)
disp.ComponentAddChildAtEnd( anno )
anno.PrintAnnoInfo()
msg = "\nAdding " + (useArrow?"arrow":"line") + ":"
msg += "\n from (" + ex + " / " + ey + ") to (" + sx + " / " + sy + ")"
msg += "\n { from (Ex/Ey) to (Sx/Sy) }"
Result( msg )
OKdialog( msg )
if ( useArrow )
anno = NewArrowAnnotation( ey, ex, sy, sx ) // note that it is YX!
else
anno = NewLineAnnotation( ey, ex, sy, sx ) // note that it is YX!
anno.ComponentSetForegroundcolor(0,1,0)
disp.ComponentAddChildAtBeginning( anno )
anno.PrintAnnoInfo()

Related

'range' cannot be used as a variable or function name

the error is:
Compilation error. Line 13: 'range' cannot be used as a variable or
function name.
//#version=5
indicator('My Script')
// 计算振幅
range = high - low
// 定义信息框显示的内容
info = "开盘价: " + tostring(open) + "\n"
+ "最高价: " + tostring(high) + "\n"
+ "最低价: " + tostring(low) + "\n"
+ "振幅: " + tostring(range) + "\n"
+ "成交量: " + tostring(volume)
// 定义当鼠标悬停在当前k线时显示信息框
bgcolor(not nz(bgcolor[1]) and barstate.ishovered, color.new(color.red, 50))
// 当鼠标悬停在当前k线时,显示信息框
label.new(bar_index, high, text=info, xloc=xloc.bar_time, yloc=yloc.abovebar
Your code is full of error.
For the range problem, just change :
range = high - low
To :
myrange = high - low

In swift is there a difference between a double and a float? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
I wrote a basic program for calculating money. If I switch the data type of the functions to a float. The count for pennies is incorrect if I set my initial value to 16.16. If I switch it to a double it corrects it. I am not sure why this is happening. I know that a double is more precise but I didn't think that would affect my program.
import UIKit
func moneyCounter(initialValue: Double) -> Array<Any> {
var money = initialValue
func countsTypesOfMoney(moneyValue: Double) -> String {
var moneyTypeAmmount = 0
while money >= moneyValue {
money -= moneyValue
moneyTypeAmmount += 1
}
return String(moneyTypeAmmount)
}
return ["$" + String(initialValue) + " = " + countsTypesOfMoney(moneyValue: 1.00) + "
dollars + " + countsTypesOfMoney(moneyValue: 0.25) + " quarters + " +
countsTypesOfMoney(moneyValue: 0.10) + " dimes + " + countsTypesOfMoney(moneyValue: 0.05) +
" nickels + " + countsTypesOfMoney(moneyValue: 0.01) + " pennies"]
}
print(moneyCounter(initialValue: 16.16))
Using a float or a double is really a bad choice when you are counting individual items. Both float's and double's can be imprecise. I've seen times where I had a value of 0.8, i subtracted 0.2 from it and I got 0.60000002. You could also get 0.59999998, or some similar slightly off value, which if you are truncating, like you do in your countTypesOfMoney method, you would go from 60 pennies to 59, just because of a rounding error.
It would be much better to just send pennies or cents and count from that.
import UIKit
func moneyCounter(initialCents: Int) -> Array<Any> {
var money = initialValue
func countsTypesOfMoney(moneyValue: Int) -> String {
var moneyTypeAmount = 0
while money >= moneyValue {
money -= moneyValue
moneyTypeAmount += 1
}
return String(moneyTypeAmount)
}
return ["$" + String(initialValue) + " = " + countsTypesOfMoney(moneyValue: 1.00) + "
dollars + " + countsTypesOfMoney(moneyValue: 0.25) + " quarters + " +
countsTypesOfMoney(moneyValue: 0.10) + " dimes + " + countsTypesOfMoney(moneyValue: 0.05) +
" nickels + " + countsTypesOfMoney(moneyValue: 0.01) + " pennies"]
print(moneyCounter(initialCents: 1616))
If you are required to input a decimal version, such as from a user input, I'd bring in a string and parse it for the decimal and convert it to pennies. If this is for some goofy school assignment, and you need to keep using floats or doubles like this, you should round to the nearest penny at the end.
Also I would use the % function for getting the different denominations.

How to add 2 lines of label on X axis on Fusion Chart?

The purpose is to have 2 lines of text on the X axis for each bar.
e.g
JUN
2018
and style each line in a different way ( like color the year label in green ) .
Can we do it?
This is how I populate the bars in a custom way.
str += '<set label="' + months[i].toUpperCase() + ' ' + currentyear + '" value="' + amount + '" color="08cf77" toolText="' + cur_symbol + amount + '" />\n';
Simply use
'
'
So the line should be updated as;
str += '<set label="' + months[i].toUpperCase() + '
' + currentyear + '" value="' + amount + '" color="08cf77" toolText="' + cur_symbol + amount + '" />\n';

Powershell is there an easy way to covert an int 5 to a string five or 68 to sixty eight?

I'm trying to figure out if there is an easy way to convert numbers into words take 9 and convert it to nine.
There is an excellent library for .NET called Humanizer that can do exactly this. I haven't tried this yet, but it looks like there is a PowerShell wrapper for it. I suspect this will do exactly what you need.
This has been asked about .NET/C#; you could put this in a class and use Add-Type in powershell to make this work.
.NET convert number to string representation (1 to one, 2 to two, etc...)
Maybe something like this (untested):
$class = #"
public class Num2Word
{
public static string NumberToText( int n)
{
if ( n < 0 )
return "Minus " + NumberToText(-n);
else if ( n == 0 )
return "";
else if ( n <= 19 )
return new string[] {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
"Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen",
"Seventeen", "Eighteen", "Nineteen"}[n-1] + " ";
else if ( n <= 99 )
return new string[] {"Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy",
"Eighty", "Ninety"}[n / 10 - 2] + " " + NumberToText(n % 10);
else if ( n <= 199 )
return "One Hundred " + NumberToText(n % 100);
else if ( n <= 999 )
return NumberToText(n / 100) + "Hundreds " + NumberToText(n % 100);
else if ( n <= 1999 )
return "One Thousand " + NumberToText(n % 1000);
else if ( n <= 999999 )
return NumberToText(n / 1000) + "Thousands " + NumberToText(n % 1000);
else if ( n <= 1999999 )
return "One Million " + NumberToText(n % 1000000);
else if ( n <= 999999999)
return NumberToText(n / 1000000) + "Millions " + NumberToText(n % 1000000);
else if ( n <= 1999999999 )
return "One Billion " + NumberToText(n % 1000000000);
else
return NumberToText(n / 1000000000) + "Billions " + NumberToText(n % 1000000000);
}
}
#"
Add-Type -TypeDefinition $class
[Num2Word]::NumberToText(555)
There's no reason you couldn't write this as pure powershell, but this was already written!

GROUP BY Function in Progress OpenEdge

I am trying to find out how to do the Progress equivalent of a "GROUP BY" function. I am trying to write a procedure that will list product inventory information for multiple locations. Right now, it is listing the product information twice; once for each location. I have tried the BREAK BY functional unsuccessfully. My current & desired output and code is below:
Current Output:
Desired Output:
DEF INPUT PARAMETER ip-um AS CHARACTER NO-UNDO.
MESSAGE
"ProdCode" + "^" +
"ProdName" + "^" +
"ProdUM" + "^" +
"GrossPkgdWeight" + "^" +
"QtyOH - LOC1" + "^" +
"QtyOH - LOC2"
SKIP.
FOR EACH product-um WHERE
product-um.gross-pkgd-weight <= 0.0000
NO-LOCK,
EACH product WHERE
product.product-key = product-um.product-key AND
product.can-be-sold = YES
NO-LOCK,
EACH inventory WHERE
inventory.product-key = product.product-key AND
inventory.qoh > 0 AND
inventory.level = 2
NO-LOCK,
EACH um WHERE
um.um-key = product-um.um-key AND
um.um = ip-um
NO-LOCK
BREAK BY product.product-code:
MESSAGE
product.product-code + "^" +
product.product-name + "^" +
um.um-code + "^" +
STRING(product-um.gross-pkgd-weight) + "^" +
IF inventory.level-key-2 = '00000001' THEN STRING(inventory.qoh) ELSE "0"
+ "^" + IF inventory.level-key-2 = '00000002' THEN STRING(inventory.qoh) ELSE "0"
SKIP.
END.
because you accumulate invesntory.qoh in dependency of inventory.level-key-2 the ACCUMULATE stmt is not realy feasible so coding the accumulation manually would be the best choise
DEFINE VARIABLE loc1 AS INTEGER NO-UNDO.
DEFINE VARIABLE loc2 AS INTEGER NO-UNDO.
FOR EACH product-um NO-LOCK
WHERE product-um.gross-pkgd-weight <= 0.0000
,
EACH product NO-LOCK
WHERE product.product-key = product-um.product-key
AND product.can-be-sold = YES
,
EACH inventory NO-LOCK
WHERE inventory.product-key = product.product-key
AND inventory.product-code = product.product-code
AND inventory.qoh > 0
AND inventory.level = 2
,
EACH um NO-LOCK
WHERE um.um-key = product-um.um-key
and um.um = ip-um
BREAK
BY product.product-code:
CASE (inventory.level-key-2):
WHEN "00000001"
THEN loc1 = loc1 + inventory.qoh.
WHEN "00000002"
THEN loc2 = loc2 + inventory.qoh.
END CASE.
IF LAST-OF(product.product-code)
THEN DO:
MESSAGE
product.product-code + "^" +
product.product-name + "^" +
um.um-code + "^" +
STRING(product-um.gross-pkgd-weight) + "^" +
STRING(loc1) + "^" +
STRING(loc2)
SKIP.
ASSIGN
loc1 = 0
loc2 = 0
.
END.
END.
BREAK BY tells the compiler to mark when the FOR EACH has come to the start or end of a break group.To detect these changes you'll need to use one of these functions to detect that change: FIRST(table.field), FIRST-OF(table.field), LAST(table.field), and LAST-OF(table.field).
Once the required function returns true, you can use the ABL supplied functions like ACCUMULATE, COUNT, TOTAL, etc. to display the desired results. Personally I find the concepts a bit hard to get my head around, so I declare some local variables and do the totals that way.