From c0e3a6f65e4b75ad88d2e1bf4b538abcc55a84be Mon Sep 17 00:00:00 2001 From: Joacim Breiler Date: Tue, 2 Jan 2024 18:09:59 +0100 Subject: [PATCH] Fixes to the designer * Now only does one pass if the start and target depth are the same * Added undoable actions for the shape settings --- .../designer/actions/ChangeFontAction.java | 49 ++++++++++ .../designer/actions/ChangeTextAction.java | 49 ++++++++++ .../ugs/nbp/designer/actions/MoveAction.java | 11 ++- .../nbp/designer/actions/ResizeAction.java | 7 +- .../nbp/designer/actions/RotateAction.java | 7 +- .../entities/controls/ResizeUtils.java | 4 +- .../entities/cuttable/AbstractCuttable.java | 6 +- .../nbp/designer/entities/cuttable/Text.java | 27 +++++ .../ugs/nbp/designer/gui/MultiplyDialog.java | 32 +++--- .../designer/gui/SelectionSettingsPanel.java | 50 +++++++--- .../designer/gui/tree/EntityCellRenderer.java | 21 +++- .../io/gcode/toolpaths/AbstractToolPath.java | 20 +++- .../gcode/toolpaths/DrillCenterToolPath.java | 21 +++- .../io/gcode/toolpaths/OutlineToolPath.java | 19 ++-- .../io/gcode/toolpaths/PocketToolPath.java | 6 +- .../ugs/nbp/designer/model/Settings.java | 22 ++++- .../gcode/toolpaths/OutlineToolPathTest.java | 98 +++++++++++++++++++ .../gcode/toolpaths/PocketToolPathTest.java | 4 +- .../ugs/nbp/designer/model/SettingsTest.java | 83 ++++++++++++++++ 19 files changed, 477 insertions(+), 59 deletions(-) create mode 100644 ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeFontAction.java create mode 100644 ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeTextAction.java create mode 100644 ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPathTest.java create mode 100644 ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/model/SettingsTest.java diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeFontAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeFontAction.java new file mode 100644 index 0000000000..e042522b96 --- /dev/null +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeFontAction.java @@ -0,0 +1,49 @@ +/* + Copyright 2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ +package com.willwinder.ugs.nbp.designer.actions; + +import com.willwinder.ugs.nbp.designer.entities.cuttable.Text; + +public class ChangeFontAction implements UndoableAction { + + private final Text entity; + private final String newFont; + private final String oldFont; + + public ChangeFontAction(Text entity, String font) { + this.entity = entity; + this.newFont = font; + this.oldFont = entity.getFontFamily(); + } + + @Override + public void redo() { + entity.setFontFamily(newFont); + } + + @Override + public void undo() { + entity.setFontFamily(oldFont); + } + + @Override + public String toString() { + return "changed font"; + } +} diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeTextAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeTextAction.java new file mode 100644 index 0000000000..1bf31257d9 --- /dev/null +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ChangeTextAction.java @@ -0,0 +1,49 @@ +/* + Copyright 2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ +package com.willwinder.ugs.nbp.designer.actions; + +import com.willwinder.ugs.nbp.designer.entities.cuttable.Text; + +public class ChangeTextAction implements UndoableAction { + + private final Text entity; + private final String newText; + private final String oldText; + + public ChangeTextAction(Text entity, String text) { + this.entity = entity; + this.newText = text; + this.oldText = entity.getText(); + } + + @Override + public void redo() { + entity.setText(newText); + } + + @Override + public void undo() { + entity.setText(oldText); + } + + @Override + public String toString() { + return "changed text"; + } +} diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/MoveAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/MoveAction.java index a25a8c2ea7..baf757bf7c 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/MoveAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/MoveAction.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -21,6 +21,7 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.entities.Entity; import java.awt.geom.Point2D; +import java.util.ArrayList; import java.util.List; /** @@ -40,12 +41,12 @@ public class MoveAction implements DrawAction, UndoableAction { * original position. * * @param entityList a selection which contains the shapes to be moved - * @param m the amount the shapes should be moved, relative to the + * @param deltaMovement the amount the shapes should be moved, relative to the * original position */ - public MoveAction(List entityList, Point2D m) { - this.entityList = entityList; - this.movement = m; + public MoveAction(List entityList, Point2D deltaMovement) { + this.entityList = new ArrayList<>(entityList); + this.movement = deltaMovement; } public void execute() { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java index b41a424a66..9de6841fd3 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ResizeAction.java @@ -1,5 +1,5 @@ /* - Copyright 2022 Will Winder + Copyright 2022-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -59,4 +59,9 @@ public void undo() { entityGroup.addAll(entities); ResizeUtils.performScaling(entityGroup, location, newSize, originalSize); } + + @Override + public String toString() { + return "resize entity"; + } } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/RotateAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/RotateAction.java index 1ad894a412..4b4ae1aa9d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/RotateAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/RotateAction.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -21,6 +21,7 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.entities.Entity; import java.awt.geom.Point2D; +import java.util.ArrayList; import java.util.List; /** @@ -45,9 +46,9 @@ public class RotateAction implements DrawAction, UndoableAction { * @param rotation the amount the shapes should be rotated, relative to the */ public RotateAction(List entityList, Point2D center, double rotation) { - this.entityList = entityList; + this.entityList = new ArrayList<>(entityList); this.rotation = rotation; - this.center = center; + this.center = new Point2D.Double(center.getX(), center.getY()); } public void execute() { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java index 2dcee49d4e..077e277fa4 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/controls/ResizeUtils.java @@ -1,5 +1,5 @@ /* - Copyright 2022 Will Winder + Copyright 2022-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -47,7 +47,7 @@ public static Point2D getDeltaMovement(Location location, Size size, Size newSiz public static void performScaling(Entity target, Location location, Size originalSize, Size newSize) { // Do not scale if the entity will become too small after operation - if (newSize.getWidth() < 1 || newSize.getHeight() < 1) { + if (newSize.getWidth() <= 0 || newSize.getHeight() <= 0) { return; } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/AbstractCuttable.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/AbstractCuttable.java index 764de5b649..f0547c77d0 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/AbstractCuttable.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/AbstractCuttable.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -91,7 +91,7 @@ public void render(Graphics2D graphics, Drawing drawing) { BasicStroke dashedStroke = new BasicStroke(strokeWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[]{dashWidth, dashWidth}, 0); Shape shape = getShape(); - if (getCutType() != CutType.NONE && getTargetDepth() == 0) { + if (getCutType() == CutType.NONE) { drawShape(graphics, dashedStroke, Colors.SHAPE_HINT, shape); } else if (getCutType() == CutType.POCKET) { graphics.setStroke(new BasicStroke(strokeWidth)); @@ -137,7 +137,7 @@ public Rectangle2D getBounds() { } private Color getCutColor() { - int color = Math.max(0, Math.min(255, (int) Math.round(255d * getCutAlpha()) - 25)); + int color = Math.max(0, Math.min(255, (int) Math.round(255d * getCutAlpha()) - 50)); return new Color(color, color, color); } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/Text.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/Text.java index 477cf172d1..7cc3c39f8d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/Text.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/entities/cuttable/Text.java @@ -1,6 +1,26 @@ +/* + Copyright 2021-2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ package com.willwinder.ugs.nbp.designer.entities.cuttable; import com.willwinder.ugs.nbp.designer.entities.Entity; +import com.willwinder.ugs.nbp.designer.entities.EntityEvent; +import com.willwinder.ugs.nbp.designer.entities.EventType; import org.apache.commons.lang3.StringUtils; import java.awt.Font; @@ -11,6 +31,11 @@ import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +/** + * A cuttable text shape + * + * @author Joacim Breiler + */ public class Text extends AbstractCuttable { private String text; private String fontFamily; @@ -41,6 +66,8 @@ private void regenerateShape() { // Create a temporary shape shape = transform.createTransformedShape(new Rectangle2D.Double(0, 0, 2, 12)); } + + notifyEvent(new EntityEvent(this, EventType.RESIZED)); } @Override diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/MultiplyDialog.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/MultiplyDialog.java index 5fb6978dc8..1e9d29289d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/MultiplyDialog.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/MultiplyDialog.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -23,15 +23,22 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.logic.Controller; import net.miginfocom.swing.MigLayout; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; +import java.awt.Dimension; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.geom.Point2D; import java.util.List; -import java.util.stream.Collectors; /** * @author Joacim Breiler @@ -39,6 +46,7 @@ This file is part of Universal Gcode Sender (UGS). public class MultiplyDialog extends JDialog implements ChangeListener, WindowListener { public static final int PADDING = 2; public static final String PANEL_LAYOUT_CONFIG = "fill, insets 2"; + public static final String SPINNER_COL_CONSTRAINTS = "width 60:100:100, wrap"; private JSpinner xCountSpinner; private JSpinner xSpacingSpinner; @@ -56,9 +64,9 @@ public MultiplyDialog(Controller controller) { this.controller.getDrawing().insertEntity(entityGroup); entityGroup.setName("Temporary multiplier group"); setTitle("Multiply object"); - setPreferredSize(new Dimension(360, 200)); + setPreferredSize(new Dimension(400, 200)); setLayout(new MigLayout("fill, insets 5", "", "")); - setResizable(false); + setResizable(true); createComponents(); addEventListeners(); @@ -84,11 +92,11 @@ private void createComponents() { BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING))); horizontalPanel.add(new JLabel("X Columns", SwingConstants.TRAILING), "grow"); xCountSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 1000, 1)); - horizontalPanel.add(xCountSpinner, "wrap"); + horizontalPanel.add(xCountSpinner, SPINNER_COL_CONSTRAINTS); horizontalPanel.add(new JLabel("X Spacing", SwingConstants.TRAILING), "grow"); xSpacingSpinner = new JSpinner(new SpinnerNumberModel(1d, 0.001, 1000, .1)); - horizontalPanel.add(xSpacingSpinner, "wrap"); + horizontalPanel.add(xSpacingSpinner, SPINNER_COL_CONSTRAINTS); add(horizontalPanel, "grow"); JPanel verticalPanel = new JPanel(new MigLayout(PANEL_LAYOUT_CONFIG)); @@ -97,14 +105,14 @@ private void createComponents() { BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING))); verticalPanel.add(new JLabel("Y Rows", SwingConstants.TRAILING), "grow"); yCountSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 1000, 1)); - verticalPanel.add(yCountSpinner, "wrap"); + verticalPanel.add(yCountSpinner, SPINNER_COL_CONSTRAINTS); verticalPanel.add(new JLabel("Y Spacing", SwingConstants.TRAILING), "grow"); ySpacingSpinner = new JSpinner(new SpinnerNumberModel(1d, 0.001, 1000, .1)); - verticalPanel.add(ySpacingSpinner, "wrap"); + verticalPanel.add(ySpacingSpinner, SPINNER_COL_CONSTRAINTS); add(verticalPanel, "grow, wrap"); - JPanel buttonPanel = new JPanel(new MigLayout("insets 0", "[center, grow]")); + JPanel buttonPanel = new JPanel(new MigLayout("insets 5", "[center, grow]")); cancelButton = new JButton("Cancel"); buttonPanel.add(cancelButton); @@ -144,7 +152,7 @@ public void stateChanged(ChangeEvent e) { EntityGroup selection = new EntityGroup(); selection.addAll(controller.getSelectionManager().getSelection().stream() .map(Entity::copy) - .collect(Collectors.toList())); + .toList()); for (int x = 0; x < (int) xCountSpinner.getValue(); x++) { for (int y = 0; y < (int) yCountSpinner.getValue(); y++) { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/SelectionSettingsPanel.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/SelectionSettingsPanel.java index 85dec8292c..2ecdedfdc3 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/SelectionSettingsPanel.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/SelectionSettingsPanel.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -20,11 +20,17 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.Utils; import com.willwinder.ugs.nbp.designer.actions.ChangeCutSettingsAction; +import com.willwinder.ugs.nbp.designer.actions.ChangeFontAction; +import com.willwinder.ugs.nbp.designer.actions.ChangeTextAction; +import com.willwinder.ugs.nbp.designer.actions.MoveAction; +import com.willwinder.ugs.nbp.designer.actions.ResizeAction; +import com.willwinder.ugs.nbp.designer.actions.RotateAction; import com.willwinder.ugs.nbp.designer.entities.Anchor; import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.entities.EntityEvent; import com.willwinder.ugs.nbp.designer.entities.EntityListener; import com.willwinder.ugs.nbp.designer.entities.EventType; +import com.willwinder.ugs.nbp.designer.entities.controls.Location; import com.willwinder.ugs.nbp.designer.entities.cuttable.CutType; import com.willwinder.ugs.nbp.designer.entities.cuttable.Cuttable; import com.willwinder.ugs.nbp.designer.entities.cuttable.Text; @@ -33,6 +39,7 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.gui.anchor.AnchorListener; import com.willwinder.ugs.nbp.designer.gui.anchor.AnchorSelectorPanel; import com.willwinder.ugs.nbp.designer.logic.Controller; +import com.willwinder.ugs.nbp.designer.logic.ControllerFactory; import com.willwinder.ugs.nbp.designer.model.Size; import com.willwinder.universalgcodesender.uielements.TextFieldUnit; import com.willwinder.universalgcodesender.uielements.TextFieldWithUnit; @@ -65,7 +72,6 @@ This file is part of Universal Gcode Sender (UGS). import java.awt.geom.Point2D; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; /** * @author Joacim Breiler @@ -292,13 +298,18 @@ public void removeUpdate(DocumentEvent e) { @Override public void changedUpdate(DocumentEvent e) { + if (controller.getSelectionManager().isEmpty()) { + return; + } + controller.getSelectionManager().removeListener(this); if (StringUtils.isNotEmpty(rotation.getText()) && e.getDocument() == rotation.getDocument()) { try { double angle = Utils.parseDouble(rotation.getText()); - controller.getSelectionManager().setRotation(angle); - controller.getDrawing().repaint(); + RotateAction rotateAction = new RotateAction(controller.getSelectionManager().getSelection(), controller.getSelectionManager().getCenter(), angle); + rotateAction.execute(); + ControllerFactory.getUndoManager().addAction(rotateAction); } catch (NumberFormatException ex) { // never mind } @@ -309,8 +320,10 @@ public void changedUpdate(DocumentEvent e) { double y = Utils.parseDouble(posYTextField.getText()); Point2D position = controller.getSelectionManager().getPosition(anchor); position.setLocation(x - position.getX(), y - position.getY()); - controller.getSelectionManager().move(position); - controller.getDrawing().repaint(); + + MoveAction moveAction = new MoveAction(controller.getSelectionManager().getSelection(), position); + moveAction.execute(); + ControllerFactory.getUndoManager().addAction(moveAction); } if (StringUtils.isNotEmpty(widthTextField.getText()) && StringUtils.isNotEmpty(heightTextField.getText()) && (e.getDocument() == widthTextField.getDocument() || e.getDocument() == heightTextField.getDocument())) { @@ -318,7 +331,7 @@ public void changedUpdate(DocumentEvent e) { double width = Utils.parseDouble(widthTextField.getText()); double height = Utils.parseDouble(heightTextField.getText()); - if (width >= 0 && height >= 0 & !lockRatioButton.isSelected()) { + if (width >= 0 && height >= 0 && !lockRatioButton.isSelected()) { double ratio = controller.getSelectionManager().getSize().getRatio(); if (e.getDocument() == widthTextField.getDocument()) { height = width / ratio; @@ -329,8 +342,9 @@ public void changedUpdate(DocumentEvent e) { } } - controller.getSelectionManager().setSize(new Size(width, height)); - controller.getDrawing().repaint(); + ResizeAction resizeAction = new ResizeAction(controller.getSelectionManager().getSelection(), Location.TOP_RIGHT, controller.getSelectionManager().getSize(), new Size(width, height)); + resizeAction.redo(); + ControllerFactory.getUndoManager().addAction(resizeAction); } catch (NumberFormatException ex) { // never mind } @@ -338,9 +352,18 @@ public void changedUpdate(DocumentEvent e) { if (!controller.getSelectionManager().isEmpty()) { Entity entity = controller.getSelectionManager().getSelection().get(0); - if (entity instanceof Text) { - ((Text) entity).setText(textTextField.getText()); - ((Text) entity).setFontFamily((String) fontDropDown.getSelectedItem()); + if (entity instanceof Text text) { + if (!text.getText().equals(textTextField.getText())) { + ChangeTextAction changeTextAction = new ChangeTextAction(text, textTextField.getText()); + changeTextAction.redo(); + ControllerFactory.getUndoManager().addAction(changeTextAction); + } + + if (!text.getFontFamily().equals(fontDropDown.getSelectedItem())) { + ChangeFontAction changeFontAction = new ChangeFontAction(text, (String) fontDropDown.getSelectedItem()); + changeFontAction.redo(); + ControllerFactory.getUndoManager().addAction(changeFontAction); + } } controller.getDrawing().repaint(); } @@ -359,7 +382,8 @@ public void stateChanged(ChangeEvent e) { List cuttables = controller.getSelectionManager().getSelection().stream() .filter(Cuttable.class::isInstance) - .map(Cuttable.class::cast).collect(Collectors.toList()); + .map(Cuttable.class::cast) + .toList(); if (!cuttables.isEmpty()) { double startDepth = (Double) startDepthSpinner.getValue(); diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/tree/EntityCellRenderer.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/tree/EntityCellRenderer.java index 224726e384..2a88681000 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/tree/EntityCellRenderer.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/tree/EntityCellRenderer.java @@ -1,3 +1,21 @@ +/* + Copyright 2021-2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ package com.willwinder.ugs.nbp.designer.gui.tree; import com.willwinder.ugs.nbp.designer.Utils; @@ -30,8 +48,7 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean UnitUtils.Units preferredUnits = backendAPI.getSettings().getPreferredUnits(); Object treeObject = getUserObject(value); - if (leaf && treeObject instanceof Cuttable) { - Cuttable cuttable = (Cuttable) treeObject; + if (leaf && treeObject instanceof Cuttable cuttable) { CutType cutType = cuttable.getCutType(); double cutDepth = UnitUtils.scaleUnits(UnitUtils.Units.MM, preferredUnits) * cuttable.getTargetDepth(); if (cuttable.isHidden()) { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/AbstractToolPath.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/AbstractToolPath.java index 02d5aafc4f..c9413a5778 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/AbstractToolPath.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/AbstractToolPath.java @@ -1,3 +1,21 @@ +/* + Copyright 2021-2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ package com.willwinder.ugs.nbp.designer.io.gcode.toolpaths; import com.willwinder.ugs.nbp.designer.io.gcode.path.GcodePath; @@ -45,7 +63,7 @@ public double getStartDepth() { } public void setStartDepth(double startDepth) { - this.startDepth = startDepth; + this.startDepth = Math.abs(startDepth); } public void setTargetDepth(double targetDepth) { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/DrillCenterToolPath.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/DrillCenterToolPath.java index 0620da0037..57e179a26f 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/DrillCenterToolPath.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/DrillCenterToolPath.java @@ -1,3 +1,21 @@ +/* + Copyright 2021-2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ package com.willwinder.ugs.nbp.designer.io.gcode.toolpaths; import com.willwinder.ugs.nbp.designer.entities.cuttable.Cuttable; @@ -25,8 +43,9 @@ public GcodePath toGcodePath() { PartialPosition centerPosition = getCenterPosition(); GcodePath gcodePath = new GcodePath(); addSafeHeightSegmentTo(gcodePath, centerPosition); + addDepthSegment(gcodePath, getStartDepth()); - double currentDepth = getStartDepth() - getDepthPerPass(); + double currentDepth = getStartDepth(); while (currentDepth < getTargetDepth()) { currentDepth += getDepthPerPass(); if (currentDepth > getTargetDepth()) { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPath.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPath.java index 00ab46d79a..669a044ea3 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPath.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPath.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -26,7 +26,6 @@ This file is part of Universal Gcode Sender (UGS). import java.awt.geom.Area; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * @author Joacim Breiler @@ -56,24 +55,28 @@ public GcodePath toGcodePath() { geometries.forEach(g -> { List geometryCoordinates = ToolPathUtils.geometryToCoordinates(g); - double currentDepth = getStartDepth() - getDepthPerPass(); - while (currentDepth < getTargetDepth()) { + addGeometriesToCoordinateList(coordinateList, geometryCoordinates, getStartDepth()); + double currentDepth = getStartDepth(); + while (currentDepth < getTargetDepth()) { currentDepth += getDepthPerPass(); if (currentDepth > getTargetDepth()) { currentDepth = getTargetDepth(); } - final double depth = -currentDepth; - coordinateList.add(geometryCoordinates.stream() - .map(numericCoordinate -> PartialPosition.builder(numericCoordinate).setZ(depth).build()) - .collect(Collectors.toList())); + addGeometriesToCoordinateList(coordinateList, geometryCoordinates, currentDepth); } }); return toGcodePath(coordinateList); } + private static void addGeometriesToCoordinateList(ArrayList> coordinateList, List geometryCoordinates, double depth) { + coordinateList.add(geometryCoordinates.stream() + .map(numericCoordinate -> PartialPosition.builder(numericCoordinate).setZ(-depth).build()) + .toList()); + } + public void setOffset(double offset) { this.offset = offset; } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPath.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPath.java index 789e1a03d9..6696779c44 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPath.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPath.java @@ -1,5 +1,5 @@ /* - Copyright 2023 Will Winder + Copyright 2023-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -53,7 +53,9 @@ public GcodePath toGcodePath() { List geometries = bufferAndCollectGeometries(geometryCollection, getToolDiameter(), stepOver); List> coordinateList = new ArrayList<>(); - double currentDepth = getStartDepth() - getDepthPerPass(); + addGeometriesToCoordinatesList(shell, geometries, coordinateList, getStartDepth()); + + double currentDepth = getStartDepth(); while (currentDepth < getTargetDepth()) { currentDepth += getDepthPerPass(); if (currentDepth > getTargetDepth()) { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Settings.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Settings.java index 17a50ef948..aa0ceaceac 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Settings.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/model/Settings.java @@ -1,5 +1,5 @@ /* - Copyright 2021 Will Winder + Copyright 2021-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -72,7 +72,7 @@ public double getToolDiameter() { } public void setToolDiameter(double toolDiameter) { - this.toolDiameter = toolDiameter; + this.toolDiameter = Math.abs(toolDiameter); notifyListeners(); } @@ -136,7 +136,15 @@ public double getToolStepOver() { } public void setToolStepOver(double toolStepOver) { + toolStepOver = Math.abs(toolStepOver); + if (toolStepOver == 0) { + toolStepOver = 0.01; + } else if (toolStepOver > 1) { + toolStepOver = 1; + } + this.toolStepOver = toolStepOver; + notifyListeners(); } public String getStockSizeDescription() { @@ -154,7 +162,12 @@ public double getDepthPerPass() { } public void setDepthPerPass(double depthPerPass) { - this.depthPerPass = depthPerPass; + if (depthPerPass == 0) { + depthPerPass = 0.001; + } + + this.depthPerPass = Math.abs(depthPerPass); + notifyListeners(); } public double getSpindleSpeed() { @@ -162,7 +175,8 @@ public double getSpindleSpeed() { } public void setSpindleSpeed(double spindleSpeed) { - this.spindleSpeed = spindleSpeed; + this.spindleSpeed = Math.abs(spindleSpeed); + notifyListeners(); } public void applySettings(Settings settings) { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPathTest.java b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPathTest.java new file mode 100644 index 0000000000..55d68225f1 --- /dev/null +++ b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/OutlineToolPathTest.java @@ -0,0 +1,98 @@ +/* + Copyright 2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ +package com.willwinder.ugs.nbp.designer.io.gcode.toolpaths; + +import com.willwinder.ugs.nbp.designer.entities.cuttable.Rectangle; +import com.willwinder.ugs.nbp.designer.io.gcode.path.GcodePath; +import com.willwinder.ugs.nbp.designer.io.gcode.path.Segment; +import com.willwinder.ugs.nbp.designer.io.gcode.path.SegmentType; +import com.willwinder.ugs.nbp.designer.model.Size; +import static org.junit.Assert.*; +import org.junit.Test; + +import java.util.List; + +public class OutlineToolPathTest { + + @Test + public void toGcodePathShouldGenerateGcodeFromStartDepth() { + Rectangle rectangle = new Rectangle(0,0); + rectangle.setSize(new Size(10, 10)); + + OutlineToolPath toolPath = new OutlineToolPath(rectangle); + toolPath.setStartDepth(-1); + toolPath.setTargetDepth(-1); + toolPath.setSafeHeight(10); + GcodePath gcodePath = toolPath.toGcodePath(); + + List segments = gcodePath.getSegments(); + + // Move to safe height + assertEquals(SegmentType.MOVE, segments.get(0).type); + assertFalse(segments.get(0).point.hasX()); + assertFalse(segments.get(0).point.hasY()); + assertEquals(10, segments.get(0).point.getZ(), 0.01); + + // Move in XY-place + assertEquals(SegmentType.MOVE, segments.get(1).type); + assertEquals(0, segments.get(1).point.getX(), 0.01); + assertEquals(0, segments.get(1).point.getY(), 0.01); + assertFalse(segments.get(1).point.hasZ()); + + // Move to Z zero + assertEquals(SegmentType.MOVE, segments.get(2).type); + assertFalse(segments.get(2).point.hasX()); + assertFalse(segments.get(2).point.hasY()); + assertEquals(0, segments.get(2).point.getZ(), 0.01); + + // Move into material + assertEquals(SegmentType.POINT, segments.get(3).type); + assertTrue(segments.get(3).point.hasX()); + assertTrue(segments.get(3).point.hasY()); + assertEquals(-1, segments.get(3).point.getZ(), 0.01); + + assertEquals(SegmentType.LINE, segments.get(4).type); + assertEquals(0, segments.get(4).point.getX(), 0.01); + assertEquals(0, segments.get(4).point.getY(), 0.01); + assertEquals(-1, segments.get(4).point.getZ(), 0.01); + + assertEquals(SegmentType.LINE, segments.get(5).type); + assertEquals(0, segments.get(5).point.getX(), 0.01); + assertEquals(10, segments.get(5).point.getY(), 0.01); + assertEquals(-1, segments.get(5).point.getZ(), 0.01); + + assertEquals(SegmentType.LINE, segments.get(7).type); + assertEquals(10, segments.get(7).point.getX(), 0.01); + assertEquals(0, segments.get(7).point.getY(), 0.01); + assertEquals(-1, segments.get(7).point.getZ(), 0.01); + + assertEquals(SegmentType.LINE, segments.get(8).type); + assertEquals(0, segments.get(8).point.getX(), 0.01); + assertEquals(0, segments.get(8).point.getY(), 0.01); + assertEquals(-1, segments.get(8).point.getZ(), 0.01); + + // Move to safe height + assertEquals(SegmentType.MOVE, segments.get(9).type); + assertFalse(segments.get(9).point.hasX()); + assertFalse(segments.get(9).point.hasY()); + assertEquals(10, segments.get(9).point.getZ(), 0.01); + + assertEquals(10, segments.size()); + } +} \ No newline at end of file diff --git a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPathTest.java b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPathTest.java index 1890c8d492..8980f2d140 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPathTest.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/io/gcode/toolpaths/PocketToolPathTest.java @@ -130,8 +130,8 @@ public void pocketOnTestFileCheckLengths() { double toolDiameter = 1; double safeHeight = 5; - double startDepth = -1; - double targetDepth = -1; + double startDepth = 1; + double targetDepth = 1; int depthPerPass = 1; double totalLength = 0; diff --git a/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/model/SettingsTest.java b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/model/SettingsTest.java new file mode 100644 index 0000000000..a112635b24 --- /dev/null +++ b/ugs-platform/ugs-platform-plugin-designer/src/test/java/com/willwinder/ugs/nbp/designer/model/SettingsTest.java @@ -0,0 +1,83 @@ +/* + Copyright 2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS 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. + + UGS 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 UGS. If not, see . + */ +package com.willwinder.ugs.nbp.designer.model; + +import com.willwinder.ugs.nbp.designer.logic.SettingsListener; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class SettingsTest { + + @Test + public void setToolStepOverPreventZero() { + Settings settings = new Settings(); + settings.setToolStepOver(0); + assertTrue(settings.getToolStepOver() > 0); + } + + @Test + public void setToolStepOverPreventNegativeValues() { + Settings settings = new Settings(); + settings.setToolStepOver(-0.1); + assertTrue(settings.getToolStepOver() > 0); + } + + @Test + public void setToolStepOverPreventMoreThanHundredPercent() { + Settings settings = new Settings(); + settings.setToolStepOver(2); + assertEquals(1, settings.getToolStepOver(), 0.01); + } + + @Test + public void setToolStepOverShouldNotifyListeners() { + SettingsListener listener = mock(SettingsListener.class); + Settings settings = new Settings(); + settings.addListener(listener); + settings.setToolStepOver(0.1); + verify(listener, times(1)).onSettingsChanged(); + } + + @Test + public void setDepthPerPassPreventZero() { + Settings settings = new Settings(); + settings.setDepthPerPass(0); + assertTrue(settings.getDepthPerPass() > 0); + } + + @Test + public void setDepthPerPassPreventNegativeValues() { + Settings settings = new Settings(); + settings.setDepthPerPass(-0.1); + assertEquals(0.1, settings.getDepthPerPass(), 0.01); + } + + @Test + public void setDepthPerPassShouldNotifyListeners() { + SettingsListener listener = mock(SettingsListener.class); + Settings settings = new Settings(); + settings.addListener(listener); + settings.setDepthPerPass(0.1); + verify(listener, times(1)).onSettingsChanged(); + } +} \ No newline at end of file