Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feed rate visualization #2515

Merged
merged 3 commits into from
May 9, 2024
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ public class GcodeViewParse {
private final Position max;
private final List<LineSegment> lines;
private double maxSpindleSpeed;
private double maxFeedRate;

public GcodeViewParse() {
maxSpindleSpeed = 0;
maxFeedRate = 0;
min = new Position(UnitUtils.Units.MM);
max = new Position(UnitUtils.Units.MM);
lines = new ArrayList<>();
Expand Down Expand Up @@ -72,6 +74,10 @@ public double getMaxSpindleSpeed() {
return maxSpindleSpeed;
}

public double getMaxFeedRate() {
return maxFeedRate;
}

/**
* Test a point and update min/max coordinates if appropriate.
*/
Expand Down Expand Up @@ -153,6 +159,7 @@ private void recalculateBoundaries() {
testExtremes(lineSegment.getStart());
testExtremes(lineSegment.getEnd());
maxSpindleSpeed = Math.max(lineSegment.getSpindleSpeed(), maxSpindleSpeed);
maxFeedRate = Math.max(lineSegment.getFeedRate(), maxFeedRate);
});
}

Expand Down
6 changes: 4 additions & 2 deletions ugs-core/src/resources/MessagesBundle_en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,10 @@ platform.visualizer.dowel.preview.desc = Show dowel preview
platform.visualizer.highlight = Show highlighted lines
platform.visualizer.highlight.desc = Highlights the selected lines from the editor
platform.visualizer.color.highlight = Editor Line Highlight Color
platform.visualizer.color.linear = Linear Movement Color (G1) max speed
platform.visualizer.color.linear.min.speed = Linear Movement Color (G1) min speed
platform.visualizer.color.linear = Linear Movement Color (G1) feed max
platform.visualizer.color.linear.min.speed = Linear Movement Color (G1) feed min
platform.visualizer.color.spindle.max.speed = Linear Movement Color (G1) spindle max
platform.visualizer.color.spindle.min.speed = Linear Movement Color (G1) spindle min
platform.visualizer.color.rapid = Rapid Movement Color (G0)
platform.visualizer.color.arc = Arc Movement Color (G2/G3)
platform.visualizer.color.plunge = Plunge/Raise Movement Color
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package com.willwinder.universalgcodesender.communicator.event;

