Experimental patch for sizeable point symbols
Jan-Oliver Wagner
jan at intevation.de
Thu Sep 23 00:57:35 CEST 2004
Hi,
attached is a patch (against current HEAD) and a sample file
that adds a size for point symbols.
It is experimental. You have to edit the .thuban file
manually to have symbols of different size.
I am also not sure if it is the best technical approach to solve this.
But I would be glad if we could as a first step agree on
whether the dtd definition is OK and can be checked in
with the sample file.
Note: I wrote this patch in the train from Düsseldorf
to Osnabrück (1h) plus some fiddling tonight with the
wxGrid to adapt to the size of the symbol.
Best
Jan
--
Jan-Oliver Wagner http://intevation.de/~jan/
Intevation GmbH http://intevation.de/
FreeGIS http://freegis.org/
-------------- next part --------------
? build
? thubaninit.py
? Data/iceland_sample_size.thuban
? test/temp
Index: Resources/XML/thuban-1.1.dtd
===================================================================
RCS file: /thubanrepository/thuban/Resources/XML/thuban-1.1.dtd,v
retrieving revision 1.1
diff -u -3 -p -r1.1 thuban-1.1.dtd
--- Resources/XML/thuban-1.1.dtd 12 Mar 2004 12:19:15 -0000 1.1
+++ Resources/XML/thuban-1.1.dtd 22 Sep 2004 22:45:12 -0000
@@ -10,7 +10,7 @@
Read the file COPYING coming with Thuban for details.
$Revision: 1.1 $
- $Source: /thubanrepository/thuban/Resources/XML/thuban-1.1.dtd,v $
+ $Source: /home/thuban/jail/thubanrepository/thuban/Resources/XML/thuban-1.1.dtd,v $
$Id: thuban-1.1.dtd,v 1.1 2004/03/12 12:19:15 bh Exp $
-->
@@ -153,12 +153,13 @@ identify the version of the file format.
<!-- the fill and stroke attributes can be either "None" or "#RRGGBB"
RGB hex values
- All of fill, stroke and stroke_width may be omitted and default to
- "None", "#000000" and "1" respectively.
+ All of fill, stroke, stroke_width and size may be omitted and default
+ to "None", "#000000", "1" and "5" respectively.
-->
<!ATTLIST layer fill CDATA "None">
<!ATTLIST layer stroke CDATA "#000000">
<!ATTLIST layer stroke_width CDATA "1">
+<!ATTLIST layer size CDATA "5">
<!-- a rasterlayer represents an image that has some geographic data
@@ -201,14 +202,15 @@ identify the version of the file format.
the fill and stroke attributes can be either "None" or "#RRGGBB"
RGB hex values
- All of fill, stroke and stroke_width may be omitted and default to
- "None", "#000000" and "1" respectively.
+ All of fill, stroke, stroke_width and size may be omitted and default to
+ "None", "#000000", "1" and "5" respectively.
-->
<!ELEMENT cldata EMPTY>
<!ATTLIST cldata
stroke CDATA #IMPLIED
stroke_width CDATA #IMPLIED
fill CDATA #IMPLIED
+ size CDATA #IMPLIED
>
Index: Thuban/Model/classification.py
===================================================================
RCS file: /thubanrepository/thuban/Thuban/Model/classification.py,v
retrieving revision 1.38
diff -u -3 -p -r1.38 classification.py
--- Thuban/Model/classification.py 3 Nov 2003 13:55:41 -0000 1.38
+++ Thuban/Model/classification.py 22 Sep 2004 22:45:12 -0000
@@ -315,7 +315,7 @@ class Classification(Publisher):
items.append(build_item(p, p.GetDisplayText()))
return (_("Classification"), items)
-
+
class ClassIterator:
"""Allows the Groups in a Classifcation to be interated over.
@@ -327,11 +327,11 @@ class ClassIterator:
"""Constructor.
default -- the default group
-
+
points -- a list of singleton groups
ranges -- a list of range groups
-
+
maps -- a list of map groups
"""
@@ -350,10 +350,10 @@ class ClassIterator:
d = self.data[self.data_index]
self.data_index += 1
return d
-
+
class ClassGroupProperties:
"""Represents the properties of a single Classification Group.
-
+
These are used when rendering a layer."""
def __init__(self, props = None):
@@ -370,6 +370,7 @@ class ClassGroupProperties:
else:
self.SetLineColor(Black)
self.SetLineWidth(1)
+ self.SetSize(5)
self.SetFill(Transparent)
def SetProperties(self, props):
@@ -378,8 +379,9 @@ class ClassGroupProperties:
assert isinstance(props, ClassGroupProperties)
self.SetLineColor(props.GetLineColor())
self.SetLineWidth(props.GetLineWidth())
+ self.SetSize(props.GetSize())
self.SetFill(props.GetFill())
-
+
def GetLineColor(self):
"""Return the line color as a Color object."""
return self.__stroke
@@ -407,10 +409,25 @@ class ClassGroupProperties:
self.__strokeWidth = lineWidth
+ def GetSize(self):
+ """Return the size."""
+ return self.__size
+
+ def SetSize(self, size):
+ """Set the size.
+
+ size -- the new size. This must be > 0.
+ """
+ assert isinstance(size, types.IntType)
+ if (size < 1):
+ raise ValueError(_("size < 1"))
+
+ self.__size = size
+
def GetFill(self):
"""Return the fill color as a Color object."""
return self.__fill
-
+
def SetFill(self, fill):
"""Set the fill color.
@@ -431,7 +448,8 @@ class ClassGroupProperties:
self.__stroke == other.__stroke) \
and (self.__fill is other.__fill or \
self.__fill == other.__fill) \
- and self.__strokeWidth == other.__strokeWidth
+ and self.__strokeWidth == other.__strokeWidth\
+ and self.__size == other.__size
def __ne__(self, other):
return not self.__eq__(other)
@@ -443,7 +461,8 @@ class ClassGroupProperties:
return ClassGroupProperties(self)
def __repr__(self):
- return repr((self.__stroke, self.__strokeWidth, self.__fill))
+ return repr((self.__stroke, self.__strokeWidth, self.__size,
+ self.__fill))
class ClassGroup:
"""A base class for all Groups within a Classification"""
@@ -466,7 +485,7 @@ class ClassGroup:
def GetLabel(self):
"""Return the Group's label."""
return self.label
-
+
def SetLabel(self, label):
"""Set the Group's label.
Index: Thuban/Model/load.py
===================================================================
RCS file: /thubanrepository/thuban/Thuban/Model/load.py,v
retrieving revision 1.48
diff -u -3 -p -r1.48 load.py
--- Thuban/Model/load.py 12 Mar 2004 12:19:15 -0000 1.48
+++ Thuban/Model/load.py 22 Sep 2004 22:45:12 -0000
@@ -554,6 +554,7 @@ class SessionLoader(XMLReader):
parse_color(attrs.get((None, 'stroke'), "None")))
self.cl_prop.SetLineWidth(
int(attrs.get((None, 'stroke_width'), "0")))
+ self.cl_prop.SetSize(int(attrs.get((None, 'size'), "5")))
self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
def end_cldata(self, name, qname):
Index: Thuban/UI/baserenderer.py
===================================================================
RCS file: /thubanrepository/thuban/Thuban/UI/baserenderer.py,v
retrieving revision 1.11
diff -u -3 -p -r1.11 baserenderer.py
--- Thuban/UI/baserenderer.py 13 Jul 2004 11:07:45 -0000 1.11
+++ Thuban/UI/baserenderer.py 22 Sep 2004 22:45:12 -0000
@@ -17,7 +17,7 @@ renderers.
from __future__ import generators
__version__ = "$Revision: 1.11 $"
-# $Source: /thubanrepository/thuban/Thuban/UI/baserenderer.py,v $
+# $Source: /home/thuban/jail/thubanrepository/thuban/Thuban/UI/baserenderer.py,v $
# $Id: baserenderer.py,v 1.11 2004/07/13 11:07:45 bh Exp $
import sys
@@ -289,7 +289,10 @@ class BaseRenderer:
data = shape.RawData()
else:
data = shape.Points()
- draw_func(draw_func_param, data, pen, brush)
+ if draw_func == self.draw_point_shape:
+ draw_func(draw_func_param, data, pen, brush, size = group.GetProperties().GetSize())
+ else:
+ draw_func(draw_func_param, data, pen, brush)
if count % 500 == 0:
yield True
@@ -421,7 +424,7 @@ class BaseRenderer:
for part in points:
self.dc.DrawLines(part)
- def draw_point_shape(self, layer, points, pen, brush):
+ def draw_point_shape(self, layer, points, pen, brush, size = 5):
"""Draw a point shape from layer with the given brush and pen
The shape is given by points argument which is a the return
@@ -435,7 +438,7 @@ class BaseRenderer:
if not points:
return
- radius = int(round(self.resolution * 5))
+ radius = int(round(self.resolution * size))
self.dc.SetBrush(brush)
self.dc.SetPen(pen)
for part in points:
Index: Thuban/UI/classifier.py
===================================================================
RCS file: /thubanrepository/thuban/Thuban/UI/classifier.py,v
retrieving revision 1.65
diff -u -3 -p -r1.65 classifier.py
--- Thuban/UI/classifier.py 7 May 2004 20:20:43 -0000 1.65
+++ Thuban/UI/classifier.py 22 Sep 2004 22:45:12 -0000
@@ -331,7 +331,7 @@ class ClassTable(wxPyGridTableBase):
row = -1
self.clazz = clazz
-
+
self.__NotifyRowChanges(old_len, self.GetNumberRows())
#
@@ -439,11 +439,11 @@ class ClassTable(wxPyGridTableBase):
"""
self.SetValueAsCustom(row, col, None, value)
-
+
def GetValueAsCustom(self, row, col, typeName):
"""Return the object that is used to represent the given
cell coordinates. This may not be a string.
-
+
typeName -- unused, but needed to overload wxPyGridTableBase
"""
@@ -915,13 +915,13 @@ class Classifier(NonModalNonParentDialog
table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
self.Enable(True)
propDlg.Destroy()
-
+
def _SetClassification(self, clazz):
"""Called from the ClassGen dialog when a new classification has
been created and should be set in the table.
"""
# FIXME: This could be implemented using a message
-
+
self.fields.SetClientData(self.__cur_field, clazz)
self.classGrid.GetTable().SetClassification(clazz)
@@ -1266,10 +1266,10 @@ class SelectPropertiesDialog(wxDialog):
topBox.Add(buttonBox, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
button_ok.SetDefault()
-
+
#EVT_BUTTON(self, wxID_OK, self._OnOK)
#EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
-
+
self.SetAutoLayout(True)
self.SetSizer(topBox)
topBox.Fit(self)
@@ -1296,7 +1296,7 @@ class SelectPropertiesDialog(wxDialog):
dialog.Destroy()
return ret
-
+
def _OnChangeLineColor(self, event):
clr = self.__GetColor(self.prop.GetLineColor())
if clr is not None:
@@ -1306,7 +1306,7 @@ class SelectPropertiesDialog(wxDialog):
def _OnChangeLineColorTrans(self, event):
self.prop.SetLineColor(Transparent)
self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
-
+
def _OnChangeFillColor(self, event):
clr = self.__GetColor(self.prop.GetFill())
if clr is not None:
@@ -1360,6 +1360,13 @@ class ClassDataPreviewer:
"""Class that actually draws a group property preview."""
def Draw(self, dc, rect, prop, shapeType):
+ """Draw the property.
+
+ returns: (w, h) as adapted extend if the drawing size
+ exceeded the given rect. This can only be the case
+ for point symbols. If the symbol fits the given rect,
+ None is returned.
+ """
assert dc is not None
assert isinstance(prop, ClassGroupProperties)
@@ -1399,12 +1406,20 @@ class ClassDataPreviewer:
elif shapeType == SHAPETYPE_POINT:
- dc.DrawCircle(x + w/2, y + h/2,
- (min(w, h) - prop.GetLineWidth())/2)
+ dc.DrawCircle(x + w/2, y + h/2, prop.GetSize())
+ circle_size = prop.GetSize() * 2 + prop.GetLineWidth() * 2
+ new_h = h
+ new_w = w
+ if h < circle_size: new_h = circle_size
+ if w < circle_size: new_w = circle_size
+ if new_h > h or new_w > w:
+ return (new_w, new_h)
elif shapeType == SHAPETYPE_POLYGON:
dc.DrawRectangle(x, y, w, h)
+ return None
+
class ClassRenderer(wxPyGridCellRenderer):
"""A wrapper class that can be used to draw group properties in a
grid table.
@@ -1426,7 +1441,26 @@ class ClassRenderer(wxPyGridCellRenderer
rect.GetWidth(), rect.GetHeight())
if not isinstance(data, ClassGroupMap):
- self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
+ new_size = self.previewer.Draw(dc, rect, data.GetProperties(),
+ self.shapeType)
+ if new_size is not None:
+ (new_w, new_h) = new_size
+ grid.SetRowSize(row, new_h)
+ grid.SetColSize(col, new_h)
+ grid.ForceRefresh()
+
+ # now that we know the height, redraw everything
+ rect.SetHeight(new_h)
+ rect.SetWidth(new_w)
+ dc.DestroyClippingRegion()
+ dc.SetClippingRegion(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+ dc.SetPen(wxPen(wxLIGHT_GREY))
+ dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
+ dc.DrawRectangle(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+ self.previewer.Draw(dc, rect, data.GetProperties(),
+ self.shapeType)
if isSelected:
dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
Index: test/test_load.py
===================================================================
RCS file: /thubanrepository/thuban/test/test_load.py,v
retrieving revision 1.38
diff -u -3 -p -r1.38 test_load.py
--- test/test_load.py 12 Mar 2004 12:19:15 -0000 1.38
+++ test/test_load.py 22 Sep 2004 22:45:12 -0000
@@ -162,6 +162,8 @@ class ClassificationTest(LoadSessionTest
props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
props.SetFill(
parse_color(data[CLASSES][i][GROUP_PROPS][2]))
+ if len(data[CLASSES][i][GROUP_PROPS]) > 3:
+ props.SetSize(data[CLASSES][i][GROUP_PROPS][3])
if data[CLASSES][i][GROUP_TYPE] == "default":
g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
@@ -384,6 +386,53 @@ class TestLayerVisibility(LoadSessionTes
layer = layers[0]
eq(layer.Visible(), False)
+
+ self.check_format()
+
+
+class TestSymbolSize(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
+ <fileshapesource filetype="shapefile" id="D813968480" filename="../../Data/iceland/cultural_landmark-point.shp"/>
+ <map title="Iceland map">
+ <layer title="cultural_landmark-point" stroke_width="1" shapestore="D813968480" visible="true" stroke="#000000" fill="#000000">
+ <classification field="CLPTLABEL" field_type="string">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" size="3" fill="#000000"/>
+ </clnull>
+ <clpoint label="" value="RUINS">
+ <cldata stroke="#000000" stroke_width="1" size="6" fill="#ffffff"/>
+ </clpoint>
+ <clpoint label="" value="FARM">
+ <cldata stroke="#000000" stroke_width="1" size="9" fill="#ffff00"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test that the size definition for point symbols is correctly
+ loaded for a layer."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ map = session.Maps()[0] # only one map in the sample
+
+ expected = [("cultural_landmark-point", 2,
+ [("default", (), "",
+ ("#000000", 1, "#000000", 3)),
+ ("single", "RUINS", "",
+ ("#000000", 1, "#ffffff", 6)),
+ ("single", "FARM", "",
+ ("#000000", 1, "#ffff00", 9))])]
+
+ self.TestLayers(map.Layers(), expected)
self.check_format()
-------------- next part --------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE session SYSTEM "thuban.dtd">
<session title="Thuban sample session">
<map title="Iceland map">
<projection>
<parameter value="zone=26"/>
<parameter value="proj=utm"/>
<parameter value="ellps=clrk66"/>
</projection>
<layer stroke="#000000" filename="iceland/political.shp" fill="#c0c0c0" stroke_width="1" title="political"/>
<layer stroke="#ffffff" filename="iceland/roads-line.shp" fill="None" stroke_width="1" title="roads-line">
<classification field="RDLNTYPE" field_type="int">
<clnull>
<cldata stroke="#ffffff" stroke_width="1" fill="None"/>
</clnull>
<clpoint value="1">
<cldata stroke="#ff0000" stroke_width="1" fill="None"/>
</clpoint>
<clpoint value="2">
<cldata stroke="#00aa00" stroke_width="1" fill="None"/>
</clpoint>
<clpoint value="3">
<cldata stroke="#0000ff" stroke_width="1" fill="None"/>
</clpoint>
</classification>
</layer>
<layer stroke="#000000" filename="iceland/cultural_landmark-point.shp" fill="#000000" stroke_width="1" title="cultural_landmark-point">
<classification field="CLPTLABEL" field_type="string">
<clnull>
<cldata stroke="#000000" stroke_width="1" size="4" fill="#000000"/>
</clnull>
<clpoint value="RUINS">
<cldata stroke="#000000" stroke_width="1" size="8" fill="#ffffff"/>
</clpoint>
<clpoint value="FARM">
<cldata stroke="#000000" stroke_width="1" size="20" fill="#ffff00"/>
</clpoint>
</classification>
</layer>
</map>
</session>
More information about the Thuban-devel
mailing list
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)