diff src/DLD-FUNCTIONS/__contourc__.cc @ 7042:e54cc03d53f6

[project @ 2007-10-19 20:43:32 by jwe]
author jwe
date Fri, 19 Oct 2007 20:43:33 +0000
parents a1dbe9d80eee
children 7593f8e83a2e
line wrap: on
line diff
--- a/src/DLD-FUNCTIONS/__contourc__.cc	Fri Oct 19 19:05:31 2007 +0000
+++ b/src/DLD-FUNCTIONS/__contourc__.cc	Fri Oct 19 20:43:33 2007 +0000
@@ -1,5 +1,6 @@
 /* Contour lines for function evaluated on a grid.
 
+Copyright (C) 2007 Kai Habel
 Copyright (C) 2004, 2007 Shai Ayal
 
 Adapted to an oct file from the stand alone contourl by Victro Munoz
@@ -35,6 +36,8 @@
 #include <config.h>
 #endif
 
+#include <cfloat>
+
 #include "quit.h"
 
 #include "defun-dld.h"
@@ -45,15 +48,13 @@
 static Matrix contourc;
 static int elem;
 
-// this is the quanta in which we increase this_contour
+// This is the quanta in which we increase this_contour.
 #define CONTOUR_QUANT 50
 
-// cl_add_point(x,y);
-//
-// Add a coordinate point (x,y) to this_contour 
+// Add a coordinate point (x,y) to this_contour.
 
 static void
-cl_add_point (double x, double y)
+add_point (double x, double y)
 {
   if (elem % CONTOUR_QUANT == 0)
     this_contour = this_contour.append (Matrix (2, CONTOUR_QUANT, 0));
@@ -63,237 +64,238 @@
   elem++;
 }
 
-// cl_end_contour();
-//
-// Adds contents of current contour to contourc.
+// Add contents of current contour to contourc.
 // this_contour.cols () - 1;
 
 static void
-cl_end_contour (void)
+end_contour (void)
 {
   if (elem > 2)
     {
       this_contour (1, 0) = elem - 1;
       contourc = contourc.append (this_contour.extract_n (0, 0, 2, elem));
     }
+
   this_contour = Matrix ();
   elem = 0;
 }
 
-// cl_start_contour(flev,x,y);
-//
-// Start a new contour, and adds contents of current one to contourc
+// Start a new contour, and add contents of current one to contourc.
 
 static void
-cl_start_contour (double flev, double x, double y)
+start_contour (double lvl, double x, double y)
 {
-  cl_end_contour ();
+  end_contour ();
   this_contour.resize (2, 0);
-  cl_add_point (flev, flev);
-  cl_add_point (x, y);
+  add_point (lvl, 0);
+  add_point (x, y);
 }
 
 static void
-cl_drawcn (RowVector & X, RowVector & Y, Matrix & Z, double flev,
-	   int krow, int kcol, double lastx, double lasty, int startedge,
-	   Matrix & ipts)
+drawcn (const RowVector& X, const RowVector& Y, const Matrix& Z,
+	double lvl, int r, int c, double ct_x, double ct_y,
+	uint start_edge, bool first, charMatrix& mark)
 {
-
-  int kx = 0, lx = Z.cols () - 1, ky = 0, ly = Z.rows () - 1;
-
-  double f[4];
-  double px[4], py[4], locx[4], locy[4];
-  int iedge[4];
-  int num, first, inext, kcolnext, krownext;
+  double px[4], py[4], pz[4], tmp;
+  uint stop_edge, next_edge, pt[2];
+  int next_r, next_c;
 
-  px[0] = X (krow + 1);
-  px[1] = X (krow);
-  px[2] = X (krow);
-  px[3] = X (krow + 1);
-  py[0] = Y (kcol);
-  py[1] = Y (kcol);
-  py[2] = Y (kcol + 1);
-  py[3] = Y (kcol + 1);
+  //get x, y, and z - lvl for current facet
+  px[0] = px[3] = X(c);
+  px[1] = px[2] = X(c+1);
 
-  f[0] = Z (krow + 1, kcol) - flev;
-  f[1] = Z (krow, kcol) - flev;
-  f[2] = Z (krow, kcol + 1) - flev;
-  f[3] = Z (krow + 1, kcol + 1) - flev;
+  py[0] = py[1] = Y(r);
+  py[2] = py[3] = Y(r+1);
 
-  for (int i = 0, j = 1; i < 4; i++, j = (j + 1) % 4)
-    {
-      iedge[i] = (f[i] * f[j] > 0.0) ? -1 : ((f[i] * f[j] < 0.0) ? 1 : 0);
-    }
-
-  // Mark this square as done
-  ipts(krow,kcol) = 1;
-
-  // Check if no contour has been crossed i.e. iedge[i] = -1
-  if (iedge[0] == -1 && iedge[1] == -1 && iedge[2] == -1 && iedge[3] == -1)
-    return;
+  pz[3] = Z(r+1, c) - lvl;
+  pz[2] = Z(r+1, c + 1) - lvl;
+  pz[1] = Z(r, c+1) - lvl;
+  pz[0] = Z(r, c) - lvl;
 
-  // Check if this is a completely flat square - in which case ignore it
-  if (f[0] == 0.0 && f[1] == 0.0 && f[2] == 0.0 && f[3] == 0.0)
-    return;
+  // Facet edge and point naming assignment.
+  //
+  //  0-----1   .-0-.
+  //  |     |   |   |
+  //  |     |   3   1
+  //  |     |   |   |
+  //  3-----2   .-2-.
 
-  // Calculate intersection points
-  num = 0;
-  if (startedge < 0)
+  // Get mark value of current facet.
+  char id = static_cast<char> (mark(r, c));
+
+  // Check startedge s.
+  if (start_edge == 255)
     {
-      first = 1;
-    }
-  else
-    {
-      locx[num] = lastx;
-      locy[num] = lasty;
-      num++;
-      first = 0;
+      // Find start edge.
+      for (uint k = 0; k < 4; k++)
+        if (static_cast<char> (pow(2, k)) & id)
+          start_edge = k;
     }
 
-  for (int k = 0, i = (startedge < 0 ? 0 : startedge); k < 4;
-       k++, i = (i + 1) % 4)
-    {
-      if (i == startedge)
-	continue;
+  if (start_edge == 255)
+    return;
+
+  // Decrease mark value of current facet for start edge.
+  mark(r, c) -= static_cast<char> (pow(2, start_edge));
 
-      // If the contour is an edge check it hasn't already been done
-      if (f[i] == 0.0 && f[(i + 1) % 4] == 0.0)
-	{
-	  kcolnext = kcol;
-	  krownext = krow;
-	  if (i == 0)
-	    kcolnext--;
-	  if (i == 1)
-	    krownext--;
-	  if (i == 2)
-	    kcolnext++;
-	  if (i == 3)
-	    krownext++;
-	  if (kcolnext < kx || kcolnext >= lx || krownext < ky
-	      || krownext >= ly || ipts(krownext,kcolnext) == 1)
-	    continue;
-	}
-      if (iedge[i] == 1 || f[i] == 0.0)
+  // Next point (clockwise).
+  pt[0] = start_edge;
+  pt[1] = (pt[0] + 1) % 4;
+
+  // Calculate contour segment start if first of contour.
+  if (first)
+    {
+      tmp = fabs (pz[pt[1]]) / fabs (pz[pt[0]]);
+
+      if (xisnan (tmp))
+        ct_x = ct_y = 0.5;
+      else
 	{
-	  int j = (i + 1) % 4;
-	  if (f[i] != 0.0)
-	    {
-	      locx[num] =
-		(px[i] * fabs (f[j]) + px[j] * fabs (f[i])) / fabs (f[j] -
-								    f[i]);
-	      locy[num] =
-		(py[i] * fabs (f[j]) + py[j] * fabs (f[i])) / fabs (f[j] -
-								    f[i]);
-	    }
-	  else
-	    {
-	      locx[num] = px[i];
-	      locy[num] = py[i];
-	    }
-	  // If this is the start of the contour then move to the point
-	  if (first == 1)
-	    {
-	      cl_start_contour (flev, locx[num], locy[num]);
-	      first = 0;
-	    }
-	  else
-	    {
-	      // Link to the next point on the contour
-	      cl_add_point (locx[num], locy[num]);
-	      // Need to follow contour into next grid box
-	      // Easy case where contour does not pass through corner
-	      if (f[i] != 0.0)
-		{
-		  kcolnext = kcol;
-		  krownext = krow;
-		  inext = (i + 2) % 4;
-		  if (i == 0)
-		    kcolnext--;
-		  if (i == 1)
-		    krownext--;
-		  if (i == 2)
-		    kcolnext++;
-		  if (i == 3)
-		    krownext++;
-		  if (kcolnext >= kx && kcolnext < lx
-		      && krownext >= ky && krownext < ly
-		      && ipts(krownext,kcolnext) == 0)
-		    {
-		      cl_drawcn (X, Y, Z, flev, krownext, kcolnext,
-				 locx[num], locy[num], inext, ipts);
-		    }
-		}
-	      // Hard case where contour passes through corner.  This
-	      // is still not perfect - it may lose the contour  which
-	      // won't upset the contour itself (we can find it again
-	      // later) but might upset the labelling (which is only
-	      // relevant for the PLPlot implementation, since we
-	      // don't worry about labels---for now!)
-	      else
-		{
-		  kcolnext = kcol;
-		  krownext = krow;
-		  inext = (i + 2) % 4;
-		  if (i == 0)
-		    {
-		      kcolnext--;
-		      krownext++;
-		    }
-		  if (i == 1)
-		    {
-		      krownext--;
-		      kcolnext--;
-		    }
-		  if (i == 2)
-		    {
-		      kcolnext++;
-		      krownext--;
-		    }
-		  if (i == 3)
-		    {
-		      krownext++;
-		      kcolnext++;
-		    }
-		  if (kcolnext >= kx && kcolnext < lx
-		      && krownext >= ky && krownext < ly
-		      && ipts(krownext,kcolnext) == 0)
-		    {
-		      cl_drawcn (X, Y, Z, flev, krownext, kcolnext,
-				 locx[num], locy[num], inext, ipts);
-		    }
+	  ct_x = px[pt[0]] + (px[pt[1]] - px[pt[0]])/(1 + tmp);
+	  ct_y = py[pt[0]] + (py[pt[1]] - py[pt[0]])/(1 + tmp);
+	}
+
+      start_contour (lvl, ct_x, ct_y);
+    }
+
+  // Find stop edge FIXME: control flow --> while.
+  for (uint k = 1; k <= 4; k++)
+    {
+      if (start_edge == 0 || start_edge == 2)
+        stop_edge = (start_edge + k) % 4;
+      else
+        stop_edge = (start_edge - k) % 4;
+
+      if (static_cast<char> (pow(2, stop_edge)) & id)
+        break;
+    }
+
+  pt[0] = stop_edge;
+  pt[1] = (pt[0] + 1) % 4;
+  tmp = fabs (pz[pt[1]]) / fabs (pz[pt[0]]);
 
-		}
-	      if (first == 1)
-		{
-		  // Move back to first point
-		  cl_start_contour (flev, locx[num], locy[num]);
-		  first = 0;
-		}
-	      else
-		{
-		  first = 1;
-		}
-	      num++;
-	    }
-	}
+  if (xisnan (tmp))
+    ct_x = ct_y = 0.5;
+  else
+    {
+      ct_x = px[pt[0]] + (px[pt[1]] - px[pt[0]])/(1 + tmp);
+      ct_y = py[pt[0]] + (py[pt[1]] - py[pt[0]])/(1 + tmp);
+    }
+
+  // Add point to contour.
+  add_point (ct_x, ct_y);
+
+  // Decrease id value of current facet for start edge.
+  mark(r, c) -= static_cast<char>(pow(2,stop_edge));
+
+  // Find next facet.
+  next_c = c;
+  next_r = r;
+
+  if (stop_edge == 0)
+    next_r--; 
+  else if (stop_edge == 1)
+    next_c++;
+  else if (stop_edge == 2)
+    next_r++;
+  else if (stop_edge == 3)
+    next_c--;
+
+  // Check if next facet is not done yet.
+  // Go to next facet.
+  if (next_r >= 0 && next_c >= 0 && next_r < mark.rows ()
+      && next_c < mark.cols () && mark(next_r, next_c) > 0)
+    {
+      next_edge = (stop_edge + 2) % 4;
+      drawcn (X, Y, Z, lvl, next_r, next_c, ct_x, ct_y, next_edge, false, mark);
     }
 }
 
 static void
-cl_cntr (RowVector & X, RowVector & Y, Matrix & Z, double flev)
+mark_facets (const Matrix& Z, charMatrix& mark, double lvl)
 {
-  Matrix ipts (Z.rows (), Z.cols (), 0);
+  uint nr = mark.rows ();
+  uint nc = mark.cols ();
+
+  double f[4];
+
+  for (uint c = 0; c < nc; c++)
+    for (uint r = 0; r < nr; r++)
+      {
+        f[0] = Z(r, c) - lvl;
+        f[1] = Z(r, c+1) - lvl;
+        f[3] = Z(r+1, c) - lvl;
+        f[2] = Z(r+1, c+1) - lvl;
+
+        for (uint i = 0; i < 4; i++)
+          if (fabs(f[i]) < DBL_EPSILON)
+            f[i] = DBL_EPSILON;
+
+        if (f[1] * f[2] < 0)
+	  mark(r, c) += 2;
+
+        if (f[0] * f[3] < 0)
+	  mark(r, c) += 8;
+      }
 
-  for (int krow = 0; krow < Z.rows () - 1; krow++)
+  for (uint r = 0; r < nr; r++)
+    for (uint c = 0; c < nc; c++)
+      {
+        f[0] = Z(r, c) - lvl;
+        f[1] = Z(r, c+1) - lvl;
+        f[3] = Z(r+1, c) - lvl;
+        f[2] = Z(r+1, c+1) - lvl;
+
+        for (uint i = 0; i < 4; i++)
+          if (fabs(f[i]) < DBL_EPSILON)
+            f[i] = DBL_EPSILON;
+
+        if (f[0] * f[1] < 0)
+	  mark(r, c) += 1;
+
+        if (f[2] * f[3] < 0)
+	  mark(r, c) += 4;
+      }
+}
+
+static void
+cntr (const RowVector& X, const RowVector& Y, const Matrix& Z, double lvl)
+{
+  uint nr = Z.rows ();
+  uint nc = Z.cols ();
+
+  charMatrix mark (nr - 1, nc - 1, 0);
+
+  mark_facets (Z, mark, lvl);
+
+  // Find contours that start at a domain edge.
+
+  for (uint c = 0; c < nc - 1; c++)
     {
-      for (int kcol = 0; kcol < Z.cols () - 1; kcol++)
-	{
-	  if (ipts(krow,kcol) == 0)
-	    {
-	      cl_drawcn (X, Y, Z, flev, krow, kcol, 0.0, 0.0, -2, ipts);
-	    }
-	}
+      // Top.
+      if (mark(0, c) & 1)
+        drawcn (X, Y, Z, lvl, 0, c, 0.0, 0.0, 0, true, mark);
+
+      // Bottom.
+      if (mark(nr - 2, c) & 4)
+	drawcn (X, Y, Z, lvl, nr - 2, c, 0.0, 0.0, 2, true, mark);
     }
+
+  for (uint r = 0; r < nr - 1; r++)
+    {
+      // Left.
+      if (mark(r, 0) & 8)
+        drawcn (X, Y, Z, lvl, r, 0, 0.0, 0.0, 3, true, mark);
+
+      // Right.
+      if (mark(r, nc - 2) & 2)
+        drawcn (X, Y, Z, lvl, r, nc - 2, 0.0, 0.0, 1, true, mark);
+    }
+
+  for (uint r = 0; r < nr - 1; r++)
+    for (uint c = 0; c < nc - 1; c++)
+      if (mark (r, c) > 0)
+        drawcn (X, Y, Z, lvl, r, c, 0.0, 0.0, 255, true, mark);
 }
 
 DEFUN_DLD (__contourc__, args, ,
@@ -308,7 +310,7 @@
     {
       RowVector X = args (0).row_vector_value ();
       RowVector Y = args (1).row_vector_value ();
-      Matrix Z = args (2).matrix_value ().transpose ();
+      Matrix Z = args (2).matrix_value ();
       RowVector L = args (3).row_vector_value ();
 
       if (! error_state)
@@ -316,9 +318,9 @@
 	  contourc.resize (2, 0);
 
 	  for (int i = 0; i < L.length (); i++)
-	    cl_cntr (X, Y, Z, L (i));
+	    cntr (X, Y, Z, L (i));
 
-	  cl_end_contour ();
+	  end_contour ();
 
 	  retval = contourc;
 	}