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

Add test to guarantee gcode export import consistency #736

Merged
merged 5 commits into from
Dec 3, 2023
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.marginallyclever</groupId>
<artifactId>Makelangelo</artifactId>
<version>7.52.1</version>
<version>7.52.2</version>
<name>Makelangelo</name>
<description>Makelangelo Software is a Java program that prepares art for CNC plotters. It is especially designed for the Makelangelo Robot.
It pairs really well with Marlin-polargraph, the code in the brain of the robot that receives instructions and moves the motors.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,8 @@ public Turtle load(InputStream in) throws Exception {
double ni = nx;
double nj = ny;

boolean codeFound=false;

String mCodeToken=tokenExists("M",tokens);
if(mCodeToken!=null) {
codeFound=true;
int mCode = Integer.parseInt(mCodeToken.substring(1));
switch(mCode) {
case 6:
Expand All @@ -107,89 +104,81 @@ public Turtle load(InputStream in) throws Exception {
// ignore all others
break;
}
continue;
}

if(!codeFound) {
String gCodeToken=tokenExists("G",tokens);
if(gCodeToken!=null) {
int gCode = Integer.parseInt(gCodeToken.substring(1));
switch(gCode) {
case 20: scaleXY=25.4; break; // in -> mm
case 21: scaleXY= 1.0; break; // mm
case 90: isAbsolute=true; break; // absolute mode
case 91: isAbsolute=false; break; // relative mode
default:
break;
}
String gCodeToken=tokenExists("G",tokens);
if(gCodeToken!=null) {
int gCode = Integer.parseInt(gCodeToken.substring(1));
switch(gCode) {
case 20: scaleXY=25.4; break; // in -> mm
case 21: scaleXY= 1.0; break; // mm
case 90: isAbsolute=true; break; // absolute mode
case 91: isAbsolute=false; break; // relative mode
default:
break;
}

if(tokenExists("X",tokens)!=null) {
double v = Float.parseFloat(tokenExists("X",tokens).substring(1)) * scaleXY;
nx = isAbsolute ? v : nx+v;
}
if(tokenExists("Y",tokens)!=null) {
double v = Float.parseFloat(tokenExists("Y",tokens).substring(1)) * scaleXY;
ny = isAbsolute ? v : ny+v;
}
if(tokenExists("Z",tokens)!=null) {
double v = Float.parseFloat(tokenExists("Z",tokens).substring(1)); // do not scale
nz = isAbsolute ? v : nz+v;
}
if(tokenExists("I",tokens)!=null) {
double v = Float.parseFloat(tokenExists("I",tokens).substring(1)) * scaleXY;
ni = isAbsolute ? v : ni+v;
}
if(tokenExists("J",tokens)!=null) {
double v = Float.parseFloat(tokenExists("J",tokens).substring(1)) * scaleXY;
nj = isAbsolute ? v : nj+v;
}
if( gCode==28 ) {
// TODO set to machine home position.
nx = ni = 0;
ny = nj = 0;
continue;
}

nx = parseScaled(tokens,"X",nx,scaleXY,isAbsolute);
ny = parseScaled(tokens,"Y",ny,scaleXY,isAbsolute);
nz = parseUnscaled(tokens,nz,isAbsolute);

if(gCode==0 || gCode==1) {
if(nz!=oz) {
// z change
if(turtle.isUp()) turtle.penDown();
else turtle.penUp();
oz=nz;
}
if(nx!=ox || ny!=oy) {
turtle.moveTo(nx, ny);
ox=nx;
oy=ny;
}
} else if(gCode==2 || gCode==3) {
// arc
int dir = (gCode==2) ? -1 : 1;

double dx = ox - ni;
double dy = oy - nj;
double radius = Math.sqrt(dx * dx + dy * dy);

// find angle of arc (sweep)
double angle1 = atan3(dy, dx);
double angle2 = atan3(ny - nj, nx - ni);
double theta = angle2 - angle1;

if (dir > 0 && theta < 0) angle2 += Math.PI * 2.0;
else if (dir < 0 && theta > 0) angle1 += Math.PI * 2.0;

theta = angle2 - angle1;

double len = Math.abs(theta) * radius;
double angle3, scale;

// TODO turtle support for arcs
// Draw the arc from a lot of little line segments.
for(double k = 0; k < len; k++) {
scale = k / len;
angle3 = theta * scale + angle1;
double ix = ni + Math.cos(angle3) * radius;
double iy = nj + Math.sin(angle3) * radius;

turtle.moveTo(ix,iy);
}
turtle.moveTo(nx,ny);
if(gCode==0 || gCode==1) {
if(nz!=oz) {
// z change
if(turtle.isUp()) turtle.penDown();
else turtle.penUp();
oz=nz;
}
if(nx!=ox || ny!=oy) {
turtle.moveTo(nx, ny);
ox=nx;
oy=ny;
}
} else if(gCode==2 || gCode==3) {
// arc
int dir = (gCode==2) ? -1 : 1;
ni = parseScaled(tokens,"I",nx,scaleXY,isAbsolute);
nj = parseScaled(tokens,"J",ny,scaleXY,isAbsolute);

double dx = ox - ni;
double dy = oy - nj;
double radius = Math.sqrt(dx * dx + dy * dy);

// find angle of arc (sweep)
double angle1 = atan3(dy, dx);
double angle2 = atan3(ny - nj, nx - ni);
double theta = angle2 - angle1;

if (dir > 0 && theta < 0) angle2 += Math.PI * 2.0;
else if (dir < 0 && theta > 0) angle1 += Math.PI * 2.0;

theta = angle2 - angle1;

double len = Math.abs(theta) * radius;
double angle3, scale;

// TODO turtle support for arcs
// Draw the arc from a lot of little line segments.
for(double k = 0; k < len; k++) {
scale = k / len;
angle3 = theta * scale + angle1;
double ix = ni + Math.cos(angle3) * radius;
double iy = nj + Math.sin(angle3) * radius;

turtle.moveTo(ix,iy);
}
turtle.moveTo(nx,ny);
ox=nx;
oy=ny;
continue;
}
// else do nothing.
}
Expand All @@ -201,4 +190,20 @@ public Turtle load(InputStream in) throws Exception {

return turtle;
}

private double parseUnscaled(String[] tokens, double nz, boolean isAbsolute) {
if(tokenExists("Z",tokens)!=null) {
double v = Float.parseFloat(tokenExists("Z",tokens).substring(1)); // do not scale
nz = isAbsolute ? v : nz+v;
}
return nz;
}

private double parseScaled(String[] tokens, String key,double nx, double scaleXY, boolean isAbsolute) {
if(tokenExists(key,tokens)!=null) {
double v = Float.parseFloat(tokenExists(key,tokens).substring(1)) * scaleXY;
nx = isAbsolute ? v : nx+v;
}
return nx;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class LanguagePreferences {
static private SelectOneOfMany languageOptions;


static SelectPanel buildPanel() {
static SelectPanel buildPanel() {
int currentIndex = Translator.getCurrentLanguageIndex();
languageOptions = new SelectOneOfMany("language","Language",languageList,currentIndex);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,11 @@
*/
@Deprecated
public class DragAndDrive extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;

private JLabel coordinates;
private JPanel dragAndDrive;
private final Plotter robot;
private final JLabel coordinates;
private final JPanel dragAndDrive;
private boolean mouseInside, mouseOn;
private double mouseLastX, mouseLastY;
private Plotter robot;

DragAndDrive(Plotter robot) {
super(new GridBagLayout());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.marginallyclever.makelangelo.makeart.io;

import com.marginallyclever.makelangelo.Translator;
import com.marginallyclever.makelangelo.makeart.tools.ReorderTurtleAction;
import com.marginallyclever.makelangelo.makeart.tools.SimplifyTurtleAction;
import com.marginallyclever.makelangelo.makeart.turtlegenerator.Generator_TruchetTiles;
import com.marginallyclever.makelangelo.paper.Paper;
import com.marginallyclever.makelangelo.plotter.plottersettings.PlotterSettingsManager;
import com.marginallyclever.makelangelo.turtle.Turtle;
import com.marginallyclever.util.PreferencesHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
* Confirm saving and loading GCode is lossless.
* @author Dan Royer
* @since 7.52.1
*/
public class SaveAndLoadGCodeTest {
@BeforeAll
public static void setup() {
PreferencesHelper.start();
Translator.start();
}

@Test
public void test() throws Exception {
Generator_TruchetTiles g = new Generator_TruchetTiles();
g.setPaper(new Paper());
g.addListener(generatedTurtle-> {
try {
saveAndLoad(generatedTurtle);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
g.generate();
}

private void saveAndLoad(Turtle original) throws Exception {
// given
File fileTemp = File.createTempFile("unit", null);

try {
SimplifyTurtleAction simplify = new SimplifyTurtleAction();
Turtle b2 = simplify.run(original);
ReorderTurtleAction reorder = new ReorderTurtleAction();
Turtle before = reorder.run(b2);

SaveGCode save = new SaveGCode();
FileOutputStream fileOutputStream = new FileOutputStream(fileTemp);
save.save(fileOutputStream, before, PlotterSettingsManager.buildMakelangelo5());
fileOutputStream.close();

LoadGCode load = new LoadGCode();
FileInputStream input = new FileInputStream(fileTemp);
Turtle after = load.load(input);
input.close();

Assertions.assertEquals(before.history.toString(),after.history.toString(),"Different history");
} finally {
fileTemp.delete();
}
}
}
17 changes: 0 additions & 17 deletions src/test/resources/translator/english_with_dup_key.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,6 @@
<!DOCTYPE language>
<language>

<!--
To facilitate the validation and avoid duplicated or empty key (//language/string/key) ,
please try to get language_no_dup_key.xsd from https://github.com/MarginallyClever/Makelangelo-software/blob/b1f418fc63d70f24288d490dccadc97d97a775e9/src/test/resources/translator/language_no_dup_key.xsd
and change the begining of the file with :

<?xml version="1.0" encoding="UTF-8"?>
<language xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="language_no_dup_key.xsd" >

-->
<meta>
<name>English_DUP</name>
<author>TEST_SET_DUP_KEY</author>
Expand All @@ -19,44 +10,36 @@
<string>
<key>BorderName</key>
<value>Outline paper</value>
<hint>Border generator</hint>
</string>

<string>
<key>LissajousName</key>
<value>Lissajous</value>
<hint>Lissajous generator</hint>
</string>
<string>
<key>KEY_A</key>
<value>...</value>
<hint></hint>
</string>
<string>
<key>KEY_A</key>
<value>...</value>
<hint></hint>
</string>
<string>
<key></key>
<value>...</value>
<hint></hint>
</string>

<string>
<key>KEY_B</key>
<value>...</value>
<hint></hint>
</string>
<string>
<key>KEY_B</key>
<value>...</value>
<hint></hint>
</string>
<string>
<key>KEY_C_DOUBLED_VALUE</key>
<value>...</value>
<value>...</value>
<hint></hint>
</string>
</language>
6 changes: 1 addition & 5 deletions src/test/resources/translator/english_with_no_dup_key.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language>
<language>
<language xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="language_no_dup_key.xsd" >
<meta>
<name>English_NO_DUP</name>
<author>TEST_SET_NO_DUP_KEY</author>
Expand All @@ -9,24 +9,20 @@
<string>
<key>KEY_A</key>
<value>...</value>
<hint></hint>
</string>

<string>
<key>KEY_B</key>
<value>...</value>
<hint></hint>
</string>

<string>
<key>BorderName</key>
<value>Outline paper</value>
<hint>Border generator</hint>
</string>

<string>
<key>LissajousName</key>
<value>Lissajous</value>
<hint>Lissajous generator</hint>
</string>
</language>
Loading