RL Design Study Log
RobertLechte (Talk | contribs) (New page: = Design Study Log = My honours project is a graphical application to display an animated figure and associated data, written in Python, and using OpenGL libraries. I wish to make this a ...) |
RobertLechte (Talk | contribs) m (Robert Lechte Design Study Log moved to RL Design Study Log) |
Revision as of 10:01, 26 October 2008
Contents |
Design Study Log
My honours project is a graphical application to display an animated figure and associated data, written in Python, and using OpenGL libraries. I wish to make this a nice slick OO application, but I'll be facing several challenges.
- Python is a loosely typed language. This makes things easier in some ways (no variable declarations, and no need to cast), but harder in others, particularly as I've never written OO in a loose language before.
- OpenGL is very procedurally based. To get around this I'll have to build some kind of nice wrapper(s) so that we can use OpenGL in an OO way.
- How to relate graphics code to object code. Should each object have a drawX() method, or will this wind up raping and pillaging the neatness of the program? We'll soon find out, so don't change that channel. I suspect this will be the core issue I face in this design study.
Initial State
Before we begin this design study we should look at the project in its present state. It's currently rather a mess. There are currently a small number of objects used, but most of it is a typical OpenGL app with procedural code.
Good
- Camera class. This class will probably make it largely unscathed into the final design.
Bad
- Still mostly procedural.
- Bvh Parser. Creates a BvhSet which has everything from the Bvh file. It would be nice to separate motion data from playback data (frame rate, etc)
- Joint class. This is crying out for subclassing, as root nodes, internal nodes and leaf nodes all behave slightly differently, and currently that functionality is roughly lumped together (eg channels/rootchannels variables).
Preliminary Design Thoughts
Probably I want an application object to work with at the very top level. That would mean a main method along the lines of:
def main(): animation_application = AnimationApplication() application.start()
Wed Aug 20: I'm starting to code up my new enhanced version. I need to deal with OpenGL's event handlers, and my first thought was the Observer pattern, where objects which respond to (say) keyboard commands register with the key-handling object, and are thus notified on key-presses. One issue I have considered is that responses to keys vary depending on the mode of the application. However for the moment I'm just going to implement the the Observer pattern and see what happens (YAGNI and all that).
Update: I'm currently implementing the Observer-based keystrokes, and I've struck a design issue. I have a keyboard object, and I'm wondering where to put it. I have an Application object, and a Window object, and I'm not sure whether keyboard should belong to Application or Window. Application doesn't actually do anything besides create a Window, so I thought possibly this is a cue to merge the two classes. Then I figured this will create one massive class, and from that I figure I'm not breaking up the code (mostly glut calls at this stage) properly. I need to make a distinction between glut initialization (which is global to the application) and window creation (which could potentially happen multiple times, though probably not in the case of my project. So, refactor time.
First OO Iteration
The program is now totally converted to OO (with the exception of a few utility functions where being static makes sense). Here's the diagram.
Mostly, I really like it.
Good
- Integration with OpenGL. I think I've got the cohesion between OpenGL and my own code about right. Specifically:
- The GlutMachine and GlutApplication classes separate the boilerplate and the custom OpenGL setup code.
- The GlutMachine standardizes all the callbacks and event handling method setup so that all that detail is abstracted away.
- The existing GlutApplication class is general enough to be used for almost any single-window Glut application, but if you were writing an application with multiple windows, it's very easy to modify the GlutApplication class for this.
- The Graphical objects are very intuitive. Objects like Windows and Viewports make the program easy to read and follow.
- Separation of concerns between graphical and logical code is reasonable. Any object drawn in the program simply implements a draw method. Python doesn't have explicit interfaces, but this is effectively the same as implementing a "Drawable" interface. While some coupling remains (changing how a graph is stored requires corresponding changes to the drawing code), this is largely unavoidable. In any case I am unable to envisage a cleaner solution (suggestions welcome).
- The GlutMachine and GlutApplication classes separate the boilerplate and the custom OpenGL setup code.
- The design manages to model the real world well. For instance, a FigureViewport has a Camera, a Floor, and an Animated figure. It's pretty easy to envisage what that's going to look like just by looking at the class diagram.
- The Composite design pattern makes the hierarchical structure of the Animated Figure very clean. Some Joints contain other Joints, thus we have the InternalJoint class acting as a Composite class in the pattern.
- The design largely follows the Acyclic dependencies principle. While the parser code and the Joint hierarchy make the diagram look a little messy, there aren't any real dependency cycles in the graph.
Bad
- The Composite design pattern isn't fully transparent, since Joint lacks some of the interface of InternalJoint. The Gang of Four book notes that making a Primitive and a Composite fully transparent has a price in safety, however. If I modify this, LeafJoint would have an add_child() method, probably a no-op. This seems to be a high price to pay, so I'll examine the code and make a decision as to which is best.
- There is significant repetition in the display() methods of each of the Joint classes. I plan to implement a Template Method pattern here to solve this.
- There are a few Law of Demeter issues floating about in the code. Will try and hunt these down and fix them.