BCad fork

Visualization extensions (planned)
Login

Visualization extensions (planned)

Clipping planes (section view)

OCCT provides Graphic3d_ClipPlane — clipping at the OpenGL level, without modifying geometry. Existing difference() for sectioning is a modelling operation; clipping planes are purely visual.

Key API (via OCC.Core)

Class/Method Role
Graphic3d_ClipPlane(gp_Pln) Clipping plane from a geometric plane
plane.SetOn() / SetOff() Toggle
plane.SetCapping(True) Fill the cut surface with a color
plane.SetCappingColor(Quantity_Color) Capping fill color
V3d_View.AddClipPlane(plane) Apply to entire viewport
V3d_View.RemoveClipPlane(plane) Remove from viewport
PrsMgr_PresentableObject.AddClipPlane(plane) Apply to a single AIS object
V3d_View.SetClipPlanes() Replace all planes at once

Two approaches

Approach Scope Capping Complexity
Per-view (V3d_View.AddClipPlane) All AIS objects Single color for all Low
Per-object (AIS_ColoredShape.AddClipPlane) Per AIS object Different per object High

Storage

IPC protocol (rqq.py)

Request Parameters Action
RQ_SET_CLIP_PLANE axis, position, on Create/reposition plane
RQ_REMOVE_CLIP_PLANES Remove all planes
RQ_SET_CAPPING on, color Toggle/set capping

GUI (main_window.py)

ImGui panel (or toolbar section):

Implementation steps (worker side)

  1. Viewer3d.set_clip_plane(axis: int, pos: float, on: bool) in boccviewer.py:
    • Remove existing clip planes from V3d_View
    • If on: create gp_Pln from axis + pos, wrap in Graphic3d_ClipPlane, call View.AddClipPlane(plane)
  2. Viewer3d.remove_clip_planes() — iterate and remove all
  3. Viewer3d.set_capping(on: bool, color: tuple) — set on active plane
  4. Handle in worker_engine.py — new branch for RQ_SET_CLIP_PLANE etc.
  5. Update image → send RP_ACK

Texture mapping

Textures are an extension of per-face appearance, logically part of color(). The same propagation machinery that handles _face_colors handles textures — they are just another attribute of a face's material.

Storage

# scl_shape.py — single dict, value is (color, texture_path) pair
_face_material: dict[int, tuple[Quantity_ColorRGBA | None, str | None]]
# (None, None)   → default material
# (color, None)  → solid color (current behaviour)
# (None, path)   → pure texture, no tint
# (color, path)  → modulated texture (color × texture)

Propagation

All existing propagation functions treat _face_material as opaque. The dict value is carried through without inspection:

Function Mechanism Change
_map_colors(builder, sources) Generated(), Modified(), IsSame() Also carries _face_material values
_map_unified_colors(unifier, ...) ShapeUpgrade_UnifySameDomain history Same
_adjacency_fill_colors(...) Edge-adjacency fill for _offset_3d Same
transform_shape() Re-hash faces through TShap Updates both tuple elements
transform_gtrsh() Same for grouped transforms Same
extrude/revolve/loft/offset Source face → all result faces Carries (color, path) pair

Display

_display_main_face_colors in scl_shape.py expands:

color texture Action
None None Default (no custom attributes)
color None SetCustomColor(face, color) — existing path
None path AIS_ColoredDrawerShadingAspectAspectSetTextureMap(map) + SetTextureMapOn(), modulate off
color path Both SetCustomColor() and SetTextureMap(), modulate on

OCCT mechanism per face: ```python from OCC.Core.Graphic3d import Graphic3d_Texture2D, Graphic3d_AspectFillArea3d from OCC.Core.AIS import AIS_ColoredDrawer

drawer = AIS_ColoredDrawer() shading = drawer.ShadingAspect() aspect = shading.Aspect() # Graphic3d_AspectFillArea3d aspect.SetTextureMap(Graphic3d_Texture2D(path)) aspect.SetTextureMapOn()

if color is also set:

ais_shp.SetCustomColor(face, color)

aspect.EnableTextureModulate() -- default is on

aspects_map.Bind(face, drawer) ```

Language syntax

// Solid color (existing)
color("red") cube(10);

// Pure texture (no tint)
color(texture="wood.png") cube(10);

// Modulated texture (tinted by color)
color("red", texture="checker.png") cube(10);

// Color + alpha + texture
color(c="red", alpha=0.5, texture="marble.png") sphere(5);

Face material propagation through booleans

union() {
  color("red", texture="wood.png") cube(10);
  color("blue") cube(5);
}

_fuse_parts_map_colors maps source faces to result faces. Each source face's (color, texture) is looked up by hash and assigned via Generated()/Modified()/IsSame() to the corresponding result face.

If a result face is new (no history) → (None, None) → default.