feat: add HighlightCorners mode to Prop3D and document Prop3D class functionality
This commit is contained in:
48
docs/code/vtk/vtk_Prop3D.md
Normal file
48
docs/code/vtk/vtk_Prop3D.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Prop3D
|
||||
|
||||
`uLib::Vtk::Prop3D` is a bridge class that wraps VTK 3D representations (`vtkProp`, `vtkProp3D`) and integrates them into the `uLib` object model. It allows the framework to manage visual objects, synchronize them with underlying data models, and expose display-specific properties to the GUI.
|
||||
|
||||
## Inheritance
|
||||
`uLib::Vtk::Prop3D` : `uLib::Object`
|
||||
|
||||
## Key Functionalities
|
||||
|
||||
### VTK Integration
|
||||
The class provides access to the underlying VTK objects:
|
||||
- `GetProp()`: Returns the `vtkProp`.
|
||||
- `GetProxyProp()`: Returns the `vtkProp3D`.
|
||||
- `GetParts()` / `GetProps()`: Returns `vtkPropCollection` for composite objects.
|
||||
|
||||
### Model-View Synchronization
|
||||
`Prop3D` ensures that the visual representation stays in sync with the domain model:
|
||||
- `Update()`: Synchronizes the VTK representation based on current internal state and properties. Should be called when model data changes.
|
||||
- `SyncFromVtk()`: Updates internal state using data from the VTK representation (e.g., after user interaction via gizmos in the 3D view).
|
||||
- `GetContent()`: Returns the `uLib::Object` that this `Prop3D` represents visually.
|
||||
|
||||
### Visual Appearance
|
||||
- **Color & Opacity**: `SetColor(r, g, b)` and `SetOpacity(alpha)`.
|
||||
- **Selection**: `SetSelectable(bool)` and `SetSelected(bool)` to manage interactivity and highlighting.
|
||||
- **BBox/Scale**: `ShowBoundingBox(bool)` and `ShowScaleMeasures(bool)`.
|
||||
|
||||
### Rendering Modes
|
||||
The rendering style can be controlled via the `Representation` enum:
|
||||
- `Points`
|
||||
- `Wireframe`
|
||||
- `Surface`
|
||||
- `SurfaceWithEdges`
|
||||
- `Volume`
|
||||
- `Outline`
|
||||
- `Slice`
|
||||
|
||||
### Display Properties System
|
||||
`Prop3D` implements a system to expose specific properties (often marked as `hrp` - human readable properties) to a property editor in the GUI.
|
||||
|
||||
- `GetDisplayProperties()`: Returns the list of properties registered for display.
|
||||
- `RegisterDisplayProperty(uLib::PropertyBase*)`: Adds a property to the display list.
|
||||
- `serialize_display(...)`: A virtual method that subclasses implement to define which properties should be exposed.
|
||||
|
||||
#### Activating Display Properties
|
||||
To automatically populate the display properties list, the `ULIB_ACTIVATE_DISPLAY_PROPERTIES` macro should be called in the constructor. This triggers `serialize_display` using a `display_properties_archive`.
|
||||
|
||||
## Implementation Details
|
||||
`Prop3D` uses the Pimpl idiom (via `Prop3DData *pd`) to hide VTK-specific implementation details and reduce header dependencies.
|
||||
@@ -93,7 +93,8 @@ public:
|
||||
m_Selectable(true),
|
||||
m_Selected(false),
|
||||
m_Visibility(true),
|
||||
m_Dragable(true)
|
||||
m_Dragable(true),
|
||||
m_HighlightMode(Prop3D::HighlightPlain)
|
||||
{
|
||||
m_Color = Vector3d(-1, -1, -1);
|
||||
}
|
||||
@@ -125,6 +126,8 @@ public:
|
||||
bool m_Visibility;
|
||||
bool m_Dragable;
|
||||
|
||||
int m_HighlightMode; // 0: Plain, 1: Corners
|
||||
|
||||
//
|
||||
TRS m_Transform;
|
||||
|
||||
@@ -212,39 +215,71 @@ public:
|
||||
}
|
||||
|
||||
if (!m_HighlightActor) {
|
||||
m_HighlightActor = vtkSmartPointer<vtkActor>::New();
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
m_HighlightActor->SetMapper(mapper);
|
||||
m_HighlightActor->GetProperty()->SetRepresentationToWireframe();
|
||||
m_HighlightActor->GetProperty()->SetColor(1.0, 0.0, 0.0); // Red
|
||||
m_HighlightActor->GetProperty()->SetLineWidth(2.0);
|
||||
m_HighlightActor->GetProperty()->SetLighting(0);
|
||||
}
|
||||
|
||||
if (m_HighlightMode == Prop3D::HighlightPlain) {
|
||||
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
|
||||
double bounds[6];
|
||||
polydata->GetBounds(bounds);
|
||||
// Add a small padding to prevent z-fighting
|
||||
double maxDim = std::max({bounds[1]-bounds[0], bounds[3]-bounds[2], bounds[5]-bounds[4]});
|
||||
double pad = maxDim * 0.02;
|
||||
if(pad < 1e-4) pad = 0.05;
|
||||
cube->SetBounds(bounds[0]-pad, bounds[1]+pad,
|
||||
bounds[2]-pad, bounds[3]+pad,
|
||||
bounds[4]-pad, bounds[5]+pad);
|
||||
|
||||
m_HighlightActor = vtkSmartPointer<vtkActor>::New();
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetInputConnection(cube->GetOutputPort());
|
||||
m_HighlightActor->SetMapper(mapper);
|
||||
m_HighlightActor->GetProperty()->SetRepresentationToWireframe();
|
||||
m_HighlightActor->GetProperty()->SetColor(1.0, 0.0, 0.0); // Red
|
||||
m_HighlightActor->GetProperty()->SetLineWidth(2.0);
|
||||
m_HighlightActor->GetProperty()->SetLighting(0);
|
||||
cube->Update();
|
||||
m_HighlightActor->GetMapper()->SetInputConnection(cube->GetOutputPort());
|
||||
} else {
|
||||
if (auto* mapper = vtkPolyDataMapper::SafeDownCast(m_HighlightActor->GetMapper())) {
|
||||
if (auto* cube = vtkCubeSource::SafeDownCast(mapper->GetInputAlgorithm())) {
|
||||
double bounds[6];
|
||||
polydata->GetBounds(bounds);
|
||||
double maxDim = std::max({bounds[1]-bounds[0], bounds[3]-bounds[2], bounds[5]-bounds[4]});
|
||||
double pad = maxDim * 0.02;
|
||||
if(pad < 1e-4) pad = 0.05;
|
||||
cube->SetBounds(bounds[0]-pad, bounds[1]+pad,
|
||||
bounds[2]-pad, bounds[3]+pad,
|
||||
bounds[4]-pad, bounds[5]+pad);
|
||||
cube->Modified();
|
||||
// Corners mode logic
|
||||
double bounds[6];
|
||||
polydata->GetBounds(bounds);
|
||||
double maxDim = std::max({bounds[1]-bounds[0], bounds[3]-bounds[2], bounds[5]-bounds[4]});
|
||||
double pad = maxDim * 0.02;
|
||||
if(pad < 1e-4) pad = 0.05;
|
||||
|
||||
double b[6] = {bounds[0]-pad, bounds[1]+pad, bounds[2]-pad, bounds[3]+pad, bounds[4]-pad, bounds[5]+pad};
|
||||
|
||||
vtkNew<vtkPoints> points;
|
||||
vtkNew<vtkCellArray> lines;
|
||||
|
||||
float len[3] = {
|
||||
(float)(b[1] - b[0]) * 0.15f,
|
||||
(float)(b[3] - b[2]) * 0.15f,
|
||||
(float)(b[5] - b[4]) * 0.15f
|
||||
};
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
double p[3];
|
||||
p[0] = b[(i & 1) ? 1 : 0];
|
||||
p[1] = b[(i & 2) ? 1 : 0];
|
||||
p[2] = b[(i & 4) ? 1 : 0];
|
||||
|
||||
for (int axis = 0; axis < 3; ++axis) {
|
||||
double p2[3] = {p[0], p[1], p[2]};
|
||||
double delta = (i & (1 << axis)) ? -len[axis] : len[axis];
|
||||
p2[axis] += delta;
|
||||
|
||||
vtkIdType id1 = points->InsertNextPoint(p);
|
||||
vtkIdType id2 = points->InsertNextPoint(p2);
|
||||
lines->InsertNextCell(2);
|
||||
lines->InsertCellPoint(id1);
|
||||
lines->InsertCellPoint(id2);
|
||||
}
|
||||
}
|
||||
|
||||
vtkNew<vtkPolyData> cornerPoly;
|
||||
cornerPoly->SetPoints(points);
|
||||
cornerPoly->SetLines(lines);
|
||||
if (auto* mapper = vtkPolyDataMapper::SafeDownCast(m_HighlightActor->GetMapper())) {
|
||||
mapper->SetInputData(cornerPoly);
|
||||
}
|
||||
}
|
||||
|
||||
// Update highlight matrix from the model world matrix
|
||||
@@ -514,6 +549,12 @@ void Prop3D::SetRepresentation(const char *mode)
|
||||
else if (s == "slice") SetRepresentation(Slice);
|
||||
}
|
||||
|
||||
void Prop3D::SetHighlightMode(HighlightMode mode)
|
||||
{
|
||||
pd->m_HighlightMode = static_cast<int>(mode);
|
||||
pd->UpdateHighlight();
|
||||
}
|
||||
|
||||
void Prop3D::SetColor(double r, double g, double b)
|
||||
{
|
||||
pd->m_Color[0] = r;
|
||||
@@ -655,6 +696,8 @@ struct AppearanceProxy {
|
||||
ar & boost::serialization::make_hrp("Dragable", pd->m_Dragable);
|
||||
ar & boost::serialization::make_hrp("ShowBoundingBox", pd->m_ShowBoundingBox);
|
||||
ar & boost::serialization::make_hrp("ShowScaleMeasures", pd->m_ShowScaleMeasures);
|
||||
ar & boost::serialization::make_hrp_enum("HighlightMode",
|
||||
pd->m_HighlightMode, {"Plain", "Corners"});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -123,6 +123,12 @@ public:
|
||||
void SetRepresentation(Representation mode);
|
||||
void SetRepresentation(const char *mode);
|
||||
|
||||
enum HighlightMode {
|
||||
HighlightPlain = 0,
|
||||
HighlightCorners = 1
|
||||
};
|
||||
void SetHighlightMode(HighlightMode mode);
|
||||
|
||||
virtual void PrintSelf(std::ostream &o) const;
|
||||
|
||||
void ShowBoundingBox(bool show);
|
||||
|
||||
Reference in New Issue
Block a user