Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,9 @@ public static boolean isItemHovered(float itemWidth, float lineHeight)
float mousePosXInWidgetFrame = mousePosXInDesktopFrame - ImGui.getWindowPosX() + ImGui.getScrollX();
float mousePosYInWidgetFrame = mousePosYInDesktopFrame - ImGui.getWindowPosY() + ImGui.getScrollY();

boolean isHovered = mousePosXInWidgetFrame >= ImGui.getCursorPosX();
boolean isHovered = mousePosXInWidgetFrame > ImGui.getCursorPosX();
isHovered &= mousePosXInWidgetFrame <= ImGui.getCursorPosX() + itemWidth + ImGui.getStyle().getFramePaddingX();
isHovered &= mousePosYInWidgetFrame >= ImGui.getCursorPosY();
isHovered &= mousePosYInWidgetFrame > ImGui.getCursorPosY();
isHovered &= mousePosYInWidgetFrame <= ImGui.getCursorPosY() + lineHeight;
isHovered &= ImGui.isWindowHovered();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import imgui.extension.implot.ImPlot;
import imgui.extension.implot.flag.ImPlotFlags;
import imgui.flag.ImGuiCond;
import imgui.internal.ImGui;
import imgui.ImGui;
import us.ihmc.behaviors.sequence.ActionNodeState;
import us.ihmc.behaviors.sequence.actions.FootstepPlanActionState;
import us.ihmc.commons.thread.ThreadTools;
Expand All @@ -25,7 +25,6 @@

public class RDXActionProgressWidgets
{
public static final float PROGRESS_BAR_HEIGHT = 18.0f;
public static final float PLOT_HEIGHT = 40.0f;
public static final int MAX_WAYPOINTS = 500;
public static final ReferenceFrame worldFrame = ReferenceFrame.getWorldFrame();
Expand Down Expand Up @@ -152,7 +151,7 @@ public void renderElapsedTimeBar(float dividedBarWidth)
double nominalDuration = action.getState().getNominalExecutionDuration();
double percentComplete = elapsedExecutionTime / nominalDuration;
double percentLeft = 1.0 - percentComplete;
ImGui.progressBar((float) percentLeft, dividedBarWidth, PROGRESS_BAR_HEIGHT, "%.2f / %.2f".formatted(elapsedExecutionTime, nominalDuration));
ImGui.progressBar((float) percentLeft, dividedBarWidth, progressBarHeight(), "%.2f / %.2f".formatted(elapsedExecutionTime, nominalDuration));
}

