Commits

Anonymous committed 089dfd8

New: setuptools packaging
Refactor: change project layout somewhat

  • Participants
  • Parent commits 9436bf4

Comments (0)

Files changed (10)

+A library and commandline tool for generating random maps using
+the method of particle deposition.
+
+Usage
+-----
+
+heightfield can be executed as a command line script by running::
+
+    $ heightfield outputfile.png
+
+This will generate a 256x256 image in PNG format. Other file formats supported
+by `PIL`_  will also work.
+
+.. _`PIL`: http://www.pythonware.com/library/pil/handbook/index.htm#appendixes
+

fractal/colours.png

Removed
Old image

fractal/heightmap.svg

-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="744.09448819"
-   height="1052.3622047"
-   id="svg2"
-   version="1.1"
-   inkscape:version="0.48.2 r9819"
-   sodipodi:docname="heightmap.svg">
-  <defs
-     id="defs4">
-    <linearGradient
-       id="linearGradient2987">
-      <stop
-         style="stop-color:#000080;stop-opacity:1"
-         offset="0"
-         id="stop2989" />
-      <stop
-         id="stop3026"
-         offset="0.11775777"
-         style="stop-color:#69b44b;stop-opacity:1;" />
-      <stop
-         style="stop-color:#94df40;stop-opacity:1"
-         offset="0.14719746"
-         id="stop3028" />
-      <stop
-         id="stop2995"
-         offset="0.15346482"
-         style="stop-color:#ffff00;stop-opacity:1" />
-      <stop
-         style="stop-color:#d4aa00;stop-opacity:1"
-         offset="0.19882396"
-         id="stop3020" />
-      <stop
-         style="stop-color:#008900;stop-opacity:1;"
-         offset="0.21884091"
-         id="stop3018" />
-      <stop
-         style="stop-color:#00cc00;stop-opacity:1;"
-         offset="0.39787126"
-         id="stop3016" />
-      <stop
-         id="stop3024"
-         offset="0.69632149"
-         style="stop-color:#b3b3b3;stop-opacity:1" />
-      <stop
-         id="stop3022"
-         offset="0.94274461"
-         style="stop-color:#e3e2db;stop-opacity:1" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1"
-         offset="1"
-         id="stop2991" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient2987"
-       id="linearGradient2993"
-       x1="12.155746"
-       y1="86.223534"
-       x2="268.15573"
-       y2="86.466644"
-       gradientUnits="userSpaceOnUse" />
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="4.1132812"
-     inkscape:cx="96.640348"
-     inkscape:cy="966.21429"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     showgrid="false"
-     inkscape:window-width="1214"
-     inkscape:window-height="776"
-     inkscape:window-x="66"
-     inkscape:window-y="24"
-     inkscape:window-maximized="1" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1">
-    <rect
-       style="color:#000000;fill:url(#linearGradient2993);stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;fill-opacity:1"
-       id="rect2985"
-       width="256"
-       height="1"
-       x="11.428572"
-       y="85.647896"
-       inkscape:export-filename="/home/mauve/dev/fractal/colours.png"
-       inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
-    <path
-       sodipodi:type="arc"
-       style="color:#000000;fill:#f6ed00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
-       id="path3798"
-       sodipodi:cx="80.34948"
-       sodipodi:cy="48.783836"
-       sodipodi:rx="9.1168089"
-       sodipodi:ry="9.2383661"
-       d="m 89.466289,48.783836 a 9.1168089,9.2383661 0 1 1 -18.233618,0 9.1168089,9.2383661 0 1 1 18.233618,0 z" />
-    <path
-       d="m 89.466289,48.783836 a 9.1168089,9.2383661 0 1 1 -18.233618,0 9.1168089,9.2383661 0 1 1 18.233618,0 z"
-       sodipodi:ry="9.2383661"
-       sodipodi:rx="9.1168089"
-       sodipodi:cy="48.783836"
-       sodipodi:cx="80.34948"
-       id="path3800"
-       style="color:#000000;fill:#32d27f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.5"
-       sodipodi:type="arc"
-       transform="translate(13.128205,0.72934473)" />
-  </g>
-</svg>

fractal/surface.py

