Ejemplo n.º 1
0
static int load_data(Xdf_t *This, off_t begin, off_t end, int retries)
{
	int ptr, nr, bytes;
	RawRequest_t requests[100];
	Compactify_t compactify;

	adjust_bounds(This, &begin, &end);
	
	ptr = begin;
	nr = 0;
	for(ptr=REC.begin; ptr < end ; ptr = REC.end)
		add_to_request_if_invalid(This, ptr, requests, &nr,
					  &compactify);
	bytes = send_cmd(This->fd,requests, nr, "reading", retries);
	if(bytes < 0)
		return bytes;
	ptr = begin;
	for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
		if(!REC.valid) {
			if(bytes >= REC.end - REC.begin) {
				bytes -= REC.end - REC.begin;
				REC.valid = 1;
			} else if(ptr > begin)
				return ptr * This->sector_size;
			else
				return -1;
		}
	}
	return end * This->sector_size;
}
Ejemplo n.º 2
0
static int load_bounds(Xdf_t *This, off_t begin, off_t end)
{
	off_t lbegin, lend;
	int endp1, endp2;

	lbegin = begin;
	lend = end;

	adjust_bounds(This, &lbegin, &lend);	

	if(begin != BEGIN(lbegin) * This->sector_size &&
	   end != BEGIN(lend) * This->sector_size &&
	   lend < END(END(lbegin)))
		/* contiguous end & begin, load them in one go */
		return load_data(This, begin, end, 4);

	if(begin != BEGIN(lbegin) * This->sector_size) {
		endp1 = load_data(This, begin, begin, 4);
		if(endp1 < 0)
			return endp1;
	}

	if(end != BEGIN(lend) * This->sector_size) {
		endp2 = load_data(This, end, end, 4);
		if(endp2 < 0)
			return BEGIN(lend) * This->sector_size;
	}
	return lend * This->sector_size;
}
Ejemplo n.º 3
0
/*!
 * \brief Split a node according to clusters.
 */
