|
Getting layer index. |
Posted by Garreth on Jun-07-2014 06:59 |
|
Hi Peter,
I can't work out how to get an identifier of a line (think support / resistance) on a Finance
chart so I can remove it. The process must be simple because I can't find anyone else
asking the same question.
My app is written using Qt and this is my (/prototype/) implementation.
1. Subclass QChartViewer to catch the mousePressedEvent to record the start coordinates.
It also informs the app that we are drawing by switching an isDrawing flag.
2. Catch onMouseMovePlotArea to record the end coordinates as the mouse moves.
3. Catch onClicked to record when the mouse has been released, and then redraw the
chart looping for addLine().
I am keeping the coordinates in QStringList (for the moment) and need a way to identify
which line was just selected. This would allow me to remove it from the list, then redraw
the chart, effectively deleting the line.
So my question is; how can I work out which line was just clicked on so I can remove it?
Thanks. |
Re: Getting layer index. |
Posted by Peter Kwan on Jun-08-2014 01:41 |
|
Hi Garreth,
If I were you, I will probably compute the distance between the mouse click point (assume
you use mouse click to select things) to the line segment. If the mouse click is close
enough to the line segment, you can consider the line segment is selected.
The "distance between a point and a line segment" is a common algorithm that can easily be
found using Google. For example:
http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-
line-segment
For your case, when the user clicks the mouse, you can loop through all the line segments
you have added and determine the line segment nearest to the click, and consider that line
segment to be selected if the distance is small enough. (It is very difficult for the mouse to
be exactly on a thin line, so you would need to consider the line segment to be selected
even if the mouse is slightly off the line.)
Hope this can help.
Regards
Peter Kwan |
Re: Getting layer index. |
Posted by Garreth on Jun-23-2014 10:02 |
|
Hi Peter,
I can't work out how to get the data set associated with an 'addLine()' layer. There doesn't
seem to be useful methods available.
Maybe it is too simple for my needs though;
Should I be using addLineIndicator() with a simple two point dataset instead?
Thanks,
Garreth |
Re: Getting layer index. |
Posted by Peter Kwan on Jun-24-2014 00:48 |
|
Hi Garreth,
When using BaseChart.addLine, your code provides the x and y pixel coordinates, but does
not provide any other "data values" or associate the line with anything on the chart. So
ChartDirector can only plot the line. It cannot know the purpose of the line or what the line
is for.
If you would like to translate the pixel coordinate to the value projected on the x-axis or y-
axis, you may use XYChart.getXValue or XYChart.getYValue.
Hope this can help.
Regards
Peter Kwan |
Re: Getting layer index. |
Posted by Garreth on Jun-24-2014 14:07 |
|
Thanks Pete, last question;
If I have the mouseX/Y how can I get which dataset index it is referencing?
For example, I have the start & end mouse coordinates for drawing a support line, but I
need to know what the data index is so I can create a dataset that joins the two points.
I am doing it this way because drawing a LineLayer would allow me to cycle through the
layers when the user right clicks and work out if they are clicking on (or really really close
to) a support line(layer).
I have come up with this, but the start / end are mouse coordinates and should be
converted to dataset indices.
[code]
DoubleArray GChartFrame::getDataPoints(double start, double end){
if(start==end)
return DoubleArray(0,0);
// get the initial value.
XYChart *xyc = (XYChart *)c->getChart(0);
xyc->layoutAxes();
// Get the price at for the start & end.
double var1 = xyc->getYValue(start);
double var2 = xyc->getYValue(end);
// get the ratio multiplier.
double ratio = (end - start) / end;
qDebug() << start<< end << var1 << var2;
double outArray[395]; // Only 395 records for now.
for(int i=0;i<395;i++){
if(i==start){
outArray[i] = var1;
}else if(i==end){
outArray[i] = var2;
}else if((i>start) && (i<end)){
outArray[i] = (i*ratio)*var2;
}else{
outArray[i] = 0;
}
}
return DoubleArray(outArray,(int)(sizeof(outArray)/sizeof(outArray[0])));
}
[/code]
Thanks again,
Garreth |
Re: Getting layer index. |
Posted by Peter Kwan on Jun-25-2014 00:14 |
|
Hi Garreth,
Is the "start" and "end" in your code the x mouse coordinates or the y mouse
coordinates? I assume they are the y mouse coordinates as you use getYValue in your
code. But then you also compare the array index with start, like in the code "if(i==start)".
So what is purpose of "outArray"? If you pass the data array to ChartDirector to create a
LineLayer, the array index is supposed to be the x-coordinate, but your outArray are build
uusing the mouse y coordinate for the array index, and using the y data value as the
array value.
Also, the outArray is a local variable allocation on the stack. In C or C++, you cannot use
it to create the return value. The return value needs to exist after the method has
returned (so it cannot be a local stack variable of the method). It needs to be a member
variable of the class or a global variable, or the memory is allocated on the heap.
It seems the intention of your code is to interpolate the data, but the interpolation
formula seems incorrect.
If you want to create a data array representing the line, please use the x-coordinate as
the array index, adjusted by any leading "extra points" that your code is using. For
example, if your have 365 visible data points and 30 extra points, the your data array
should be 395 in size. (Remember to allocate the array so that it persists outside of the
method.) You may use getXValue to translate the mouse x-coordinate into the visible x
data coordinate. The actual x-coordinate used in the array is then the visible x data
coordinate + 30 (the extra points).
You mentioned "drawing a LineLayer would allow me to cycle through the layers when the
user right clicks and work out if they are clicking on (or really really close
to) a support line(layer)". From my understanding, the support line is drawn using the
mouse coordinates. When the user right clicks, you can obtain the right click mouse
coordinates. So the issue is to determine if the right click mouse coordinates is near the
line created using mouse coordinates. The entire thing is in mouse coordinates and there
should not be a need to use data coordinates. You just need to keep track of where is
the support line (that is, your code needs to remember the mouse coordinates used to
create the support line, so that it can compare it with the right click mouse coordinates
later).
Regards
Peter Kwan |
Re: Getting layer index. |
Posted by Garreth on Jun-25-2014 07:03 |
|
Hi Peter,
That is correct, the start & stop are mouseY coordinates (getChartMouseY to be specific). I
want them to be dataset indices though (which is why I am doing if(i==start) already) so I
can tell where to start and stop the data points for the line.
I am passing the returned DoubleArray by value, not by reference. Once I have the value,
the variables within the context of getDataPoints can go out of scope as they are no longer
needed.
Once addLineLayer is called all it should create its own vars within the context of itself
again allowing any of /my/ variables to go out of scope because it has again created its
own datasets.
I suppose the problem I am having is that the x-coordinate values are not what I expect.
When there are only 395 datapoints it is returning values as high as 790.
Thanks,
Garreth |
Re: Getting layer index. |
Posted by Peter Kwan on Jun-25-2014 14:25 |
|
Hi Garreth,
I am not sure if I understand how your system works. Is the user selecting two points,
and you are drawing a line joining the two points?
Suppose your user clicks a point on the bottom-center of the plot area, and then another
point on the top-right of the plot area. Your code does not use the x-coordinates and
use only the y-coordinates, so we only know it clicks on the bottom and top of the plot
area, but does not know where at the bottom or the top. In other words, we cannot
distinguish whether the first click is at the bottom-left, bottom-center or bottom-right or
some other points at the bottom, because they all have the same y-coordinate. In this
case, would you mind to clarify what x-coordinates are you expecting? I am thinking, we
probably cannot know where does the line starts or stops without the x-coordinates.
For the array going out of scope, although DoubleArray returned by value, but it does not
maintain a copy of the outArray. Whhe DoubleArray is created, only a pointer to the
outArray is passed to it. As according to ChartDirector documentation, the DoubleArray
only stores the pointer, but would not create a deep copy of the array. When the caller
of your subroutine receives a copy of the DoubleArray by value, it is receiving a copy of
the pointer to outArray. At that time, the pointer would be pointing at invalid memory.
It is correct that once addLineLayer is called, the array will be copied to ChartDirector.
But in your current code structure, the addLineLayer is called outside your method, so
you must return the DoubleArray first (which becomes invalid outside the method due to
the invalid pointer to outArray) before you can call addLineLayer. So the array becomes
invalid before ChartDirector has a chance to copy it.
Regards
Peter Kwan |
|