-import sys
-import os
-import math
-import random
-from PIL import Image
-
-colours = Image.open('colours.png')
-
-class Surface(object):
-    def __init__(self, size, fill=0):
-        self.surface = [fill] * size * size
-        self.size = size
-
-    def index(self, pos):
-        x, y = pos
-        if 0 <= x < self.size:
-            if 0 <= y < self.size:
-                return x + y * self.size
-        raise IndexError("out of range")
-
-    def __getitem__(self, pos):
-        return self.surface[self.index(pos)]
-
-    def __setitem__(self, pos, value):
-        self.surface[self.index(pos)] = value
-
-    def __repr__(self):
-        s = []
-        for y in xrange(self.size):
-            for x in xrange(self.size):
-                h = self[x, y]
-                s.append("%5.2f " % h)
-            s.append('\n')
-        return ''.join(s)
-            
-
-    @staticmethod
-    def make_cone(size, height):
-        s = Surface(size)
-        w = float(size - 1)
-        for x in range(size):
-            for y in range(size):
-                dx = 2.0 * x / w - 1.0
-                dy = 2.0 * y / w - 1.0
-                h = max(0, 1.0 - math.sqrt(dx ** 2 + dy ** 2))
-                s[x, y] = h * height
-        return s
-
-    def blit(self, img, x, y):
-        for sy in range(img.size): 
-            for sx in range(img.size):
-                dx = sx + x
-                dy = sy + y
-                try:
-                    self[dx, dy] += img[sx, sy]
-                except IndexError:
-                    pass
-
-    def to_pil(self):
-        im = Image.new(colours.mode, (self.size, self.size))
-        for y in xrange(self.size):
-            for x in xrange(self.size):
-                h = self[x, y]
-                val = max(0, min(1.0, h * 0.1) * 255)
-                col = colours.getpixel((int(val), 0))
-                im.putpixel((x, y), col)
-        return im
-
-
-if __name__ == '__main__':
-    SIZE = 512
-    landscape = Surface(256, fill=-0.25)
-
-    for i in range(4):
-        d = 25 * i + 20
-        c = Surface.make_cone(d, (i + 1) * 0.2)
-        sys.stdout.write('.')
-        sys.stdout.flush()
-        for i in range(100 * (5 - i)):
-            landscape.blit(c, random.randint(-d, SIZE), random.randint(-d, SIZE))
-    print
-
-    landscape.to_pil().save('out.png')
-    os.system('gnome-open out.png')

heightfield/__init__.py

Empty file added.

heightfield/data/heightmap.png

Added
New image

heightfield/main.py

+import sys
+import random
+from .surface import Surface
+
+
+def main():
+    if len(sys.argv) != 2:
+        sys.exit("Usage: heightfield <output file>")
+
+    outfile = sys.argv[1]
+    SIZE = 512
+    landscape = Surface(256, fill=-0.25)
+
+    for i in range(4):
+        d = 25 * i + 20
+        c = Surface.make_cone(d, (i + 1) * 0.2)
+        sys.stdout.write('.')
+        sys.stdout.flush()
+        for i in range(100 * (5 - i)):
+            xpos = random.randint(-d, SIZE)
+            ypos = random.randint(-d, SIZE)
+            landscape.blit(c, xpos, ypos)
+    print
+
+    landscape.to_pil().save(outfile)

heightfield/surface.py

+import math
+from PIL import Image
+from pkg_resources import resource_stream
+
+colours = Image.open(resource_stream(__name__, 'data/heightmap.png'))
+
+
+class Surface(object):
+    def __init__(self, size, fill=0):
+        self.surface = [fill] * size * size
+        self.size = size
+
+    def _index(self, pos):
+        """Compute the index in self.surface of a given position pos"""
+        x, y = pos
+        if 0 <= x < self.size:
+            if 0 <= y < self.size:
+                return x + y * self.size
+        raise IndexError("out of range")
+
+    def __getitem__(self, pos):
+        return self.surface[self._index(pos)]
+
+    def __setitem__(self, pos, value):
+        self.surface[self._index(pos)] = value
+
+    def __repr__(self):
+        s = []
+        for y in xrange(self.size):
+            for x in xrange(self.size):
+                h = self[x, y]
+                s.append("%5.2f " % h)
+            s.append('\n')
+        return ''.join(s)
+
+    @staticmethod
+    def make_cone(size, height):
+        """Create a surface of size x size representing a cone of height"""
+        s = Surface(size)
+        w = float(size - 1)
+        for x in range(size):
+            for y in range(size):
+                dx = 2.0 * x / w - 1.0
+                dy = 2.0 * y / w - 1.0
+                h = max(0, 1.0 - math.sqrt(dx ** 2 + dy ** 2))
+                s[x, y] = h * height
+        return s
+
+    def blit(self, img, x, y):
+        """Add the heights in img to this surface at (x, y)"""
+        for sy in range(img.size):
+            for sx in range(img.size):
+                dx = sx + x
+                dy = sy + y
+                try:
+                    self[dx, dy] += img[sx, sy]
+                except IndexError:
+                    pass
+
+    def to_pil(self):
+        im = Image.new(colours.mode, (self.size, self.size))
+        for y in xrange(self.size):
+            for x in xrange(self.size):
+                h = self[x, y]
+                val = max(0, min(1.0, h * 0.1) * 255)
+                col = colours.getpixel((int(val), 0))
+                im.putpixel((x, y), col)
+        return im
+import os
+from setuptools import setup, find_packages
+
+# Load long_description from README.rst
+readme = os.path.join(os.path.dirname(__file__), 'README.rst')
+long_description = open(readme, 'rU').read().decode('utf8')
+
+setup(
+    name='heightfield',
+    version="0.1",
+    packages=find_packages(),
+    description=u"Generate random maps by particle deposition",
+    long_description=long_description,
+    author='Daniel Pope / Reading Python Dojo',
+    author_email='lord.mauve@gmail.com',
+    install_requires=[
+        'PIL>=1.1.6',
+    ],
+    license='LGPL',
+    classifiers=[
+        'Development Status :: 2 - Pre-Alpha',
+        'Environment :: Console',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+        'Operating System :: OS Independent',
+        'Topic :: Multimedia :: Graphics',
+    ],
+    package_data={
+        'heightfield': ['data/*.png'],
+    },
+    entry_points={
+        'console_scripts': [
+            'heightfield = heightfield.main:main',
+        ]
+    }
+)