static void
split_node (struct rtree_node *node)
{
  int i;
  struct rtree_node *new_node;

  assert (node);
  assert (node->flags.is_leaf ? (void *) node->u.rects[M_SIZE].
          bptr : (void *) node->u.kids[M_SIZE]);
  new_node = find_clusters (node);
  if (node->parent == NULL)     /* split root node */
    {
      struct rtree_node *second;

      second = (struct rtree_node *)calloc (1, sizeof (*second));
      *second = *node;
      if (!second->flags.is_leaf)
        for (i = 0; i < M_SIZE; i++)
          if (second->u.kids[i])
            second->u.kids[i]->parent = second;
      node->flags.is_leaf = 0;
      node->flags.manage = 0;
      second->parent = new_node->parent = node;
      node->u.kids[0] = new_node;
      node->u.kids[1] = second;
      for (i = 2; i < M_SIZE + 1; i++)
        node->u.kids[i] = NULL;
      adjust_bounds (node);
      sort_node (node);
#ifdef SLOW_ASSERTS
      assert (__r_tree_is_good (node));
#endif
      return;
    }
  for (i = 0; i < M_SIZE; i++)
    if (!node->parent->u.kids[i])
      break;
  node->parent->u.kids[i] = new_node;
#ifdef SLOW_ASSERTS
  assert (__r_node_is_good (node));
  assert (__r_node_is_good (new_node));
#endif
  if (i < M_SIZE)
    {
#ifdef SLOW_ASSERTS
      assert (__r_node_is_good (node->parent));
#endif
      sort_node (node->parent);
      return;
    }
  split_node (node->parent);
}
Ejemplo n.º 4
0
static void mark_dirty(Xdf_t *This, off_t begin, off_t end)
{
	int ptr;

	adjust_bounds(This, &begin, &end);
	
	ptr = begin;
	for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
		REC.valid = 1;
		if(!REC.phantom)
			REC.dirty = 1;
	}
}
Ejemplo n.º 5
0
void highlight_contour (MISC *misc, OPTIONS *options, NV_FLOAT64 lat, NV_FLOAT64 lon, nvMap *map)
{
  //  Save the MISP depth for drawing contours (depending on the type of MISP surface)

  NV_F64_COORD2 xy;
  BIN_RECORD bin;

  xy.y = lat;
  xy.x = lon;


  //  Try to find the highest layer with a valid value to grab the contour level.

  for (NV_INT32 pfm = 0 ; pfm < misc->abe_share->pfm_count ; pfm++)
    {
      if (bin_inside_ptr (&misc->abe_share->open_args[pfm].head, xy))
	{
	  read_bin_record_xy (misc->pfm_handle[pfm], xy, &bin);


	  //  Check the validity.

	  if ((bin.validity & PFM_DATA) || (bin.validity & PFM_INTERPOLATED)) break;
	}
    }


  NV_FLOAT32 save_level = (NV_FLOAT32) (NINT (bin.avg_filtered_depth));


  //  Custom contour levels...

  if (misc->abe_share->cint == 0.0)
    {
      NV_FLOAT32 mindiff = 999999999.0;
      NV_INT32 j = 0;
      for (NV_INT32 i = 0 ; i < misc->abe_share->num_levels ; i++)
	{
	  NV_FLOAT32 diff = fabs (save_level - misc->abe_share->contour_levels[i]);
	  if (diff < mindiff)
	    {
	      diff = mindiff;
	      j = i;
	    }
	}

      misc->draw_contour_level = misc->abe_share->contour_levels[j];
    }


  //  Normal contour interval...

  else
    {
      NV_INT32 mult = NINT ((save_level * options->z_factor + options->z_offset) / misc->abe_share->cint);
      misc->draw_contour_level = misc->abe_share->cint * (NV_FLOAT32) mult;
    }


  //  Draw the current contours in highlight color so the "artist" can see where he can connect
  //  his/her drawn contour

  if (options->contour)
    {
      for (NV_INT32 pfm = misc->abe_share->pfm_count - 1 ; pfm >= 0 ; pfm--)
	{
	  if (misc->abe_share->display_pfm[pfm])
	    {
	      //  Adjust bounds to nearest grid point

	      adjust_bounds (misc, pfm);


	      misc->hatchr_start_x = 0;
	      misc->hatchr_end_x = misc->displayed_area_width[pfm];
	      misc->hatchr_start_y = 0;
	      misc->hatchr_end_y = misc->displayed_area_height[pfm];


	      //  Allocate the needed arrays.

	      NV_INT32 size;
	      NV_FLOAT32 *ar = NULL;

	      size = misc->displayed_area_width[pfm] * misc->displayed_area_height[pfm];
	      ar = (NV_FLOAT32 *) calloc (size, sizeof (NV_FLOAT32));

	      if (ar == NULL)
		{
		  perror (pfmView::tr ("Allocating ar array in highlight_contour").toAscii ());
		  exit (-1);
		}

	      BIN_RECORD *current_record = (BIN_RECORD *) calloc (misc->displayed_area_width[pfm], sizeof (BIN_RECORD));

	      if (current_record == NULL)
		{
		  perror (pfmView::tr ("Allocating current_record array in highlight_contour").toAscii ());
		  exit (-1);
		}

	      misc->current_row = (NV_FLOAT32 *) calloc (misc->displayed_area_width[pfm], sizeof (NV_FLOAT32));
	      misc->current_flags = (NV_U_CHAR *) calloc (misc->displayed_area_width[pfm], sizeof (NV_CHAR));


	      //  If the calloc failed, error out.

	      if (misc->current_flags == NULL)
		{
		  perror (pfmView::tr (" Unable to allocate current_flags in highlight_contour.\n").toAscii ());
		  exit (-1);
		}


	      //  Read input data row by row and allot data to appropriate
	      //  subplot files until current row of subplots is complete.

	      for (NV_INT32 jj = misc->hatchr_start_y ; jj < misc->hatchr_end_y ; jj++)
		{
		  //  Read data from disk.

		  read_bin_row (misc->pfm_handle[pfm], misc->displayed_area_width[pfm], misc->displayed_area_row[pfm] + jj, 
				misc->displayed_area_column[pfm], current_record);

		  loadArrays (misc->abe_share->layer_type, misc->displayed_area_width[pfm], current_record, misc->current_row, NULL, 0,
                              misc->current_flags, options->highlight, options->h_count, misc->pfm_handle[pfm], misc->abe_share->open_args[pfm],
                              options->highlight_percent, misc->surface_val);


		  for (NV_INT32 i = 0 ; i < misc->displayed_area_width[pfm] ; i++)
		    {
		      ar[(jj - misc->hatchr_start_y) * misc->displayed_area_width[pfm] + i] = misc->current_row[i] *
			options->z_factor + options->z_offset;
		    }
		}
	      free (current_record);
	      free (misc->current_row);
	      free (misc->current_flags);

	      scribe (map, options, misc, pfm, ar, misc->draw_contour_level);

	      free (ar);
	    }
	}
    }
}
Ejemplo n.º 6
0
/*!
 * \brief Split the node into two nodes putting clusters in each use the
 * k-means clustering algorithm.
 */
