-
Notifications
You must be signed in to change notification settings - Fork 1
/
20110811a.py
220 lines (199 loc) · 6.63 KB
/
20110811a.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
"""
Draw nine hardcoded interlacing shape superpositions.
The command line version will create tikz files.
"""
import argparse
import math
import os
import sys
import numpy as np
import sympy
import Form
import FormOut
import tikz
import interlace
import interlacesample
import pcurve
import bezier
import sympyutils
import bezintersect
import color
import moretypes
STYLE_X = 'x-style'
STYLE_Y = 'y-style'
STYLE_Z = 'z-style'
STYLE_CURVE = 'curve-style'
def get_form():
"""
@return: a list of form objects
"""
# define the form objects
form_objects = [
Form.TikzFormat()]
return form_objects
def get_form_out():
return FormOut.Tikz()
def get_tikz_pane(sample, width=6, height=6):
shapes = None
try:
shapes = sample.get_superposition_shapes()
except AttributeError as e:
pass
if shapes:
return interlace.tikz_shape_superposition(shapes, width, height)
else:
return _get_tikz_pane_tree(sample)
def project_to_2d(point):
return point[1:]
class Stroke(pcurve.BezierPath):
def set_style(self, style):
self.style = style
def shatter(self, *args, **kwargs):
pieces = pcurve.BezierPath.shatter(self, *args, **kwargs)
for p in pieces:
p.set_style(self.style)
return pieces
def bpath_to_stroke(bpath, style):
stroke = Stroke(bpath.bchunks)
stroke.set_style(style)
return stroke
def get_tikz_style_definitions():
return [
'\\tikzstyle{x-style}=[thick,draw=white,double=w-blue,'
'double distance=\\pgflinewidth]',
'\\tikzstyle{y-style}=[thick,draw=white,double=w-red,'
'double distance=\\pgflinewidth]',
'\\tikzstyle{z-style}=[thick,draw=white,double=w-olive,'
'double distance=\\pgflinewidth]',
'\\tikzstyle{curve-style}=[thick,draw=white,double=black,'
'double distance=\\pgflinewidth]']
def get_tikz_bezier(bpath):
lines = []
# draw everything except for the last point of the last chunk
for b in bpath.bchunks:
pts = [tikz.point_to_tikz(p[1:]) for p in b.get_points()[:-1]]
lines.append('%s .. controls %s and %s ..' % tuple(pts))
# draw the last point of the last chunk
lines.append('%s;' % tikz.point_to_tikz(bpath.bchunks[-1].p3[1:]))
return '\n'.join(lines)
def _get_scene(tree_sample):
"""
Define all of the bezier paths.
@param tree_sample: an interlacesample.Sample object
@return: a list of strokes
"""
# define the strokes
strokes = []
# define the scaling factor and the shape
sf = 1.0
styles = (STYLE_CURVE, STYLE_X, STYLE_Y, STYLE_Z)
layout_width = 8.0
layout_height = 8.0
value_height = 8.0
shapes = tree_sample.get_tree_superposition_shapes(
layout_width, layout_height, value_height)
for shape, style in zip(shapes, styles):
# add the scaled bezier paths of the shape
for bpath in shape.get_bezier_paths():
bpath.scale(sf)
strokes.append(bpath_to_stroke(bpath, style))
# return the strokes
return strokes
def _get_tikz_pane_tree(tree_sample):
"""
@return: a tikz text string
"""
min_gridsize = 0.001
strokes = _get_scene(tree_sample)
# rotate every control point in every bchunk in each curve
for stroke in strokes:
stroke.transform(interlacesample.rotate_to_view)
# get the intersection times
time_lists = bezintersect.get_intersection_times(
strokes, project_to_2d, min_gridsize, 3*min_gridsize)
# shatter the strokes, tracking the times of interest and the styles
shattered_strokes = []
for time_list, stroke in zip(time_lists, strokes):
shattered_strokes.extend(stroke.shatter(time_list))
depth_stroke_pairs = []
for stroke in shattered_strokes:
x, y, z = stroke.evaluate(stroke.characteristic_time)
depth_stroke_pairs.append((x, stroke))
ordered_strokes = [s for d, s in sorted(depth_stroke_pairs)]
# draw the depth sorted strokes and patches
arr = []
for stroke in ordered_strokes:
line = '\\draw[%s]' % stroke.style
arr.append(line)
arr.append(get_tikz_bezier(stroke))
return '\n'.join(arr)
def get_tikz_lines():
"""
@param fs: user input
@return: a sequence of tikz lines
"""
arr = []
# draw the matrix
samples = interlacesample.get_samples()
arr.extend([
'\\matrix{',
get_tikz_pane(samples[0]),
'&',
get_tikz_pane(samples[1]),
'&',
get_tikz_pane(samples[2]),
'\\\\',
get_tikz_pane(samples[3]),
'&',
get_tikz_pane(samples[4]),
'&',
get_tikz_pane(samples[5]),
'\\\\',
get_tikz_pane(samples[6]),
'&',
get_tikz_pane(samples[7]),
'&',
get_tikz_pane(samples[8]),
'\\\\};'])
return arr
def get_response_content(fs):
"""
@param fs: a FieldStorage object containing the cgi arguments
@return: the response
"""
tikz_body = '\n'.join(get_tikz_lines())
tikzpicture = tikz.get_picture(tikz_body, 'auto')
packages = ['color']
preamble_lines = []
preamble_lines.append(tikz.get_w_color_preamble())
preamble_lines.extend(get_tikz_style_definitions())
preamble = '\n'.join(preamble_lines)
return tikz.get_response(tikzpicture, fs.tikzformat, packages, preamble)
def main(args):
for i, sample in enumerate(interlacesample.get_samples()):
filename = os.path.join(args.outdir, 'sample-%04d.tikz' % i)
with open(filename, 'w') as fout:
print 'writing', filename
arr = []
# add the remark about the invocation of the generating script
arr.append('% ' + ' '.join(sys.argv))
# add the commands to define custom colors
for name, rgb in color.wolfram_name_color_pairs:
arr.append(tikz.define_color(name, rgb))
# add style definitions for the trees
arr.extend(get_tikz_style_definitions())
# add the tikz drawing functions
arr.append(get_tikz_pane(sample, args.width, args.height))
# write the file
print >> fout, '\n'.join(arr)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--width',
default=6, type=moretypes.pos_float,
help='max width in default tikz units')
parser.add_argument('--height',
default=6, type=moretypes.pos_float,
help='max height in default tikz units')
parser.add_argument('--outdir',
default='', help='output directory')
main(parser.parse_args())