add mesh plotting functionality and use this functionality for the surface style
[PyX/mjg.git] / pyx / mesh.py
blob91d38448ae36ded158fa1b0873e25ed3aaf0ace1
1 # -*- coding: ISO-8859-1 -*-
4 # Copyright (C) 2006 André Wobst <wobsta@users.sourceforge.net>
6 # This file is part of PyX (http://pyx.sourceforge.net/).
8 # PyX is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # PyX is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with PyX; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 # Just a quick'n'dirty ascii art (I'll do a nice PyX plot later on):
26 # node1 *
27 # | \
28 # | \ neighbor2
29 # | \
30 # | \
31 # neighbor3 |element * node3
32 # | /
33 # | /
34 # | / neighbor1
35 # | /
36 # node2 *
39 import struct, binascii, zlib
40 import bbox, canvas, color, pdfwriter, unit
43 class mesh:
45 def __init__(self, elements):
46 self.elements = elements
49 class node_pt:
51 def __init__(self, coords_pt, value):
52 self.coords_pt = coords_pt
53 self.value = value
56 class node(node_pt):
58 def __init__(self, coords, value):
59 node_pt.__init__(self, [unit.topt(coord) for coord in coords], value)
62 class element:
64 def __init__(self, nodes, neighbors=None):
65 self.nodes = nodes
66 self.neighbors = neighbors
69 def coords24bit_pt(coords_pt, min_pt, max_pt):
70 return struct.pack(">I", int((coords_pt-min_pt)*16777215.0/(max_pt-min_pt)))[1:]
73 class PDFGenericResource(pdfwriter.PDFobject):
75 def __init__(self, type, name, content):
76 pdfwriter.PDFobject.__init__(self, type, name)
77 self.content = content
79 def write(self, file, writer, registry):
80 file.write(self.content)
83 class canvasmesh(mesh, canvas.canvasitem):
85 def __init__(self, elements, check=1):
86 mesh.__init__(self, elements)
87 if check:
88 colorspacestring = ""
89 for element in elements:
90 if len(element.nodes) != 3:
91 raise ValueError("triangular mesh expected")
92 try:
93 for node in element.nodes:
94 if not colorspacestring:
95 colorspacestring = node.value.colorspacestring()
96 elif node.value.colorspacestring() != colorspacestring:
97 raise ValueError("color space mismatch")
98 except AttributeError:
99 raise ValueError("gray, rgb or cmyk color values expected")
100 for node in element.nodes:
101 if len(node.coords_pt) != 2:
102 raise ValueError("two dimensional coordinates expected")
104 def bbox(self):
105 return bbox.bbox_pt(min([node.coords_pt[0] for element in self.elements for node in element.nodes]),
106 min([node.coords_pt[1] for element in self.elements for node in element.nodes]),
107 max([node.coords_pt[0] for element in self.elements for node in element.nodes]),
108 max([node.coords_pt[1] for element in self.elements for node in element.nodes]))
110 def data(self, bbox):
111 return "".join(["\000%s%s%s" % (coords24bit_pt(node.coords_pt[0], bbox.llx_pt, bbox.urx_pt),
112 coords24bit_pt(node.coords_pt[1], bbox.lly_pt, bbox.ury_pt),
113 node.value.tostring8bit())
114 for element in self.elements for node in element.nodes])
116 def processPS(self, file, writer, context, registry, bbox):
117 thisbbox = self.bbox()
118 bbox += thisbbox
119 file.write("""<< /ShadingType 4
120 /ColorSpace %s
121 /BitsPerCoordinate 24
122 /BitsPerComponent 8
123 /BitsPerFlag 8
124 /Decode [%f %f %f %f %s]
125 /DataSource currentfile /ASCIIHexDecode filter /FlateDecode filter
126 >> shfill\n""" % (self.elements[0].nodes[0].value.colorspacestring(),
127 thisbbox.llx_pt, thisbbox.urx_pt, thisbbox.lly_pt, thisbbox.ury_pt,
128 " ".join(["0 1" for value in self.elements[0].nodes[0].value.tostring8bit()])))
129 file.write(binascii.b2a_hex(zlib.compress(self.data(thisbbox))))
130 file.write("\n")
132 def processPDF(self, file, writer, context, registry, bbox):
133 thisbbox = self.bbox()
134 bbox += thisbbox
135 d = self.data(thisbbox)
136 if writer.compress:
137 filter = "/Filter /FlateDecode\n"
138 d = zlib.compress(d)
139 else:
140 filter = ""
141 name = "shading-%s" % id(self)
142 shading = PDFGenericResource("shading", name, """<< /ShadingType 4
143 /ColorSpace %s
144 /BitsPerCoordinate 24
145 /BitsPerComponent 8
146 /BitsPerFlag 8
147 /Decode [%f %f %f %f %s]
148 /Length %i
149 %s>>
150 stream
152 endstream\n""" % (self.elements[0].nodes[0].value.colorspacestring(),
153 thisbbox.llx_pt, thisbbox.urx_pt, thisbbox.lly_pt, thisbbox.ury_pt,
154 " ".join(["0 1" for value in self.elements[0].nodes[0].value.tostring8bit()]),
155 len(d), filter, d))
156 registry.add(shading)
157 registry.addresource("Shading", name, shading)
158 file.write("/%s sh\n" % name)