-1

I have a Conrec nightmare. I am trying to implement contour lines in ActionScript using Conrec. I have looked at both the java and javascript implementation and am still stuck. These are found here: http://paulbourke.net/papers/conrec/

Conrec will take grid data and assemble continuous contour lines. The problem is that it does not necessarily draw those lines in a continuous fashion. For example, it will draw A->B and then C->B and then C->D instead of A, B, C, D, etc.

The javascript implementation seems to be accounting for this and serializing the instructions into an array of draw points. Which is what I too want to accomplish in the end. That is it takes the instructions from the core Conrec logic (eg: A->B, C->B, C->D, etc) and organizes it into an A, B, C, D series. I think it will also return the series as a multi-dimensional array to accommodate broken lines (eg: [[A, B, C, D], [E, F, G]]). This last functionality is what I need to do in Actionscript.

This last part is where I am stuck. Ignore Conrec for now (I have given up on finding an Actionscript implementation), how can I organize these instructions into a collection of serial points? When Conrec gives me "draw point from X->Y" how can I first check if X or Y are already in a series and append either X or Y (whichever is not in the series) into the series? AND if neither are in the series, start a NEW series with X, Y as the starting set. Then check subsequent instructions against all existing series and connect series if they now start and stop on the same point? Also, I need to be able to allow for a series to close itself (eg: A, B, C, A) -- a loop (is that even possible?!).

I hope this makes sense. I'm not sure if there is a technical term for what I want to do beyond "concatenation". I also hope someone out there has done this with Conrec and can give me some pointers.

In the meantime, I am going to continue to plug away at this and see if I can come up with something but I am not confident in my abilities. I would really be thankful for some veteran or professional advice.

PS: If you know another way to draw contour lines from grid data, I am open to alternatives. But I have to be able to implement it in Actionscript.

jpwrunyan
  • 530
  • 5
  • 22
  • Ok, coming back to this, I have finally learned Conrec and implemented it myself. No more crappy 3rd party logic. It is nigh impossible to get Conrec to concatenate its lines. It is made to draw lines on a grid square-by-square basis. You would have to implement some additional logic to keep track of and compare a grid square's line to the lines of its neighbors. This is not just difficult, but will cause such a hit to performance that I fear it may not be realistic. – jpwrunyan Dec 16 '11 at 03:51

3 Answers3

0

Ok, here is my first attempt at getting what I need done. I am not terribly happy with the result, but it seems to work.

