test_pysketcher.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. from pysketcher import *
  2. def equal_dict(d1, d2):
  3. """Return True if nested dicts d1 and d2 are equal."""
  4. for k in d1:
  5. #print 'comparing', k
  6. if k not in d2:
  7. return False
  8. else:
  9. if isinstance(d1[k], dict):
  10. if not equal_dict(d1[k], d2[k]):
  11. return False
  12. else:
  13. # Hack: remove u' for unicode if present
  14. d1_k = d1[k].replace("u'", "'")
  15. d2_k = d2[k].replace("u'", "'")
  16. if d1_k != d2_k:
  17. #print 'values differ: [%s] vs [%s]' % (d1_k, d2_k)
  18. return False
  19. return True
  20. def test_Axis():
  21. drawing_tool.set_coordinate_system(
  22. xmin=0, xmax=15, ymin=-7, ymax=8, axis=True,
  23. instruction_file='tmp_Axis.py')
  24. # Draw normal x and y axis with origin at (7.5, 2)
  25. # in the coordinate system of the sketch: [0,15]x[-7,8]
  26. x_axis = Axis((7.5,2), 5, 'x', rotation_angle=0)
  27. y_axis = Axis((7.5,2), 5, 'y', rotation_angle=90)
  28. system = Composition({'x axis': x_axis, 'y axis': y_axis})
  29. system.draw()
  30. drawing_tool.display()
  31. # Rotate this system 40 degrees counter clockwise
  32. # and draw it with dashed lines
  33. system.set_linestyle('dashed')
  34. system.rotate(40, (7.5,2))
  35. system.draw()
  36. drawing_tool.display()
  37. # Rotate this system another 220 degrees and show
  38. # with dotted lines
  39. system.set_linestyle('dotted')
  40. system.rotate(220, (7.5,2))
  41. system.draw()
  42. drawing_tool.display()
  43. drawing_tool.display('Axis')
  44. drawing_tool.savefig('tmp_Axis')
  45. expected = {
  46. 'x axis': {
  47. 'arrow': {
  48. 'head left': {'line': "2 (x,y) coords linestyle='dotted'",},
  49. 'line': {'line': "2 (x,y) coords linestyle='dotted'",},
  50. 'head right': {'line': "2 (x,y) coords linestyle='dotted'",},},
  51. 'label': "Text at (6.57388,-3.25231)",},
  52. 'y axis': {
  53. 'arrow': {
  54. 'head left': {'line': "2 (x,y) coords linestyle='dotted'",},
  55. 'line': {'line': "2 (x,y) coords linestyle='dotted'",},
  56. 'head right': {'line': "2 (x,y) coords linestyle='dotted'",},},
  57. 'label': "Text at (12.7523,1.07388)",},}
  58. computed = eval(repr(system))
  59. msg = 'expected=%s, computed=%s' % (expected, computed)
  60. assert equal_dict(computed, expected), msg
  61. def test_Distance_wText():
  62. drawing_tool.set_coordinate_system(
  63. xmin=0, xmax=10, ymin=0, ymax=6,
  64. axis=True, instruction_file='tmp_Distance_wText.py')
  65. fontsize=14
  66. t = r'$ 2\pi R^2 $' # sample text
  67. examples = Composition({
  68. 'a0': Distance_wText((4,5), (8, 5), t, fontsize),
  69. 'a6': Distance_wText((4,5), (4, 4), t, fontsize),
  70. 'a1': Distance_wText((0,2), (2, 4.5), t, fontsize),
  71. 'a2': Distance_wText((0,2), (2, 0), t, fontsize),
  72. 'a3': Distance_wText((2,4.5), (0, 5.5), t, fontsize),
  73. 'a4': Distance_wText((8,4), (10, 3), t, fontsize,
  74. text_spacing=-1./60),
  75. 'a5': Distance_wText((8,2), (10, 1), t, fontsize,
  76. text_spacing=-1./40, alignment='right'),
  77. 'c1': Text_wArrow('text_spacing=-1./60',
  78. (4, 3.5), (9, 3.2),
  79. fontsize=10, alignment='left'),
  80. 'c2': Text_wArrow('text_spacing=-1./40, alignment="right"',
  81. (4, 0.5), (9, 1.2),
  82. fontsize=10, alignment='left'),
  83. })
  84. examples.draw()
  85. drawing_tool.display('Distance_wText and text positioning')
  86. drawing_tool.savefig('tmp_Distance_wText')
  87. expected = {
  88. 'a1': {
  89. 'text': "Text at (1.13014,3.14588)",
  90. 'arrow': {
  91. 'arrow': {
  92. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  93. 'a0': {
  94. 'text': "Text at (6,5.16667)",
  95. 'arrow': {'arrow': {
  96. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  97. 'a3': {
  98. 'text': "Text at (1.07454,5.14907)",
  99. 'arrow': {'arrow': {
  100. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  101. 'a2': {
  102. 'text': "Text at (1.11785,1.11785)",
  103. 'arrow': {'arrow': {
  104. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  105. 'a5': {
  106. 'text': "Text at (8.8882,1.27639)",
  107. 'arrow': {'arrow': {
  108. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  109. 'a4': {
  110. 'text': "Text at (8.92546,3.35093)",
  111. 'arrow': {'arrow': {
  112. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  113. 'a6': {
  114. 'text': "Text at (4.16667,4.5)",
  115. 'arrow': {'arrow': {
  116. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  117. 'c2': "Text_wArrow at (4,0.5)",
  118. 'c1': "Text_wArrow at (4,3.5)",
  119. }
  120. computed = eval(repr(examples))
  121. msg = 'expected=%s, computed=%s' % (expected, computed)
  122. assert equal_dict(computed, expected), msg
  123. def test_Rectangle():
  124. L = 3.0
  125. W = 4.0
  126. drawing_tool.set_coordinate_system(
  127. xmin=0, xmax=2*W, ymin=-L/2, ymax=2*L,
  128. axis=True, instruction_file='tmp_Rectangle.py')
  129. drawing_tool.set_linecolor('blue')
  130. drawing_tool.set_grid(True)
  131. xpos = W/2
  132. r = Rectangle(lower_left_corner=(xpos,0), width=W, height=L)
  133. r.draw()
  134. r.draw_dimensions()
  135. drawing_tool.display('Rectangle')
  136. drawing_tool.savefig('tmp_Rectangle')
  137. expected = {'rectangle': "5 (x,y) coords",}
  138. computed = eval(repr(r))
  139. msg = 'expected=%s, computed=%s' % (expected, computed)
  140. assert equal_dict(computed, expected), msg
  141. def test_Triangle():
  142. L = 3.0
  143. W = 4.0
  144. drawing_tool.set_coordinate_system(
  145. xmin=0, xmax=2*W, ymin=-L/2, ymax=1.2*L,
  146. axis=True, instruction_file='tmp_Triangle.py')
  147. drawing_tool.set_linecolor('blue')
  148. drawing_tool.set_grid(True)
  149. xpos = 1
  150. t = Triangle(p1=(W/2,0), p2=(3*W/2,W/2), p3=(4*W/5.,L))
  151. t.draw()
  152. t.draw_dimensions()
  153. drawing_tool.display('Triangle')
  154. drawing_tool.savefig('tmp_Triangle')
  155. expected = {'triangle': "4 (x,y) coords",}
  156. computed = eval(repr(t))
  157. msg = 'expected=%s, computed=%s' % (expected, computed)
  158. assert equal_dict(computed, expected), msg
  159. def test_Arc():
  160. L = 4.0
  161. W = 4.0
  162. drawing_tool.set_coordinate_system(
  163. xmin=-W/2, xmax=W, ymin=-L/2, ymax=1.5*L,
  164. axis=True, instruction_file='tmp_Arc.py')
  165. drawing_tool.set_linecolor('blue')
  166. drawing_tool.set_grid(True)
  167. center = point(0,0)
  168. radius = L/2
  169. start_angle = 60
  170. arc_angle = 45
  171. a = Arc(center, radius, start_angle, arc_angle)
  172. a.draw()
  173. R1 = 1.25*radius
  174. R2 = 1.5*radius
  175. R = 2*radius
  176. a.dimensions = {
  177. 'start_angle':
  178. Arc_wText(
  179. 'start_angle', center, R1, start_angle=0,
  180. arc_angle=start_angle, text_spacing=1/10.),
  181. 'arc_angle':
  182. Arc_wText(
  183. 'arc_angle', center, R2, start_angle=start_angle,
  184. arc_angle=arc_angle, text_spacing=1/20.),
  185. 'r=0':
  186. Line(center, center +
  187. point(R*cos(radians(start_angle)),
  188. R*sin(radians(start_angle)))),
  189. 'r=start_angle':
  190. Line(center, center +
  191. point(R*cos(radians(start_angle+arc_angle)),
  192. R*sin(radians(start_angle+arc_angle)))),
  193. 'r=start+arc_angle':
  194. Line(center, center +
  195. point(R, 0)).set_linestyle('dashed'),
  196. 'radius': Distance_wText(center, a(0), 'radius', text_spacing=1/40.),
  197. 'center': Text('center', center-point(radius/10., radius/10.)),
  198. }
  199. for dimension in a.dimensions:
  200. if dimension.startswith('r='):
  201. dim = a.dimensions[dimension]
  202. dim.set_linestyle('dashed')
  203. dim.set_linewidth(1)
  204. dim.set_linecolor('black')
  205. a.draw_dimensions()
  206. drawing_tool.display('Arc')
  207. drawing_tool.savefig('tmp_Arc')
  208. expected = {'arc': "181 (x,y) coords"}
  209. computed = eval(repr(a))
  210. msg = 'expected=%s, computed=%s' % (expected, computed)
  211. assert equal_dict(computed, expected), msg
  212. expected = {
  213. 'center': 'text "center" at (-0.2,-0.2)',
  214. 'start_angle': {'text': "Text at (2.68468,1.55)",
  215. 'arc': {'arc': "181 (x,y) coords",},},
  216. 'r=start+arc_angle': {
  217. 'line': "2 (x,y) coords linecolor='k' linewidth=1 linestyle='dashed'",},
  218. 'r=0': {'line': "2 (x,y) coords linecolor='k' linewidth=1 linestyle='dashed'",},
  219. 'radius': {'text': "Text at (0.629904,0.791025)",
  220. 'arrow': {'arrow': {
  221. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  222. 'r=start_angle': {'line': "2 (x,y) coords linecolor='k' linewidth=1 linestyle='dashed'",},
  223. 'arc_angle': {'text': "Text at (0.430736,3.27177)",
  224. 'arc': {'arc': "181 (x,y) coords",},}
  225. }
  226. computed = eval(repr(a.dimensions))
  227. msg = 'expected=%s, computed=%s' % (expected, computed)
  228. assert equal_dict(computed, expected), msg
  229. def test_Spring():
  230. L = 5.0
  231. W = 2.0
  232. drawing_tool.set_coordinate_system(
  233. xmin=0, xmax=7*W, ymin=-L/2, ymax=1.5*L,
  234. axis=True, instruction_file='tmp_Spring.py')
  235. drawing_tool.set_linecolor('blue')
  236. drawing_tool.set_grid(True)
  237. xpos = W
  238. s1 = Spring((W,0), L, teeth=True)
  239. s1_title = Text('Default Spring',
  240. s1.geometric_features()['end'] + point(0,L/10))
  241. s1.draw()
  242. s1_title.draw()
  243. #s1.draw_dimensions()
  244. xpos += 3*W
  245. s2 = Spring(start=(xpos,0), length=L, width=W/2.,
  246. bar_length=L/6., teeth=False)
  247. s2.draw()
  248. s2.draw_dimensions()
  249. drawing_tool.display('Spring')
  250. drawing_tool.savefig('tmp_Spring')
  251. # Check s1 and s1.dimensions
  252. expected = {
  253. 'bar1': {'line': "2 (x,y) coords",},
  254. 'bar2': {'line': "2 (x,y) coords",},
  255. 'spiral': "45 (x,y) coords",}
  256. computed = eval(repr(s1))
  257. msg = 'expected=%s, computed=%s' % (expected, computed)
  258. assert equal_dict(computed, expected), msg
  259. expected = {
  260. 'bar_length1': {'text': "Text_wArrow at (-1.5,1.75)",
  261. 'arrow': {'arrow': {
  262. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  263. 'bar_length2': {'text': "Text_wArrow at (-1.5,5.5)",
  264. 'arrow': {'arrow': {
  265. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  266. 'width': {'text': "Text at (2,-1.51667)",
  267. 'arrow': {'arrow': {
  268. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  269. 'start': 'annotation "start" at (1.25,-0.75) with arrow to (2,0)',
  270. 'length': {'text': "Text at (3.73333,2.5)",
  271. 'arrow': {'arrow': {
  272. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  273. 'num_windings': 'annotation "num_windings" at (3,5.5) with arrow to (2.6,2.5)'
  274. }
  275. computed = eval(repr(s1.dimensions))
  276. msg = 'expected=%s, computed=%s' % (expected, computed)
  277. assert equal_dict(computed, expected), msg
  278. def test_Dashpot():
  279. L = 5.0
  280. W = 2.0
  281. xpos = 0
  282. drawing_tool.set_coordinate_system(
  283. xmin=xpos, xmax=xpos+5.5*W, ymin=-L/2, ymax=1.5*L,
  284. axis=True, instruction_file='tmp_Dashpot.py')
  285. drawing_tool.set_linecolor('blue')
  286. drawing_tool.set_grid(True)
  287. # Default (simple) dashpot
  288. xpos = 1.5
  289. d1 = Dashpot(start=(xpos,0), total_length=L)
  290. d1_title = Text('Dashpot (default)',
  291. d1.geometric_features()['end'] + point(0,L/10))
  292. d1.draw()
  293. d1_title.draw()
  294. # Dashpot for animation with fixed bar_length, dashpot_length and
  295. # prescribed piston_pos
  296. xpos += 2.5*W
  297. d2 = Dashpot(start=(xpos,0), total_length=1.2*L, width=W/2,
  298. bar_length=W, dashpot_length=L/2, piston_pos=2*W)
  299. d2.draw()
  300. d2.draw_dimensions()
  301. drawing_tool.display('Dashpot')
  302. drawing_tool.savefig('tmp_Dashpot')
  303. expected = {
  304. 'line start': {'line': "2 (x,y) coords",},
  305. 'piston': {
  306. 'line': {'line': "2 (x,y) coords",},
  307. 'rectangle': {
  308. 'rectangle': "5 (x,y) coords fillcolor='' fillpattern='X'",},},
  309. 'pot': "4 (x,y) coords",
  310. }
  311. computed = eval(repr(d2))
  312. msg = 'expected=%s, computed=%s' % (expected, computed)
  313. assert equal_dict(computed, expected), msg
  314. expected = {
  315. 'width': {'text': "Text at (6.5,-1.56667)",
  316. 'arrow': {'arrow': {
  317. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  318. 'start': 'annotation "start" at (5.75,-0.75) with arrow to (6.5,0)',
  319. 'bar_length': {'text': "Text_wArrow at (3.5,1.5)",
  320. 'arrow': {'arrow': {
  321. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  322. 'total_length': {'text': "Text_wArrow at (8.75,5)",
  323. 'arrow': {'arrow': {
  324. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  325. 'dashpot_length': {'text': "Text_wArrow at (7,-0.5)",
  326. 'arrow': {'arrow': {
  327. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},},
  328. 'piston_pos': {'text': "Text_wArrow at (3.5,3.6875)",
  329. 'arrow': {'arrow': {
  330. 'line': "2 (x,y) coords linecolor='k' linewidth=1 arrow='<->'",},},}
  331. }
  332. computed = eval(repr(d2.dimensions))
  333. msg = 'expected=%s, computed=%s' % (expected, computed)
  334. assert equal_dict(computed, expected), msg
  335. def test_Wavy():
  336. drawing_tool.set_coordinate_system(xmin=0, xmax=1.5,
  337. ymin=-0.5, ymax=5,
  338. axis=True,
  339. instruction_file='tmp_Wavy.py')
  340. w = Wavy(main_curve=lambda x: 1 + sin(2*x),
  341. interval=[0,1.5],
  342. wavelength_of_perturbations=0.3,
  343. amplitude_of_perturbations=0.1,
  344. smoothness=0.05)
  345. w.draw()
  346. drawing_tool.display('Wavy')
  347. drawing_tool.savefig('tmp_Wavy')
  348. expected = {'wavy': "2001 (x,y) coords",}
  349. computed = eval(repr(w))
  350. msg = 'expected=%s, computed=%s' % (expected, computed)
  351. assert equal_dict(computed, expected), msg
  352. def diff_files(files1, files2, mode='HTML'):
  353. import difflib, time
  354. n = 3
  355. for fromfile, tofile in zip(files1, files2):
  356. fromdate = time.ctime(os.stat(fromfile).st_mtime)
  357. todate = time.ctime(os.stat(tofile).st_mtime)
  358. fromlines = open(fromfile, 'U').readlines()
  359. tolines = open(tofile, 'U').readlines()
  360. diff_html = difflib.HtmlDiff().\
  361. make_file(fromlines,tolines,
  362. fromfile,tofile,context=True,numlines=n)
  363. diff_plain = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
  364. filename_plain = fromfile + '.diff.txt'
  365. filename_html = fromfile + '.diff.html'
  366. if os.path.isfile(filename_plain):
  367. os.remove(filename_plain)
  368. if os.path.isfile(filename_html):
  369. os.remove(filename_html)
  370. f = open(filename_plain, 'w')
  371. f.writelines(diff_plain)
  372. f.close()
  373. size = os.path.getsize(filename_plain)
  374. if size > 4:
  375. print 'found differences:', fromfile, tofile
  376. f = open(filename_html, 'w')
  377. f.writelines(diff_html)
  378. f.close()
  379. def _test_test():
  380. """Compare files."""
  381. # Does not work yet.
  382. os.chdir('test')
  383. funcs = [name for name in globals() if name.startswith('test_') and callable(globals()[name])]
  384. funcs.remove('test_test')
  385. new_files = []
  386. res_files = []
  387. for func in funcs:
  388. mplfile = func.replace('test_', 'tmp_') + '.py'
  389. #exec(func + '()')
  390. new_files.append(mplfile)
  391. resfile = mplfile.replace('tmp_', 'res_')
  392. res_files.append(resfile)
  393. diff_files(new_files, res_files)
  394. test_Arc()