public void renderPositionError(float dividedBarWidth, boolean renderAsPlots)
Expand Down Expand Up @@ -198,7 +197,7 @@ public void renderPositionError(float dividedBarWidth, boolean renderAsPlots)
double barEndValue = Math.max(Math.min(initialToEnd, currentToEnd), 2.0 * tolerance);
double toleranceMarkPercent = tolerance / barEndValue;
double percentLeft = currentToEnd / barEndValue;
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT,
ImGuiTools.markedProgressBar(progressBarHeight(),
dividedBarWidth,
dataColor,
percentLeft,
Expand Down Expand Up @@ -255,7 +254,7 @@ public void renderOrientationError(float dividedBarWidth, boolean renderAsPlots)
double barEndValue = Math.max(Math.min(initialToEnd, currentToEnd), 2.0 * tolerance);
double toleranceMarkPercent = tolerance / barEndValue;
double percentLeft = currentToEnd / barEndValue;
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT,
ImGuiTools.markedProgressBar(progressBarHeight(),
dividedBarWidth,
dataColor,
percentLeft,
Expand Down Expand Up @@ -312,7 +311,7 @@ public void renderJointspacePositionError(int jointIndex, float dividedBarWidth,
double barEndValue = Math.max(Math.min(initialToEnd, currentToEnd), 2.0 * tolerance);
double toleranceMarkPercent = tolerance / barEndValue;
double percentLeft = currentToEnd / barEndValue;
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT,
ImGuiTools.markedProgressBar(progressBarHeight(),
dividedBarWidth,
dataColor,
percentLeft,
Expand Down Expand Up @@ -351,7 +350,7 @@ else if (action instanceof RDXScrewPrimitiveAction screwPrimitiveAction)
}
else
{
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT, dividedBarWidth, dataColor, force / limit, 0.5, "%.2f".formatted(force));
ImGuiTools.markedProgressBar(progressBarHeight(), dividedBarWidth, dataColor, force / limit, 0.5, "%.2f".formatted(force));
}
}
else
Expand Down Expand Up @@ -385,7 +384,7 @@ else if (action instanceof RDXScrewPrimitiveAction screwPrimitiveAction)
}
else
{
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT, dividedBarWidth, dataColor, torque / limit, 0.5, "%.2f".formatted(torque));
ImGuiTools.markedProgressBar(progressBarHeight(), dividedBarWidth, dataColor, torque / limit, 0.5, "%.2f".formatted(torque));
}
}
else
Expand All @@ -412,7 +411,7 @@ public void renderFootstepCompletion(float dividedBarWidth, boolean renderAsPlot
}
else
{
ImGui.progressBar((float) percentLeft, dividedBarWidth, PROGRESS_BAR_HEIGHT, overlay);
ImGui.progressBar((float) percentLeft, dividedBarWidth, progressBarHeight(), overlay);
}
}
else
Expand Down Expand Up @@ -465,7 +464,7 @@ public void renderFootPositions(float dividedBarWidth, boolean renderAsPlots)
double barEndValue = Math.max(Math.min(initialToEnd, currentToEnd), 2.0 * tolerance);
double toleranceMarkPercent = tolerance / barEndValue;
double percentLeft = currentToEnd / barEndValue;
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT,
ImGuiTools.markedProgressBar(progressBarHeight(),
halfDividedBarWidth,
dataColor,
percentLeft,
Expand Down Expand Up @@ -527,7 +526,7 @@ public void renderFootOrientations(float dividedBarWidth, boolean renderAsPlots)
double barEndValue = Math.max(Math.min(initialToEnd, currentToEnd), 2.0 * tolerance);
double toleranceMarkPercent = tolerance / barEndValue;
double percentLeft = currentToEnd / barEndValue;
ImGuiTools.markedProgressBar(PROGRESS_BAR_HEIGHT,
ImGuiTools.markedProgressBar(progressBarHeight(),
halfDividedBarWidth,
dataColor,
percentLeft,
Expand All @@ -554,11 +553,16 @@ public static void renderBlankProgress(String emptyPlotLabel, float width, boole
{
if (renderAsPlots && supportsPlots)
{
ImPlotTools.renderEmptyPlotArea(emptyPlotLabel, width, RDXActionProgressWidgets.PLOT_HEIGHT);
ImPlotTools.renderEmptyPlotArea(emptyPlotLabel, width, PLOT_HEIGHT);
}
else
{
ImGui.progressBar(Float.NaN, width, RDXActionProgressWidgets.PROGRESS_BAR_HEIGHT, "");
ImGui.progressBar(Float.NaN, width, progressBarHeight(), "");
}
}

private static float progressBarHeight()
{
return 1.2f * ImGui.getTextLineHeight();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,34 @@
import us.ihmc.rdx.ui.behavior.actions.RDXHandPoseAction;
import us.ihmc.rdx.ui.behavior.actions.RDXSakeHandCommandAction;
import us.ihmc.rdx.ui.behavior.actions.RDXScrewPrimitiveAction;
import us.ihmc.rdx.ui.behavior.tree.RDXBehaviorTree;
import us.ihmc.robotics.EuclidCoreMissingTools;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;

/**
* Renders action execution status tracking UI elements.
*
* TODO: Add even more compressed representation. Radial plots.
*/
public class RDXActionProgressWidgetsManager
{
public enum Type
{
/** Show only the estimated time remaining as a progress bar.. */
TIME_ONLY,
/** Show progress bars which are more compact than full plots. */
PROGRESS_BARS,
/** Show full side scrolling plots which show more information about execution but take up more space. */
SCROLLING_PLOTS
}
private final ImGuiUniqueLabelMap labels = new ImGuiUniqueLabelMap(getClass());
private final ImGuiLabelledWidgetAligner widgetAligner = new ImGuiLabelledWidgetAligner();
private final SortedSet<RDXActionNode<?, ?>> sortedActionNodesToRender = new TreeSet<>(Comparator.comparingInt(node -> node.getState().getLeafIndex()));
private final ArrayList<RDXActionNode<?, ?>> actionNodesToRender = new ArrayList<>();
private boolean renderAsPlots = true;
private int emptyPlotIndex;
private int numberOfLines;

Expand Down Expand Up @@ -52,6 +66,7 @@ public void render()
}
boolean showPosePlots = containsFootsteps || containsHandMovements;

ImGui.spacing();
widgetAligner.text("Expected time remaining:");
float dividedBarWidth = computeDividedBarWidth(); // Must be computed after above text
handleRenderingBlankBar(false);
Expand All @@ -63,95 +78,100 @@ public void render()
++numberOfLines;
ImGui.spacing();

if (containsFootsteps)
{
widgetAligner.text("Footstep completion:");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
actionNodesToRender.get(i).getProgressWidgets().renderFootstepCompletion(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();
}

if (showPosePlots)
{
widgetAligner.text("Position error (m):");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
if (actionNodesToRender.get(i) instanceof RDXFootstepPlanAction)
actionNodesToRender.get(i).getProgressWidgets().renderFootPositions(dividedBarWidth, renderAsPlots);
else
actionNodesToRender.get(i).getProgressWidgets().renderPositionError(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();

widgetAligner.text("Orientation error (%s):".formatted(EuclidCoreMissingTools.DEGREE_SYMBOL));
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
if (actionNodesToRender.get(i) instanceof RDXFootstepPlanAction)
actionNodesToRender.get(i).getProgressWidgets().renderFootOrientations(dividedBarWidth, renderAsPlots);
else
actionNodesToRender.get(i).getProgressWidgets().renderOrientationError(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();
}

if (containsHandMovements)
boolean timeOnly = RDXBehaviorTree.SETTINGS.getProgressWidgetsType() == Type.TIME_ONLY;
boolean renderAsPlots = RDXBehaviorTree.SETTINGS.getProgressWidgetsType() == Type.SCROLLING_PLOTS;
if (!timeOnly)
{
widgetAligner.text("Hand force (N):");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
if (containsFootsteps)
{
actionNodesToRender.get(i).getProgressWidgets().renderHandForce(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
widgetAligner.text("Footstep completion:");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
actionNodesToRender.get(i).getProgressWidgets().renderFootstepCompletion(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();
}
++numberOfLines;
ImGui.spacing();

widgetAligner.text("Hand torque (Nm):");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
if (showPosePlots)
{
actionNodesToRender.get(i).getProgressWidgets().renderHandTorque(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
widgetAligner.text("Position error (m):");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
if (actionNodesToRender.get(i) instanceof RDXFootstepPlanAction)
actionNodesToRender.get(i).getProgressWidgets().renderFootPositions(dividedBarWidth, renderAsPlots);
else
actionNodesToRender.get(i).getProgressWidgets().renderPositionError(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();

widgetAligner.text("Orientation error (%s):".formatted(EuclidCoreMissingTools.DEGREE_SYMBOL));
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
if (actionNodesToRender.get(i) instanceof RDXFootstepPlanAction)
actionNodesToRender.get(i).getProgressWidgets().renderFootOrientations(dividedBarWidth, renderAsPlots);
else
actionNodesToRender.get(i).getProgressWidgets().renderOrientationError(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();
}
++numberOfLines;
ImGui.spacing();
}

if (containsHandConfiguration)
{
widgetAligner.text("Knuckle X1 (%s):".formatted(EuclidCoreMissingTools.DEGREE_SYMBOL));
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
if (containsHandMovements)
{
actionNodesToRender.get(i).getProgressWidgets().renderJointspacePositionError(0, dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
widgetAligner.text("Hand force (N):");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
actionNodesToRender.get(i).getProgressWidgets().renderHandForce(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();

widgetAligner.text("Hand torque (Nm):");
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
actionNodesToRender.get(i).getProgressWidgets().renderHandTorque(dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();
}
++numberOfLines;
ImGui.spacing();

widgetAligner.text("Knuckle X2 (%s):".formatted(EuclidCoreMissingTools.DEGREE_SYMBOL));
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
if (containsHandConfiguration)
{
actionNodesToRender.get(i).getProgressWidgets().renderJointspacePositionError(1, dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
widgetAligner.text("Knuckle X1 (%s):".formatted(EuclidCoreMissingTools.DEGREE_SYMBOL));
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
actionNodesToRender.get(i).getProgressWidgets().renderJointspacePositionError(0, dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();

widgetAligner.text("Knuckle X2 (%s):".formatted(EuclidCoreMissingTools.DEGREE_SYMBOL));
handleRenderingBlankBar(true);
for (int i = 0; i < actionNodesToRender.size(); i++)
{
actionNodesToRender.get(i).getProgressWidgets().renderJointspacePositionError(1, dividedBarWidth, renderAsPlots);
sameLineExceptLast(i);
}
++numberOfLines;
ImGui.spacing();
}
++numberOfLines;
ImGui.spacing();
}

while (numberOfLines < 5)
while (numberOfLines < (timeOnly ? 1 : 5))
{
widgetAligner.text("");
renderBlankBar(true);
Expand Down Expand Up @@ -190,19 +210,10 @@ private void handleRenderingBlankBar(boolean supportsPlots)

private void renderBlankBar(boolean supportsPlots)
{
boolean renderAsPlots = RDXBehaviorTree.SETTINGS.getProgressWidgetsType() == Type.SCROLLING_PLOTS;
RDXActionProgressWidgets.renderBlankProgress(labels.get("Empty Plot", emptyPlotIndex++), ImGui.getColumnWidth(), renderAsPlots, supportsPlots);
}

public boolean getRenderAsPlots()
{
return renderAsPlots;
}

public void setRenderAsPlots(boolean renderAsPlots)
{
this.renderAsPlots = renderAsPlots;
}

public SortedSet<RDXActionNode<?, ?>> getActionNodesToRender()
{
return sortedActionNodesToRender;
Expand Down
Loading
Loading