mirror of
https://github.com/euphy/polargraphcontroller
synced 2025-01-08 19:24:25 +01:00
v2.5.2 - UI changes to make cycling er, work properly. Changed the .toMM() method of the Machine class to be floaty. This helps rendering a bit.
This commit is contained in:
parent
f2b1df7405
commit
5e7e010a79
436
FileLoading.pde
Normal file
436
FileLoading.pde
Normal file
@ -0,0 +1,436 @@
|
||||
/**
|
||||
Polargraph controller
|
||||
Copyright Sandy Noble 2018.
|
||||
|
||||
This file is part of Polargraph Controller.
|
||||
|
||||
Polargraph Controller is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Polargraph Controller is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Polargraph Controller. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Requires the excellent ControlP5 GUI library available from http://www.sojamo.de/libraries/controlP5/.
|
||||
Requires the excellent Geomerative library available from http://www.ricardmarxer.com/geomerative/.
|
||||
|
||||
This is an application for controlling a polargraph machine, communicating using ASCII command language over a serial link.
|
||||
|
||||
sandy.noble@gmail.com
|
||||
http://www.polargraph.co.uk/
|
||||
https://github.com/euphy/polargraphcontroller
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void loadImageWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run() {
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastImageDirectory != null) fc.setCurrentDirectory(lastImageDirectory);
|
||||
fc.setFileFilter(new ImageFileFilter());
|
||||
fc.setDialogTitle("Choose an image file...");
|
||||
|
||||
int returned = fc.showOpenDialog(frame);
|
||||
|
||||
lastImageDirectory = fc.getCurrentDirectory();
|
||||
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
// see if it's an image
|
||||
PImage img = loadImage(file.getPath());
|
||||
if (img != null)
|
||||
{
|
||||
img = null;
|
||||
getDisplayMachine().loadNewImageFromFilename(file.getPath());
|
||||
if (getDisplayMachine().pixelsCanBeExtracted() && isBoxSpecified())
|
||||
{
|
||||
getDisplayMachine().extractPixelsFromArea(getBoxVector1(), getBoxVectorSize(), getGridSize(), sampleArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class ImageFileFilter extends javax.swing.filechooser.FileFilter
|
||||
{
|
||||
public boolean accept(File file) {
|
||||
String filename = file.getName();
|
||||
filename.toLowerCase();
|
||||
if (file.isDirectory() || filename.endsWith(".png") || filename.endsWith(".jpg") || filename.endsWith(".jpeg"))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Image files (PNG or JPG)";
|
||||
}
|
||||
}
|
||||
|
||||
void loadVectorWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run() {
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastImageDirectory != null)
|
||||
{
|
||||
fc.setCurrentDirectory(lastImageDirectory);
|
||||
}
|
||||
|
||||
fc.setFileFilter(new VectorFileFilter());
|
||||
fc.setDialogTitle("Choose a vector file...");
|
||||
int returned = fc.showOpenDialog(frame);
|
||||
lastImageDirectory = fc.getCurrentDirectory();
|
||||
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
if (file.exists())
|
||||
{
|
||||
RShape shape = loadShapeFromFile(file.getPath());
|
||||
if (shape != null)
|
||||
{
|
||||
setVectorFilename(file.getPath());
|
||||
setVectorShape(shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
println("File not found (" + file.getPath() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class VectorFileFilter extends javax.swing.filechooser.FileFilter
|
||||
{
|
||||
public boolean accept(File file) {
|
||||
String filename = file.getName();
|
||||
filename.toLowerCase();
|
||||
if (file.isDirectory() || filename.endsWith(".svg") || isGCodeExtension(filename))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Vector graphic files (SVG, GCode)";
|
||||
}
|
||||
}
|
||||
|
||||
void loadNewPropertiesFilenameWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastPropertiesDirectory != null) fc.setCurrentDirectory(lastPropertiesDirectory);
|
||||
fc.setFileFilter(new PropertiesFileFilter());
|
||||
|
||||
fc.setDialogTitle("Choose a config file...");
|
||||
|
||||
int returned = fc.showOpenDialog(frame);
|
||||
|
||||
lastPropertiesDirectory = fc.getCurrentDirectory();
|
||||
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
if (file.exists())
|
||||
{
|
||||
println("New properties file exists.");
|
||||
newPropertiesFilename = file.toString();
|
||||
println("new propertiesFilename: "+ newPropertiesFilename);
|
||||
propertiesFilename = newPropertiesFilename;
|
||||
// clear old properties.
|
||||
props = null;
|
||||
loadFromPropertiesFile();
|
||||
|
||||
// set values of number spinners etc
|
||||
updateNumberboxValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class PropertiesFileFilter extends javax.swing.filechooser.FileFilter
|
||||
{
|
||||
public boolean accept(File file) {
|
||||
String filename = file.getName();
|
||||
filename.toLowerCase();
|
||||
if (file.isDirectory() || filename.endsWith(".properties.txt"))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Properties files (*.properties.txt)";
|
||||
}
|
||||
}
|
||||
|
||||
void saveNewPropertiesFileWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastPropertiesDirectory != null) fc.setCurrentDirectory(lastPropertiesDirectory);
|
||||
fc.setFileFilter(new PropertiesFileFilter());
|
||||
|
||||
fc.setDialogTitle("Enter a config file name...");
|
||||
|
||||
int returned = fc.showSaveDialog(frame);
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
newPropertiesFilename = file.toString();
|
||||
newPropertiesFilename.toLowerCase();
|
||||
if (!newPropertiesFilename.endsWith(".properties.txt"))
|
||||
newPropertiesFilename+=".properties.txt";
|
||||
|
||||
println("new propertiesFilename: "+ newPropertiesFilename);
|
||||
propertiesFilename = newPropertiesFilename;
|
||||
savePropertiesFile();
|
||||
// clear old properties.
|
||||
props = null;
|
||||
loadFromPropertiesFile();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
RShape loadShapeFromFile(String filename) {
|
||||
RShape sh = null;
|
||||
if (filename.toLowerCase().endsWith(".svg")) {
|
||||
sh = RG.loadShape(filename);
|
||||
}
|
||||
else if (isGCodeExtension(filename)) {
|
||||
sh = loadShapeFromGCodeFile(filename);
|
||||
}
|
||||
return sh;
|
||||
}
|
||||
|
||||
|
||||
boolean isGCodeExtension(String filename) {
|
||||
return (filename.toLowerCase().endsWith(".gcode") || filename.toLowerCase().endsWith(".g") || filename.toLowerCase().endsWith(".ngc") || filename.toLowerCase().endsWith(".txt"));
|
||||
}
|
||||
|
||||
|
||||
int countLines(String filename) throws IOException {
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(filename));
|
||||
try {
|
||||
byte[] c = new byte[1024];
|
||||
int count = 0;
|
||||
int readChars = 0;
|
||||
boolean empty = true;
|
||||
while ((readChars = is.read(c)) != -1) {
|
||||
empty = false;
|
||||
for (int i = 0; i < readChars; ++i) {
|
||||
if (c[i] == '\n') {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (count == 0 && !empty) ? 1 : count+1;
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
RShape loadShapeFromGCodeFile(String filename) {
|
||||
noLoop();
|
||||
RShape parent = null;
|
||||
BufferedReader reader = null;
|
||||
long totalPoints = 0;
|
||||
long time = millis();
|
||||
long countLines = 0;
|
||||
|
||||
try {
|
||||
countLines = countLines(filename);
|
||||
println("" + countLines + " lines found.");
|
||||
if (countLines < 1) {
|
||||
throw new IOException("No lines found in GCode file.");
|
||||
}
|
||||
reader = createReader(filename);
|
||||
parent = new RShape();
|
||||
String line;
|
||||
boolean drawLine = false;
|
||||
int gCodeZAxisChanges = 0;
|
||||
|
||||
long lineNo = 0;
|
||||
float lastPercent = 0.0f;
|
||||
boolean reportStatus = true;
|
||||
while ((line = reader.readLine ()) != null) {
|
||||
lineNo++;
|
||||
// println("Line: " + line);
|
||||
|
||||
if (reportStatus) {
|
||||
float percent = ((float)lineNo / (float)countLines) * 100.0;
|
||||
println("----" + percent + "% of the way through.");
|
||||
lastPercent = percent;
|
||||
}
|
||||
|
||||
if (line.toUpperCase().startsWith("G")) {
|
||||
if (reportStatus) {
|
||||
println(new StringBuilder().append(lineNo).append(" of ").append(countLines).append(": ").append(line).append(". Points: ").append(totalPoints).toString());
|
||||
long free = Runtime.getRuntime().freeMemory();
|
||||
long maximum = Runtime.getRuntime().maxMemory();
|
||||
println(new StringBuilder().append("Free: ").append(free).append(", max: ").append(maximum).toString());
|
||||
}
|
||||
|
||||
Map<String, Float> ins = null;
|
||||
try {
|
||||
ins = unpackGCodeInstruction(line);
|
||||
}
|
||||
catch (Exception e) {
|
||||
println(e.toString());
|
||||
continue;
|
||||
}
|
||||
// println("Ins: " + ins);
|
||||
Integer code = Math.round(ins.get("G"));
|
||||
|
||||
Float z = ins.get("Z");
|
||||
if (z != null) {
|
||||
gCodeZAxisChanges++;
|
||||
if (gCodeZAxisChanges == 2) {
|
||||
println("Assume second z axis change is to drop the pen to start drawing " + z);
|
||||
gcodeZAxisDrawingHeight = z;
|
||||
drawLine = true;
|
||||
}
|
||||
else if (gCodeZAxisChanges > 2) {
|
||||
drawLine = isGCodeZAxisForDrawing(z);
|
||||
}
|
||||
else {
|
||||
println("Assume first z axis change is to RAISE the pen " + z);
|
||||
drawLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
Float x = ins.get("X");
|
||||
Float y = ins.get("Y");
|
||||
if (x != null && y == null) {
|
||||
// move x axis only, use y of last
|
||||
RPoint[][] points = parent.getPointsInPaths();
|
||||
RPoint rp = points[points.length-1][points[points.length-1].length-1];
|
||||
y = rp.y;
|
||||
}
|
||||
else if (x == null && y != null) {
|
||||
// move y axis only, use x of last
|
||||
RPoint[][] points = parent.getPointsInPaths();
|
||||
RPoint rp = points[points.length-1][points[points.length-1].length-1];
|
||||
x = rp.x;
|
||||
}
|
||||
|
||||
if (x != null && y != null) {
|
||||
// move both x and y axis
|
||||
if (drawLine) {
|
||||
parent.addLineTo(x, y);
|
||||
}
|
||||
else {
|
||||
parent.addMoveTo(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
|
||||
if ((millis() - time) > 500) {
|
||||
time = millis();
|
||||
reportStatus = true;
|
||||
}
|
||||
else {
|
||||
reportStatus = false;
|
||||
}
|
||||
|
||||
if (lineNo == (countLines-1)) {
|
||||
reportStatus = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
println("IOExecption reading lines from the gcode file " + filename);
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
reader.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
println("IOException closing the gcode file " + filename);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
RPoint[][] points = parent.getPointsInPaths();
|
||||
totalPoints = 0;
|
||||
if (points != null) {
|
||||
for (int i = 0; i<points.length; i++) {
|
||||
if (points[i] != null) {
|
||||
for (int j = 0; j<points[i].length; j++) {
|
||||
totalPoints++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String conclusionMessage = "Imported " + totalPoints + " points from " + countLines + " lines of code in the file.";
|
||||
println(conclusionMessage);
|
||||
javax.swing.JOptionPane.showMessageDialog(null, conclusionMessage);
|
||||
|
||||
loop();
|
||||
return parent;
|
||||
}
|
||||
|
||||
Boolean isGCodeZAxisForDrawing(float z) {
|
||||
return gcodeZAxisDrawingHeight.compareTo(z) == 0;
|
||||
}
|
||||
|
||||
Map<String, Float> unpackGCodeInstruction(String line) throws Exception {
|
||||
Map<String, Float> instruction = new HashMap<String, Float>(4);
|
||||
try {
|
||||
String[] splitted = line.trim().split(" ");
|
||||
for (int i = 0; i < splitted.length; i++) {
|
||||
// remove ; character
|
||||
splitted[i] = splitted[i].replace(";", "");
|
||||
String axis = splitted[i].substring(0, 1);
|
||||
String sanitisedValue = splitted[i].substring(1);
|
||||
sanitisedValue = sanitisedValue.replace(",", ".");
|
||||
Float value = Float.parseFloat(sanitisedValue);
|
||||
if ("X".equalsIgnoreCase(axis) || "Y".equalsIgnoreCase(axis) || "Z".equalsIgnoreCase(axis) || "G".equalsIgnoreCase(axis)) {
|
||||
instruction.put(axis.toUpperCase(), value);
|
||||
}
|
||||
}
|
||||
// println("instruction: " + instruction);
|
||||
if (instruction.isEmpty()) {
|
||||
throw new Exception("Empty instruction");
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
println("Number format exception: " + nfe.getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("e: " + e);
|
||||
throw new Exception("Exception while reading the lines from a gcode file: " + line + ", " + e.getMessage());
|
||||
}
|
||||
|
||||
return instruction;
|
||||
}
|
12
Machine.pde
12
Machine.pde
@ -186,9 +186,15 @@ class Machine
|
||||
return mmInt;
|
||||
}
|
||||
|
||||
public float inMMFloat(float steps)
|
||||
{
|
||||
double mm = steps / getStepsPerMM();
|
||||
return (float) mm;
|
||||
}
|
||||
|
||||
public PVector inMM (PVector steps)
|
||||
{
|
||||
PVector mm = new PVector(inMM(steps.x), inMM(steps.y));
|
||||
PVector mm = new PVector(inMMFloat(steps.x), inMMFloat(steps.y));
|
||||
return mm;
|
||||
}
|
||||
|
||||
@ -322,8 +328,8 @@ class Machine
|
||||
|
||||
public PVector asCartesianCoords(PVector pgCoords)
|
||||
{
|
||||
float calcX = int((pow(getWidth(), 2) - pow(pgCoords.y, 2) + pow(pgCoords.x, 2)) / (getWidth()*2));
|
||||
float calcY = int(sqrt(pow(pgCoords.x,2)-pow(calcX,2)));
|
||||
float calcX = (pow(getWidth(), 2.0) - pow(pgCoords.y, 2.0) + pow(pgCoords.x, 2.0)) / (getWidth()*2.0);
|
||||
float calcY = sqrt(pow(pgCoords.x,2.0)-pow(calcX,2.0));
|
||||
PVector vect = new PVector(calcX, calcY);
|
||||
return vect;
|
||||
}
|
||||
|
@ -133,7 +133,6 @@ class Panel
|
||||
{
|
||||
for (Controller c : this.getControls())
|
||||
{
|
||||
// println("Control: " + c.getName());
|
||||
PVector pos = getControlPositions().get(c.getName());
|
||||
float x = pos.x+getOutline().getLeft();
|
||||
float y = pos.y+getOutline().getTop();
|
||||
@ -166,6 +165,13 @@ class Panel
|
||||
locked = true;
|
||||
}
|
||||
|
||||
// if there's no vector loaded, then hide vector controls
|
||||
if (getControlsToLockIfVectorNotLoaded().contains(c.getName()) && vectorFilename == null)
|
||||
{
|
||||
locked = true;
|
||||
}
|
||||
|
||||
|
||||
if (c.getName().equals(MODE_LOAD_VECTOR_FILE))
|
||||
{
|
||||
if (getVectorShape() != null)
|
||||
@ -211,6 +217,7 @@ class Panel
|
||||
this.getOutline().setHeight(getMinimumHeight());
|
||||
else
|
||||
this.getOutline().setHeight(h);
|
||||
|
||||
setControlPositions(buildControlPositionsForPanel(this));
|
||||
|
||||
float left = 0.0;
|
||||
|
@ -323,6 +323,7 @@ void button_mode_loadImage()
|
||||
getDisplayMachine().setImageFilename(null);
|
||||
}
|
||||
}
|
||||
|
||||
void button_mode_loadVectorFile()
|
||||
{
|
||||
if (getVectorShape() == null)
|
||||
@ -336,6 +337,7 @@ void button_mode_loadVectorFile()
|
||||
vectorFilename = null;
|
||||
}
|
||||
}
|
||||
|
||||
void numberbox_mode_pixelBrightThreshold(float value)
|
||||
{
|
||||
pixelExtractBrightThreshold = (int) value;
|
||||
@ -730,17 +732,11 @@ void numberbox_mode_previewCordOffsetValue(int value)
|
||||
previewQueue(true);
|
||||
}
|
||||
|
||||
void button_mode_cycleDensityPreviewStyle()
|
||||
void dropdown_mode_cycleDensityPreviewStyle(int index)
|
||||
{
|
||||
Controller c = cp5.getController(MODE_CYCLE_DENSITY_PREVIEW_STYLE);
|
||||
c.setLabel(this.controlLabels.get(MODE_CYCLE_DENSITY_PREVIEW_STYLE) + ": " + densityPreviewStyle);
|
||||
|
||||
if (densityPreviewStyle == DENSITY_PREVIEW_STYLE_COUNT) {
|
||||
densityPreviewStyle = 0;
|
||||
}
|
||||
else {
|
||||
densityPreviewStyle++;
|
||||
}
|
||||
println("In dropdown_mode_cycleDensityPreviewStyle");
|
||||
densityPreviewStyle = index;
|
||||
println("Style: " + densityPreviewStyle);
|
||||
}
|
||||
|
||||
void numberbox_mode_changeDensityPreviewPosterize(int value) {
|
||||
@ -760,20 +756,17 @@ void numberbox_mode_changePolygonizerLength(float value) {
|
||||
setupPolygonizer();
|
||||
}
|
||||
|
||||
|
||||
void button_mode_cyclePolygonizer()
|
||||
{
|
||||
|
||||
// this is a bit silly for only two choices
|
||||
if (polygonizer == 1) {
|
||||
polygonizer = 0;
|
||||
}
|
||||
else {
|
||||
polygonizer++;
|
||||
}
|
||||
void numberbox_mode_changePolygonizerAdaptativeAngle(float value) {
|
||||
println("numberbox_mode_changePolygonizerAdaptativeAngle");
|
||||
polygonizerAdaptativeAngle = value;
|
||||
setupPolygonizer();
|
||||
}
|
||||
|
||||
|
||||
void dropdown_mode_changePolygonizer(int value)
|
||||
{
|
||||
polygonizer = value;
|
||||
setupPolygonizer();
|
||||
Controller c = cp5.getController(MODE_CHANGE_POLYGONIZER);
|
||||
c.setLabel(this.controlLabels.get(MODE_CHANGE_POLYGONIZER) + ": " + polygonizer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,6 +83,14 @@ Set<String> getControlsToLockIfImageNotLoaded() {
|
||||
return this.controlsToLockIfImageNotLoaded;
|
||||
}
|
||||
|
||||
Set<String> getControlsToLockIfVectorNotLoaded() {
|
||||
if (this.controlsToLockIfVectorNotLoaded == null)
|
||||
{
|
||||
this.controlsToLockIfVectorNotLoaded = buildControlsToLockIfVectorNotLoaded();
|
||||
}
|
||||
return this.controlsToLockIfVectorNotLoaded;
|
||||
}
|
||||
|
||||
void hideAllControls() {
|
||||
for (String key : allControls.keySet())
|
||||
{
|
||||
@ -227,9 +235,37 @@ Set<String> buildControlsToLockIfImageNotLoaded()
|
||||
result.add(MODE_CHANGE_SAMPLE_AREA);
|
||||
result.add(MODE_SELECT_PICTUREFRAME);
|
||||
|
||||
result.add(MODE_CHANGE_PIXEL_SCALING);
|
||||
result.add(MODE_CHOOSE_CHROMA_KEY_COLOUR);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Set<String> buildControlsToLockIfVectorNotLoaded()
|
||||
{
|
||||
Set<String> result = new HashSet<String>();
|
||||
result.add(MODE_CHANGE_MIN_VECTOR_LINE_LENGTH);
|
||||
result.add(MODE_RESIZE_VECTOR);
|
||||
result.add(MODE_MOVE_VECTOR);
|
||||
result.add(MODE_CHANGE_POLYGONIZER_LENGTH);
|
||||
result.add(MODE_CHANGE_POLYGONIZER);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CallbackListener toFront = new CallbackListener() {
|
||||
public void controlEvent(CallbackEvent theEvent) {
|
||||
theEvent.getController().bringToFront();
|
||||
((ScrollableList)theEvent.getController()).open();
|
||||
}
|
||||
};
|
||||
|
||||
CallbackListener close = new CallbackListener() {
|
||||
public void controlEvent(CallbackEvent theEvent) {
|
||||
((ScrollableList)theEvent.getController()).close();
|
||||
}
|
||||
};
|
||||
|
||||
Map<String, Controller> buildAllControls()
|
||||
{
|
||||
|
||||
@ -243,6 +279,8 @@ Map<String, Controller> buildAllControls()
|
||||
{
|
||||
Button b = cp5.addButton(controlName, 0, 100, 100, 100, 100);
|
||||
b.setLabel(getControlLabels().get(controlName));
|
||||
controlP5.Label l = b.getCaptionLabel();
|
||||
l.getStyle().marginLeft = 4; //move to the right
|
||||
b.hide();
|
||||
map.put(controlName, b);
|
||||
// println("Added button " + controlName);
|
||||
@ -283,11 +321,29 @@ Map<String, Controller> buildAllControls()
|
||||
map.put(controlName, n);
|
||||
// println("Added numberbox " + controlName);
|
||||
}
|
||||
else if (controlName.startsWith("dropdown_"))
|
||||
{
|
||||
ScrollableList sl = cp5.addScrollableList(controlName, 100, 100, 100, 100);
|
||||
sl.setBarHeight(20);
|
||||
sl.setItemHeight(20);
|
||||
sl.setLabel(getControlLabels().get(controlName));
|
||||
sl.setType(ScrollableList.DROPDOWN);
|
||||
sl.onEnter(toFront);
|
||||
sl.onLeave(close);
|
||||
sl.setHeight(100);
|
||||
sl.hide();
|
||||
|
||||
controlP5.Label l = sl.getCaptionLabel();
|
||||
map.put(controlName, sl);
|
||||
println("Added dropdown " + controlName);
|
||||
}
|
||||
}
|
||||
|
||||
initialiseButtonValues(map);
|
||||
initialiseToggleValues(map);
|
||||
initialiseNumberboxValues(map);
|
||||
initialiseDropdownContents(map);
|
||||
initialiseDropdownValues(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
@ -298,12 +354,7 @@ Map<String, Controller> initialiseButtonValues(Map<String, Controller> map)
|
||||
if (key.startsWith("button_"))
|
||||
{
|
||||
Button n = (Button) map.get(key);
|
||||
|
||||
if (MODE_CYCLE_DENSITY_PREVIEW_STYLE.equals(key)) {
|
||||
n.setValue(densityPreviewStyle);
|
||||
n.setLabel(this.controlLabels.get(MODE_CYCLE_DENSITY_PREVIEW_STYLE) + ": " + densityPreviewStyle);
|
||||
}
|
||||
else if (MODE_CHANGE_POLYGONIZER.equals(key)) {
|
||||
if (MODE_CHANGE_POLYGONIZER.equals(key)) {
|
||||
n.setValue(polygonizer);
|
||||
n.setLabel(this.controlLabels.get(MODE_CHANGE_POLYGONIZER) + ": " + polygonizer);
|
||||
}
|
||||
@ -536,8 +587,8 @@ Map<String, Controller> initialiseNumberboxValues(Map<String, Controller> map)
|
||||
}
|
||||
else if (MODE_ADJUST_PREVIEW_CORD_OFFSET.equals(key))
|
||||
{
|
||||
n.setDecimalPrecision(0);
|
||||
n.setValue(0);
|
||||
n.setDecimalPrecision(2);
|
||||
n.setValue(0.0);
|
||||
n.setMultiplier(0.5);
|
||||
}
|
||||
else if (MODE_CHANGE_DENSITY_PREVIEW_POSTERIZE.equals(key))
|
||||
@ -553,7 +604,13 @@ Map<String, Controller> initialiseNumberboxValues(Map<String, Controller> map)
|
||||
n.setMin(1.0);
|
||||
n.setDecimalPrecision(1);
|
||||
n.setMultiplier(0.1);
|
||||
|
||||
}
|
||||
else if (MODE_CHANGE_POLYGONIZER_ADAPTATIVE_ANGLE.equals(key)) {
|
||||
n.setValue(polygonizerAdaptativeAngle);
|
||||
n.setMin(0.0);
|
||||
n.setMax(1.57079632679);
|
||||
n.setDecimalPrecision(2);
|
||||
n.setMultiplier(0.01);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -614,6 +671,51 @@ Map<String, Controller> initialiseToggleValues(Map<String, Controller> map)
|
||||
return map;
|
||||
}
|
||||
|
||||
Map<String, Controller> initialiseDropdownContents(Map<String, Controller> map)
|
||||
{
|
||||
println("Init dropdown contents");
|
||||
for (String key : map.keySet())
|
||||
{
|
||||
if (MODE_CYCLE_DENSITY_PREVIEW_STYLE.equals(key))
|
||||
{
|
||||
println("Adding " + key);
|
||||
ScrollableList sl = (ScrollableList) map.get(key);
|
||||
sl.setItems(densityPreviewStyles);
|
||||
}
|
||||
if (MODE_CHANGE_POLYGONIZER.equals(key))
|
||||
{
|
||||
println("Adding " + key);
|
||||
ScrollableList sl = (ScrollableList) map.get(key);
|
||||
sl.setItems(polygonizerStyles);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
Map<String, Controller> initialiseDropdownValues(Map<String, Controller> map)
|
||||
{
|
||||
println("Init dropdown values");
|
||||
for (String key : map.keySet())
|
||||
{
|
||||
if (MODE_CYCLE_DENSITY_PREVIEW_STYLE.equals(key))
|
||||
{
|
||||
println("Adding " + key);
|
||||
ScrollableList sl = (ScrollableList) map.get(key);
|
||||
sl.setValue(densityPreviewStyle);
|
||||
sl.close();
|
||||
}
|
||||
else if (MODE_CHANGE_POLYGONIZER.equals(key))
|
||||
{
|
||||
println("Adding " + key);
|
||||
ScrollableList sl = (ScrollableList) map.get(key);
|
||||
sl.setValue(polygonizer);
|
||||
sl.close();
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
String getControlLabel(String butName)
|
||||
{
|
||||
if (controlLabels.containsKey(butName))
|
||||
@ -642,6 +744,18 @@ Map<String, PVector> buildControlPositionsForPanel(Panel panel)
|
||||
col++;
|
||||
}
|
||||
}
|
||||
else if (controller.getName().startsWith("dropdown_"))
|
||||
{
|
||||
PVector p = new PVector(col*(DEFAULT_CONTROL_SIZE.x+CONTROL_SPACING.x), row*(DEFAULT_CONTROL_SIZE.y+CONTROL_SPACING.y));
|
||||
println(controller);
|
||||
map.put(controller.getName(), p);
|
||||
row++;
|
||||
if (p.y + (DEFAULT_CONTROL_SIZE.y*2) >= panel.getOutline().getHeight())
|
||||
{
|
||||
row = 0;
|
||||
col++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PVector p = new PVector(col*(DEFAULT_CONTROL_SIZE.x+CONTROL_SPACING.x), row*(DEFAULT_CONTROL_SIZE.y+CONTROL_SPACING.y));
|
||||
@ -671,6 +785,11 @@ Map<String, PVector> buildControlSizesForPanel(Panel panel)
|
||||
PVector s = new PVector(DEFAULT_CONTROL_SIZE.y, DEFAULT_CONTROL_SIZE.y);
|
||||
map.put(controller.getName(), s);
|
||||
}
|
||||
else if (controller.getName().startsWith("dropdown_"))
|
||||
{
|
||||
PVector s = new PVector(DEFAULT_CONTROL_SIZE.x, DEFAULT_CONTROL_SIZE.y * 4);
|
||||
map.put(controller.getName(), s);
|
||||
}
|
||||
else
|
||||
{
|
||||
PVector s = new PVector(DEFAULT_CONTROL_SIZE.x, DEFAULT_CONTROL_SIZE.y);
|
||||
@ -732,8 +851,6 @@ List<String> getControlNamesForInputPanel()
|
||||
controlNames.add(MODE_CHANGE_SAMPLE_AREA);
|
||||
controlNames.add(MODE_CHOOSE_CHROMA_KEY_COLOUR);
|
||||
controlNames.add(MODE_CHANGE_PIXEL_SCALING);
|
||||
controlNames.add(MODE_CHANGE_DENSITY_PREVIEW_POSTERIZE);
|
||||
controlNames.add(MODE_CYCLE_DENSITY_PREVIEW_STYLE);
|
||||
|
||||
controlNames.add(MODE_RENDER_PIXEL_DIALOG);
|
||||
// controlNames.add(MODE_DRAW_GRID);
|
||||
@ -744,20 +861,23 @@ List<String> getControlNamesForInputPanel()
|
||||
controlNames.add(MODE_LOAD_VECTOR_FILE);
|
||||
controlNames.add(MODE_RESIZE_VECTOR);
|
||||
controlNames.add(MODE_MOVE_VECTOR);
|
||||
controlNames.add(MODE_CHANGE_MIN_VECTOR_LINE_LENGTH);
|
||||
//controlNames.add(MODE_VECTOR_PATH_LENGTH_HIGHPASS_CUTOFF);
|
||||
controlNames.add(MODE_RENDER_VECTORS);
|
||||
|
||||
controlNames.add(MODE_ADJUST_PREVIEW_CORD_OFFSET);
|
||||
|
||||
controlNames.add(MODE_RENDER_VECTORS);
|
||||
controlNames.add(MODE_CHANGE_MIN_VECTOR_LINE_LENGTH);
|
||||
controlNames.add(MODE_CHANGE_POLYGONIZER);
|
||||
controlNames.add(MODE_CHANGE_POLYGONIZER_LENGTH);
|
||||
// controlNames.add(MODE_CHANGE_POLYGONIZER_ADAPTATIVE_ANGLE);
|
||||
|
||||
controlNames.add(MODE_SHOW_IMAGE);
|
||||
controlNames.add(MODE_SHOW_VECTOR);
|
||||
controlNames.add(MODE_SHOW_QUEUE_PREVIEW);
|
||||
controlNames.add(MODE_SHOW_DENSITY_PREVIEW);
|
||||
controlNames.add(MODE_SHOW_GUIDES);
|
||||
|
||||
controlNames.add(MODE_SHOW_DENSITY_PREVIEW);
|
||||
controlNames.add(MODE_PREVIEW_PIXEL_DENSITY_RANGE);
|
||||
controlNames.add(MODE_CHANGE_DENSITY_PREVIEW_POSTERIZE);
|
||||
controlNames.add(MODE_CYCLE_DENSITY_PREVIEW_STYLE);
|
||||
|
||||
|
||||
return controlNames;
|
||||
@ -1025,13 +1145,14 @@ Map<String, String> buildControlLabels()
|
||||
result.put(MODE_SEND_BUTTON_DEACTIVATE, "Deactivate button");
|
||||
|
||||
result.put(MODE_ADJUST_PREVIEW_CORD_OFFSET, "Cord offset");
|
||||
result.put(MODE_CYCLE_DENSITY_PREVIEW_STYLE, "Cycle preview style");
|
||||
result.put(MODE_CYCLE_DENSITY_PREVIEW_STYLE, "Density preview style");
|
||||
|
||||
result.put(MODE_CHANGE_DENSITY_PREVIEW_POSTERIZE, "Pixel posterize");
|
||||
result.put(MODE_PREVIEW_PIXEL_DENSITY_RANGE, "Show density range");
|
||||
|
||||
result.put(MODE_CHANGE_POLYGONIZER, "Cycle polygonizer");
|
||||
result.put(MODE_CHANGE_POLYGONIZER, "Polygonizer style");
|
||||
result.put(MODE_CHANGE_POLYGONIZER_LENGTH, "Polygonizer length");
|
||||
result.put(MODE_CHANGE_POLYGONIZER_ADAPTATIVE_ANGLE, "Polygonizer angle");
|
||||
|
||||
|
||||
return result;
|
||||
@ -1184,6 +1305,7 @@ Set<String> buildControlNames()
|
||||
|
||||
result.add(MODE_CHANGE_POLYGONIZER_LENGTH);
|
||||
result.add(MODE_CHANGE_POLYGONIZER);
|
||||
result.add(MODE_CHANGE_POLYGONIZER_ADAPTATIVE_ANGLE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -912,12 +912,12 @@ List<PVector> filterPointsLowPass(RPoint[] points, long filterParam, float scali
|
||||
{
|
||||
p = scaled.get(j);
|
||||
// and even then, only bother drawing if it's a move of over "x" steps
|
||||
int diffx = int(p.x) - int(result.get(result.size()-1).x);
|
||||
int diffy = int(p.y) - int(result.get(result.size()-1).y);
|
||||
int diffx = abs(int(p.x) - int(result.get(result.size()-1).x));
|
||||
int diffy = abs(int(p.y) - int(result.get(result.size()-1).y));
|
||||
|
||||
if (abs(diffx) > filterParam || abs(diffy) > filterParam)
|
||||
if (diffx > filterParam || diffy > filterParam)
|
||||
{
|
||||
println(j + ". Adding point " + p + ", last: " + result.get(result.size()-1));
|
||||
println(j + ". Adding point " + p + " because diffx (" + diffx + ") or diffy (" + diffy + ") is > " + filterParam + ", last: " + result.get(result.size()-1));
|
||||
result.add(p);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
Polargraph controller
|
||||
Copyright Sandy Noble 2015.
|
||||
Copyright Sandy Noble 2018.
|
||||
|
||||
This file is part of Polargraph Controller.
|
||||
|
||||
@ -35,11 +35,8 @@ import diewald_CV_kit.utility.*;
|
||||
import diewald_CV_kit.blobdetection.*;
|
||||
|
||||
import geomerative.*;
|
||||
//import org.apache.batik.svggen.font.table.*;
|
||||
//import org.apache.batik.svggen.font.*;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
|
||||
// for OSX
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
@ -58,7 +55,7 @@ import java.lang.reflect.Method;
|
||||
|
||||
int majorVersionNo = 2;
|
||||
int minorVersionNo = 5;
|
||||
int buildNo = 1;
|
||||
int buildNo = 2;
|
||||
|
||||
String programTitle = "Polargraph Controller v" + majorVersionNo + "." + minorVersionNo + " build " + buildNo;
|
||||
ControlP5 cp5;
|
||||
@ -340,16 +337,16 @@ static final String MODE_SEND_BUTTON_DEACTIVATE = "button_mode_sendButtonDeactiv
|
||||
|
||||
static final String MODE_ADJUST_PREVIEW_CORD_OFFSET = "numberbox_mode_previewCordOffsetValue";
|
||||
|
||||
static final String MODE_CYCLE_DENSITY_PREVIEW_STYLE = "button_mode_cycleDensityPreviewStyle";
|
||||
static final String MODE_CYCLE_DENSITY_PREVIEW_STYLE = "dropdown_mode_cycleDensityPreviewStyle";
|
||||
|
||||
static final String MODE_CHANGE_DENSITY_PREVIEW_POSTERIZE = "numberbox_mode_changeDensityPreviewPosterize";
|
||||
static final String MODE_PREVIEW_PIXEL_DENSITY_RANGE = "minitoggle_mode_previewPixelDensityRange";
|
||||
|
||||
static final String MODE_CHANGE_POLYGONIZER = "button_mode_cyclePolygonizer";
|
||||
static final String MODE_CHANGE_POLYGONIZER = "dropdown_mode_changePolygonizer";
|
||||
static final String MODE_CHANGE_POLYGONIZER_LENGTH = "numberbox_mode_changePolygonizerLength";
|
||||
static final String MODE_CHANGE_POLYGONIZER_ADAPTATIVE_ANGLE = "numberbox_mode_changePolygonizerAdaptativeAngle";
|
||||
|
||||
|
||||
|
||||
List<String> polygonizerStyles = Arrays.asList("ADAPTATIVE", "UNIFORMLENGTH");
|
||||
|
||||
|
||||
PVector statusTextPosition = new PVector(300.0, 12.0);
|
||||
@ -386,6 +383,8 @@ boolean displayingDensityPreview = false;
|
||||
|
||||
boolean displayingGuides = true;
|
||||
|
||||
|
||||
List<String> densityPreviewStyles = Arrays.asList("Round", "Diamond", "Native Simple", "Native Arc", "Round size", "Native size");
|
||||
static final int DENSITY_PREVIEW_STYLE_COUNT = 6;
|
||||
|
||||
static final int DENSITY_PREVIEW_ROUND = 0;
|
||||
@ -496,6 +495,7 @@ float vectorScaling = 100;
|
||||
PVector vectorPosition = new PVector(0.0,0.0);
|
||||
int minimumVectorLineLength = 2;
|
||||
public static final int VECTOR_FILTER_LOW_PASS = 0;
|
||||
public Set<String> controlsToLockIfVectorNotLoaded = null;
|
||||
|
||||
|
||||
String storeFilename = "comm.txt";
|
||||
@ -544,6 +544,7 @@ boolean rescaleDisplayMachine = true;
|
||||
// Polygonization. It's a geomerative thing.
|
||||
int polygonizer = 0;
|
||||
float polygonizerLength = 0.0;
|
||||
float polygonizerAdaptativeAngle = 0.0F;
|
||||
|
||||
void setup()
|
||||
{
|
||||
@ -1081,411 +1082,6 @@ void showGroupBox()
|
||||
|
||||
}
|
||||
|
||||
void loadImageWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run() {
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastImageDirectory != null) fc.setCurrentDirectory(lastImageDirectory);
|
||||
fc.setFileFilter(new ImageFileFilter());
|
||||
fc.setDialogTitle("Choose an image file...");
|
||||
|
||||
int returned = fc.showOpenDialog(frame);
|
||||
|
||||
lastImageDirectory = fc.getCurrentDirectory();
|
||||
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
// see if it's an image
|
||||
PImage img = loadImage(file.getPath());
|
||||
if (img != null)
|
||||
{
|
||||
img = null;
|
||||
getDisplayMachine().loadNewImageFromFilename(file.getPath());
|
||||
if (getDisplayMachine().pixelsCanBeExtracted() && isBoxSpecified())
|
||||
{
|
||||
getDisplayMachine().extractPixelsFromArea(getBoxVector1(), getBoxVectorSize(), getGridSize(), sampleArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class ImageFileFilter extends javax.swing.filechooser.FileFilter
|
||||
{
|
||||
public boolean accept(File file) {
|
||||
String filename = file.getName();
|
||||
filename.toLowerCase();
|
||||
if (file.isDirectory() || filename.endsWith(".png") || filename.endsWith(".jpg") || filename.endsWith(".jpeg"))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Image files (PNG or JPG)";
|
||||
}
|
||||
}
|
||||
|
||||
void loadVectorWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run() {
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastImageDirectory != null)
|
||||
{
|
||||
fc.setCurrentDirectory(lastImageDirectory);
|
||||
}
|
||||
|
||||
fc.setFileFilter(new VectorFileFilter());
|
||||
fc.setDialogTitle("Choose a vector file...");
|
||||
int returned = fc.showOpenDialog(frame);
|
||||
lastImageDirectory = fc.getCurrentDirectory();
|
||||
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
if (file.exists())
|
||||
{
|
||||
RShape shape = loadShapeFromFile(file.getPath());
|
||||
if (shape != null)
|
||||
{
|
||||
setVectorFilename(file.getPath());
|
||||
setVectorShape(shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
println("File not found (" + file.getPath() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class VectorFileFilter extends javax.swing.filechooser.FileFilter
|
||||
{
|
||||
public boolean accept(File file) {
|
||||
String filename = file.getName();
|
||||
filename.toLowerCase();
|
||||
if (file.isDirectory() || filename.endsWith(".svg") || isGCodeExtension(filename))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Vector graphic files (SVG, GCode)";
|
||||
}
|
||||
}
|
||||
|
||||
void loadNewPropertiesFilenameWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastPropertiesDirectory != null) fc.setCurrentDirectory(lastPropertiesDirectory);
|
||||
fc.setFileFilter(new PropertiesFileFilter());
|
||||
|
||||
fc.setDialogTitle("Choose a config file...");
|
||||
|
||||
int returned = fc.showOpenDialog(frame);
|
||||
|
||||
lastPropertiesDirectory = fc.getCurrentDirectory();
|
||||
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
if (file.exists())
|
||||
{
|
||||
println("New properties file exists.");
|
||||
newPropertiesFilename = file.toString();
|
||||
println("new propertiesFilename: "+ newPropertiesFilename);
|
||||
propertiesFilename = newPropertiesFilename;
|
||||
// clear old properties.
|
||||
props = null;
|
||||
loadFromPropertiesFile();
|
||||
|
||||
// set values of number spinners etc
|
||||
updateNumberboxValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class PropertiesFileFilter extends javax.swing.filechooser.FileFilter
|
||||
{
|
||||
public boolean accept(File file) {
|
||||
String filename = file.getName();
|
||||
filename.toLowerCase();
|
||||
if (file.isDirectory() || filename.endsWith(".properties.txt"))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Properties files (*.properties.txt)";
|
||||
}
|
||||
}
|
||||
|
||||
void saveNewPropertiesFileWithFileChooser()
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (lastPropertiesDirectory != null) fc.setCurrentDirectory(lastPropertiesDirectory);
|
||||
fc.setFileFilter(new PropertiesFileFilter());
|
||||
|
||||
fc.setDialogTitle("Enter a config file name...");
|
||||
|
||||
int returned = fc.showSaveDialog(frame);
|
||||
if (returned == JFileChooser.APPROVE_OPTION)
|
||||
{
|
||||
File file = fc.getSelectedFile();
|
||||
newPropertiesFilename = file.toString();
|
||||
newPropertiesFilename.toLowerCase();
|
||||
if (!newPropertiesFilename.endsWith(".properties.txt"))
|
||||
newPropertiesFilename+=".properties.txt";
|
||||
|
||||
println("new propertiesFilename: "+ newPropertiesFilename);
|
||||
propertiesFilename = newPropertiesFilename;
|
||||
savePropertiesFile();
|
||||
// clear old properties.
|
||||
props = null;
|
||||
loadFromPropertiesFile();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
RShape loadShapeFromFile(String filename) {
|
||||
RShape sh = null;
|
||||
if (filename.toLowerCase().endsWith(".svg")) {
|
||||
sh = RG.loadShape(filename);
|
||||
}
|
||||
else if (isGCodeExtension(filename)) {
|
||||
sh = loadShapeFromGCodeFile(filename);
|
||||
}
|
||||
return sh;
|
||||
}
|
||||
|
||||
|
||||
boolean isGCodeExtension(String filename) {
|
||||
return (filename.toLowerCase().endsWith(".gcode") || filename.toLowerCase().endsWith(".g") || filename.toLowerCase().endsWith(".ngc") || filename.toLowerCase().endsWith(".txt"));
|
||||
}
|
||||
|
||||
|
||||
int countLines(String filename) throws IOException {
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(filename));
|
||||
try {
|
||||
byte[] c = new byte[1024];
|
||||
int count = 0;
|
||||
int readChars = 0;
|
||||
boolean empty = true;
|
||||
while ((readChars = is.read(c)) != -1) {
|
||||
empty = false;
|
||||
for (int i = 0; i < readChars; ++i) {
|
||||
if (c[i] == '\n') {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (count == 0 && !empty) ? 1 : count+1;
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
RShape loadShapeFromGCodeFile(String filename) {
|
||||
noLoop();
|
||||
RShape parent = null;
|
||||
BufferedReader reader = null;
|
||||
long totalPoints = 0;
|
||||
long time = millis();
|
||||
long countLines = 0;
|
||||
|
||||
try {
|
||||
countLines = countLines(filename);
|
||||
println("" + countLines + " lines found.");
|
||||
if (countLines < 1) {
|
||||
throw new IOException("No lines found in GCode file.");
|
||||
}
|
||||
reader = createReader(filename);
|
||||
parent = new RShape();
|
||||
String line;
|
||||
boolean drawLine = false;
|
||||
int gCodeZAxisChanges = 0;
|
||||
|
||||
long lineNo = 0;
|
||||
float lastPercent = 0.0f;
|
||||
boolean reportStatus = true;
|
||||
while ((line = reader.readLine ()) != null) {
|
||||
lineNo++;
|
||||
// println("Line: " + line);
|
||||
|
||||
if (reportStatus) {
|
||||
float percent = ((float)lineNo / (float)countLines) * 100.0;
|
||||
println("----" + percent + "% of the way through.");
|
||||
lastPercent = percent;
|
||||
}
|
||||
|
||||
if (line.toUpperCase().startsWith("G")) {
|
||||
if (reportStatus) {
|
||||
println(new StringBuilder().append(lineNo).append(" of ").append(countLines).append(": ").append(line).append(". Points: ").append(totalPoints).toString());
|
||||
long free = Runtime.getRuntime().freeMemory();
|
||||
long maximum = Runtime.getRuntime().maxMemory();
|
||||
println(new StringBuilder().append("Free: ").append(free).append(", max: ").append(maximum).toString());
|
||||
}
|
||||
|
||||
Map<String, Float> ins = null;
|
||||
try {
|
||||
ins = unpackGCodeInstruction(line);
|
||||
}
|
||||
catch (Exception e) {
|
||||
println(e.toString());
|
||||
continue;
|
||||
}
|
||||
// println("Ins: " + ins);
|
||||
Integer code = Math.round(ins.get("G"));
|
||||
|
||||
Float z = ins.get("Z");
|
||||
if (z != null) {
|
||||
gCodeZAxisChanges++;
|
||||
if (gCodeZAxisChanges == 2) {
|
||||
println("Assume second z axis change is to drop the pen to start drawing " + z);
|
||||
gcodeZAxisDrawingHeight = z;
|
||||
drawLine = true;
|
||||
}
|
||||
else if (gCodeZAxisChanges > 2) {
|
||||
drawLine = isGCodeZAxisForDrawing(z);
|
||||
}
|
||||
else {
|
||||
println("Assume first z axis change is to RAISE the pen " + z);
|
||||
drawLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
Float x = ins.get("X");
|
||||
Float y = ins.get("Y");
|
||||
if (x != null && y == null) {
|
||||
// move x axis only, use y of last
|
||||
RPoint[][] points = parent.getPointsInPaths();
|
||||
RPoint rp = points[points.length-1][points[points.length-1].length-1];
|
||||
y = rp.y;
|
||||
}
|
||||
else if (x == null && y != null) {
|
||||
// move y axis only, use x of last
|
||||
RPoint[][] points = parent.getPointsInPaths();
|
||||
RPoint rp = points[points.length-1][points[points.length-1].length-1];
|
||||
x = rp.x;
|
||||
}
|
||||
|
||||
if (x != null && y != null) {
|
||||
// move both x and y axis
|
||||
if (drawLine) {
|
||||
parent.addLineTo(x, y);
|
||||
}
|
||||
else {
|
||||
parent.addMoveTo(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
|
||||
if ((millis() - time) > 500) {
|
||||
time = millis();
|
||||
reportStatus = true;
|
||||
}
|
||||
else {
|
||||
reportStatus = false;
|
||||
}
|
||||
|
||||
if (lineNo == (countLines-1)) {
|
||||
reportStatus = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
println("IOExecption reading lines from the gcode file " + filename);
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
reader.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
println("IOException closing the gcode file " + filename);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
RPoint[][] points = parent.getPointsInPaths();
|
||||
totalPoints = 0;
|
||||
if (points != null) {
|
||||
for (int i = 0; i<points.length; i++) {
|
||||
if (points[i] != null) {
|
||||
for (int j = 0; j<points[i].length; j++) {
|
||||
totalPoints++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String conclusionMessage = "Imported " + totalPoints + " points from " + countLines + " lines of code in the file.";
|
||||
println(conclusionMessage);
|
||||
javax.swing.JOptionPane.showMessageDialog(null, conclusionMessage);
|
||||
|
||||
loop();
|
||||
return parent;
|
||||
}
|
||||
|
||||
Boolean isGCodeZAxisForDrawing(float z) {
|
||||
return gcodeZAxisDrawingHeight.compareTo(z) == 0;
|
||||
}
|
||||
|
||||
Map<String, Float> unpackGCodeInstruction(String line) throws Exception {
|
||||
Map<String, Float> instruction = new HashMap<String, Float>(4);
|
||||
try {
|
||||
String[] splitted = line.trim().split(" ");
|
||||
for (int i = 0; i < splitted.length; i++) {
|
||||
// remove ; character
|
||||
splitted[i] = splitted[i].replace(";", "");
|
||||
String axis = splitted[i].substring(0, 1);
|
||||
String sanitisedValue = splitted[i].substring(1);
|
||||
sanitisedValue = sanitisedValue.replace(",", ".");
|
||||
Float value = Float.parseFloat(sanitisedValue);
|
||||
if ("X".equalsIgnoreCase(axis) || "Y".equalsIgnoreCase(axis) || "Z".equalsIgnoreCase(axis) || "G".equalsIgnoreCase(axis)) {
|
||||
instruction.put(axis.toUpperCase(), value);
|
||||
}
|
||||
}
|
||||
// println("instruction: " + instruction);
|
||||
if (instruction.isEmpty()) {
|
||||
throw new Exception("Empty instruction");
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
println("Number format exception: " + nfe.getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("e: " + e);
|
||||
throw new Exception("Exception while reading the lines from a gcode file: " + line + ", " + e.getMessage());
|
||||
}
|
||||
|
||||
return instruction;
|
||||
}
|
||||
|
||||
|
||||
void setPictureFrameDimensionsToBox()
|
||||
@ -1799,7 +1395,7 @@ void mouseClicked()
|
||||
if (getDisplayMachine().pixelsCanBeExtracted() && isBoxSpecified())
|
||||
getDisplayMachine().extractPixelsFromArea(getBoxVector1(), getBoxVectorSize(), getGridSize(), sampleArea);
|
||||
}
|
||||
else if (currentMode.equals(MODE_MOVE_VECTOR))
|
||||
else if (currentMode.equals(MODE_MOVE_VECTOR) && vectorShape != null)
|
||||
{
|
||||
// offset mouse vector so it grabs the centre of the shape
|
||||
PVector centroid = new PVector(getVectorShape().width/2, getVectorShape().height/2);
|
||||
@ -1934,23 +1530,23 @@ void leftButtonMachineClick()
|
||||
void mouseWheel(int delta)
|
||||
{
|
||||
noLoop();
|
||||
|
||||
if (mouseOverMachine()) {
|
||||
// get the mouse position on the machine, before changing the machine scaling
|
||||
PVector pos = getDisplayMachine().scaleToDisplayMachine(getMouseVector());
|
||||
changeMachineScaling(delta);
|
||||
|
||||
// now work out what the machine position needs to be to line the pos up with mousevector again
|
||||
PVector scaledPos = getDisplayMachine().scaleToDisplayMachine(getMouseVector());
|
||||
// println("original pos: " + pos);
|
||||
// println("scaled pos: " + scaledPos);
|
||||
|
||||
PVector change = PVector.sub(scaledPos, pos);
|
||||
// println("change: " + change);
|
||||
|
||||
// and adjust for the new scaling factor
|
||||
change.mult(machineScaling);
|
||||
|
||||
// finally update the machine offset (position)
|
||||
getDisplayMachine().getOffset().add(change);
|
||||
}
|
||||
|
||||
loop();
|
||||
}
|
||||
|
||||
@ -3082,6 +2678,9 @@ void loadFromPropertiesFile()
|
||||
// println("home point loaded: " + homePointCartesian + ", " + getHomePoint());
|
||||
|
||||
// Geomerative stuff
|
||||
println("RG.ADAPTATIVE is " + RG.ADAPTATIVE);
|
||||
println("RG.UNIFORMLENGTH is " + RG.UNIFORMLENGTH);
|
||||
println("RG.UNIFORMSTEP is " + RG.UNIFORMSTEP);
|
||||
polygonizer = getIntProperty("controller.geomerative.polygonizer", RG.ADAPTATIVE);
|
||||
polygonizerLength = getFloatProperty("controller.geomerative.polygonizerLength", 1.0);
|
||||
setupPolygonizer();
|
||||
@ -3342,12 +2941,15 @@ Integer getBaudRate()
|
||||
void setupPolygonizer() {
|
||||
RG.setPolygonizer(polygonizer); // http://www.polargraph.co.uk/forum/polargraphs-group2/troubleshooting-forum5/svg-differences-between-polargraphcontroller-2-1-1-2-3-0-thread523.0
|
||||
switch(polygonizer) {
|
||||
case 1: RG.setPolygonizerLength(polygonizerLength); break;
|
||||
// case 0:
|
||||
// RG.setPolygonizerAngle(polygonizerAdaptativeAngle);
|
||||
// break;
|
||||
case 1:
|
||||
RG.setPolygonizerLength(polygonizerLength);
|
||||
break;
|
||||
}
|
||||
}
|
||||
println("Polygonizer: " + polygonizer);
|
||||
println("PolygonizerLength: " + polygonizerLength);
|
||||
|
||||
}
|
||||
void initLogging()
|
||||
{
|
||||
try
|
||||
|
Loading…
Reference in New Issue
Block a user