MS RFC 107:支持MapServer中的像素边缘(OGC)扩展模型

日期

2014/01

作者

塔玛斯塞克勒斯

联系

szekerest@gmail.com

状态

草稿

版本

MAPServer 7

此RFC与 MS RFC 25 它解决了同样的问题,但是我们现在打算通过使用不同的实现方案来保持像素范围模型的当前边缘。

1。概述

根据 MS RFC 25 “MapServer使用的像素和范围模型与WCS和WMS等OGC服务定义的不同。MapServer使用像素的中心来表示其唯一的坐标值。范围被解释为从图像中的ul像素中心到图像中lr像素中心的边界框。为什么?好吧,它可以追溯到MapServer旁边的配套软件,显示存储在ERDAS中的卫星数据,ERDAS使用中心到中心的范围模型。数学很简单,并且有一定的逻辑让范围实际代表像素值——也就是说,如果你将范围呈现为多边形,你会得到图像的精确边缘,正如人们所期望的那样。

另一方面,OGC服务规范定义了一个范围(bbox),以引用所请求图像外边缘的尺寸。这似乎是一种更常见的表达感兴趣领域的方法。”

为了处理mapserver和ogc扩展模型之间的差异,在mapserver中应用了调整代码(即在mapwms.c、mapwmslayer.c中):

dx = (map->extent.maxx - map->extent.minx) / map->width;
map->extent.minx += dx*0.5;
map->extent.maxx -= dx*0.5;

dy = (map->extent.maxy - map->extent.miny) / map->height;
map->extent.miny += dy*0.5;
map->extent.maxy -= dy*0.5;

但此修复程序仍然无法解决以下几个问题:

  • 搜索矩形每边减少一半像素,因此我们从基于mapserver的ogc服务器获得的信息量更少。

  • MSAdjustextent仍然会导致范围失真(特别是对于小图像),因为(宽度-1)/(高度-1)不等于宽度/高度。

此外,mapscript用户可能错误地假设我们使用了ogc扩展模型(setextent/getextent的文档似乎没有提供指导),这会导致他们通常期望的不同比例和不正确的宽度/高度调整。

在这个RFC中,我将为OGC扩展模型和当前模型提供支持,可以通过添加到mapfile的新参数来选择这些模型。

2。建议的解决方案

实现的关键点是将范围/比例计算中的“1”常量值替换为新的Pixeladjustment参数。此参数可在映射文件中定义为:

MAP
    # 0 for using the OGC extent model 2 for the current edge-of-pixel model
    PIXELADJUSTMENT 0
...
END

值1将表示当前(像素边缘)行为(这将是默认设置),而将此参数设置为0将切换MapServer以使用OGC扩展模型。引入这个新参数使得实现相当简单,不需要在代码库中添加相当多的“if”条件。

关于性能,使用公式中的新Pixeladjustment参数而不是常量1进行计算不应导致可察觉的性能下降。

三。实施细节

此实现的核心将通过添加新参数(在mapfile.h中)来更改cellsize计算宏,如下所示:

#define MS_CELLSIZE(min,max,d,a) ((max - min)/(d-a))

我们修改了msadjustextent(maputil.c):

double msAdjustExtent(rectObj *rect, int width, int height, int pixeladjustment)
{
  double cellsize, ox, oy;

  if(width == 1 || height == 1)
    return 0;

  cellsize = MS_MAX(MS_CELLSIZE(rect->minx, rect->maxx, width, pixeladjustment), MS_CELLSIZE(rect->miny, rect->maxy, height, pixeladjustment));

  if(cellsize <= 0) /* avoid division by zero errors */
    return(0);

  ox = MS_MAX(((width - pixeladjustment) - (rect->maxx - rect->minx)/cellsize)/2,0); /* these were width-1 and height-1 */
  oy = MS_MAX(((height - pixeladjustment) - (rect->maxy - rect->miny)/cellsize)/2,0);

  rect->minx = rect->minx - ox*cellsize;
  rect->miny = rect->miny - oy*cellsize;
  rect->maxx = rect->maxx + ox*cellsize;
  rect->maxy = rect->maxy + oy*cellsize;

  return(cellsize);
}

和mscalculatescale(mapscale.c):

int msCalculateScale(rectObj extent, int units, int width, int height, int pixeladjustment,  double resolution, double *scale)
{
  double md, gd, center_y;

  /* if((extent.maxx == extent.minx) || (extent.maxy == extent.miny))   */
  if(!MS_VALID_EXTENT(extent)) {
    msSetError(MS_MISCERR, "Invalid image extent, minx=%lf, miny=%lf, maxx=%lf, maxy=%lf.", "msCalculateScale()", extent.minx, extent.miny, extent.maxx, extent.maxy);
    return(MS_FAILURE);
  }

  if((width <= 0) || (height <= 0)) {
    msSetError(MS_MISCERR, "Invalid image width or height.", "msCalculateScale()");
    return(MS_FAILURE);
  }

  switch (units) {
    case(MS_DD):
    case(MS_METERS):
    case(MS_KILOMETERS):
    case(MS_MILES):
    case(MS_NAUTICALMILES):
    case(MS_INCHES):
    case(MS_FEET):
      center_y = (extent.miny+extent.maxy)/2.0;
      md = (width - pixeladjustment)/(resolution*msInchesPerUnit(units, center_y));
      gd = extent.maxx - extent.minx;
      *scale = gd/md;
      break;
    default:
      *scale = -1; /* this is not an error */
      break;
  }

  return(MS_SUCCESS);
}

