| 1 | |
| 2 | import wx |
| 3 | |
| 4 | # Stuff to integrate FloatCanvas into wxPython Demo |
| 5 | try: |
| 6 | import Numeric |
| 7 | haveNumeric = True |
| 8 | except ImportError: |
| 9 | haveNumeric = False |
| 10 | |
| 11 | |
| 12 | if not haveNumeric: |
| 13 | errorText = """\ |
| 14 | The FloatCanvas requires the Numeric module: |
| 15 | You can get it at: |
| 16 | http://sourceforge.net/projects/numpy |
| 17 | """ |
| 18 | def runTest(frame, nb, log): |
| 19 | dlg = wx.MessageDialog( |
| 20 | frame, errorText, 'Sorry', wx.OK | wx.ICON_INFORMATION |
| 21 | ) |
| 22 | |
| 23 | dlg.ShowModal() |
| 24 | dlg.Destroy() |
| 25 | |
| 26 | overview = "" |
| 27 | |
| 28 | else: |
| 29 | from wxPython.lib import floatcanvas |
| 30 | import wxPython.lib.colourdb |
| 31 | |
| 32 | ID_ABOUT_MENU = wx.NewId() |
| 33 | ID_EXIT_MENU = wx.NewId() |
| 34 | ID_ZOOM_TO_FIT_MENU = wx.NewId() |
| 35 | ID_DRAWTEST_MENU = wx.NewId() |
| 36 | ID_LINETEST_MENU = wx.NewId() |
| 37 | ID_DRAWMAP_MENU = wx.NewId() |
| 38 | ID_DRAWMAP2_MENU = wx.NewId() |
| 39 | ID_CLEAR_MENU = wx.NewId() |
| 40 | |
| 41 | |
| 42 | colors = [] |
| 43 | LineStyles = floatcanvas.draw_object.LineStyleList.keys() |
| 44 | |
| 45 | |
| 46 | |
| 47 | class DrawFrame(wx.Frame): |
| 48 | |
| 49 | """ |
| 50 | |
| 51 | A frame used for the FloatCanvas Demo |
| 52 | |
| 53 | """ |
| 54 | |
| 55 | def __init__(self, parent, id, title, position, size): |
| 56 | wx.Frame.__init__(self,parent, id,title,position, size) |
| 57 | |
| 58 | # Set up the MenuBar |
| 59 | |
| 60 | MenuBar = wx.MenuBar() |
| 61 | |
| 62 | file_menu = wx.Menu() |
| 63 | file_menu.Append(ID_EXIT_MENU, "&Close","Close this frame") |
| 64 | self.Bind(wx.EVT_MENU, self.OnQuit, id=ID_EXIT_MENU) |
| 65 | MenuBar.Append(file_menu, "&File") |
| 66 | |
| 67 | draw_menu = wx.Menu() |
| 68 | draw_menu.Append(ID_DRAWTEST_MENU, "&Draw Test","Run a test of drawing random components") |
| 69 | self.Bind(wx.EVT_MENU, self.DrawTest, id=ID_DRAWTEST_MENU) |
| 70 | draw_menu.Append(ID_LINETEST_MENU, "&Line Test","Run a test of drawing random lines") |
| 71 | self.Bind(wx.EVT_MENU, self.LineTest, id=ID_LINETEST_MENU) |
| 72 | draw_menu.Append(ID_DRAWMAP_MENU, "Draw &Map","Run a test of drawing a map") |
| 73 | self.Bind(wx.EVT_MENU, self.DrawMap, id=ID_DRAWMAP_MENU) |
| 74 | draw_menu.Append(ID_CLEAR_MENU, "&Clear","Clear the Canvas") |
| 75 | self.Bind(wx.EVT_MENU, self.Clear, id=ID_CLEAR_MENU) |
| 76 | MenuBar.Append(draw_menu, "&Draw") |
| 77 | |
| 78 | view_menu = wx.Menu() |
| 79 | view_menu.Append(ID_ZOOM_TO_FIT_MENU, "Zoom to &Fit","Zoom to fit the window") |
| 80 | self.Bind(wx.EVT_MENU, self.ZoomToFit, id=ID_ZOOM_TO_FIT_MENU) |
| 81 | MenuBar.Append(view_menu, "&View") |
| 82 | |
| 83 | help_menu = wx.Menu() |
| 84 | help_menu.Append(ID_ABOUT_MENU, "&About", |
| 85 | "More information About this program") |
| 86 | self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_ABOUT_MENU) |
| 87 | MenuBar.Append(help_menu, "&Help") |
| 88 | |
| 89 | self.SetMenuBar(MenuBar) |
| 90 | |
| 91 | self.CreateStatusBar() |
| 92 | self.SetStatusText("") |
| 93 | |
| 94 | self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) |
| 95 | |
| 96 | # Other event handlers: |
| 97 | self.Bind(wx.EVT_RIGHT_DOWN, self.RightButtonEvent) |
| 98 | |
| 99 | # Add the Canvas |
| 100 | self.Canvas = floatcanvas.FloatCanvas(self,-1,(500,500), |
| 101 | ProjectionFun = 'FlatEarth', |
| 102 | Debug = 0, |
| 103 | EnclosingFrame = self, |
| 104 | BackgroundColor = "DARK SLATE BLUE", |
| 105 | UseBackground = 0, |
| 106 | UseToolbar = 1) |
| 107 | self.Show(True) |
| 108 | |
| 109 | self.object_list = [] |
| 110 | |
| 111 | return None |
| 112 | |
| 113 | def RightButtonEvent(self,event): |
| 114 | print "Right Button has been clicked in DrawFrame" |
| 115 | print "coords are: %i, %i"%(event.GetX(),event.GetY()) |
| 116 | event.Skip() |
| 117 | |
| 118 | def OnAbout(self, event): |
| 119 | dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n" |
| 120 | "the use of the FloatCanvas\n", |
| 121 | "About Me", wx.OK | wx.ICON_INFORMATION) |
| 122 | dlg.ShowModal() |
| 123 | dlg.Destroy() |
| 124 | |
| 125 | def SetMode(self,event): |
| 126 | for id in [ID_ZOOM_IN_BUTTON,ID_ZOOM_OUT_BUTTON,ID_MOVE_MODE_BUTTON]: |
| 127 | self.ToolBar.ToggleTool(id,0) |
| 128 | |
| 129 | self.ToolBar.ToggleTool(event.GetId(),1) |
| 130 | |
| 131 | if event.GetId() == ID_ZOOM_IN_BUTTON: |
| 132 | self.Canvas.SetGUIMode("ZoomIn") |
| 133 | |
| 134 | elif event.GetId() == ID_ZOOM_OUT_BUTTON: |
| 135 | self.Canvas.SetGUIMode("ZoomOut") |
| 136 | |
| 137 | elif event.GetId() == ID_MOVE_MODE_BUTTON: |
| 138 | self.Canvas.SetGUIMode("Move") |
| 139 | |
| 140 | def ZoomToFit(self,event): |
| 141 | self.Canvas.ZoomToBB() |
| 142 | |
| 143 | def Clear(self,event = None): |
| 144 | self.Canvas.RemoveObjects(self.object_list) |
| 145 | self.object_list = [] |
| 146 | self.Canvas.Draw() |
| 147 | |
| 148 | def OnQuit(self,event): |
| 149 | self.Close(True) |
| 150 | |
| 151 | def OnCloseWindow(self, event): |
| 152 | self.Destroy() |
| 153 | |
| 154 | def DrawTest(self,event): |
| 155 | wx.GetApp().Yield() |
| 156 | |
| 157 | import random |
| 158 | import RandomArray |
| 159 | |
| 160 | Range = (-10,10) |
| 161 | |
| 162 | Canvas = self.Canvas |
| 163 | object_list = self.object_list |
| 164 | |
| 165 | # Random tests of everything: |
| 166 | |
| 167 | # Rectangles |
| 168 | for i in range(5): |
| 169 | x,y = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) |
| 170 | lw = random.randint(1,5) |
| 171 | cf = random.randint(0,len(colors)-1) |
| 172 | h = random.randint(1,5) |
| 173 | w = random.randint(1,5) |
| 174 | object_list.append(Canvas.AddRectangle(x,y,h,w,LineWidth = lw,FillColor = colors[cf])) |
| 175 | |
| 176 | # Ellipses |
| 177 | for i in range(5): |
| 178 | x,y = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) |
| 179 | lw = random.randint(1,5) |
| 180 | cf = random.randint(0,len(colors)-1) |
| 181 | h = random.randint(1,5) |
| 182 | w = random.randint(1,5) |
| 183 | object_list.append(Canvas.AddEllipse(x,y,h,w,LineWidth = lw,FillColor = colors[cf])) |
| 184 | |
| 185 | # Dots |
| 186 | for i in range(5): |
| 187 | x,y = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) |
| 188 | D = random.randint(1,50) |
| 189 | lw = random.randint(1,5) |
| 190 | cf = random.randint(0,len(colors)-1) |
| 191 | cl = random.randint(0,len(colors)-1) |
| 192 | object_list.append(Canvas.AddDot(x,y,D,LineWidth = lw,LineColor = colors[cl],FillColor = colors[cf])) |
| 193 | |
| 194 | # Circles |
| 195 | for i in range(5): |
| 196 | x,y = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) |
| 197 | D = random.randint(1,5) |
| 198 | lw = random.randint(1,5) |
| 199 | cf = random.randint(0,len(colors)-1) |
| 200 | cl = random.randint(0,len(colors)-1) |
| 201 | object_list.append(Canvas.AddCircle(x,y,D,LineWidth = lw,LineColor = colors[cl],FillColor = colors[cf])) |
| 202 | self.object_list.append(self.Canvas.AddText("Circle # %i"%(i),x,y,Size = 12,BackGround = None,Position = "cc")) |
| 203 | |
| 204 | # Lines |
| 205 | for i in range(5): |
| 206 | points = [] |
| 207 | for j in range(random.randint(2,10)): |
| 208 | point = (random.randint(Range[0],Range[1]),random.randint(Range[0],Range[1])) |
| 209 | points.append(point) |
| 210 | lw = random.randint(1,10) |
| 211 | cf = random.randint(0,len(colors)-1) |
| 212 | cl = random.randint(0,len(colors)-1) |
| 213 | self.object_list.append(self.Canvas.AddLine(points, LineWidth = lw, LineColor = colors[cl])) |
| 214 | |
| 215 | # Polygons |
| 216 | for i in range(3): |
| 217 | points = [] |
| 218 | for j in range(random.randint(2,6)): |
| 219 | point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) |
| 220 | points.append(point) |
| 221 | lw = random.randint(1,6) |
| 222 | cf = random.randint(0,len(colors)-1) |
| 223 | cl = random.randint(0,len(colors)-1) |
| 224 | self.object_list.append(self.Canvas.AddPolygon(points, |
| 225 | LineWidth = lw, |
| 226 | LineColor = colors[cl], |
| 227 | FillColor = colors[cf], |
| 228 | FillStyle = 'Solid')) |
| 229 | |
| 230 | |
| 231 | ## Pointset |
| 232 | for i in range(4): |
| 233 | points = [] |
| 234 | points = RandomArray.uniform(Range[0],Range[1],(100,2)) |
| 235 | cf = random.randint(0,len(colors)-1) |
| 236 | D = random.randint(1,4) |
| 237 | self.object_list.append(self.Canvas.AddPointSet(points, Color = colors[cf], Diameter = D)) |
| 238 | |
| 239 | # Text |
| 240 | String = "Some text" |
| 241 | for i in range(10): |
| 242 | ts = random.randint(10,40) |
| 243 | cf = random.randint(0,len(colors)-1) |
| 244 | x,y = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) |
| 245 | self.object_list.append(self.Canvas.AddText(String,x,y,Size = ts,ForeGround = colors[cf],Position = "cc")) |
| 246 | |
| 247 | self.Canvas.ZoomToBB() |
| 248 | |
| 249 | def DrawMap(self,event = None): |
| 250 | wx.GetApp().Yield() |
| 251 | import os, time |
| 252 | ## Test of Actual Map Data |
| 253 | self.Clear() |
| 254 | start = time.clock() |
| 255 | Shorelines = Read_MapGen(os.path.join("data",'world.dat'),stats = 0) |
| 256 | print "It took %f seconds to load %i shorelines"%(time.clock() - start,len(Shorelines) ) |
| 257 | start = time.clock() |
| 258 | for segment in Shorelines: |
| 259 | self.object_list.append(self.Canvas.AddLine(segment)) |
| 260 | print "It took %f seconds to add %i shorelines"%(time.clock() - start,len(Shorelines) ) |
| 261 | start = time.clock() |
| 262 | self.Canvas.ZoomToBB() |
| 263 | print "It took %f seconds to draw %i shorelines"%(time.clock() - start,len(Shorelines) ) |
| 264 | |
| 265 | ## def LineTest(self,event = None): |
| 266 | ## wxGetApp().Yield() |
| 267 | ## import os, time |
| 268 | ## import random |
| 269 | ## Range = (-10,10) |
| 270 | ## ## Test of drawing lots of lines |
| 271 | ## self.Clear() |
| 272 | ## start = time.clock() |
| 273 | ## linepoints = [] |
| 274 | ## linecolors = [] |
| 275 | ## linewidths = [] |
| 276 | ## linestyles = [] |
| 277 | ## for i in range(500): |
| 278 | ## points = (random.randint(Range[0],Range[1]), |
| 279 | ## random.randint(Range[0],Range[1])) |
| 280 | ## linepoints.append(points) |
| 281 | ## points = (random.randint(Range[0],Range[1]), |
| 282 | ## random.randint(Range[0],Range[1])) |
| 283 | ## linepoints.append(points) |
| 284 | ## linewidths.append(random.randint(1,10) ) |
| 285 | ## linecolors.append(colors[random.randint(0,len(colors)-1) ]) |
| 286 | ## linestyles.append(LineStyles[random.randint(0, len(LineStyles)-1)]) |
| 287 | |
| 288 | ## self.object_list.append(self.Canvas.AddLineSet(linepoints, LineWidths = linewidths, LineColors = linecolors, LineStyles = linestyles)) |
| 289 | ## print "It took %f seconds to add %i lines"%(time.clock() - start,len(linepoints) ) |
| 290 | ## start = time.clock() |
| 291 | ## self.Canvas.ZoomToBB() |
| 292 | ## print "It took %f seconds to draw %i lines"%(time.clock() - start,len(linepoints) ) |
| 293 | |
| 294 | def LineTest(self,event = None): |
| 295 | wx.GetApp().Yield() |
| 296 | import os, time |
| 297 | import random |
| 298 | Range = (-10,10) |
| 299 | ## Test of drawing lots of lines |
| 300 | self.Clear() |
| 301 | start = time.clock() |
| 302 | linepoints = [] |
| 303 | linecolors = [] |
| 304 | linewidths = [] |
| 305 | for i in range(2000): |
| 306 | points = (random.randint(Range[0],Range[1]), |
| 307 | random.randint(Range[0],Range[1]), |
| 308 | random.randint(Range[0],Range[1]), |
| 309 | random.randint(Range[0],Range[1])) |
| 310 | linepoints.append(points) |
| 311 | linewidths.append(random.randint(1,10) ) |
| 312 | linecolors.append(random.randint(0,len(colors)-1) ) |
| 313 | for (points,color,width) in zip(linepoints,linecolors,linewidths): |
| 314 | self.object_list.append(self.Canvas.AddLine((points[0:2],points[2:4]), LineWidth = width, LineColor = colors[color])) |
| 315 | print "It took %f seconds to add %i lines"%(time.clock() - start,len(linepoints) ) |
| 316 | start = time.clock() |
| 317 | self.Canvas.ZoomToBB() |
| 318 | print "It took %f seconds to draw %i lines"%(time.clock() - start,len(linepoints) ) |
| 319 | |
| 320 | class DemoApp(wx.App): |
| 321 | """ |
| 322 | How the demo works: |
| 323 | |
| 324 | Under the Draw menu, there are three options: |
| 325 | |
| 326 | *Draw Test: will put up a picture of a bunch of randomly generated |
| 327 | objects, of each kind supported. |
| 328 | |
| 329 | *Draw Map: will draw a map of the world. Be patient, it is a big map, |
| 330 | with a lot of data, and will take a while to load and draw (about 10 sec |
| 331 | on my 450Mhz PIII). Redraws take about 2 sec. This demonstrates how the |
| 332 | performance is not very good for large drawings. |
| 333 | |
| 334 | *Clear: Clears the Canvas. |
| 335 | |
| 336 | Once you have a picture drawn, you can zoom in and out and move about |
| 337 | the picture. There is a tool bar with three tools that can be |
| 338 | selected. |
| 339 | |
| 340 | The magnifying glass with the plus is the zoom in tool. Once selected, |
| 341 | if you click the image, it will zoom in, centered on where you |
| 342 | clicked. If you click and drag the mouse, you will get a rubber band |
| 343 | box, and the image will zoom to fit that box when you release it. |
| 344 | |
| 345 | The magnifying glass with the minus is the zoom out tool. Once selected, |
| 346 | if you click the image, it will zoom out, centered on where you |
| 347 | clicked. (note that this takes a while when you are looking at the map, |
| 348 | as it has a LOT of lines to be drawn. The image is double buffered, so |
| 349 | you don't see the drawing in progress) |
| 350 | |
| 351 | The hand is the move tool. Once selected, if you click and drag on the |
| 352 | image, it will move so that the part you clicked on ends up where you |
| 353 | release the mouse. Nothing is changed while you are dragging. The |
| 354 | drawing is too slow for that. |
| 355 | |
| 356 | I'd like the cursor to change as you change tools, but the stock |
| 357 | wxCursors didn't include anything I liked, so I stuck with the |
| 358 | pointer. Please let me know if you have any nice cursor images for me to |
| 359 | use. |
| 360 | |
| 361 | |
| 362 | Any bugs, comments, feedback, questions, and especially code are welcome: |
| 363 | |
| 364 | -Chris Barker |
| 365 | |
| 366 | Chris.Barker@noaa.gov |
| 367 | |
| 368 | """ |
| 369 | |
| 370 | def OnInit(self): |
| 371 | global colors |
| 372 | wxPython.lib.colourdb.updateColourDB() |
| 373 | colors = wxPython.lib.colourdb.getColourList() |
| 374 | |
| 375 | frame = DrawFrame(None, -1, "FloatCanvas Demo App", |
| 376 | wx.DefaultPosition, (700,700)) |
| 377 | |
| 378 | self.SetTopWindow(frame) |
| 379 | |
| 380 | return True |
| 381 | |
| 382 | def Read_MapGen(filename,stats = 0,AllLines=0): |
| 383 | """ |
| 384 | This function reads a MapGen Format file, and |
| 385 | returns a list of NumPy arrays with the line segments in them. |
| 386 | |
| 387 | Each NumPy array in the list is an NX2 array of Python Floats. |
| 388 | |
| 389 | The demo should have come with a file, "world.dat" that is the |
| 390 | shorelines of the whole world, in MapGen format. |
| 391 | |
| 392 | """ |
| 393 | import string |
| 394 | from Numeric import array |
| 395 | file = open(filename,'rt') |
| 396 | data = file.readlines() |
| 397 | data = map(string.strip,data) |
| 398 | |
| 399 | Shorelines = [] |
| 400 | segment = [] |
| 401 | for line in data: |
| 402 | if line: |
| 403 | if line == "# -b": #New segment beginning |
| 404 | if segment: Shorelines.append(array(segment)) |
| 405 | segment = [] |
| 406 | else: |
| 407 | segment.append(map(float,string.split(line))) |
| 408 | if segment: Shorelines.append(array(segment)) |
| 409 | |
| 410 | if stats: |
| 411 | NumSegments = len(Shorelines) |
| 412 | NumPoints = 0 |
| 413 | for segment in Shorelines: |
| 414 | NumPoints = NumPoints + len(segment) |
| 415 | AvgPoints = NumPoints / NumSegments |
| 416 | print "Number of Segments: ", NumSegments |
| 417 | print "Average Number of Points per segment: ",AvgPoints |
| 418 | if AllLines: |
| 419 | Lines = [] |
| 420 | for segment in Shorelines: |
| 421 | Lines.append(segment[0]) |
| 422 | for point in segment[1:-1]: |
| 423 | Lines.append(point) |
| 424 | Lines.append(point) |
| 425 | Lines.append(segment[-1]) |
| 426 | #print Shorelines |
| 427 | #for point in Lines: print point |
| 428 | return Lines |
| 429 | else: |
| 430 | return Shorelines |
| 431 | |
| 432 | |
| 433 | #---------------------------------------------------------------------- |
| 434 | |
| 435 | def runTest(frame, nb, log): |
| 436 | """ |
| 437 | This method is used by the wxPython Demo Framework for integrating |
| 438 | this demo with the rest. |
| 439 | """ |
| 440 | global colors |
| 441 | wxPython.lib.colourdb.updateColourDB() |
| 442 | colors = wxPython.lib.colourdb.getColourList() |
| 443 | |
| 444 | win = DrawFrame(None, -1, "FloatCanvas Drawing Window", |
| 445 | wx.DefaultPosition, (500,500)) |
| 446 | frame.otherWin = win |
| 447 | win.Show(True) |
| 448 | |
| 449 | |
| 450 | |
| 451 | |
| 452 | ## for the wxPython demo: |
| 453 | overview = floatcanvas.FloatCanvas.__doc__ |
| 454 | |
| 455 | |
| 456 | |
| 457 | if __name__ == "__main__": |
| 458 | if not haveNumeric: |
| 459 | print errorText |
| 460 | else: |
| 461 | app = DemoApp(0) |
| 462 | |
| 463 | import wx.lib.colourdb |
| 464 | wx.lib.colourdb.updateColourDB() |
| 465 | colors = wx.lib.colourdb.getColourList() |
| 466 | |
| 467 | app.MainLoop() |
| 468 | |
| 469 | |
| 470 | |
| 471 | |