ModView Model Editor

Introduction
This is a Cocoa port of the earlier Motif-based ModView model editor:
ModView 2.3.dmg (589 KB disk image)
One day, I might even describe what it does. For now, the original page should have enough information. Some features are still missing compared to the Motif version: display of face edge numbers and edge node numbers in the selection panel, hyperplane-based face selection, reading and writing of surface mesh model file format, printing, view cropping and edge splitting. Oh yeah, and just like the X11 version, the program can become unresponsive and start consuming all available CPU cycles when the zoom level is increased enough.
Empowerment
The hidden gem in ModView is the IGES (3D model interchange format) export capability. This lets one use ModView to quickly construct simple geometric models for later import into higher-end CAD or mesh generation packages, such as Gridgen.Usage
Click and drag (left) mouse button in the viewer area to rotate the model, option-click (or middle-click) to select nodes, edges or faces, and control-click (or right-click) to pop up a menu with viewing options. Holding down the shift key while selecting adds to the already selected objects, allowing e.g. to select a set of edges to create a face. Holding down the command key while selecting faces also selects all the nodes and edges which define that face.ModView accepts the following input events:
| Event | Modifier | Description |
| drag or left drag | - | rotate model |
| option-click or middle-click | - | select node, edge or face |
| option-click or middle-click | Shift | add/subtract node, edge or face to/from selection |
| option-click or middle-click | Command | select node, edge or face including all components |
| control-click or right-click | - | pop up a menu of rendering options |
Key N |
- | toggle rendering of nodes |
Key E |
- | toggle rendering of edges |
Key F |
- | toggle rendering of faces |
Key B |
- | toggle rendering of the bounding box |
Key 1 |
- | toggle rendering of the point tool |
Key 2 |
- | toggle rendering of the line tool |
Key 3 |
- | toggle rendering of the surface tool |
When creating the model faces, add edges to selection clockwise when looking from outside of the fluid-filled domain. The face color should be dark blue rather than turquoise for the faces wetted by the fluid. When the orientation of some faces is not correct, simply select them and choose Invert from the Face menu.
Remaining description forthcoming.
Quaternion Notes
Model rotation in ModView is tracked using quaternions. Quarternion is a 4-component vector Q = (x, y, z, w), where the first three components define the axis of rotation divided by sine of half-angle of rotation, and the last component is the cosine of half-angle of rotation. Some links on this subject:
- Quaternion demonstrator from Stanford
- Quarternion references from Berkeley
- Quaternion powers from GameDev

SpaceBall Notes
ModView version 2.3 or later supports SpaceBall 3D controllers, or to be precise, SpaceBall 5000 USB. The Mac OS X SDK is available on request, and provides C-callable functions to open and close the device, and a callback mechanism to get events from the controller. The included examples are pure C, but it's not hard to integrate the provided interface into a Cocoa program. In the case of ModView, this meant:
- Adding
libHIDUtilities.ato the Frameworks andHID_Utilities_External.h,generic3dx.handgeneric3dx.cto sources. - In the window controller (app controller would be more suitable, but we don't have it) header file
MainController.h, adding terms shown in red:
#import "HID_Utilities_External.h" #import "generic3dx.h" ... extern Generic3DxDevice ∗generic3Dxhandle;
@interface MainController : NSWindowController { ... @end
void ApplicationGeneric3DxCallback(Generic3DxEvent ∗event);
- In the window controller class file
MainController.m, adding:
...
static Generic3DxDevice ∗generic3Dxhandle = NULL;
...
@implementation MainController
...
+ (void)initialize {
if (generic3Dxhandle == NULL) {
generic3Dxhandle = Generic3DxOpen(ApplicationGeneric3DxCallback);
}
...
}
...
@end
void ApplicationGeneric3DxCallback(Generic3DxEvent ∗event)
{
float motion[ 6];
const float ScaleTranslationBase = 1.0/ 8000.0;
const float ScaleRotationBase = 1.0/30000.0;
switch (event->type) {
case MotionEvent:
motion[ 0] = event->motion[ 0] ∗ ScaleTranslationBase;
motion[ 1] = event->motion[ 1] ∗ ScaleTranslationBase;
motion[ 2] = event->motion[ 2] ∗ ScaleTranslationBase;
motion[ 3] = event->motion[ 3] ∗ ScaleRotationBase;
motion[ 4] = event->motion[ 4] ∗ ScaleRotationBase;
motion[ 5] = event->motion[ 5] ∗ ScaleRotationBase;
if ([[[NSApp mainWindow] delegate]
isKindOfClass:[MainController class]])
[[(MainController ∗)[[NSApp mainWindow]
delegate] view] spaceballMoved:motion];
break;
case ButtonPressEvent:
break;
case ButtonReleaseEvent:
break;
}
}
The spaceballMoved method of our view (MVOpenGLView in this case) knows what to do with the 6 motion parameters. In fact, it ignores translation, and converts rotations about each axis to quaternions, which are then added together. Note that this code does not call Generic3DxActivateInterface, so it will not coexist with other SpaceBall applications, does not call Generic3DxClose (it would if we were doing this in an application controller and had a dealloc method), and ignores button press events. Nobody is perfect.




