Everybody heard about the test driven development. But have you ever heard about the watch driven development?

If you are involved in development of some kind of graphic or geometric software, e.g. cad/cam/2d/3d modeler, editor, etc., you should know how difficult it can be to debug such applications. The main problem is that the data structures you use in your code are mainly of geometric nature (points, curves, surfaces, meshes, etc.) while the debugging environment is focused strictly on representing textual information. Thus debugging turns into a big headache: you write out the coordinates of points on a piece of paper, than try to imagine how those points are positioned in the space, connect them, of course you are not a talented painter, and you never can draw straight lines and perfect circles, so you do not understand your draft and thus the sources of errors in your algorithm, and finally you got tired and leave your task unsolved… forever.

This is the real life example.

One such unhappy day I decided to put an end to this madness, and I’ve come up with the idea of GeWatch. Gewatch is a standalone application which has the COM interface for receiving a tree of geometric entities, and it can represent that tree in two forms: as a feature tree on the left pane and as a tree of visual objects in the OpenGL canvas in the middle. The most important word here is STANDALONE. As GeWatch is a standalone process it doesn’t depend on the application you are currently debugging, so you can stop your debugged application while still being able to watch the actual state of all the geometric data structures live in GeWatch, and it is even possible to watch how your algorithms work live.

The interface of Gewatch looks like that.

` ISTGeWatch `**=** **interface(**IUnknown**)
** **[**'{13C5118F-1364-4D77-99D0-1AA652A4787A}'**]
** **function** OpenObject**(const** Id**:** WideString**;** ReWrite**:** WordBool**):** WordBool**;
** **procedure** CloseObject**;
** **procedure** StartCurve**(**x**,** y**:** Double**);
** **procedure** StopCurve**(**IsClosed**:** WordBool**);
** **procedure** CutTo**(**x**,** y**:** Double**);
** **procedure** ArcTo**(**x**,** y**,** xc**,** yc**,** r**:** Double**);
** **procedure** Point**(**x**,** y**:** Double**);
** **procedure** Arrow**(**x**,** y**:** Double**;** tx**,** ty**:** Double**);
** **procedure** Box**(**xMin**,** yMin**,** xMax**,** yMax**:** Double**);
** **procedure** SetProperty**(const** Name**:** WideString**;** Value**:** Double**);
** **procedure** SetFormat**(**Attribute**:** GeFormatAttribute**;** Value**:** Integer**);
** **procedure** Clear**;
** **procedure** ClearImmediate**;
** **procedure** Line**(**x1**,** y1**,** x2**,** y2**:** Double**);
** **procedure** Circle**(**xc**,** yc**,** r**:** Double**);
** **procedure** Arc**(**x1**,** y1**,** x2**,** y2**,** xc**,** yc**,** r**:** Double**);
** **procedure** LineColor**(**Value**:** Integer**);
** **procedure** LineWidth**(**Value**:** Integer**);
** **procedure** StartCurve3d**(**x**,** y**,** z**:** Double**);
** **procedure** StopCurve3d**(**IsClosed**:** WordBool**);
** **procedure** CutTo3d**(**x**,** y**,** z**:** Double**);
** **procedure** Point3d**(**x**,** y**,** z**:** Double**);
** **procedure** Arrow3d**(**x**,** y**,** z**,** tx**,** ty**,** tz**:** Double**);
** **procedure** StartTriangles**;
** **procedure** AddTriangleVertex**(**x**,** y**,** z**:** Double**);
** **procedure** SetVertexNormal**(**x**,** y**,** z**:** Double**);
** **procedure** CloseTriangles**;
** **procedure** Cube**(**xMin**,** yMin**,** zMin**,** xMax**,** yMax**,** zMax**:** Double**);
** **end;
**

To use it in our code I created the module AbstractGeWatch with the following stuff.

` IWatchableObject `**=** **interface
** **[**'{DF9FA5EF-3F5F-4E86-B0F0-395C908C2610}'**]
** **procedure** Watch**(const** w**:** ISTGeWatch**);
** **end;
** **function** agw**:** IAbstractGeWatch**;
** **begin
** result **:=** fAgw**;
** **end;
** **procedure** isdf**(const** Unk**:** IUnknown**;** **const** ObjName**:** WideString **=** ''**);
** **var** w**:** IAbstractGeWatch**;
** wobj**:** ISTGeWatch**;
** **begin
** **try
** **if** unk**=nil** **then** Exit**;
** **if** Cast**(**unk**,** IWatchableObject**,** wobj**)** **then** **begin
** w **:=** agw**;
** **if** w**=nil** **then** Exit**;
** **if** ObjName**=**'' **then** **begin
** wobj**.**Watch**(**w**);
** **end** **else** **begin
** w**.**OpenObject**(**ObjName**);
** wobj**.**Watch**(**w**);
** w**.**CloseObject**;
** **end;
** **end;
** **except
** **end;
** **end;
**

So you can either use agw function to directly draw in GeWatch, or you can implement the IWatchableObject interface in your geometric data structures and watch them with the isdf function. When you stop your debugged application by breakpoint or whatever you have access to both of those functions in the Evaluate/Modify dialog.

Gewatch saved months of my life and turned development of geometric algorithms into fun which it is intended to be.

Shame on those of you, who didn’t leave a comment!