source/heightmap.svg

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="256"
+   height="1"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="heightmap.svg"
+   inkscape:export-filename="/home/mauve/dev/heightfield/fractal/colours.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient2987">
+      <stop
+         style="stop-color:#1b2765;stop-opacity:1"
+         offset="0"
+         id="stop2989" />
+      <stop
+         style="stop-color:#7bf6e3;stop-opacity:1"
+         offset="0.14719746"
+         id="stop3028" />
+      <stop
+         id="stop3111"
+         offset="0.15028511"
+         style="stop-color:#ffffff;stop-opacity:1" />
+      <stop
+         id="stop2995"
+         offset="0.15346482"
+         style="stop-color:#ffff00;stop-opacity:1" />
+      <stop
+         style="stop-color:#d4aa00;stop-opacity:1"
+         offset="0.19882396"
+         id="stop3020" />
+      <stop
+         style="stop-color:#008900;stop-opacity:1;"
+         offset="0.21884091"
+         id="stop3018" />
+      <stop
+         style="stop-color:#00cc00;stop-opacity:1;"
+         offset="0.39787126"
+         id="stop3016" />
+      <stop
+         id="stop3024"
+         offset="0.69632149"
+         style="stop-color:#b3b3b3;stop-opacity:1" />
+      <stop
+         id="stop3022"
+         offset="0.94274461"
+         style="stop-color:#e3e2db;stop-opacity:1" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="1"
+         id="stop2991" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2987"
+       id="linearGradient2993"
+       x1="11.581223"
+       y1="86.267731"
+       x2="268.15573"
+       y2="86.466644"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="24.566761"
+     inkscape:cy="-1.5667928"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1854"
+     inkscape:window-height="1176"
+     inkscape:window-x="66"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-11.428572,-85.647896)">
+    <rect
+       style="color:#000000;fill:url(#linearGradient2993);fill-opacity:1;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2985"
+       width="256"
+       height="1"
+       x="11.428572"
+       y="85.647896"
+       inkscape:export-filename="/home/mauve/dev/fractal/colours.png"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       sodipodi:type="arc"
+       style="color:#000000;fill:#f6ed00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="path3798"
+       sodipodi:cx="80.34948"
+       sodipodi:cy="48.783836"
+       sodipodi:rx="9.1168089"
+       sodipodi:ry="9.2383661"
+       d="m 89.466289,48.783836 c 0,5.102209 -4.081735,9.238366 -9.116809,9.238366 -5.035075,0 -9.116809,-4.136157 -9.116809,-9.238366 0,-5.102208 4.081734,-9.238366 9.116809,-9.238366 5.035074,0 9.116809,4.136158 9.116809,9.238366 z" />
+    <path
+       d="m 89.466289,48.783836 c 0,5.102209 -4.081735,9.238366 -9.116809,9.238366 -5.035075,0 -9.116809,-4.136157 -9.116809,-9.238366 0,-5.102208 4.081734,-9.238366 9.116809,-9.238366 5.035074,0 9.116809,4.136158 9.116809,9.238366 z"
+       sodipodi:ry="9.2383661"
+       sodipodi:rx="9.1168089"
+       sodipodi:cy="48.783836"
+       sodipodi:cx="80.34948"
+       id="path3800"
+       style="opacity:0.5;color:#000000;fill:#00ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       sodipodi:type="arc"
+       transform="translate(13.128205,0.72934473)" />
+  </g>
+</svg>