E Voelkl
E Voelkl

Reputation: 55

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

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.

Upvotes: 0

Views: 140

Answers (2)

BmyGuest
BmyGuest

Reputation: 2949

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: enter image description here

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()

Upvotes: 0

E Voelkl
E Voelkl

Reputation: 55

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.

Upvotes: 0

Related Questions