Skip to content

Commit

Permalink
Improved measurement tool
Browse files Browse the repository at this point in the history
  • Loading branch information
Travis CI committed Sep 27, 2021
1 parent a98994e commit 05c6b14
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 23 deletions.
20 changes: 20 additions & 0 deletions src/3D/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,26 @@ glm::vec3 osc::PolarPerspectiveCamera::getPos() const noexcept {
return -focusPoint + glm::vec3{x, y, z};
}

glm::vec2 osc::PolarPerspectiveCamera::projectOntoScreenRect(
glm::vec3 const& worldspaceLoc,
glm::vec2 const& topLeft,
glm::vec2 const& bottomRight) const noexcept {

glm::vec2 dims = bottomRight - topLeft;
glm::mat4 MV = getProjMtx(dims.x / dims.y) * getViewMtx();

glm::vec4 ndc = MV * glm::vec4{worldspaceLoc, 1.0f};
ndc /= ndc.w; // perspective divide

glm::vec2 ndc2D;
ndc2D = {ndc.x, -ndc.y}; // [-1, 1], Y points down
ndc2D += 1.0f; // [0, 2]
ndc2D *= 0.5f; // [0, 1]
ndc2D *= dims; // [0, w]
ndc2D += topLeft; // [x, x + w]
return ndc2D;
}

