Package stsci :: Package numdisplay :: Module overlay
[hide private]
[frames] | no frames]

Source Code for Module stsci.numdisplay.overlay

  1  from __future__ import division # confidence high 
  2   
  3  import math 
  4  import struct 
  5   
  6  import numpy as N 
  7  import stsci.numdisplay as numdisplay 
  8  import ichar  
  9   
 10  """The public functions are the following.  For point, rectangle, circle 
 11  and polyline, arguments shown on separate lines are alternate ways to 
 12  specify the location and size of the figure to be drawn. 
 13   
 14  point (x=x0, y=y0, 
 15         center=(x0,y0)) 
 16  rectangle (left=x1, right=x2, lower=y1, upper=y2, 
 17             center=(x0,y0), width=w, height=h) 
 18  circle (x=x0, y=y0, radius=r, 
 19          center=(x0,y0), radius=r) 
 20  polyline (points=[(x1,y1), (x2,y2), (x3,y3), ...], 
 21            vertices=[(x1,y1), (x2,y2), (x3,y3), ...]) 
 22  undo() 
 23  set (color, radius) 
 24   
 25  color is an optional argument to point, rectangle, circle, and polyline. 
 26  The allowed values for color are: 
 27  C_BLACK, C_WHITE, C_RED, C_GREEN, C_BLUE, C_YELLOW, C_CYAN, C_MAGENTA, 
 28  C_CORAL, C_MAROON, C_ORANGE, C_KHAKI, C_ORCHID, C_TURQUOISE, C_VIOLET, C_WHEAT 
 29  """ 
 30   
 31  C_BLACK     = 202 
 32  C_WHITE     = 203 
 33  C_RED       = 204 
 34  C_GREEN     = 205 
 35  C_BLUE      = 206 
 36  C_YELLOW    = 207 
 37  C_CYAN      = 208 
 38  C_MAGENTA   = 209 
 39  # the following all seem to display as magenta when using ds9 
 40  C_CORAL     = 210 
 41  C_MAROON    = 211 
 42  C_ORANGE    = 212 
 43  C_KHAKI     = 213 
 44  C_ORCHID    = 214 
 45  C_TURQUOISE = 215 
 46  C_VIOLET    = 216 
 47  C_WHEAT     = 217 
 48   
 49  # These two are used for saving the displayed values before drawing 
 50  # an overlay, to allow restoring the display (via undo). 
 51  global_save = [] 
 52  global_byte_buf = N.zeros (1, dtype=N.uint8) 
 53   
 54  # These two are for convenience, so they can take default values rather 
 55  # than having to be specified for each function call.  The radius is 
 56  # only relevant for circles.  Either or both of these can be set via 
 57  # the set() function. 
 58  global_color = N.array ((C_CYAN,), dtype=N.uint8) 
 59  global_radius = 3 
 60   
