views:

36

answers:

1

The program will show the student a line graph. The student will have to recreate that line graph by moving a character away from or toward a motion detector using the arrow keys, creating a distance-time plot. I can capture the data points that the program generates when drawing its graph. I can also capture the data points gnerated by the student. How can I compare the two graphs while allowing for some tolerance on the student's part? Should I try to detect incorrect graphs as they are being drawn or after all data points are recorded? While some of the graphs will be linear and easy to compare others will be piecewise functions with positive, negative, and zero slopes at random intervals.

Thanks!

A: 

Does the order in which the graph lines are drawn matter ?

You could record the points with a certain threshold into an Array/Vector and compare.

A quick'n'dirty way would be using 2 binary(monochrome, just black and white) images:

  1. One image will be a 'print screen'(BitmapData.draw()) of the graph(e.g. black on white)
  2. The other image will be a white(blank) BitmapData that you'll use to write black pixels where the user/student draws(has the mouse while it's pressed).

e.g.

userBitmapData.setPixel(mouseX,mouseY,0x000000);

When the drawing is complete(either the mouse is released or whatever rule you set), you run a function that checks how much black pixels from the source(original graph) image are matched in the destination(user graph) image.

Either you create a BitmapData containing the other two bitmaps blended on Difference mode, so anything that isn't black is not a match, or just loop through all the pixels once and manually check if the pixels match. Note that this relies on the fact that dimensions(width,height) of the two images are the same.

Here's a bit of code to illustrate this:

function compare(source:BitmapData,destination:BitmapData,threshold:Number):Boolean{
    var commonPixels:Number = 0, totalPixels:Number = 0;

    for(var j:int = 0 ; j < source.height ; j++){
        for(var i:int = 0 ; i < source.width; i++){
            pixels++;
            if(source.getPixel(i,j) == destination.getPixel(i,j)) commonPixels++;
        }
    }
    trace('matching: ' + (commonPixels/pixels * 100) + ' % ');//delete this line,just testing
    if(commonPixels/pixels >= threshold) return true;
    else                     return false;  
}

//usage:
trace('is the graph correct ?: ' + compare(graphBitmapData,userBitmapData,0.7));

The Vector/Array version would be similar, but there would be no visual cues. Depending on your setup, you might want to test which would work best for you: BitmapData takes more memory than Arrays, but you can easily create a Bitmap, add it to the display list and check if looks right, etc.

If speed is an issue:

  • using Vector. instead of Array might be faster
  • looping in reverse(highest number to 0, decrementing) also should speed up things a bit
  • you probably get away with one loop instead of two e.g.

    var pixels:int = source.width * source.height; for(pixels; pixels >=0; pixels--)

HTH

George Profenza
Thank you, George, for your insight. I haven't yet worked with BitmapData but I've been running into it quite a lot lately. This might be a good opportunity to finally learn more about it. I understand the general idea you've proposed and can follow the logic. This definitely gives me some direction and a better way of thinking about the problem. Thanks again!
colleenk