struct rtree_node *
find_clusters (struct rtree_node *node)
{
  float total_a, total_b;
  float a_X, a_Y, b_X, b_Y;
  bool belong[M_SIZE + 1];
  struct centroid center[M_SIZE + 1];
  int clust_a, clust_b, tries;
  int a_manage = 0, b_manage = 0;
  int i, old_ax, old_ay, old_bx, old_by;
  struct rtree_node *new_node;
  BoxType *b;

  for (i = 0; i < M_SIZE + 1; i++)
    {
      if (node->flags.is_leaf)
        b = &(node->u.rects[i].bounds);
      else
        b = &(node->u.kids[i]->box);
      center[i].x = 0.5 * (b->X1 + b->X2);
      center[i].y = 0.5 * (b->Y1 + b->Y2);
      /* adding 1 prevents zero area */
      center[i].area = 1. + (float) (b->X2 - b->X1) * (float) (b->Y2 - b->Y1);
    }
  /* starting 'A' cluster center */
  a_X = center[0].x;
  a_Y = center[0].y;
  /* starting 'B' cluster center */
  b_X = center[M_SIZE].x;
  b_Y = center[M_SIZE].y;
  /* don't allow the same cluster centers */
  if (b_X == a_X && b_Y == a_Y)
    {
      b_X += 10000;
      a_Y -= 10000;
    }
  for (tries = 0; tries < M_SIZE; tries++)
    {
      old_ax = (int) a_X;
      old_ay = (int) a_Y;
      old_bx = (int) b_X;
      old_by = (int) b_Y;
      clust_a = clust_b = 0;
      for (i = 0; i < M_SIZE + 1; i++)
        {
          float dist1, dist2;

          dist1 = SQUARE (a_X - center[i].x) + SQUARE (a_Y - center[i].y);
          dist2 = SQUARE (b_X - center[i].x) + SQUARE (b_Y - center[i].y);
          if (dist1 * (clust_a + M_SIZE / 2) < dist2 * (clust_b + M_SIZE / 2))
            {
              belong[i] = true;
              clust_a++;
            }
          else
            {
              belong[i] = false;
              clust_b++;
            }
        }
      /* kludge to fix degenerate cases */
      if (clust_a == M_SIZE + 1)
        belong[M_SIZE / 2] = false;
      else if (clust_b == M_SIZE + 1)
        belong[M_SIZE / 2] = true;
      /* compute new center of gravity of clusters */
      total_a = total_b = 0;
      a_X = a_Y = b_X = b_Y = 0;
      for (i = 0; i < M_SIZE + 1; i++)
        {
          if (belong[i])
            {
              a_X += center[i].x * center[i].area;
              a_Y += center[i].y * center[i].area;
              total_a += center[i].area;
            }
          else
            {
              b_X += center[i].x * center[i].area;
              b_Y += center[i].y * center[i].area;
              total_b += center[i].area;
            }
        }
      a_X /= total_a;
      a_Y /= total_a;
      b_X /= total_b;
      b_Y /= total_b;
      if (old_ax == (int) a_X && old_ay == (int) a_Y &&
          old_bx == (int) b_X && old_by == (int) b_Y)
        break;
    }
  /* Now 'belong' has the partition map */
  new_node = (struct rtree_node *)calloc (1, sizeof (*new_node));
  new_node->parent = node->parent;
  new_node->flags.is_leaf = node->flags.is_leaf;
  clust_a = clust_b = 0;
  if (node->flags.is_leaf)
    {
      int flag, a_flag, b_flag;
      flag = a_flag = b_flag = 1;
      for (i = 0; i < M_SIZE + 1; i++)
        {
          if (belong[i])
            {
              node->u.rects[clust_a++] = node->u.rects[i];
              if (node->flags.manage & flag)
                a_manage |= a_flag;
              a_flag <<= 1;
            }
          else
            {
              new_node->u.rects[clust_b++] = node->u.rects[i];
              if (node->flags.manage & flag)
                b_manage |= b_flag;
              b_flag <<= 1;
            }
          flag <<= 1;
        }
    }
  else
    {
      for (i = 0; i < M_SIZE + 1; i++)
        {
          if (belong[i])
            node->u.kids[clust_a++] = node->u.kids[i];
          else
            {
              node->u.kids[i]->parent = new_node;
              new_node->u.kids[clust_b++] = node->u.kids[i];
            }
        }
    }
  node->flags.manage = a_manage;
  new_node->flags.manage = b_manage;
  assert (clust_a != 0);
  assert (clust_b != 0);
  if (node->flags.is_leaf)
    for (; clust_a < M_SIZE + 1; clust_a++)
      node->u.rects[clust_a].bptr = NULL;
  else
    for (; clust_a < M_SIZE + 1; clust_a++)
      node->u.kids[clust_a] = NULL;
  adjust_bounds (node);
  sort_node (node);
  adjust_bounds (new_node);
  sort_node (new_node);
  return (new_node);
}
Ejemplo n.º 7
0
bool
__r_delete (struct rtree_node *node, const BoxType * query)
{
  int i, flag, mask, a;

  /* the tree might be inconsistent during delete */
  if (query->X1 < node->box.X1 || query->Y1 < node->box.Y1
      || query->X2 > node->box.X2 || query->Y2 > node->box.Y2)
    return false;
  if (!node->flags.is_leaf)
    {
      for (i = 0; i < M_SIZE; i++)
        {
          /* if this is us being removed, free and copy over */
          if (node->u.kids[i] == (struct rtree_node *) query)
            {
              free ((void *) query);
              for (; i < M_SIZE; i++)
                {
                  node->u.kids[i] = node->u.kids[i + 1];
                  if (!node->u.kids[i])
                    break;
                }
              /* nobody home here now ? */
              if (!node->u.kids[0])
                {
                  if (!node->parent)
                    {
                      /* wow, the root is empty! */
                      node->flags.is_leaf = 1;
                      /* changing type of node, be sure it's all zero */
                      for (i = 1; i < M_SIZE + 1; i++)
                        node->u.rects[i].bptr = NULL;
                      return true;
                    }
                  return (__r_delete (node->parent, &node->box));
                }
              else
                /* propegate boundary adjust upward */
                while (node)
                  {
                    adjust_bounds (node);
                    node = node->parent;
                  }
              return true;
            }
          if (node->u.kids[i])
            {
              if (__r_delete (node->u.kids[i], query))
                return true;
            }
          else
            break;
        }
      return false;
    }
  /* leaf node here */
  mask = 0;
  a = 1;
  for (i = 0; i < M_SIZE; i++)
    {
#ifdef DELETE_BY_POINTER
      if (!node->u.rects[i].bptr || node->u.rects[i].bptr == query)
#else
      if (node->u.rects[i].bounds.X1 == query->X1 &&
          node->u.rects[i].bounds.X2 == query->X2 &&
          node->u.rects[i].bounds.Y1 == query->Y1 &&
          node->u.rects[i].bounds.Y2 == query->Y2)
#endif
        break;
      mask |= a;
      a <<= 1;
    }
  if (!node->u.rects[i].bptr)
    return false;               /* not at this leaf */
  if (node->flags.manage & a)
    {
      free ((void *) node->u.rects[i].bptr);
      node->u.rects[i].bptr = NULL;
    }
  /* squeeze the manage flags together */
  flag = node->flags.manage & mask;
  mask = (~mask) << 1;
  node->flags.manage = flag | ((node->flags.manage & mask) >> 1);
  /* remove the entry */
  for (; i < M_SIZE; i++)
    {
      node->u.rects[i] = node->u.rects[i + 1];
      if (!node->u.rects[i].bptr)
        break;
    }
  if (!node->u.rects[0].bptr)
    {
      if (node->parent)
        __r_delete (node->parent, &node->box);
      return true;
    }
  else
    /* propagate boundary adjustment upward */
    while (node)
      {
        adjust_bounds (node);
        node = node->parent;
      }
  return true;
}
Ejemplo n.º 8
0
void paint_surface (MISC *misc, OPTIONS *options, nvMap *map, NVMAP_DEF *mapdef, NV_BOOL cov_area_defined)
{
  static NV_FLOAT32 prev_min = CHRTRNULL, prev_max = -CHRTRNULL;


  NV_FLOAT32 *next_attr = NULL;
  NV_U_CHAR *next_flags = NULL;

  
  NV_BOOL compute_layer_min_max (MISC *misc, OPTIONS *options);
  void hatchr (nvMap *map, OPTIONS *options, NV_BOOL clear, NV_F64_XYMBR mbr, NV_F64_XYMBR edit_mbr, NV_FLOAT32 min_z, NV_FLOAT32 max_z, NV_FLOAT32 range,
               NV_FLOAT64 x_bin_size, NV_FLOAT64 y_bin_size, NV_INT32 height, NV_INT32 start_x, NV_INT32 end_x, NV_FLOAT32 ss_null, NV_FLOAT64 cell_size_x,
               NV_FLOAT64 cell_size_y, NV_FLOAT32 *current_row, NV_FLOAT32 *next_row, NV_FLOAT32 *current_attr, NV_U_CHAR *current_flags, NV_U_BYTE alpha,
               NV_INT32 row, NV_INT32 attribute);
  void geotiff (nvMap *map, MISC *misc, OPTIONS *options);
  void overlayData (nvMap *map, MISC *misc, OPTIONS *options);


  if (!cov_area_defined) return;


  misc->total_displayed_area.min_y = mapdef->bounds[mapdef->zoom_level].min_y;
  misc->total_displayed_area.min_x = mapdef->bounds[mapdef->zoom_level].min_x;
  misc->total_displayed_area.max_y = mapdef->bounds[mapdef->zoom_level].max_y;
  misc->total_displayed_area.max_x = mapdef->bounds[mapdef->zoom_level].max_x;


  if (misc->total_displayed_area.min_x > misc->total_displayed_area.max_x)
    {
      //  Only adjust the lons if the displayed area does not cross the dateline.
            
      if ((misc->total_displayed_area.max_x > 0.0 && misc->total_displayed_area.min_x > 0.0) || 
	  (misc->total_displayed_area.max_x < 0.0 && misc->total_displayed_area.min_x < 0.0))
	{
	  NV_FLOAT64 temp = misc->total_displayed_area.min_x;
	  misc->total_displayed_area.min_x = misc->total_displayed_area.max_x;
	  misc->total_displayed_area.max_x = temp;
	}
    }


  //  Save the displayed area for other ABE programs.  Some key off of the editor/viewer area (displayed_area)
  //  and some key off of just the viewer area (viewer_displayed_area) so, at this point, we set them both.

  misc->abe_share->displayed_area = misc->abe_share->viewer_displayed_area = misc->total_displayed_area;


  //  Compute center point for sun angle arrow

  NV_FLOAT64 center_map_x = misc->total_displayed_area.min_x + (misc->total_displayed_area.max_x - misc->total_displayed_area.min_x) / 2.0;
  NV_FLOAT64 center_map_y = misc->total_displayed_area.min_y + (misc->total_displayed_area.max_y - misc->total_displayed_area.min_y) / 2.0;
  NV_FLOAT64 dum_map_z;
  NV_INT32 dum_z;
  map->map_to_screen (1, &center_map_x, &center_map_y, &dum_map_z, &misc->center_point.x, &misc->center_point.y, &dum_z);


  //  Compute the min and max for the displayed area (using values from all PFM layers).

  if (!compute_layer_min_max (misc, options)) return;


  //  Check to see if we want to force clearing because the min and/or max value changed.

  if (misc->color_by_attribute)
    {
      if (prev_min != misc->displayed_area_attr_min || prev_max != misc->displayed_area_attr_max) misc->clear = NVTrue;
      prev_min = misc->displayed_area_attr_min;
      prev_max = misc->displayed_area_attr_max;
    }
  else
    {
      if (prev_min != misc->displayed_area_min || prev_max != misc->displayed_area_max) misc->clear = NVTrue;
      prev_min = misc->displayed_area_min;
      prev_max = misc->displayed_area_max;
    }


  //  Fill the background with the background color so we don't have to paint the background in hatchr.
  //  Also so we can display the GeoTIFF under the data if requested.

  //  Whole area

  if (misc->clear)
    {
      map->fillRectangle (misc->total_displayed_area.min_x, misc->total_displayed_area.min_y,
                          misc->total_displayed_area.max_x, misc->total_displayed_area.max_y,
                          options->background_color, NVFalse);
    }


  //  Partial area (edited area)

  else
    {
      map->fillRectangle (misc->abe_share->edit_area.min_x, misc->abe_share->edit_area.min_y,
                          misc->abe_share->edit_area.max_x, misc->abe_share->edit_area.max_y,
                          options->background_color, NVFalse);
    }


  for (NV_INT32 pfm = misc->abe_share->pfm_count - 1 ; pfm >= 0 ; pfm--)
    {
      //  Only if we want to display it.

      if (misc->abe_share->display_pfm[pfm])
        {
          //  Adjust bounds to nearest grid point

          adjust_bounds (misc, pfm);


          //  Redraw everything

          if (misc->clear)
            {
              misc->hatchr_start_x = 0;
              misc->hatchr_end_x = misc->displayed_area_width[pfm];
              misc->hatchr_start_y = 0;
              misc->hatchr_end_y = misc->displayed_area_height[pfm];
            }


          //  Redraw a portion (what we edited)

          else
            {
              NV_F64_XYMBR tmp_mbr = misc->abe_share->edit_area;


              //  Adjust edit bounds to nearest grid point (with a border of 1 grid point to clean up the edges).

              tmp_mbr.min_y = misc->abe_share->open_args[pfm].head.mbr.min_y + 
                (NINT ((misc->abe_share->edit_area.min_y - misc->abe_share->open_args[pfm].head.mbr.min_y) /
                       misc->abe_share->open_args[pfm].head.y_bin_size_degrees) - 1) *
                misc->abe_share->open_args[pfm].head.y_bin_size_degrees;
              tmp_mbr.max_y = misc->abe_share->open_args[pfm].head.mbr.min_y + 
                (NINT ((misc->abe_share->edit_area.max_y - misc->abe_share->open_args[pfm].head.mbr.min_y) /
                       misc->abe_share->open_args[pfm].head.y_bin_size_degrees) + 1) * 
                misc->abe_share->open_args[pfm].head.y_bin_size_degrees;
              tmp_mbr.min_x = misc->abe_share->open_args[pfm].head.mbr.min_x + 
                (NINT ((misc->abe_share->edit_area.min_x - misc->abe_share->open_args[pfm].head.mbr.min_x) /
                       misc->abe_share->open_args[pfm].head.x_bin_size_degrees) - 1) *
                misc->abe_share->open_args[pfm].head.x_bin_size_degrees;
              tmp_mbr.max_x = misc->abe_share->open_args[pfm].head.mbr.min_x + 
                (NINT ((misc->abe_share->edit_area.max_x - misc->abe_share->open_args[pfm].head.mbr.min_x) /
                       misc->abe_share->open_args[pfm].head.x_bin_size_degrees) + 1) *
                misc->abe_share->open_args[pfm].head.x_bin_size_degrees;


              tmp_mbr.min_y = qMax (tmp_mbr.min_y, misc->abe_share->open_args[pfm].head.mbr.min_y);
              tmp_mbr.max_y = qMin (tmp_mbr.max_y, misc->abe_share->open_args[pfm].head.mbr.max_y);
              tmp_mbr.min_x = qMax (tmp_mbr.min_x, misc->abe_share->open_args[pfm].head.mbr.min_x);
              tmp_mbr.max_x = qMin (tmp_mbr.max_x, misc->abe_share->open_args[pfm].head.mbr.max_x);



              misc->hatchr_start_x = NINT ((tmp_mbr.min_x - misc->displayed_area[pfm].min_x) / misc->abe_share->open_args[pfm].head.x_bin_size_degrees);
              misc->hatchr_end_x = misc->hatchr_start_x + (NINT ((tmp_mbr.max_x - tmp_mbr.min_x) / misc->abe_share->open_args[pfm].head.x_bin_size_degrees));

              misc->hatchr_start_y = NINT ((tmp_mbr.min_y - misc->displayed_area[pfm].min_y) / misc->abe_share->open_args[pfm].head.y_bin_size_degrees);
              misc->hatchr_end_y = misc->hatchr_start_y + (NINT ((tmp_mbr.max_y - tmp_mbr.min_y) / misc->abe_share->open_args[pfm].head.y_bin_size_degrees));
            }


          //  If the width or height is 0 we have asked for an area outside of the PFM's MBR so we don't want to do anything.

          if (misc->displayed_area_width[pfm] > 0 && misc->displayed_area_height[pfm] > 0)
            {
              //  If misc->display_GeoTIFF is -1 we want to draw the GeoTIFF first.

              if (pfm == misc->abe_share->pfm_count - 1 && misc->display_GeoTIFF < 0) geotiff (map, misc, options);


              //  The only time we don't want to go through here is when we have an open GeoTIFF file, we are displaying
              //  the GeoTIFF surface, and the GeoTIFF alpha value (transparency) is 255.

              if (misc->display_GeoTIFF <= 0 || options->GeoTIFF_alpha < 255)
                {
                  //  We only want to do attributes if we're coloring by non-PFM attributes (like number or stddev), or if we're on the top level.

                  NV_INT32 attribute = 0;
                  if ((misc->color_by_attribute > 0 && misc->color_by_attribute < PRE_ATTR) || (!pfm && misc->color_by_attribute))
                    attribute = misc->color_by_attribute;


                  //  Allocate the needed arrays.

                  NV_INT32 size;
                  NV_FLOAT32 *ar = NULL;

                  if (options->contour)
                    {
                      size = (misc->displayed_area_width[pfm] + 1) * (misc->displayed_area_height[pfm] + 1);

                      ar = (NV_FLOAT32 *) calloc (size, sizeof (NV_FLOAT32));

                      if (ar == NULL)
                        {
                          perror (pfmView::tr ("Allocating ar array in paint_surface").toAscii ());
                          exit (-1);
                        }
                    }


                  BIN_RECORD *current_record = (BIN_RECORD *) calloc (misc->displayed_area_width[pfm], sizeof (BIN_RECORD));
                  if (current_record == NULL)
                    {
                      perror (pfmView::tr ("Allocating current_record in paint_surface").toAscii ());
                      exit (-1);
                    }

                  misc->next_row = (NV_FLOAT32 *) calloc (misc->displayed_area_width[pfm], sizeof (NV_FLOAT32));
                  if (misc->next_row == NULL)
                    {
                      perror (pfmView::tr ("Allocating next_row in paint_surface").toAscii ());
                      exit (-1);
                    }

                  if (attribute)
                    {
                      next_attr = (NV_FLOAT32 *) calloc (misc->displayed_area_width[pfm], sizeof (NV_FLOAT32));
                      if (next_attr == NULL)
                        {
                          perror (pfmView::tr ("Allocating next_attr in paint_surface").toAscii ());
                          exit (-1);
                        }
                    }

                  next_flags = (NV_U_CHAR *) calloc (misc->displayed_area_width[pfm], sizeof (NV_CHAR));
                  if (next_flags == NULL)
                    {
                      perror (pfmView::tr ("Allocating next_flags in paint_surface").toAscii ());
                      exit (-1);
                    }

                  misc->current_row = (NV_FLOAT32 *) calloc (misc->displayed_area_width[pfm], sizeof (NV_FLOAT32));
                  if (misc->current_row == NULL)
                    {
                      perror (pfmView::tr ("Allocating current_row in paint_surface").toAscii ());
                      exit (-1);
                    }

                  if (attribute)
                    {
                      misc->current_attr = (NV_FLOAT32 *) calloc (misc->displayed_area_width[pfm], sizeof (NV_FLOAT32));
                      if (misc->current_attr == NULL)
                        {
                          perror (pfmView::tr ("Allocating current_attr in paint_surface").toAscii ());
                          exit (-1);
                        }
                    }


                  misc->current_flags = (NV_U_CHAR *) calloc (misc->displayed_area_width[pfm], sizeof (NV_CHAR));
                  if (misc->current_flags == NULL)
                    {
                      perror (pfmView::tr ("Allocating current_flags in paint_surface").toAscii ());
                      exit (-1);
                    }


                  //  Read input data row by row.  Note that hatchr_start_y and hatchr_end_y may not be the same as the
                  //  entire displayed area since we may only be redrawing a small edited portion of the display.

                  for (NV_INT32 jj = misc->hatchr_start_y ; jj <= misc->hatchr_end_y ; jj++)
                    {
                      //  Read data from disk.

                      if (jj == misc->hatchr_start_y)
                        {
                          read_bin_row (misc->pfm_handle[pfm], misc->displayed_area_width[pfm], misc->displayed_area_row[pfm] + jj, 
                                        misc->displayed_area_column[pfm], current_record);

                          loadArrays (misc->abe_share->layer_type, misc->displayed_area_width[pfm], current_record, misc->current_row, 
                                      misc->current_attr, attribute, misc->current_flags, options->highlight, options->h_count, misc->pfm_handle[pfm],
                                      misc->abe_share->open_args[pfm], options->highlight_percent, misc->surface_val);

                          memcpy (misc->next_row, misc->current_row, misc->displayed_area_width[pfm] * sizeof (NV_FLOAT32));

                          if (attribute) memcpy (next_attr, misc->current_attr, misc->displayed_area_width[pfm] * sizeof (NV_FLOAT32));

                          memcpy (next_flags, misc->current_flags, misc->displayed_area_width[pfm] * sizeof (NV_CHAR));
                        }
                      else
                        {
                          memcpy (misc->current_row, misc->next_row, misc->displayed_area_width[pfm] * sizeof (NV_FLOAT32));

                          if (attribute) memcpy (misc->current_attr, next_attr, misc->displayed_area_width[pfm] * sizeof (NV_FLOAT32));

                          memcpy (misc->current_flags, next_flags, misc->displayed_area_width[pfm] * sizeof (NV_CHAR));


                          //  If not at top edge, read another row.

                          if (jj < misc->abe_share->open_args[pfm].head.bin_height) 
                            {
                              read_bin_row (misc->pfm_handle[pfm], misc->displayed_area_width[pfm], misc->displayed_area_row[pfm] + jj, 
                                            misc->displayed_area_column[pfm], current_record);

                              loadArrays (misc->abe_share->layer_type, misc->displayed_area_width[pfm], current_record, misc->next_row,
                                          next_attr, attribute, next_flags, options->highlight, options->h_count, misc->pfm_handle[pfm],
                                          misc->abe_share->open_args[pfm], options->highlight_percent, misc->surface_val);
                            }
                        }


                      //  HSV fill and sunshade.

                      hatchr (map, options, misc->clear, misc->displayed_area[pfm], misc->abe_share->edit_area, misc->color_min, misc->color_max,
                              misc->color_range, misc->abe_share->open_args[pfm].head.x_bin_size_degrees, misc->abe_share->open_args[pfm].head.y_bin_size_degrees,
                              misc->abe_share->open_args[pfm].head.bin_height, misc->hatchr_start_x, misc->hatchr_end_x,
                              misc->abe_share->open_args[pfm].head.null_depth, misc->ss_cell_size_x[pfm], misc->ss_cell_size_y[pfm], misc->current_row,
                              misc->next_row, misc->current_attr, misc->current_flags, misc->pfm_alpha[pfm], jj, attribute);


                      if (options->contour)
                        {
                          for (NV_INT32 i = 0 ; i < misc->displayed_area_width[pfm] ; i++)
                            {
                              //  We use next_row for sunshading on all but the first row to send to scribe.

                              if (i)
                                {
                                  ar[(jj - misc->hatchr_start_y) * misc->displayed_area_width[pfm] + i] = misc->next_row[i] * 
                                    options->z_factor + options->z_offset;
                                }
                              else
                                {
                                  ar[(jj - misc->hatchr_start_y) * misc->displayed_area_width[pfm] + i] = misc->current_row[i] * 
                                    options->z_factor + options->z_offset;
                                }
                            }
                        }

                      if (qApp->hasPendingEvents ())
                        {
                          qApp->processEvents();
                          if (misc->drawing_canceled) break;
                        }
                    }


                  //  Flush all of the saved fillRectangles from hatchr to screen

                  map->flush ();


                  //  Free allocated memory.

                  free (current_record);
                  free (misc->next_row);
                  if (attribute) free (next_attr);
                  free (next_flags);
                  free (misc->current_row);
                  if (attribute) free (misc->current_attr);
                  free (misc->current_flags);


                  if (!misc->drawing_canceled)
                    {
                      //  If you asked for contours, do it.

                      if (options->contour)
                        {
                          if (misc->function == DRAW_CONTOUR)
                            {
                              scribe (map, options, misc, pfm, ar, misc->draw_contour_level);
                            }
                          else
                            {
                              scribe (map, options, misc, pfm, ar, 99999.0);
                            }
                        }
                    }


                  //  Free allocated scribe memory.

                  if (options->contour) free (ar);
                }


              //  Issue a warning when the user is displaying more bins than pixels

              if (!misc->tposiafps && (misc->clear && (misc->displayed_area_width[pfm] > mapdef->draw_width ||
                                                       misc->displayed_area_height[pfm] > mapdef->draw_height)))
                {
                  QString warning_message = pfmView::tr ("Number of bins displayed exceeds number of pixels.\n");
                  warning_message += pfmView::tr ("Some data masking will occur.\n");
                  warning_message += pfmView::tr ("Increase window size or decrease area size.\n\n");
                  warning_message +=
                    QString (pfmView::tr ("Bin width  = %1  ,  Pixel width  = %2\n")).arg (misc->displayed_area_width[pfm]).arg (mapdef->draw_width);
                  warning_message +=
                    QString (pfmView::tr ("Bin height = %1  ,  Pixel height = %2\n")).arg (misc->displayed_area_height[pfm]).arg (mapdef->draw_height);

                  QMessageBox msgBox (QMessageBox::Warning, pfmView::tr ("pfmView TPOSIAFPS"), warning_message);

                  msgBox.setStandardButtons (QMessageBox::Close);
                  msgBox.setDefaultButton (QMessageBox::Close);

                  QCheckBox dontShow (pfmView::tr ("I understand that I can't see everything due to resolution but don't show this again!"), &msgBox);
                  msgBox.addButton (&dontShow, QMessageBox::HelpRole);
                  msgBox.exec ();
                  misc->tposiafps = ((bool) dontShow.checkState ());
                }
            }
        }
    }


  if (!misc->drawing_canceled)
    {
      //  Display GeoTIFF data if available.

      if (misc->display_GeoTIFF == 1) geotiff (map, misc, options);


      //  Overlay any files that have been requested.

      overlayData (map, misc, options);


      //  Display suspect, feature, selected, or reference info if enabled.

      if (options->display_suspect || options->display_feature || options->display_selected || options->display_reference)
        overlayFlag (map, options, misc, NVTrue, NVTrue, NVTrue);


      //  Display filter masks if any are defined.

      for (NV_INT32 i = 0 ; i < misc->poly_filter_mask_count ; i++)
        {
          if (!misc->poly_filter_mask[i].displayed)
            {
              //  Check to see if this mask (that we are going to redraw) overlaps another (that we weren't planning on redrawing).
              //  If so, set the flag to redraw the other one.

              for (NV_INT32 j = 0 ; j < misc->poly_filter_mask_count ; j++)
                {
                  if (j != i && misc->poly_filter_mask[j].displayed)
                    {
                      if (polygon_collision2 (misc->poly_filter_mask[i].x, misc->poly_filter_mask[i].y, misc->poly_filter_mask[i].count,
                                              misc->poly_filter_mask[j].x, misc->poly_filter_mask[j].y, misc->poly_filter_mask[j].count))
                        misc->poly_filter_mask[j].displayed = NVFalse;
                    }
                }
            }
        }


      for (NV_INT32 i = 0 ; i < misc->poly_filter_mask_count ; i++)
        {
          if (!misc->poly_filter_mask[i].displayed)
            {
              if (options->poly_filter_mask_color.alpha () < 255)
                {
                  map->fillPolygon (misc->poly_filter_mask[i].count, misc->poly_filter_mask[i].x, misc->poly_filter_mask[i].y, 
                                    options->poly_filter_mask_color, NVTrue);
                }
              else
                {
                  //  We don't have to worry about clipping this because moving the area discards the mask areas.

                  map->drawPolygon (misc->poly_filter_mask[i].count, misc->poly_filter_mask[i].x, misc->poly_filter_mask[i].y,
                                    options->poly_filter_mask_color, 2, NVTrue, Qt::SolidLine, NVTrue);
                }
              misc->poly_filter_mask[i].displayed = NVTrue;
            }
        }


      if (options->landmask && misc->total_displayed_area.max_x - misc->total_displayed_area.min_x < 5.0 &&
          misc->total_displayed_area.max_y - misc->total_displayed_area.min_y < 5.0)
        {
          map->setLandmask (NVTrue);
        }
      else
        {
          map->setLandmask (NVFalse);
        }


      //  Flag minimum, maximum, and maximum std dev if enabled.

      if (options->display_minmax) displayMinMax (map, options, misc);
    }
}