import com.willwinder.universalgcodesender.communicator.ICommunicatorListener;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static com.willwinder.universalgcodesender.utils.ThreadHelper.waitUntil;
import org.junit.After;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AsyncCommunicatorEventDispatcherTest {
private AsyncCommunicatorEventDispatcher eventDispatcher;

Expand All @@ -32,13 +31,13 @@ public void tearDown() {
}

@Test
public void dispatchShouldStartWorkerThread() throws TimeoutException, InterruptedException {
public void dispatchShouldStartWorkerThread() throws TimeoutException {
ICommunicatorListener listener = mock(ICommunicatorListener.class);
eventDispatcher.addListener(listener);

eventDispatcher.communicatorPausedOnError();

waitUntil(() -> eventDispatcher.getEventCount() == 0, 1100, TimeUnit.MILLISECONDS);
waitUntil(() -> eventDispatcher.getEventCount() == 0, 2000, TimeUnit.MILLISECONDS);

verify(listener, times(1)).communicatorPausedOnError();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,27 @@ This file is part of Universal Gcode Sender (UGS).

import com.google.common.collect.ImmutableList;
import com.willwinder.universalgcodesender.gcode.util.Code;
import static com.willwinder.universalgcodesender.gcode.util.Code.G1;
import static com.willwinder.universalgcodesender.gcode.util.Code.G2;
import static com.willwinder.universalgcodesender.gcode.util.Code.G3;
import static com.willwinder.universalgcodesender.gcode.util.Code.G38_2;
import static com.willwinder.universalgcodesender.gcode.util.Code.G92_1;
import com.willwinder.universalgcodesender.gcode.util.Plane;
import com.willwinder.universalgcodesender.gcode.util.PlaneFormatter;
import com.willwinder.universalgcodesender.model.PartialPosition;
import com.willwinder.universalgcodesender.model.Position;
import com.willwinder.universalgcodesender.model.UnitUtils;
import static com.willwinder.universalgcodesender.model.UnitUtils.Units.INCH;
import static com.willwinder.universalgcodesender.model.UnitUtils.Units.MM;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.willwinder.universalgcodesender.gcode.util.Code.*;
import static com.willwinder.universalgcodesender.gcode.util.Code.G1;
import static com.willwinder.universalgcodesender.model.UnitUtils.Units.INCH;
import static com.willwinder.universalgcodesender.model.UnitUtils.Units.MM;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;

/**
* @author Joacim Breiler
*/
Expand Down Expand Up @@ -335,6 +338,32 @@ public void overridePositionShouldAddMissingCoordinatesToCommand() {
assertEquals("G0X1Y2Z3A4B5C6", newCommand);
}

@Test
public void updatePointWithCommandShouldSetPositionIfOriginalIsNaN() {
Position position = new Position(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, MM);
Position newPosition = GcodePreprocessorUtils.updatePointWithCommand(position, 1, 2, 3, 4, 5,6, false);
assertEquals(1, newPosition.getX(), 0.01);
assertEquals(2, newPosition.getY(), 0.01);
assertEquals(3, newPosition.getZ(), 0.01);
assertEquals(4, newPosition.getA(), 0.01);
assertEquals(5, newPosition.getB(), 0.01);
assertEquals(6, newPosition.getC(), 0.01);
assertEquals(MM, newPosition.getUnits());
}

@Test
public void updatePointWithCommandShouldAddToPosition() {
Position position = new Position(1, 2, 3, 4, 5, 6, MM);
Position newPosition = GcodePreprocessorUtils.updatePointWithCommand(position, 1, 2, 3, 4, 5,6, false);
assertEquals(2, newPosition.getX(), 0.01);
assertEquals(4, newPosition.getY(), 0.01);
assertEquals(6, newPosition.getZ(), 0.01);
assertEquals(8, newPosition.getA(), 0.01);
assertEquals(10, newPosition.getB(), 0.01);
assertEquals(12, newPosition.getC(), 0.01);
assertEquals(MM, newPosition.getUnits());
}

static void assertThatPointsAreWithinBoundary(Position start, Position end, double radius, List<Position> points) {
assertTrue(points.stream().allMatch(p -> p.x >= start.x));
assertTrue(points.stream().allMatch(p -> p.x <= end.x));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public class VisualizerOptions extends ArrayList<Option<?>> {
public static String VISUALIZER_OPTION_MODEL_DESC = "platform.visualizer.model.desc";
public static String VISUALIZER_OPTION_LINEAR = "platform.visualizer.color.linear";
public static String VISUALIZER_OPTION_LINEAR_MIN_SPEED = "platform.visualizer.color.linear.min.speed";
public static String VISUALIZER_OPTION_SPINDLE_MAX_SPEED = "platform.visualizer.color.spindle.max.speed";
public static String VISUALIZER_OPTION_SPINDLE_MIN_SPEED = "platform.visualizer.color.spindle.min.speed";
public static String VISUALIZER_OPTION_RAPID = "platform.visualizer.color.rapid";
public static String VISUALIZER_OPTION_ARC = "platform.visualizer.color.arc";
public static String VISUALIZER_OPTION_PLUNGE = "platform.visualizer.color.plunge";
Expand Down Expand Up @@ -114,7 +116,9 @@ public VisualizerOptions() {
// GcodeModel renderable
add(getOption(VISUALIZER_OPTION_MODEL, Localization.getString(VISUALIZER_OPTION_MODEL_DESC), true));
add(getOption(VISUALIZER_OPTION_LINEAR, "", new Color(0,0,158)));
add(getOption(VISUALIZER_OPTION_LINEAR_MIN_SPEED, "", new Color(0,0,158, 125)));
add(getOption(VISUALIZER_OPTION_LINEAR_MIN_SPEED, "", new Color(204,255,255)));
add(getOption(VISUALIZER_OPTION_SPINDLE_MAX_SPEED, "", new Color(0,0,158)));
add(getOption(VISUALIZER_OPTION_SPINDLE_MIN_SPEED, "", new Color(204,255,255)));
add(getOption(VISUALIZER_OPTION_RAPID, "", new Color(204,204,0)));
add(getOption(VISUALIZER_OPTION_ARC, "", new Color(178,34,34)));
add(getOption(VISUALIZER_OPTION_PLUNGE, "", new Color(0,100,0)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ This file is part of Universal Gcode Sender (UGS).
package com.willwinder.ugs.nbm.visualizer.renderables;

import com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions;
import com.willwinder.universalgcodesender.visualizer.LineSegment;

import java.awt.Color;

import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_ARC;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_COMPLETE;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_LINEAR;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_LINEAR_MIN_SPEED;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_PLUNGE;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_RAPID;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_SPINDLE_MAX_SPEED;
import static com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions.VISUALIZER_OPTION_SPINDLE_MIN_SPEED;
import com.willwinder.universalgcodesender.visualizer.LineSegment;

import java.awt.Color;

/**
* Generates a color based on the current line segment
Expand All @@ -37,8 +38,11 @@ This file is part of Universal Gcode Sender (UGS).
*/
public class GcodeLineColorizer {
private double maxSpindleSpeed = 0;
private double maxFeedRate = 0;
private Color feedMinColor = Color.BLACK;
private Color feedMaxColor = Color.BLACK;
private Color spindleMinColor = Color.BLACK;
private Color spindleMaxColor = Color.BLACK;
private Color rapidColor = Color.BLACK;
private Color arcColor = Color.BLACK;
private Color plungeColor = Color.BLACK;
Expand All @@ -47,6 +51,8 @@ public class GcodeLineColorizer {
public void reloadPreferences(VisualizerOptions vo) {
feedMaxColor = vo.getOptionForKey(VISUALIZER_OPTION_LINEAR).value;
feedMinColor = vo.getOptionForKey(VISUALIZER_OPTION_LINEAR_MIN_SPEED).value;
spindleMaxColor = vo.getOptionForKey(VISUALIZER_OPTION_SPINDLE_MAX_SPEED).value;
spindleMinColor = vo.getOptionForKey(VISUALIZER_OPTION_SPINDLE_MIN_SPEED).value;
rapidColor = vo.getOptionForKey(VISUALIZER_OPTION_RAPID).value;
arcColor = vo.getOptionForKey(VISUALIZER_OPTION_ARC).value;
plungeColor = vo.getOptionForKey(VISUALIZER_OPTION_PLUNGE).value;
Expand All @@ -63,26 +69,67 @@ public Color getColor(LineSegment lineSegment, long currentCommandNumber) {
} else if (lineSegment.isZMovement()) {
return plungeColor;
} else {
return getFeedColor(lineSegment.getSpindleSpeed());
return getFeedColor(lineSegment.getFeedRate(), lineSegment.getSpindleSpeed());
}
}

private Color getFeedColor(double spindleSpeed) {
if (maxSpindleSpeed == 0) {
return feedMaxColor;
}

private Color getFeedColor(double feedRate, double spindleSpeed) {
double currentSpindleSpeed = Math.max(spindleSpeed, 0.1);
double currentFeedRate = Math.max(feedRate, 0.1);

double feedRatePercent = currentFeedRate / maxFeedRate;
Color feedColor = maxFeedRate < 0.01 ? feedMaxColor : getColor(feedMinColor, feedMaxColor, feedRatePercent);

double speedPercent = currentSpindleSpeed / maxSpindleSpeed;
int red = Math.min(255, feedMinColor.getRed() + (int) (speedPercent * (feedMaxColor.getRed() - feedMinColor.getRed())));
int green = Math.min(255, feedMinColor.getGreen() + (int) (speedPercent * (feedMaxColor.getGreen() - feedMinColor.getGreen())));
int blue = Math.min(255, feedMinColor.getBlue() + (int) (speedPercent * (feedMaxColor.getBlue() - feedMinColor.getBlue())));
int alpha = Math.min(255, feedMinColor.getAlpha() + (int) (speedPercent * (feedMaxColor.getAlpha() - feedMinColor.getAlpha())));
Color speedColor = maxSpindleSpeed < 0.1 ? spindleMaxColor : getColor(spindleMinColor, spindleMaxColor, speedPercent);
return blend(speedColor, feedColor);
}

/**
* Blends multiple colors with the equal amount to one color
*
* @param colors a list of colors to blend
* @return a blended color
*/
public static Color blend(Color... colors) {
if (colors == null || colors.length == 0) {
return null;
}
float ratio = 1f / (colors.length);

int a = 0;
int r = 0;
int g = 0;
int b = 0;

for (Color color : colors) {
int rgb = color.getRGB();
int a1 = (rgb >> 24 & 0xff);
int r1 = ((rgb & 0xff0000) >> 16);
int g1 = ((rgb & 0xff00) >> 8);
int b1 = (rgb & 0xff);
a += a1 * ratio;
r += r1 * ratio;
g += g1 * ratio;
b += b1 * ratio;
}

return new Color(a << 24 | r << 16 | g << 8 | b);
}

private Color getColor(Color minColor, Color maxColor, double percent) {
int red = Math.min(255, minColor.getRed() + (int) (percent * (maxColor.getRed() - minColor.getRed())));
int green = Math.min(255, minColor.getGreen() + (int) (percent * (maxColor.getGreen() - minColor.getGreen())));
int blue = Math.min(255, minColor.getBlue() + (int) (percent * (maxColor.getBlue() - minColor.getBlue())));
int alpha = Math.min(255, minColor.getAlpha() + (int) (percent * (maxColor.getAlpha() - minColor.getAlpha())));
return new Color(red, green, blue, alpha);
}

public void setMaxSpindleSpeed(double maxSpindleSpeed) {
this.maxSpindleSpeed = maxSpindleSpeed;
}

public void setMaxFeedRate(double maxFeedRate) {
this.maxFeedRate = maxFeedRate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ private boolean generateObject() {
this.objectMin = gcvp.getMinimumExtremes();
this.objectMax = gcvp.getMaximumExtremes();
this.colorizer.setMaxSpindleSpeed(gcvp.getMaxSpindleSpeed());
this.colorizer.setMaxFeedRate(gcvp.getMaxFeedRate());

if (gcodeLineList.isEmpty()) {
return false;
Expand Down
Loading