Opened 20 years ago
Last modified 20 years ago
#710 assigned defect
Scalefactor calculation logic not present in msDrawLayer function
Reported by: | Owned by: | sdlime | |
---|---|---|---|
Priority: | high | Milestone: | |
Component: | MapServer C Library | Version: | 4.2 |
Severity: | major | Keywords: | |
Cc: | sgillies@… |
Description
The logic for calculating a layer's scalefactor is present in the msDrawMap function in the file mapdraw.c but not in the msDrawLayer function. This is a particular problem when using the mapscript API and the $layerObj->draw($imageObj) functionality in conjunction with a layer's SIZEUNITS or SYMBOLSCALE properties. The result in such a case is that msDrawMap (and the scaling logic) is bypassed and symbols are not scaled. The problem is further described in the submitted URL. Our solution was to move the scalefactor calculation logic: for(i=0;i<map->numlayers; i++) { if(map->layers[i].sizeunits != MS_PIXELS) map->layers[i].scalefactor = (msInchesPerUnit(map->layers[i].sizeunits, 0)/msInchesPerUnit(map->units,0)) / map->cellsize; else if(map->layers[i].symbolscale > 0 && map->scale > 0) map->layers[i].scalefactor = map->layers[i].symbolscale/map->scale; else map->layers[i].scalefactor = 1; } down to the top of the msDrawLayer function: if(layer->sizeunits != MS_PIXELS) layer->scalefactor = (msInchesPerUnit(layer->sizeunits,0) /msInchesPerUnit(map->units,0)) / map->cellsize; else if(layer->symbolscale > 0 && map->scale > 0) layer->scalefactor = layer->symbolscale/map->scale; else layer->scalefactor = 1; The result is that symbols are scaled correctly if layers are drawn individually. This logic, however, is now missing from the other layer drawing functions: msDrawWMSLayerLow msDrawWMSLayerSWF msDrawWMSLayerPDF This bug is also present in version 4.0
Change History (7)
comment:2 by , 20 years ago
I know there's a reason for this, but I'll have to think about it for a minute...
comment:3 by , 20 years ago
Cc: | added |
---|
Hey, I couldn't resist adding myself to this issue since I have been thinking very hard about the mapscript drawing API. Instead of adding more logic to the msDrawLayer* functions, I suggest that we enhance the draw method of mapObj, making it: draw([imageObj image=NULL]) : imageObj Have the draw method accept an optional imageObj argument. If this argument is provided, we draw on it and return the result. Easy to implement and test and only requires adding an imageObj argument to msDrawMap. You'd take advantage of this enhancement like # Base image, might also come from prepareImage() image = mapscript.imageObj(200, 200, 'GD/PNG', 'example.png') # Turn off all map layers for i in range(the_map.numlayers): the_map.getLayer(i).status = mapscript.MS_OFF # Draw layer of interest the_map.getLayerByName('example').status = mapscript.MS_ON image = the_map.draw(image) To make it even more user-friendly, maybe we give mapObj a new drawLayer() method like drawLayer(layerObj layer [, imageObj image]) : image so that you don't have to fiddle with status of all layers.
comment:4 by , 20 years ago
Having thought about it a bit more it's clear to me that the problem stems from the fact that the layer scaling is being done in the wrong place; instead of occurring whenever something needs to be drawn it should be done whenever the scale changes. This could be accomplished, for instance, by wrapping the msAdjustExtent and msCalculateScale functions in a function (e.g. msScaleMap/msRescale) which additionally sets the scalefactor for all the layers. Regarding Sean's proposed mapscript API change, I can see how this would solve the layer scaling issue but what about the point drawing? Also it seems to me that conceptually any method dealing with drawing a specific layer should be associated with the layer object and not the map object.
comment:5 by , 20 years ago
I forgot to mention in Comment #4 that the only place the msScaleMap/msRescale need be called is from within the mapscript zoom* and setextent functions...
comment:6 by , 20 years ago
Status: | new → assigned |
---|
The point drawing methods are pure convience. I got sick of wrapping points in shapeObj's. If one needed the full capabilities then shapeObj's would have to be used. I don't like placing the scaling functionality in any of the zoom* functions. Too far away from the drawing, and those functions are not required to draw anything. Once the image is created, either with a draw or a prepare image seems the logical place, that was the plan anyway. That scalefactor should only have to be computed once per map. Do you have a code snippet? I'm just curious of the sequence you're going through in MapScript. Steve
comment:7 by , 20 years ago
Homme, we are already adjusting extent and re-calculating the map scale inside mapObj.setExtent and mapObj.zoom* so that should be fine. There is a related issue that when you resize a map through setting map.width and map.height, the extents and scale are not adjusted. My work-around has been to call map.prepareImage after zooming or re-sizing. This method has some side-effects on the map that adjust it properly. About the drawing API: I disagree that the Layer is the most natural main noun in the drawing API. A Layer is the only object which defines the symbols and styles used to render the data. These are like our brushes or pens (to use terms from other graphical software). The Layer doesn't know anything about the size of our mapping canvas and doesn't know anything about spatial extents or mapping scale. Also, in a well designed object oriented API, objects should modify only themselves. This principle leads me to conclude that the best drawing API to aim for in the future has imageObj.drawLayer, imageObj.drawPoint, &c. I'm putting more thoughts about this in the mapserver wiki at http://mapserver.gis.umn.edu/cgi-bin/wiki.pl?RefactoringDrawingAPI
Note:
See TracTickets
for help on using tickets.