package {
  import flash.display.Sprite;

  public class lineSeriesPointConcat extends Sprite {
    public function lineSeriesPointConcat() {
      init();
    }
    //directions [X -> Y]
    //case 1: both counterclockwise, result is counterclockwise
    private var case1:Array = [
      ["G1", "F1"], 
      ["F1", "E1"], 

      ["D1", "C1"],
      ["C1", "B1"],
      ["B1", "A1"], 

      ["E1", "D1"], //link
      ["G1", "A1"] //loop
    ];

    //case 2: clockwise, counterclockwise, result is clockwise
    private var case2:Array = [
      ["E2", "F2"], 
      ["F2", "G2"], 

      ["D2", "C2"], 
      ["C2", "B2"], 
      ["B2", "A2"], 

      ["E2", "D2"], //link
      ["G2", "A2"] //loop
    ];

    //case 3: both clockwise, result is clockwise
    private var case3:Array = [
      ["E3", "F3"], 
      ["F3", "G3"], 

      ["A3", "B3"], 
      ["B3", "C3"], 
      ["C3", "D3"], 

      ["E3", "D3"], //link
      ["G3", "A3"] //loop
    ];

    //case 4: counterclockwise, clockwise, result is clockwise
    private var case4:Array = [
      ["G4", "F4"], 
      ["F4", "E4"], 

      ["A4", "B4"], 
      ["B4", "C4"], 
      ["C4", "D4"], 

      ["E4", "D4"], //link
      ["G4", "A4"] //loop
    ];


    private var collectedSeries:Array = [];

    private function init():void {
      var directions:Array = case1.concat(case2.concat(case3.concat(case4)));
      for each (var direction:Array in directions) {
        connect(direction[0], direction[1]);
      }
      trace ("final series:\n\t" + collectedSeries.join("\n\t"));
    }

    private function connect(from:String, to:String):void {
      var series:Array;
      var seriesStart:String;
      var seriesEnd:String;
      var seriesIndex:int;
      var n:int = collectedSeries.length;
      var i:int;
      for (i = 0; i < n; i++) {
        series = collectedSeries[i];
        seriesStart = series[0];
        seriesEnd = series[series.length - 1];

        if (seriesStart == to) {
          seriesStart = from;
          series.unshift(from);
          break;
        } else if (seriesStart == from) {
          seriesStart = to;
          series.unshift(to);
          break;
        } else if (seriesEnd == to) {
          seriesEnd = from;
          series.push(from);
          break;
        } else if (seriesEnd == from) {
          seriesEnd = to;
          series.push(to);
          break;
        }
      }

      if (i == n) {
        //this is a new series segment
        series = [from, to];
        seriesStart = from;
        seriesEnd = to;
        collectedSeries.push(series);
      }

      for (var j:int = 0; j < n; j++) {
        var compareSeries:Array = collectedSeries[j];
        if (compareSeries == series) {
          //don't compare the series to itself.
          continue;
        }
        var compSeriesStart:String = compareSeries[0];
        var compSeriesEnd:String = compareSeries[compareSeries.length - 1];
        if (compSeriesStart == compSeriesEnd) { 
          //this series loops on itself, it will not concatenate further
          continue;
        }
        if (compSeriesStart == seriesEnd) {
          trace ("case 1");
          series = series.concat(compareSeries.slice(1));
        } else if (compSeriesStart == seriesStart) {
          trace ("case 2");
          series = compareSeries.reverse().concat(series.slice(1));
        } else if (compSeriesEnd == seriesStart) {
          trace ("case 3");
          series = compareSeries.concat(series.slice(1));
        } else if (compSeriesEnd == seriesEnd) {
          trace ("case 4");
          series = compareSeries.concat(series.reverse().slice(1));
        } else {
          //no linkage between these two series
          continue;
        }
        collectedSeries[i] = series; //replace one of the two segements
        collectedSeries.splice(j, 1); //splice out the other
        break;
      }
      trace ("series: " + series + (i == n ? " new" : ""));
    }
  }
}

This will give the following results:

A1,G1,F1,E1,D1,C1,B1,A1

G2,A2,B2,C2,D2,E2,F2,G2

G3,A3,B3,C3,D3,E3,F3,G3

G4,A4,B4,C4,D4,E4,F4,G4

I would still really appreciate any advice/feedback I can get. Does no one use Conrec?!

Edit: woops! I had a bug with the original splice()! sorry! fixed now

jpwrunyan
  • 530
  • 5
  • 22
0

I just ported ConRec to Actionscript3 and seems to work fine, I haven't tested it thoroughly, but it draws my contours the way I expect. Try it out if you will, I'm curious if it's a correct port. it's here:

http://www.jvanderspek.com/DEV/ConRec/ConRec.as

Jonathan
  • 11
  • 3
  • Thanks, I will try it out when I have a spare moment and get back to you. I've unfortunately had to move on with another problem in my project. 2 things I can say immediately, though: 1) your implementation uses moveTo() and lineTo() for each segment, which I believe will prohibit fills. That means it won't accomplish my end goal. 2) You use Vectors instead of Arrays, which is good except that I am getting NetCDF data from a server using BlazeDS. If I recall correctly, Vector is not a type that can be translated from Java. I would suggest changing Vector to Array for this reason. – jpwrunyan Apr 07 '11 at 01:57
  • Basically, you ported from the same java code we ported from. Which in turn was ported from some Fortran code. Do you know what the "castab" logic is achieving? Because I don't. I know it is for checking line drawing conditions... but why? A relic from its Fortran days? It's utterly human-unreadable. And standard if-else blocks, while more verbose, are at least understandable and in AS seem to even be performing faster. In the end, Vector was the way to go, though. – jpwrunyan Dec 16 '11 at 03:45
-1

Ok, so there may be a much better alternative for Flash. I just found this link and it looks impressive. If this works, it obviates the original problem...

isolining package for ActionScript 3

jpwrunyan
  • 530
  • 5
  • 22
  • Update. I took a look at his internal source and it is a spaghetti mess. Furthermore, trying to port it to Flex gave me so many errors that I gave up. Utter fail. – jpwrunyan Dec 16 '11 at 03:40