Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/polyscope/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ struct Context {
uint64_t nextPickBufferInd = 1;
std::unordered_map<Structure*, std::tuple<uint64_t, uint64_t>> structureRanges;
std::unordered_map<Quantity*, std::tuple<uint64_t, uint64_t>> quantityRanges;
std::list<std::function<void(PickResult)>> pickCallbacks;

// ======================================================
// === Internal globals from internal.h
Expand Down
4 changes: 4 additions & 0 deletions include/polyscope/pick.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include <cstdint>
#include <list>
#include <string>
#include <tuple>
#include <utility>
Expand Down Expand Up @@ -56,6 +57,9 @@ bool haveSelection();
void resetSelectionIfStructure(Structure* s); // If something from this structure is selected, clear the selection
// (useful if a structure is being deleted)

std::list<std::function<void(PickResult)>>::iterator registerPickCallback(const std::function<void(PickResult)>& f);
void removePickCallback(std::list<std::function<void(PickResult)>>::iterator callback);

namespace pick {

// Old, deprecated picking API. Use the above functions instead.
Expand Down
3 changes: 3 additions & 0 deletions include/polyscope/polyscope.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include <functional>
#include <list>
#include <map>
#include <memory>
#include <set>
Expand Down Expand Up @@ -108,6 +109,8 @@ extern bool& doDefaultMouseInteraction;
// a callback function used to render a "user" gui
extern std::function<void()>& userCallback;

extern std::list<std::function<void(PickResult)>>& pickCallbacks;

// representative center for all registered structures
glm::vec3 center();

Expand Down
4 changes: 4 additions & 0 deletions include/polyscope/structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class Structure : public render::ManagedBufferRegistry, public virtual WeakRefer
Structure* setTransformGizmoEnabled(bool newVal);
bool getTransformGizmoEnabled();

Structure* setPickable(bool pickable);
bool getPickable();

protected:
// = State
PersistentValue<bool> enabled;
Expand All @@ -130,6 +133,7 @@ class Structure : public render::ManagedBufferRegistry, public virtual WeakRefer
PersistentValue<bool> cullWholeElements;

PersistentValue<std::vector<std::string>> ignoredSlicePlaneNames;
PersistentValue<bool> pickable;

// Manage the bounding box & length scale
// (this is defined _before_ the object transform is applied. To get the scale/bounding box after transforms, use the
Expand Down
20 changes: 17 additions & 3 deletions include/polyscope/surface_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ class SurfaceMesh : public QuantityStructure<SurfaceMesh> {
virtual void buildCustomOptionsUI() override;
virtual void buildPickUI(const PickResult&) override;

void registerVertexPickCallback(const std::function<void(size_t)>& f);
void registerEdgePickCallback(const std::function<void(size_t)>& f);
void registerHalfedgePickCallback(const std::function<void(size_t)>& f);
void registerFacePickCallback(const std::function<void(size_t)>& f);
void registerCornerPickCallback(const std::function<void(size_t)>& f);

// Render the the structure on screen
virtual void draw() override;
virtual void drawDelayed() override;
Expand Down Expand Up @@ -237,8 +243,8 @@ class SurfaceMesh : public QuantityStructure<SurfaceMesh> {
size_t nEdges(); // NOTE causes population of nEdgesCount

size_t nCornersCount = 0; // = nHalfedges = sum face degree
size_t nCorners() const { return nCornersCount; }
size_t nHalfedges() const { return nCornersCount; }
size_t nCorners() const { return cornerDataSize == INVALID_IND ? nCornersCount : cornerDataSize; }
size_t nHalfedges() const { return halfedgeDataSize == INVALID_IND ? nCornersCount : halfedgeDataSize; }

// = Mesh helpers
void nestedFacesToFlat(const std::vector<std::vector<size_t>>& nestedInds);
Expand Down Expand Up @@ -357,7 +363,6 @@ class SurfaceMesh : public QuantityStructure<SurfaceMesh> {
std::vector<uint32_t>
halfedgeEdgeCorrespondence; // ugly hack used to save a pick buffer attr, filled out lazily w/ edge indices


// Visualization settings
PersistentValue<glm::vec3> surfaceColor;
PersistentValue<glm::vec3> edgeColor;
Expand Down Expand Up @@ -399,6 +404,15 @@ class SurfaceMesh : public QuantityStructure<SurfaceMesh> {
void buildHalfedgeInfoGui(const SurfaceMeshPickResult& result);
void buildCornerInfoGui(const SurfaceMeshPickResult& result);

std::list<std::function<void(size_t)>> vertexPickCallbacks;
std::list<std::function<void(size_t)>> edgePickCallbacks;
std::list<std::function<void(size_t)>> halfedgePickCallbacks;
std::list<std::function<void(size_t)>> facePickCallbacks;
std::list<std::function<void(size_t)>> cornerPickCallbacks;
std::list<std::function<void(PickResult)>>::iterator pickCallbackHandle;
bool hasPickCallback = false;
void handlePick(PickResult result);

// Manage per-element transparency
// which (scalar) quantity to set point size from
// TODO make these PersistentValue<>?
Expand Down
6 changes: 6 additions & 0 deletions include/polyscope/surface_mesh.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ void SurfaceMesh::setEdgePermutation(const T& perm, size_t expectedSize) {

// now that we have edge indexing, enable edge-related stuff
markEdgesAsUsed();

triangleAllEdgeInds.recomputeIfPopulated();
}

template <class T>
Expand Down Expand Up @@ -163,6 +165,8 @@ void SurfaceMesh::setHalfedgePermutation(const T& perm, size_t expectedSize) {
}

markHalfedgesAsUsed();
triangleAllEdgeInds.recomputeIfPopulated();
triangleAllHalfedgeInds.recomputeIfPopulated();
}

template <class T>
Expand Down Expand Up @@ -190,6 +194,8 @@ void SurfaceMesh::setCornerPermutation(const T& perm, size_t expectedSize) {
}

markCornersAsUsed();
triangleAllEdgeInds.recomputeIfPopulated();
triangleAllCornerInds.recomputeIfPopulated();
}


Expand Down
2 changes: 1 addition & 1 deletion src/curve_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void CurveNetwork::drawDelayed() {
}

void CurveNetwork::drawPick() {
if (!isEnabled()) {
if (!isEnabled() || !getPickable()) {
return;
}

Expand Down
8 changes: 8 additions & 0 deletions src/pick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ void setSelection(PickResult newPick) {
}
}

std::list<std::function<void(PickResult)>>::iterator registerPickCallback(const std::function<void(PickResult)>& f) {
return state::globalContext.pickCallbacks.insert(state::globalContext.pickCallbacks.end(), f);
}

void removePickCallback(std::list<std::function<void(PickResult)>>::iterator callback) {
state::globalContext.pickCallbacks.erase(callback);
}


namespace pick {

Expand Down
2 changes: 1 addition & 1 deletion src/point_cloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void PointCloud::drawDelayed() {
}

void PointCloud::drawPick() {
if (!isEnabled()) {
if (!isEnabled() || !getPickable()) {
return;
}

Expand Down
3 changes: 3 additions & 0 deletions src/polyscope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ void processInputEvents() {
glm::vec2 screenCoords{io.MousePos.x, io.MousePos.y};
PickResult pickResult = pickAtScreenCoords(screenCoords);
setSelection(pickResult);
for (std::function<void(PickResult)>& callback : state::globalContext.pickCallbacks) {
callback(pickResult);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ std::vector<std::unique_ptr<SlicePlane>>& slicePlanes = globalContext.slicePlane
std::vector<WeakHandle<Widget>>& widgets = globalContext.widgets;
bool& doDefaultMouseInteraction = globalContext.doDefaultMouseInteraction;
std::function<void()>& userCallback = globalContext.userCallback;
std::list<std::function<void(PickResult)>>& pickCallbacks = globalContext.pickCallbacks;

} // namespace state
} // namespace polyscope
10 changes: 9 additions & 1 deletion src/structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ Structure::Structure(std::string name_, std::string subtypeName_)
transformGizmo(subtypeName + "#" + name + "#transform_gizmo", objectTransform.get(), &objectTransform),
cullWholeElements(subtypeName + "#" + name + "#cullWholeElements", false),
ignoredSlicePlaneNames(subtypeName + "#" + name + "#ignored_slice_planes", {}),
pickable(subtypeName + "#" + name + "#pickable", true),
objectSpaceBoundingBox(
std::tuple<glm::vec3, glm::vec3>{glm::vec3{-777, -777, -777}, glm::vec3{-777, -777, -777}}),
objectSpaceLengthScale(-777) {
validateName(name);
}

Structure::~Structure() {};
Structure::~Structure(){};

Structure* Structure::setEnabled(bool newEnabled) {
if (newEnabled == isEnabled()) return this;
Expand Down Expand Up @@ -318,6 +319,13 @@ Structure* Structure::setTransformGizmoEnabled(bool newVal) {
}
bool Structure::getTransformGizmoEnabled() { return transformGizmo.enabled.get(); }

Structure* Structure::setPickable(bool newPickable) {
pickable = newPickable;
requestRedraw();
return this;
}
bool Structure::getPickable() { return pickable.get(); }

Structure* Structure::setIgnoreSlicePlane(std::string name, bool newValue) {

if (getIgnoreSlicePlane(name) == newValue) {
Expand Down
92 changes: 83 additions & 9 deletions src/surface_mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ void SurfaceMesh::computeTriangleAllEdgeInds() {
triangleAllEdgeInds.data.resize(3 * 3 * nFacesTriangulation());
halfedgeEdgeCorrespondence.resize(nHalfedges());

bool haveCustomHalfedgeIndex = !halfedgePerm.empty();

// used to loop over edges
std::unordered_map<std::pair<size_t, size_t>, size_t, polyscope::hash_combine::hash<std::pair<size_t, size_t>>>
seenEdgeInds;
Expand Down Expand Up @@ -242,7 +244,10 @@ void SurfaceMesh::computeTriangleAllEdgeInds() {
thisEdgeInd = seenEdgeInds[key];
}

halfedgeEdgeCorrespondence[start + j] = thisEdgeInd;
size_t he = start + j;
if (haveCustomHalfedgeIndex) he = halfedgePerm[he];

halfedgeEdgeCorrespondence[he] = thisEdgeInd;
thisTriInds[j] = thisEdgeInd;
}

Expand Down Expand Up @@ -779,7 +784,7 @@ void SurfaceMesh::drawDelayed() {
}

void SurfaceMesh::drawPick() {
if (!isEnabled()) {
if (!isEnabled() || !getPickable()) {
return;
}

Expand Down Expand Up @@ -822,7 +827,7 @@ void SurfaceMesh::drawPick() {
}

void SurfaceMesh::drawPickDelayed() {
if (!isEnabled()) {
if (!isEnabled() || !getPickable()) {
return;
}

Expand Down Expand Up @@ -1188,6 +1193,81 @@ glm::vec2 SurfaceMesh::projectToScreenSpace(glm::vec3 coord) {
return glm::vec2{screenPoint.x, screenPoint.y} / screenPoint.w;
}

void SurfaceMesh::registerVertexPickCallback(const std::function<void(size_t)>& f) {
if (!hasPickCallback) {
pickCallbackHandle = registerPickCallback([&](PickResult result) { handlePick(result); });
hasPickCallback = true;
}
vertexPickCallbacks.insert(vertexPickCallbacks.end(), f);
}
void SurfaceMesh::registerEdgePickCallback(const std::function<void(size_t)>& f) {
if (!hasPickCallback) {
pickCallbackHandle = registerPickCallback([&](PickResult result) { handlePick(result); });
hasPickCallback = true;
}
edgePickCallbacks.insert(edgePickCallbacks.end(), f);
}
void SurfaceMesh::registerHalfedgePickCallback(const std::function<void(size_t)>& f) {
if (!hasPickCallback) {
pickCallbackHandle = registerPickCallback([&](PickResult result) { handlePick(result); });
hasPickCallback = true;
}
halfedgePickCallbacks.insert(halfedgePickCallbacks.end(), f);
}
void SurfaceMesh::registerFacePickCallback(const std::function<void(size_t)>& f) {
if (!hasPickCallback) {
pickCallbackHandle = registerPickCallback([&](PickResult result) { handlePick(result); });
hasPickCallback = true;
}
facePickCallbacks.insert(facePickCallbacks.end(), f);
}
void SurfaceMesh::registerCornerPickCallback(const std::function<void(size_t)>& f) {
if (!hasPickCallback) {
pickCallbackHandle = registerPickCallback([&](PickResult result) { handlePick(result); });
hasPickCallback = true;
}
cornerPickCallbacks.insert(cornerPickCallbacks.end(), f);
}
void SurfaceMesh::handlePick(PickResult rawResult) {
if (!rawResult.isHit || rawResult.structureName != name) return;
SurfaceMeshPickResult result = interpretPickResult(rawResult);

switch (result.elementType) {
case MeshElement::VERTEX: {
for (const std::function<void(size_t)>& f : vertexPickCallbacks) f(result.index);
break;
}
case MeshElement::FACE: {
for (const std::function<void(size_t)>& f : facePickCallbacks) f(result.index);
break;
}
case MeshElement::EDGE: {
for (const std::function<void(size_t)>& f : edgePickCallbacks) f(result.index);
break;
}
case MeshElement::HALFEDGE: {
for (const std::function<void(size_t)>& f : halfedgePickCallbacks) f(result.index);

// Also call edge pick callbacks while we're here
if (edgesHaveBeenUsed) {
// do the edge one too (see note in pick buffer filler)
uint32_t halfedgeInd = result.index;
if (halfedgeInd >= halfedgeEdgeCorrespondence.size()) {
exception("problem with halfedge edge indices");
}
uint32_t edgeInd = halfedgeEdgeCorrespondence[halfedgeInd];
for (const std::function<void(size_t)>& f : edgePickCallbacks) f(edgeInd);
}

break;
}
case MeshElement::CORNER: {
for (const std::function<void(size_t)>& f : cornerPickCallbacks) f(result.index);
break;
}
};
}

void SurfaceMesh::buildVertexInfoGui(const SurfaceMeshPickResult& result) {
size_t vInd = result.index;
size_t displayInd = vInd;
Expand Down Expand Up @@ -1242,9 +1322,6 @@ void SurfaceMesh::buildFaceInfoGui(const SurfaceMeshPickResult& result) {
void SurfaceMesh::buildEdgeInfoGui(const SurfaceMeshPickResult& result) {
size_t eInd = result.index;
size_t displayInd = eInd;
if (edgePerm.size() > 0) {
displayInd = edgePerm[eInd];
}
ImGui::TextUnformatted(("Edge #" + std::to_string(displayInd)).c_str());

ImGui::Spacing();
Expand All @@ -1266,9 +1343,6 @@ void SurfaceMesh::buildEdgeInfoGui(const SurfaceMeshPickResult& result) {
void SurfaceMesh::buildHalfedgeInfoGui(const SurfaceMeshPickResult& result) {
size_t heInd = result.index;
size_t displayInd = heInd;
if (halfedgePerm.size() > 0) {
displayInd = halfedgePerm[heInd];
}
ImGui::TextUnformatted(("Halfedge #" + std::to_string(displayInd)).c_str());

ImGui::Spacing();
Expand Down
4 changes: 2 additions & 2 deletions src/volume_grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void VolumeGrid::drawDelayed() {
}

void VolumeGrid::drawPick() {
if (!isEnabled()) {
if (!isEnabled() || !getPickable()) {
return;
}

Expand All @@ -170,7 +170,7 @@ void VolumeGrid::drawPick() {
// Draw the actual grid
render::engine->setBackfaceCull(true);
pickProgram->draw();

for (auto& x : quantities) {
x.second->drawPick();
}
Expand Down
2 changes: 1 addition & 1 deletion src/volume_mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ void VolumeMesh::drawDelayed() {
}

void VolumeMesh::drawPick() {
if (!isEnabled()) {
if (!isEnabled() || !getPickable()) {
return;
}

Expand Down
Loading