61 -def _open_display(frame=1):
62 """Open the device.""" 63 fd = numdisplay.getHandle() 64 65 fd.setFrame(frame_num=frame) 66 (tx, ty, fbwidth, fbheight) = fd.readInfo() 67 return (fd, tx, ty, fbwidth, fbheight)
68
69 -def close_display(frame=1):
70 """Close the device.""" 71 fd = numdisplay.getHandle() 72 fd.close() 73 numdisplay.close()
74
75 -def set (color=None, radius=None):
76 """Specify the color or the radius. 77 78 @param color: color code to use for graphic overlays; the allowed 79 values (202..217) are: 80 C_BLACK, C_WHITE, C_RED, C_GREEN, C_BLUE, C_YELLOW, C_CYAN, C_MAGENTA, 81 C_CORAL, C_MAROON, C_ORANGE, C_KHAKI, C_ORCHID, C_TURQUOISE, C_VIOLET, 82 C_WHEAT 83 @type color: int 84 @param radius: radius to use when drawing circles 85 @type radius: int 86 """ 87 88 global global_color, global_radius 89 90 if color is not None: 91 global_color = _checkColor (color) 92 if radius is not None: 93 if radius < 0: 94 raise ValueError, "radius must be non-negative" 95 global_radius = radius
96 97
98 -def _transformPoint (x, y, tx, ty):
99 """Convert image pixel coords to frame buffer coords (IIS convention). 100 101 @param x: image X coordinate of point 102 @type x: float 103 @param y: image Y coordinate of point 104 @type y: float 105 @param tx: X offset of frame buffer in image (positive if image is larger) 106 @type tx: float 107 @param ty: image coordinate corresponding to top line of frame buffer 108 @type ty: float 109 """ 110 111 x -= tx 112 y = ty - y 113 return (x, y)
114
115 -def _checkColor (color=None):
116 """Return a valid color. 117 118 @param color: color code to use; if color=None, use default 119 @type color: int 120 """ 121 122 global global_color 123 124 if color is None: 125 color = global_color 126 elif color < C_BLACK or color > C_WHEAT: 127 raise ValueError, "%d is not a valid color" % color 128 else: 129 color = N.array ((color,), dtype=N.uint8) 130 return color
131
132 -def _update_save (fd, x, y, list_of_points, last_overlay, undo=True):
133 """Save info in local lists list_of_points and last_overlay. 134 135 @param fd: for reading from image display 136 @type fd: file handle 137 @param x: X coordinate (IIS convention, not image coordinates) 138 @type x: int 139 @param y: Y coordinate (IIS convention, not image coordinates) 140 @type y: int 141 @param list_of_points: pixels that have been written to by the graphic 142 overlay that called this function (updated by this function) 143 @type list_of_points: list of (x,y) tuples 144 @param last_overlay: pixel coordinates and current value of display 145 (updated by this function) 146 @type last_overlay: list of (x,y,value) tuples 147 """ 148 149 global global_byte_buf 150 if undo: 151 if (x, y) not in list_of_points: 152 value = fd.readData (x, y, global_byte_buf) 153 value = struct.unpack ('B', value) 154 list_of_points.append ((x, y)) 155 last_overlay.append ((x, y, value[0]))
156
157 -def point (**kwargs):
158 """Draw a point. 159 160 @param x: image X coordinate of point 161 @type x: int 162 @param y: image Y coordinate of point 163 @type y: int 164 @param center: (x,y) coordinates of point 165 @type center: tuple 166 @param color: color code to use; if not specified, use default 167 @type color: int 168 @param undo: if specified [default=True], keep track of overlays for undo() 169 @type undo: bool 170 171 syntax: 172 overlay.point (x=x0, y=y0) 173 overlay.point (center=(x0,y0)) 174 overlay.point (x=x0, y=y0, color=overlay.C_<color>) 175 """ 176 177 # These are used for saving what is currently displayed, for use by 178 # the undo() function. 179 global global_save, global_byte_buf 180 last_overlay = [] 181 list_of_points = [] 182 183 allowed_arguments = ["x", "y", "center", "color", "frame", "undo"] 184 x = None; y = None; center = None; color = None; frame = None; undo = True 185 keys = kwargs.keys() 186 if "center" in keys and ("x" in keys or "y" in keys): 187 raise ValueError, \ 188 "Specify either 'center' or 'x' and 'y', but not both." 189 for key in keys: 190 if key in allowed_arguments: 191 if key == "center": 192 (x, y) = kwargs["center"] 193 elif key == "x": 194 x = kwargs["x"] 195 elif key == "y": 196 y = kwargs["y"] 197 elif key == "color": 198 color = kwargs["color"] 199 elif key == "frame": 200 frame = kwargs["frame"] 201 elif key == "undo": 202 undo = kwargs["undo"] 203 else: 204 raise ValueError, \ 205 "Invalid argument to 'point'; use 'x', 'y', 'center', 'color', 'frame' or 'undo'." 206 if x is None or y is None: 207 raise ValueError, "You must specify either 'x' and 'y' or 'center'." 208 209 color = _checkColor (color) 210 211 (fd, tx, ty, fbwidth, fbheight) = _open_display(frame=frame) 212 213 (x, y) = _transformPoint (x, y, tx, ty) 214 if x >= 0 and y >= 0 and x < fbwidth and y < fbheight: 215 # save the value that is currently at (x,y) 216 _update_save (fd, x, y, list_of_points, last_overlay,undo=undo) 217 # write a new value at (x,y) 218 fd.writeData (x, y, color) 219 220 global_save.append (last_overlay)
221 222 # The close() method needs to be called by the calling routine. 223 #fd.close() 224
225 -def marker (**kwargs):
226 """Draw a character. 227 228 @param x: image X coordinate of point 229 @type x: int 230 @param y: image Y coordinate of point 231 @type y: int 232 @param mark: character to be drawn 233 @type mark: string 234 @param size: magnification to be used in drawing the character 235 @type size: int 236 @param color: color code to use; if not specified, use default 237 @type color: int 238 @param undo: if specified [default=True], keep track of overlays for undo() 239 @type undo: bool 240 241 syntax: 242 overlay.marker (x=x0, y=y0, mark='+') 243 overlay.marker (x=x0, y=y0, mark='+', size=2) 244 overlay.marker (x=x0, y=y0, mark='+', color=overlay.C_<color>) 245 """ 246 247 # These are used for saving what is currently displayed, for use by 248 # the undo() function. 249 global global_save, global_byte_buf 250 last_overlay = [] 251 list_of_points = [] 252 253 allowed_arguments = ["x", "y", "mark", "color", "frame", "size", "undo"] 254 x = None; y = None; center = None; color = None; frame = None; undo=True 255 keys = kwargs.keys() 256 257 for key in keys: 258 if key in allowed_arguments: 259 if key == "x": 260 x = kwargs["x"] 261 elif key == "y": 262 y = kwargs["y"] 263 elif key == "color": 264 color = kwargs["color"] 265 elif key == "mark": 266 mark = kwargs["mark"] 267 elif key == "size": 268 txsize = kwargs["size"] 269 elif key == "frame": 270 frame = kwargs["frame"] 271 elif key == "undo": 272 undo = kwargs["undo"] 273 else: 274 raise ValueError, \ 275 "Invalid argument to 'point'; use 'x', 'y', 'mark', 'size', 'color', 'frame' or 'undo'." 276 if x is None or y is None: 277 raise ValueError, "You must specify 'x' and 'y'." 278 279 color = _checkColor (color) 280 281 (fd, tx, ty, fbwidth, fbheight) = _open_display(frame=frame) 282 283 (x, y) = _transformPoint (x, y, tx, ty) 284 285 idict = ichar.initichar() 286 sprite = idict[mark] 287 # Should have the '+' for center of image 288 sprite = ichar.expandchar(sprite, txsize) 289 ixsize = 5*txsize 290 iysize = 7*txsize 291 # Simple version: just use overlay with a thickness of 1 292 points = sprite 293 npts = len(points[0]) 294 for i in range(npts): 295 iy = y - iysize//2 + points[0][i] 296 ix = x - ixsize//2 + points[1][i] 297 298 if ix >= 0 and iy >= 0 and ix < fbwidth and iy < fbheight: 299 # save the value that is currently at (x,y) 300 _update_save (fd, ix, iy, list_of_points, last_overlay,undo=undo) 301 # write a new value at (x,y) 302 fd.writeData (ix, iy, color) 303 304 global_save.append (last_overlay)
305 306 # The close() method needs to be called by the calling routine. 307 #fd.close() 308
309 -def rectangle (**kwargs):
310 """Draw a rectangle. 311 312 @param left: image X coordinate of left edge 313 @type left: int 314 @param right: image X coordinate of right edge 315 @type right: int 316 @param lower: image Y coordinate of lower edge 317 @type lower: int 318 @param upper: image Y coordinate of upper edge 319 @type upper: int 320 @param center: (x,y) coordinates of middle of rectangle 321 @type center: tuple 322 @param width: width of rectangle (X direction) 323 @type width: int 324 @param height: height of rectangle (Y direction) 325 @type height: int 326 @param color: color code to use; if not specified, use default 327 @type color: int 328 @param undo: if specified [default=True], keep track of overlays for undo() 329 @type undo: bool 330 331 syntax: 332 overlay.rectangle (left=x1, right=x2, lower=y1, upper=y2) 333 overlay.rectangle (center=(x0,y0), width=w, height=h) 334 overlay.rectangle (left=x1, lower=y1, center=(x0,y0)) 335 overlay.rectangle (left=x1, lower=y1, width=w, height=h) 336 overlay.rectangle (right=x2, upper=y2, width=w, height=h) 337 overlay.rectangle (right=x2, upper=y2, center=(x0,y0)) 338 overlay.rectangle (left=x1, right=x2, lower=y1, upper=y2, 339 color=overlay.C_<color>) 340 """ 341 342 # These are used for saving what is currently displayed, for use by 343 # the undo() function. 344 global global_save, global_byte_buf 345 last_overlay = [] 346 list_of_points = [] 347 348 allowed_arguments = ["left", "right", "lower", "upper", 349 "center", "width", "height", "color", "undo"] 350 x1 = None; x2 = None; y1 = None; y2 = None 351 center = None; width = None; height = None; color = None; undo = True 352 353 error_message = "Invalid argument(s) to 'rectangle'; use one of:\n" \ 354 " left=x1, right=x2, lower=y1, upper=y2, or\n" \ 355 " center=(x0,y0), width=w, height=h, or\n" \ 356 " left=x1, lower=y1, width=w, height=h, or\n" \ 357 " right=x2, upper=y2, width=w, height=h\n" \ 358 " color and undo may also be specified." 359 360 keys = kwargs.keys() 361 if "center" in keys: 362 if "width" not in keys or "height" not in keys: 363 raise ValueError, error_message 364 if "left" in keys: 365 if "right" not in keys and "width" not in keys: 366 raise ValueError, error_message 367 if "lower" in keys: 368 if "upper" not in keys and "height" not in keys: 369 raise ValueError, error_message 370 if "right" in keys: 371 if "left" not in keys and "width" not in keys: 372 raise ValueError, error_message 373 if "upper" in keys: 374 if "lower" not in keys and "height" not in keys: 375 raise ValueError, error_message 376 377 for key in keys: 378 if key in allowed_arguments: 379 if key == "center": 380 center = kwargs["center"] 381 if not isinstance (center, (list, tuple)): 382 raise ValueError, error_message 383 (x0, y0) = center 384 elif key == "left": 385 x1 = kwargs["left"] 386 elif key == "right": 387 x2 = kwargs["right"] 388 elif key == "lower": 389 y1 = kwargs["lower"] 390 elif key == "upper": 391 y2 = kwargs["upper"] 392 elif key == "width": 393 width = kwargs["width"] 394 elif key == "height": 395 height = kwargs["height"] 396 elif key == "color": 397 color = kwargs["color"] 398 elif key == "undo": 399 undo = kwargs["undo"] 400 else: 401 raise ValueError, error_message 402 403 if x1 is None: 404 if center is not None and width is not None: 405 x1 = int (round (x0 - width/2.)) 406 elif x2 is not None and width is not None: 407 x1 = x2 - width 408 if x2 is None: 409 if center is not None and width is not None: 410 x2 = int (round (x0 + width/2.)) 411 elif x1 is not None and width is not None: 412 x2 = x1 + width 413 if y1 is None: 414 if center is not None and height is not None: 415 y1 = int (round (y0 - height/2.)) 416 elif y2 is not None and height is not None: 417 y1 = y2 - height 418 if y2 is None: 419 if center is not None and height is not None: 420 y2 = int (round (y0 + height/2.)) 421 elif y1 is not None and height is not None: 422 y2 = y1 + height 423 424 if x1 is None or x2 is None or y1 is None or y2 is None: 425 raise ValueError, error_message 426 427 color = _checkColor (color) 428 429 (fd, tx, ty, fbwidth, fbheight) = _open_display() 430 431 (x1, y1) = _transformPoint (x1, y1, tx, ty) 432 (x2, y2) = _transformPoint (x2, y2, tx, ty) 433 434 if x2 < x1: 435 (x1, x2) = (x2, x1) 436 if y2 < y1: 437 (y1, y2) = (y2, y1) 438 439 imin = max (0, x1) 440 imax = min (x2+1, fbwidth) 441 if y1 >= 0 and y1 < fbheight: 442 for i in range (imin, imax): 443 _update_save (fd, i, y1, list_of_points, last_overlay, undo=undo) 444 fd.writeData (i, y1, color) 445 if y2 >= 0 and y2 < fbheight: 446 for i in range (imin, imax): 447 _update_save (fd, i, y2, list_of_points, last_overlay, undo=undo) 448 fd.writeData (i, y2, color) 449 450 jmin = max (0, y1) 451 jmax = min (y2+1, fbheight) 452 if x1 >= 0 and x1 < fbwidth: 453 for j in range (jmin, jmax): 454 _update_save (fd, x1, j, list_of_points, last_overlay, undo=undo) 455 fd.writeData (x1, j, color) 456 if x2 >= 0 and x2 < fbwidth: 457 for j in range (jmin, jmax): 458 _update_save (fd, x2, j, list_of_points, last_overlay, undo=undo) 459 fd.writeData (x2, j, color) 460 461 global_save.append (last_overlay)
462 463 # The close() method needs to be called by the calling routine. 464 #fd.close() 465
466 -def circle (**kwargs):
467 """Draw a circle. 468 469 @param x: image X coordinate of center 470 @type x: int 471 @param y: image Y coordinate of center 472 @type y: int 473 @param center: (x,y) coordinates of center 474 @type center: tuple 475 @param radius: radius of circle 476 @type radius: int 477 @param color: color code to use; if not specified, use default 478 @type color: int 479 @param undo: if specified [default=True], keep track of overlays for undo() 480 @type undo: bool 481 482 syntax: 483 overlay.circle (x=x0, y=y0, radius=r) 484 overlay.circle (center=(x0,y0), radius=r) 485 overlay.circle (x=x0, y=y0, radius=r, color=overlay.C_<color>) 486 """ 487 488 # These are used for saving what is currently displayed, for use by 489 # the undo() function. 490 global global_save, global_byte_buf 491 last_overlay = [] 492 list_of_points = [] 493 494 allowed_arguments = ["x", "y", "center", "radius", "color", "frame", "undo"] 495 x0 = None; y0 = None; center = None; 496 radius = global_radius; color = None; frame = None; undo = True 497 498 error_message = "Invalid argument(s) to 'circle'; use either:\n" \ 499 " x=x0, y=x0, radius=r, or\n" \ 500 " center=(x0,y0), radius=r\n" \ 501 " color, frame and undo may also be specified." 502 503 keys = kwargs.keys() 504 if "center" in keys and ("x" in keys or "y" in keys): 505 raise ValueError, error_message 506 for key in keys: 507 if key in allowed_arguments: 508 if key == "center": 509 center = kwargs["center"] 510 if not isinstance (center, (list, tuple)): 511 raise ValueError, error_message 512 (x0, y0) = center 513 elif key == "x": 514 x0 = kwargs["x"] 515 elif key == "y": 516 y0 = kwargs["y"] 517 elif key == "radius": 518 radius = kwargs["radius"] 519 elif key == "color": 520 color = kwargs["color"] 521 elif key == "frame": 522 frame = kwargs["frame"] 523 elif key == "undo": 524 undo = kwargs["undo"] 525 else: 526 raise ValueError, error_message 527 if x0 is None or y0 is None or radius is None: 528 raise ValueError, error_message 529 530 color = _checkColor (color) 531 532 (fd, tx, ty, fbwidth, fbheight) = _open_display(frame=frame) 533 534 (x0, y0) = _transformPoint (x0, y0, tx, ty) 535 quarter = int (math.ceil (radius * math.sqrt (0.5))) 536 r2 = radius**2 537 538 for dy in range (-quarter, quarter+1): 539 dx = math.sqrt (r2 - dy**2) 540 j = int (round (dy + y0)) 541 i = int (round (x0 - dx)) # left arc 542 if i >= 0 and j >= 0 and i < fbwidth and j < fbheight: 543 _update_save (fd, i, j, list_of_points, last_overlay, undo = undo) 544 fd.writeData (i, j, color) 545 i = int (round (x0 + dx)) # right arc 546 if i >= 0 and j >= 0 and i < fbwidth and j < fbheight: 547 _update_save (fd, i, j, list_of_points, last_overlay, undo = undo) 548 fd.writeData (i, j, color) 549 550 for dx in range (-quarter, quarter+1): 551 dy = math.sqrt (r2 - dx**2) 552 i = int (round (dx + x0)) 553 j = int (round (y0 - dy)) # bottom arc 554 if i >= 0 and j >= 0 and i < fbwidth and j < fbheight: 555 _update_save (fd, i, j, list_of_points, last_overlay, undo=undo) 556 fd.writeData (i, j, color) 557 j = int (round (y0 + dy)) # top arc 558 if i >= 0 and j >= 0 and i < fbwidth and j < fbheight: 559 _update_save (fd, i, j, list_of_points, last_overlay, undo=undo) 560 fd.writeData (i, j, color) 561 562 global_save.append (last_overlay)
563 564 # The close() method needs to be called by the calling routine. 565 #fd.close() 566
567 -def polyline (**kwargs):
568 """Draw a series of connected line segments. 569 570 @param points: (x,y) points to connect with line segments 571 @type points: list of tuples 572 @param vertices: (x,y) points to connect with line segments 573 @type vertices: list of tuples 574 @param color: color code to use; if not specified, use default 575 @type color: int 576 @param undo: if specified [default=True], keep track of overlays for undo() 577 @type undo: bool 578 579 syntax: 580 overlay.polyline (points=[(x1,y1), (x2,y2), (x3,y3)]) 581 overlay.polyline (vertices=[(x1,y1), (x2,y2), (x3,y3)]) 582 overlay.polyline (points=[(x1,y1), (x2,y2), (x3,y3)], 583 color=overlay.C_<color>) 584 """ 585 586 # These are used for saving what is currently displayed, for use by 587 # the undo() function. 588 global global_save, global_byte_buf 589 last_overlay = [] 590 list_of_points = [] 591 592 allowed_arguments = ["points", "vertices", "color", "frame", "undo"] 593 points = None; vertices = None; color = None; frame = None; undo=True 594 595 error_message = "Invalid argument(s) to 'polyline'; use either:\n" \ 596 " points=[(x1,y1), (x2,y2), (x3,y3), <...>] or\n" \ 597 " vertices=[(x1,y1), (x2,y2), (x3,y3), <...>]\n" \ 598 " color, frame, or undo may also be specified." 599 600 keys = kwargs.keys() 601 if "points" not in keys and "vertices" not in keys: 602 raise ValueError, error_message 603 for key in keys: 604 if key in allowed_arguments: 605 if key == "points": 606 points = kwargs["points"] 607 if not isinstance (points, (list, tuple)): 608 raise ValueError, error_message 609 elif key == "vertices": 610 vertices = kwargs["vertices"] 611 if not isinstance (vertices, (list, tuple)): 612 raise ValueError, error_message 613 elif key == "color": 614 color = kwargs["color"] 615 elif key == "frame": 616 frame = kwargs["frame"] 617 elif key == "undo": 618 undo = kwargs["undo"] 619 else: 620 raise ValueError, error_message 621 622 if points is not None and vertices is not None: 623 raise ValueError, error_message 624 if vertices is not None: 625 keyword = "vertices" 626 points = vertices 627 else: 628 keyword = "points" 629 630 color = _checkColor (color) 631 632 (fd, tx, ty, fbwidth, fbheight) = _open_display(frame=frame) 633 634 expected_a_tuple = \ 635 "Each point in %s for polyline must be a two-element list or tuple,\n" \ 636 "giving the X and Y image pixel coordinates of a vertex." 637 638 first = True 639 for point in points: 640 if not isinstance (point, (list, tuple)): 641 raise ValueError, expected_a_tuple 642 (x, y) = point 643 (x, y) = _transformPoint (x, y, tx, ty) 644 if first: 645 (xlast, ylast) = (x, y) 646 first = False 647 continue 648 if x == xlast and y == ylast: 649 continue 650 dx = x - xlast 651 dy = y - ylast 652 (x1, x2, y1, y2) = (xlast, x, ylast, y) 653 if abs (dy) <= abs (dx): 654 if x >= xlast: 655 step = 1 656 else: 657 step = -1 658 slope = float(dy) / float(dx) 659 if step > 0: 660 imin = max (0, x1) 661 imax = min (x2+1, fbwidth) 662 else: 663 imin = min (x1, fbwidth-1) 664 imax = max (x2-1, -1) 665 for i in range (imin, imax, step): 666 j = slope * (i - x1) + y1 667 j = int (round (j)) 668 if j >= 0 and j < fbheight: 669 _update_save (fd, i, j, list_of_points, last_overlay, undo=undo) 670 fd.writeData (i, j, color) 671 else: 672 if y >= ylast: 673 step = 1 674 else: 675 step = -1 676 slope = float(dx) / float(dy) 677 if step > 0: 678 jmin = max (0, y1) 679 jmax = min (y2+1, fbheight) 680 else: 681 jmin = min (y1, fbheight-1) 682 jmax = max (y2-1, -1) 683 for j in range (jmin, jmax, step): 684 i = slope * (j - y1) + x1 685 i = int (round (i)) 686 if i >= 0 and i < fbwidth: 687 _update_save (fd, i, j, list_of_points, last_overlay, undo=undo) 688 fd.writeData (i, j, color) 689 xlast = x 690 ylast = y 691 692 global_save.append (last_overlay)
693 694 # The close() method needs to be called by the calling routine. 695 #fd.close() 696
697 -def undo():
698 """Restore the values before the last overlay was written.""" 699 700 global global_save, global_byte_buf 701 702 if len (global_save) == 0: 703 return 704 705 (fd, tx, ty, fbwidth, fbheight) = _open_display() 706 707 last_overlay = global_save.pop() 708 for (x, y, value) in last_overlay: 709 global_byte_buf[0] = value 710 fd.writeData (x, y, global_byte_buf)
711 712 # The close() method needs to be called by the calling routine. 713 #fd.close() 714