Line osc::PolarPerspectiveCamera::unprojectScreenposToWorldRay(glm::vec2 pos, glm::vec2 dims) const noexcept {
glm::mat4 projMtx = getProjMtx(dims.x/dims.y);
glm::mat4 viewMtx = getViewMtx();
Expand Down
12 changes: 9 additions & 3 deletions src/3D/Model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,15 @@ namespace osc {
// and the scene will look wrong.
void rescaleZNearAndZFarBasedOnRadius() noexcept;

[[nodiscard]] glm::mat4 getViewMtx() const noexcept;
[[nodiscard]] glm::mat4 getProjMtx(float aspect_ratio) const noexcept;
[[nodiscard]] glm::vec3 getPos() const noexcept;
glm::mat4 getViewMtx() const noexcept;
glm::mat4 getProjMtx(float aspect_ratio) const noexcept;

// project's a worldspace coordinate onto a screen-space rectangle
glm::vec2 projectOntoScreenRect(glm::vec3 const& worldspaceLoc,
glm::vec2 const& topLeft,
glm::vec2 const& bottomRight) const noexcept;

glm::vec3 getPos() const noexcept;

// converts a `pos` (top-left) in the output `dims` into a line in worldspace by unprojection
Line unprojectScreenposToWorldRay(glm::vec2 pos, glm::vec2 dims) const noexcept;
Expand Down
75 changes: 55 additions & 20 deletions src/UI/UiModelViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,13 @@ namespace {
enum class State { Inactive, WaitingForFirstPoint, WaitingForSecondPoint };
State m_State = State::Inactive;
glm::vec3 m_StartWorldPos = {0.0f, 0.0f, 0.0f};
glm::vec2 m_StartScreenPos = {0.0f, 0.0f};

public:
void draw(std::pair<OpenSim::Component const*, glm::vec3> const& htResult) {
void draw(std::pair<OpenSim::Component const*, glm::vec3> const& htResult,
PolarPerspectiveCamera const& sceneCamera,
glm::vec2 renderTopLeft,
glm::vec2 renderBottomRight) {

if (m_State == State::Inactive) {
return;
}
Expand All @@ -180,38 +183,70 @@ namespace {

glm::vec2 mouseLoc = ImGui::GetMousePos();
ImDrawList* dl = ImGui::GetForegroundDrawList();
ImU32 circleMousedOverNothingColor = ImGui::ColorConvertFloat4ToU32({1.0f, 0.0f, 0.0f, 0.6f});
ImU32 circleColor = ImGui::ColorConvertFloat4ToU32({1.0f, 1.0f, 1.0f, 0.8f});
ImU32 lineColor = circleColor;
ImU32 textBgColor = ImGui::ColorConvertFloat4ToU32({1.0f, 1.0f, 1.0f, 1.0f});
ImU32 textColor = ImGui::ColorConvertFloat4ToU32({0.0f, 0.0f, 0.0f, 1.0f});
float circleRadius = 5.0f;
float lineThickness = 3.0f;
glm::vec2 labelOffsetWhenNoLine = {10.0f, -10.0f};

auto drawTooltipWithBg = [&dl, &textBgColor, &textColor](glm::vec2 const& pos, char const* text) {
glm::vec2 sz = ImGui::CalcTextSize(text);
float bgPad = 5.0f;
float edgeRounding = bgPad - 2.0f;

dl->AddRectFilled(pos - bgPad, pos + sz + bgPad, textBgColor, edgeRounding);
dl->AddText(pos, textColor, text);
};

if (m_State == State::WaitingForFirstPoint) {
if (!htResult.first) { // not mousing over anything
dl->AddCircleFilled(mouseLoc, 5.0f, 0xff0000ff);
dl->AddCircleFilled(mouseLoc, circleRadius, circleMousedOverNothingColor);
return;
} else { // mousing over something
dl->AddCircleFilled(mouseLoc, 5.0f, 0xffffffff);
dl->AddCircleFilled(mouseLoc, circleRadius, circleColor);
char buf[1024];
std::snprintf(buf, sizeof(buf), "%s @ (%.2f, %.2f, %.2f)", htResult.first->getName().c_str(), htResult.second.x, htResult.second.y, htResult.second.z);
dl->AddText(mouseLoc + glm::vec2{10.0f, -7.0f}, 0xff000000, buf);
drawTooltipWithBg(mouseLoc + labelOffsetWhenNoLine, buf);

if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
m_State = State::WaitingForSecondPoint;
m_StartWorldPos = htResult.second;
m_StartScreenPos = mouseLoc;
}
return;
}
} else if (m_State == State::WaitingForSecondPoint) {
dl->AddCircleFilled(m_StartScreenPos, 5.0f, 0xffffffff);

if (htResult.first) { // draw a line + circle between the two hitlocs
dl->AddLine(m_StartScreenPos, mouseLoc, 0xff0000ff, 3.0f);
dl->AddCircleFilled(mouseLoc, 5.0f, 0xffffffff);
glm::vec2 midpoint = (m_StartScreenPos + mouseLoc)/2.0f;
midpoint += 15.0f; // offset it slightly away from the line
float dist = glm::length(htResult.second - m_StartWorldPos);
char buf[1024];
std::snprintf(buf, sizeof(buf), "%.2f", dist);
dl->AddText(midpoint, 0xff000000, buf);
std::snprintf(buf, sizeof(buf), "%s @ (%.2f, %.2f, %.2f)", htResult.first->getName().c_str(), htResult.second.x, htResult.second.y, htResult.second.z);
dl->AddText(mouseLoc + glm::vec2{10.0f, -7.0f}, 0xff000000, buf);
glm::vec2 startScreenPos = sceneCamera.projectOntoScreenRect(m_StartWorldPos, renderTopLeft, renderBottomRight);

if (htResult.first) {
// user is moused over something, so draw a line + circle between the two hitlocs
glm::vec2 endScreenPos = mouseLoc;
glm::vec2 lineScreenDir = glm::normalize(startScreenPos - endScreenPos);
glm::vec2 offsetVec = 15.0f * glm::vec2{lineScreenDir.y, -lineScreenDir.x};
glm::vec2 lineMidpoint = (startScreenPos + endScreenPos) / 2.0f;
float lineWorldLen = glm::length(htResult.second - m_StartWorldPos);

dl->AddCircleFilled(startScreenPos, circleRadius, circleColor);
dl->AddLine(startScreenPos, endScreenPos, lineColor, lineThickness);
dl->AddCircleFilled(endScreenPos, circleRadius, circleColor);

// label the line's length
{
char buf[1024];
std::snprintf(buf, sizeof(buf), "%.2f", lineWorldLen);
drawTooltipWithBg(lineMidpoint + offsetVec, buf);
}

// label the endpoint's component + coord
{
char buf[1024];
std::snprintf(buf, sizeof(buf), "%s @ (%.2f, %.2f, %.2f)", htResult.first->getName().c_str(), htResult.second.x, htResult.second.y, htResult.second.z);
drawTooltipWithBg(mouseLoc + offsetVec, buf);
}
} else {
dl->AddCircleFilled(startScreenPos, circleRadius, circleColor);
}
}
}
Expand Down Expand Up @@ -1184,7 +1219,7 @@ UiModelViewerResponse osc::UiModelViewer::draw(RenderableScene const& rs) {
drawSceneTexture(impl, rs);
drawOverlays(impl, rs);
if (impl.ruler.IsMeasuring()) {
impl.ruler.draw(htResult);
impl.ruler.draw(htResult, impl.camera, impl.renderTopLeft, impl.renderBottomRight);
}
blitSceneTexture(impl);
ImGui::EndChild();
Expand Down

0 comments on commit 05c6b14

Please sign in to comment.