大多数进一步的实现将意味着更改所有出现的msadjustextent、mscalculatescale和ms-cellsize,以从映射对象提供这个新参数。详情见以下分章。

3.1添加像素调整

一个新的整数参数将添加到mapobj(在mapserver.h中),我们还将修改lexer(maplexer.l,maplexer.c)以识别这个新设置。mapfile读写器(在mapfile.c,mapfile.h中)将被修改为读/写这个新值,并将pixeladjustment的默认值初始化为1。

3.2修改WMS半像素调整代码

现在应将OGC调整代码(如上所述)更改为:

dx = (map->extent.maxx - map->extent.minx) / map->width;
map->extent.minx += dx*0.5*map->pixeladjustment;
map->extent.maxx -= dx*0.5*map->pixeladjustment;

dy = (map->extent.maxy - map->extent.miny) / map->height;
map->extent.miny += dy*0.5*map->pixeladjustment;
map->extent.maxy -= dy*0.5*map->pixeladjustment;

3.3为msadjustextent和mscalculatescale和ms-cellsize提供pixeladjustment参数

我们枚举所有出现的这些函数,并提供来自mapobj->pixeladjustment或mapservobj->map->pixeladjustment的新参数。有关此更改中受影响的所有文件的列表,请参阅第4章。

3.4修改搜索矩形的计算

在搜索形状时,我们应该在某些地方修改代码,以使用像素调整参数,例如:

/* identify target shapes */
if(layer->transform == MS_TRUE)
  searchrect = map->extent;
else {
  searchrect.minx = searchrect.miny = 0;
  searchrect.maxx = map->width - map->pixeladjustment;
  searchrect.maxy = map->height - map->pixeladjustment;
}

3.5修改msmapcomputegeotransform

计算应修改为(在mapobject.c中):

map->gt.geotransform[1] =
  cos(rot_angle) * geo_width / (map->width - map->pixeladjustment);
map->gt.geotransform[2] =
  sin(rot_angle) * geo_height / (map->height - map->pixeladjustment);
map->gt.geotransform[0] = center_x
                          - (map->width * 0.5) * map->gt.geotransform[1]
                          - (map->height * 0.5) * map->gt.geotransform[2];
map->gt.geotransform[4] =
  sin(rot_angle) * geo_width / (map->width - map->pixeladjustment);
map->gt.geotransform[5] =
  - cos(rot_angle) * geo_height / (map->height - map->pixeladjustment);
map->gt.geotransform[3] = center_y
                          - (map->width * 0.5) * map->gt.geotransform[4]
                          - (map->height * 0.5) * map->gt.geotransform[5];

4。受影响的文件

  • mapchart.c:修改搜索矩形的计算(见3.4)

  • mapcluster.c:修改搜索矩形的计算(参见3.4)

  • mapdraw.c:修改msadjustextent和mscalculatescale的调用(参见3.3)

  • mapfile.c:mofify读写器(见3.1)

  • mapfile.h:定义pixelajustment

  • mapgraticle.c:修改msadjustextent(3.3)和搜索矩形(3.4)的调用

  • maplegend.c:修改msadjustextent和mscalculatescale的调用(参见3.3)

  • maplexer.c:添加对读取pixeladjustment的支持(参见3.1)

  • maplexer.l:添加对读取像素调整的支持(参见3.1)

  • mapobject.c:修改msadjustextent和mscalculateScale(3.3)的调用,修改msmapcomputegeotransform(3.5)

  • mapquery.c:修改msadjustextent和ms-cellsize的调用(参见3.3)

  • mapgraster.c:修改msadjustextent的调用(参见3.3)

  • maprasterquery.c:修改msadjustextent的调用(参见3.3)

  • mapscale.c:在mscalculatescale中实现更改(参见第3章)并修改调用(3.3)

  • mapserver.h:实现ms-cellsize中的更改,向mapobj中添加pixeladjustment,修改msadjustextent和mscalculatescale的调用

  • mapservutil.c:修改msadjustextent、ms-cellsoze和mscalculatescale的调用(参见3.3)

  • maptemplate.c:修改setextent中的计算(fromimgbox、fromimgpnt、fromrefpnt、fromscale),更改checkwebscale中msadjustextent的调用

  • maptile.c:修改mstileTextent中的调整代码(参见3.2)

  • maputil.c:在msadjustextent中实现更改(参见第3章)

  • mapuvraster.c:修改形状所在的msuvrasterlayer中的单元大小和范围计算

  • mapwcs.c:在重新计算bbox时,修改mswcsgetcoverage以在公式中包含pixeladjustment。

  • mapwms.c:修改调整代码(3.2)、msadjustextent和ms-cellsize调用(3.3)

  • mapwmslayer.c:修改调整代码(3.2)、mscalculateScale和ms-cellsize调用(3.3)

  • mapscript/swiginc/map.i:修改mscalculatescale的调用(见3.3)

  • mapscript/swiginc/mapzoom.i:修改msadjustextent和mscalculatescale的调用(见3.6)

  • mapscript/swiginc/rect.i:修改“fit”的签名(见3.6)

  • mapscript/php/map.c:修改msadjustextent和mscalculatescale的调用(见3.6)

  • mapscript/php/mapscript_i.c:修改mscalculatescale的调用,修改“fit”的签名(见3.6)

5.向后兼容性问题

Pixeladjustment的默认值将保留计算的当前行为,但我们需要修改mapscript函数的签名:“fit”。

6。臭虫识别码

TBD

7。投票历史

TBD