Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Module Structure

The application state lives on NullCadApp, split across several app_* files by concern (canvas, dialogs, menus, tools, properties, layers, status bar, input, I/O), backed by a set of focused subsystem modules.

ModulePurpose
app.rsMain application state and egui integration
app_canvas_ui.rs, app_dialogs_ui.rs, app_menu_ui.rs, app_tool_ui.rs, app_properties_ui.rs, app_layer_ui.rs, app_statusbar_ui.rs, app_input.rs, app_io.rsUI and input, split by concern
document/Document model, geometry objects, spatial index, comparisons, selection sets
operations/Operation types, history, executor, snapshots — see Operation System
commands/Legacy command system (superseded by operations/, still present, being migrated out)
geometry/Geometry primitives (Point, Line, Polyline, Polygon, Rectangle, Circle, Arc, Text, PlanImage, TIN surface, page proxy, viewport)
renderer/wgpu renderer, camera, auto-contrast, line types, PDF/image underlays, tile rendering — see Precision Handling
tools/Interactive tool modules (point, edit, trim, offset, text/callout annotation, TIN, page proxy, viewport)
annotations/Text and callout annotations with anchoring, styling, and leaders
labels/Point label generation with collision detection
selection/, select_similar.rsSelection set management, hit testing, select-by-attribute
snapping/Snap point detection and configuration
layers/, codelist/Layer/group management and code→layer import mapping
gis_io/native/Pure-Rust import/export: Shapefile, GeoJSON, DXF, CSV, .ncweb web bundle
gis_io/gdal/Optional GDAL formats: KML, GeoPackage, MapInfo TAB, FileGDB
pdf_export/, pdf_viewer.rsVector PDF export (page proxies → pages) and in-app PDF plan viewer
mcp/In-process MCP server exposing the document to AI agents
plugins/Lua plugin system: commands, tools, panels/dialogs, event hooks
console/Application message log
settings/, autosave.rs, template.rsPersistent settings, autosave/crash recovery, document templates
ui/Reusable UI components (operation log, phase tabs, resource panel, color/codelist pickers)
archive/ZIP-based .nullcad file reading/writing with resource management
utils/DMS parsing, unit conversions

Document model (src/document/)

  • Document — the central store; geometry in a HashMap keyed by GeometryId.
  • GeometryId — UUID v4, for global uniqueness (collaboration-ready).
  • GeometryObject — wraps a Geometry with metadata (created_by, timestamps, phase, layer, name/code, tombstone).
  • Spatial index — an rstar R-tree, auto-maintained on create/delete/modify and rebuilt on load; powers O(log n) hit testing and range queries.

Geometry (src/geometry/)

The Geometry enum covers Point, Line, Polyline, Polygon, Text, Circle, Arc, Rectangle, PlanImage (a PDF page placed in world space), TinSurface, PageProxy, Viewport, and ViewportView. All coordinates are f64; the crate integrates with the geo crate’s types.

Modular tool development

Interactive tools are self-contained modules in src/tools/, each encapsulating its own state and behavior, which keeps the app_* files thin and lets tools be unit-tested in isolation.

A tool module typically provides:

  • A state struct (new(), reset()).
  • A tool struct holding that state, with name(), instructions(), handle_click(...) -> (Option<OperationType>, bool) (the bool = should-exit), render_ui(...), and reset().

To add a new tool:

  1. Add pub mod my_tool; in src/tools/mod.rs and a variant to the Tool enum (plus its name()/instructions() arms).
  2. Add a tool instance field to NullCadApp and initialize it.
  3. Dispatch clicks and UI rendering from the app_* files based on the active tool.
  4. Add a toolbar button that sets the active tool and calls reset().

src/tools/point_tool.rs is the reference implementation. Best practices: keep all tool logic in the module, route every mutation through DocumentState::apply_operation(), reset tool state on activation, provide clear instructions() text, handle edge cases (invalid input, no snap point), and unit-test the module.

Adding a new geometry type

  1. Add the type in src/geometry/ using f64 coordinates.
  2. Add a variant to the Geometry enum in geometry/mod.rs.
  3. Handle it in the renderer’s vertex generation.
  4. Handle it everywhere else the Geometry enum is matched (hit testing, serialization, export paths, MCP tools.rs, etc.) — the compiler will point these out.

Camera controls (renderer/camera.rs)

  • Pan: middle mouse drag (PAN_SENSITIVITY, default 0.005), zoom-scaled.
  • Zoom: scroll wheel toward cursor; clamp range ~0.001–10000.
  • Position lives in f64; the view-projection matrix handles only zoom/aspect, never translation (see Precision Handling).