From 08bfec7ce0dbffe2baad898eb2e028a2b9239d1f Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Fri, 31 Jan 2020 09:35:05 +0100 Subject: [PATCH 01/22] Make cloning possible Cloning of a board enables us two important things: with this we can detect an (fairly typical) endless loop in the algorithm, because we can calculate a unique hash of a board, and maintain a list of board layouts that were already checked. The second very important improvement is that with cloning it will be possible to design multi-threaded routing algorithms and improve the efficiency and speed significantly. --- .../autoroute/BatchAutorouter.java | 23 ++++-- .../freerouting/board/BasicBoard.java | 72 +++++++++++++++++++ .../eu/mihosoft/freerouting/board/Item.java | 2 +- .../interactive/BoardHandling.java | 2 + 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java index ad91fd4..4c5ff41 100644 --- a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java +++ b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java @@ -18,11 +18,7 @@ */ package eu.mihosoft.freerouting.autoroute; -import java.util.Iterator; -import java.util.Collection; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.*; import eu.mihosoft.freerouting.datastructures.TimeLimit; import eu.mihosoft.freerouting.datastructures.UndoableObjects; @@ -46,6 +42,7 @@ import eu.mihosoft.freerouting.logger.FRLogger; */ public class BatchAutorouter { + private HashSet already_checked_board_hashes = new HashSet(); /** * Autoroutes ripup passes until the eu.mihosoft.freerouting.board is completed or the autorouter is stopped by the user, @@ -124,12 +121,21 @@ public class BatchAutorouter { this.is_interrupted = true; } + + var current_board_hash = this.routing_board.get_hash(); + if (already_checked_board_hashes.contains(current_board_hash)) + { + FRLogger.logger.warn("This board was already evaluated, so we stop autorouter to avoid the endless loop."); + break; + } + Integer curr_pass_no = hdlg.get_settings().autoroute_settings.get_pass_no(); String start_message = resources.getString("batch_autorouter") + " " + resources.getString("stop_message") + " " + resources.getString("pass") + " " + curr_pass_no.toString() + ": "; hdlg.screen_messages.set_status_message(start_message); - FRLogger.traceEntry("BatchAutorouter.autoroute_pass("+curr_pass_no+")"); + FRLogger.traceEntry("BatchAutorouter.autoroute_pass("+curr_pass_no+") on board '"+current_board_hash+"'"); + already_checked_board_hashes.add(this.routing_board.get_hash()); still_unrouted_items = autoroute_pass(curr_pass_no, true); - FRLogger.traceExit("BatchAutorouter.autoroute_pass("+curr_pass_no+")"); + FRLogger.traceExit("BatchAutorouter.autoroute_pass("+curr_pass_no+") on board '"+current_board_hash+"'"); if (still_unrouted_items && !is_interrupted) { hdlg.get_settings().autoroute_settings.increment_pass_no(); @@ -140,6 +146,9 @@ public class BatchAutorouter // clean up the route if the eu.mihosoft.freerouting.board is completed and if fanout is used. remove_tails(Item.StopConnectionOption.NONE); } + + already_checked_board_hashes.clear(); + return !this.is_interrupted; } diff --git a/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java b/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java index 945ed66..b88dbcc 100644 --- a/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java +++ b/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java @@ -30,6 +30,11 @@ import eu.mihosoft.freerouting.geometry.planar.TileShape; import java.awt.Graphics; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.MessageDigest; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; @@ -85,6 +90,73 @@ public class BasicBoard implements java.io.Serializable insert_outline(p_outline_shapes, p_outline_cl_class_no); } + private byte[] serialize() + { + try + { + var output_stream = new ByteArrayOutputStream(); + var object_stream = new ObjectOutputStream(output_stream); + + object_stream.writeObject(this); + object_stream.close(); + + return output_stream.toByteArray(); + } + catch (Exception e) { + FRLogger.logger.error(e); + } + + return null; + } + + private static BasicBoard deserialize(byte[] object_byte_array) + { + try + { + var input_stream = new ByteArrayInputStream(object_byte_array); + var object_stream = new ObjectInputStream(input_stream); + + return (BasicBoard)object_stream.readObject(); + } + catch (Exception e) { + FRLogger.logger.error(e); + } + + return null; + } + + public BasicBoard clone() + { + return deserialize(this.serialize()); + } + + public String get_hash() + { + try + { + MessageDigest digest = MessageDigest.getInstance("MD5"); + digest.update(this.serialize()); + byte[] hashedBytes = digest.digest(); + + return convert_byte_array_to_hex_string(hashedBytes); + } + catch (Exception e) { + FRLogger.logger.error(e); + } + + return null; + } + + private static String convert_byte_array_to_hex_string(byte[] arrayBytes) { + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 0; i < arrayBytes.length; i++) { + stringBuffer.append(Integer.toString((arrayBytes[i] & 0xff) + 0x100, 16) + .substring(1)); + } + return stringBuffer.toString(); + } + + /** * Inserts a trace into the eu.mihosoft.freerouting.board, whose geometry is described by * a Polyline. p_clearance_class is the index in the clearance_matix, diff --git a/src/main/java/eu/mihosoft/freerouting/board/Item.java b/src/main/java/eu/mihosoft/freerouting/board/Item.java index f449e6c..43b0d08 100644 --- a/src/main/java/eu/mihosoft/freerouting/board/Item.java +++ b/src/main/java/eu/mihosoft/freerouting/board/Item.java @@ -1453,7 +1453,7 @@ public abstract class Item implements Drawable, SearchTreeObject, ObjectInfoPane * to other items */ private int clearance_class; - /** The eu.mihosoft.freerouting.board this Itewm is on */ + /** The eu.mihosoft.freerouting.board this Item is on */ transient public BasicBoard board; /** The nets, to which this item belongs */ int[] net_no_arr; diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java b/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java index 8c03ce4..ad252c0 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java @@ -43,6 +43,7 @@ import eu.mihosoft.freerouting.geometry.planar.PolylineShape; import eu.mihosoft.freerouting.gui.BoardPanel; import eu.mihosoft.freerouting.gui.ComboBoxLayer; +import eu.mihosoft.freerouting.logger.FRLogger; import eu.mihosoft.freerouting.rules.BoardRules; import eu.mihosoft.freerouting.board.LayerStructure; import eu.mihosoft.freerouting.board.RoutingBoard; @@ -1023,6 +1024,7 @@ public class BoardHandling extends BoardHandlingImpl } catch (Exception e) { + FRLogger.logger.error(e); return false; } board.set_test_level(p_test_level); From 498b7a4140b7b194a6e805a4c2eab5f8b1e30b62 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 14:33:43 +0100 Subject: [PATCH 02/22] Widend the text box of the autorouter's pass parameter a little more --- .../freerouting/gui/WindowAutorouteDetailParameter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java b/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java index b4903ee..0494c65 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java @@ -88,7 +88,7 @@ public class WindowAutorouteDetailParameter extends BoardSavableSubWindow main_panel.add(start_pass_label); start_pass_no = new javax.swing.JFormattedTextField(number_format); - start_pass_no.setColumns(4); + start_pass_no.setColumns(5); this.start_pass_no.addKeyListener(new StartPassFieldKeyListener()); this.start_pass_no.addFocusListener(new StartPassFieldFocusListener()); gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; From 760b44d9f90e93e968ced5d99e7d49b7dfc2598d Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 14:34:05 +0100 Subject: [PATCH 03/22] Changed the maximum allowed value for the pass number --- .../eu/mihosoft/freerouting/interactive/AutorouteSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java b/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java index c98dca6..f48d940 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java @@ -138,7 +138,7 @@ public class AutorouteSettings implements java.io.Serializable public void set_pass_no(int p_value) { start_pass_no = Math.max(p_value, 1); - start_pass_no = Math.min(start_pass_no, 99); + start_pass_no = Math.min(start_pass_no, 99999); } public int get_pass_no() From ba9c6a24c0b06d00db4b2e262da9ebb0646cd705 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 14:37:18 +0100 Subject: [PATCH 04/22] Added an extra option to the logger class to display the method result while measuring performance --- src/main/java/eu/mihosoft/freerouting/logger/FRLogger.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/freerouting/logger/FRLogger.java b/src/main/java/eu/mihosoft/freerouting/logger/FRLogger.java index f9be437..4fdf32a 100644 --- a/src/main/java/eu/mihosoft/freerouting/logger/FRLogger.java +++ b/src/main/java/eu/mihosoft/freerouting/logger/FRLogger.java @@ -29,6 +29,11 @@ public class FRLogger { } public static void traceExit(String perfId) + { + traceExit(perfId, null); + } + + public static void traceExit(String perfId, Object result) { var timeElapsed = Duration.between(perfData.get(perfId.hashCode()), java.time.Instant.now()).toMillis(); @@ -36,6 +41,6 @@ public class FRLogger { if (timeElapsed < 0) { timeElapsed = 0; } - logger.trace("Method '" + perfId + "' was performed in " + performanceFormat.format(timeElapsed/1000.0) + " seconds."); + logger.trace("Method '" + perfId.replace("{}", result != null ? result.toString() : "(null)") + "' was performed in " + performanceFormat.format(timeElapsed/1000.0) + " seconds."); } } From f8d2e671eeb6b4b9b5e0612a79ee8e6d8012ca9d Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 14:38:08 +0100 Subject: [PATCH 05/22] Separated the business logic and the GUI methods in the .dsn file reader --- .../mihosoft/freerouting/gui/BoardFrame.java | 83 +++++++++---------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/BoardFrame.java b/src/main/java/eu/mihosoft/freerouting/gui/BoardFrame.java index 04af7ab..2c57a18 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/BoardFrame.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/BoardFrame.java @@ -173,78 +173,69 @@ public class BoardFrame extends javax.swing.JFrame * If p_is_import, the design is read from a scpecctra dsn file. * Returns false, if the file is invalid. */ - boolean read(java.io.InputStream p_input_stream, boolean p_is_import, javax.swing.JTextField p_message_field) - { + boolean read(java.io.InputStream p_input_stream, boolean p_is_import, javax.swing.JTextField p_message_field) { java.awt.Point viewport_position = null; - if (p_is_import) - { - DsnFile.ReadResult read_result = board_panel.board_handling.import_design(p_input_stream, this.board_observers, + DsnFile.ReadResult read_result = null; + if (p_is_import) { + read_result = board_panel.board_handling.import_design(p_input_stream, this.board_observers, this.item_id_no_generator, this.test_level); - if (read_result != DsnFile.ReadResult.OK) - { - if (p_message_field != null) - { - if (read_result == DsnFile.ReadResult.OUTLINE_MISSING) - { - p_message_field.setText(resources.getString("error_7")); - } - else - { - p_message_field.setText(resources.getString("error_6")); - } - } - return false; + if (read_result == DsnFile.ReadResult.OK) { + viewport_position = new java.awt.Point(0, 0); + initialize_windows(); } - viewport_position = new java.awt.Point(0,0); - initialize_windows(); - } - else - { + } else { java.io.ObjectInputStream object_stream = null; - try - { + try { object_stream = new java.io.ObjectInputStream(p_input_stream); - } - catch (java.io.IOException e) - { + } catch (java.io.IOException e) { return false; } boolean read_ok = board_panel.board_handling.read_design(object_stream, this.test_level); - if (!read_ok) - { + if (!read_ok) { return false; } java.awt.Point frame_location; java.awt.Rectangle frame_bounds; - try - { + try { viewport_position = (java.awt.Point) object_stream.readObject(); frame_location = (java.awt.Point) object_stream.readObject(); frame_bounds = (java.awt.Rectangle) object_stream.readObject(); - } - catch (Exception e) - { + } catch (Exception e) { return false; } this.setLocation(frame_location); this.setBounds(frame_bounds); - + allocate_permanent_subwindows(); - - for (int i = 0; i < this.permanent_subwindows.length; ++i) - { + + for (int i = 0; i < this.permanent_subwindows.length; ++i) { this.permanent_subwindows[i].read(object_stream); } } - try - { + try { p_input_stream.close(); - } - catch (java.io.IOException e) - { + } catch (java.io.IOException e) { return false; } - + + return update_gui(p_is_import, read_result, viewport_position, p_message_field); + } + + private boolean update_gui(boolean p_is_import, DsnFile.ReadResult read_result, java.awt.Point viewport_position, javax.swing.JTextField p_message_field) + { + if (p_is_import) { + if (read_result != DsnFile.ReadResult.OK) { + if (p_message_field != null) { + if (read_result == DsnFile.ReadResult.OUTLINE_MISSING) { + p_message_field.setText(resources.getString("error_7")); + } else { + p_message_field.setText(resources.getString("error_6")); + } + } + return false; + } + } + java.awt.Dimension panel_size = board_panel.board_handling.graphics_context.get_panel_size(); board_panel.setSize(panel_size); board_panel.setPreferredSize(panel_size); From fceeeac07cd4078185be8e1de86a208d649bc8ea Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 15:01:12 +0100 Subject: [PATCH 06/22] Added a warning if there were not many changes in the last 20 passes --- .../autoroute/BatchAutorouter.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java index 4c5ff41..2e43e1c 100644 --- a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java +++ b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java @@ -106,6 +106,8 @@ public class BatchAutorouter this.retain_autoroute_database = false; } + private LinkedList diffBetweenBoards = new LinkedList(); + /** * Autoroutes ripup passes until the eu.mihosoft.freerouting.board is completed or the autorouter is stopped by the user. * Returns true if the eu.mihosoft.freerouting.board is completed. @@ -132,10 +134,33 @@ public class BatchAutorouter Integer curr_pass_no = hdlg.get_settings().autoroute_settings.get_pass_no(); String start_message = resources.getString("batch_autorouter") + " " + resources.getString("stop_message") + " " + resources.getString("pass") + " " + curr_pass_no.toString() + ": "; hdlg.screen_messages.set_status_message(start_message); - FRLogger.traceEntry("BatchAutorouter.autoroute_pass("+curr_pass_no+") on board '"+current_board_hash+"'"); + + var boardBefore = this.routing_board.clone(); + + FRLogger.traceEntry("BatchAutorouter.autoroute_pass #"+curr_pass_no+" on board '"+current_board_hash+"' making {} changes"); already_checked_board_hashes.add(this.routing_board.get_hash()); still_unrouted_items = autoroute_pass(curr_pass_no, true); - FRLogger.traceExit("BatchAutorouter.autoroute_pass("+curr_pass_no+") on board '"+current_board_hash+"'"); + + // let's check if there was enough change in the last pass, because if it were little, so should probably stop + var newTraceDifferences = this.routing_board.diff_traces(boardBefore); + diffBetweenBoards.add(newTraceDifferences); + + if (diffBetweenBoards.size() > 20) { + diffBetweenBoards.removeFirst(); + + OptionalDouble average = diffBetweenBoards + .stream() + .mapToDouble(a -> a) + .average(); + + if (average.getAsDouble() < 20.0) + { + FRLogger.logger.warn("There were only " + average.getAsDouble() + " changes in the last 20 passes, so it's very likely that autorouter can't improve the result much further. It is recommended to stop it and finish the board manually."); + } + } + FRLogger.traceExit("BatchAutorouter.autoroute_pass #"+curr_pass_no+" on board '"+current_board_hash+"' making {} changes", newTraceDifferences); + + // check if there are still unrouted items if (still_unrouted_items && !is_interrupted) { hdlg.get_settings().autoroute_settings.increment_pass_no(); @@ -143,7 +168,7 @@ public class BatchAutorouter } if (!(this.remove_unconnected_vias || still_unrouted_items || this.is_interrupted)) { - // clean up the route if the eu.mihosoft.freerouting.board is completed and if fanout is used. + // clean up the route if the board is completed and if fanout is used. remove_tails(Item.StopConnectionOption.NONE); } From f3d43a8ebad7aff295282cadde2d67c99495435e Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 15:03:47 +0100 Subject: [PATCH 07/22] Added the diff_traces method the compare to board wirings --- .../freerouting/board/BasicBoard.java | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java b/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java index b88dbcc..4539cc7 100644 --- a/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java +++ b/src/main/java/eu/mihosoft/freerouting/board/BasicBoard.java @@ -35,12 +35,7 @@ import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.MessageDigest; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.*; import eu.mihosoft.freerouting.datastructures.ShapeTree.TreeEntry; @@ -90,14 +85,21 @@ public class BasicBoard implements java.io.Serializable insert_outline(p_outline_shapes, p_outline_cl_class_no); } - private byte[] serialize() + private byte[] serialize(boolean basicProfile) { try { var output_stream = new ByteArrayOutputStream(); var object_stream = new ObjectOutputStream(output_stream); - object_stream.writeObject(this); + if (basicProfile) { + object_stream.writeObject(this.get_traces()); + object_stream.writeObject(this.get_vias()); + object_stream.writeObject(this.item_list); + } else { + object_stream.writeObject(this); + } + object_stream.close(); return output_stream.toByteArray(); @@ -127,15 +129,15 @@ public class BasicBoard implements java.io.Serializable public BasicBoard clone() { - return deserialize(this.serialize()); + return deserialize(this.serialize(false)); } - + public String get_hash() { try { MessageDigest digest = MessageDigest.getInstance("MD5"); - digest.update(this.serialize()); + digest.update(this.serialize(true)); byte[] hashedBytes = digest.digest(); return convert_byte_array_to_hex_string(hashedBytes); @@ -147,6 +149,27 @@ public class BasicBoard implements java.io.Serializable return null; } + public int diff_traces(BasicBoard compare_to) + { + int result = 0; + HashSet traceIds = new HashSet(); + for (Trace trace : this.get_traces()) { + traceIds.add(trace.get_id_no()); + } + + for (Trace trace : compare_to.get_traces()) { + if (!traceIds.contains(trace.get_id_no())) + { + result++; + } else { + traceIds.remove(trace.get_id_no()); + } + } + result += traceIds.size(); + + return result; + } + private static String convert_byte_array_to_hex_string(byte[] arrayBytes) { StringBuffer stringBuffer = new StringBuffer(); for (int i = 0; i < arrayBytes.length; i++) { From 903433a1e86873860c89e90053cdc364eda06ab4 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 17:24:10 +0100 Subject: [PATCH 08/22] Added a few new startup options to make testing and command line execution easier --- .../freerouting/gui/MainApplication.java | 8 ++-- .../freerouting/gui/StartupOptions.java | 43 ++++++++++++++----- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 4022696..740208b 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -76,17 +76,17 @@ public class MainApplication extends javax.swing.JFrame board_option = BoardFrame.Option.SINGLE_FRAME; } - FRLogger.logger.info("Opening '"+startupOptions.design_file_name+"'..."); - DesignFile design_file = DesignFile.get_instance(startupOptions.design_file_name, false); + FRLogger.logger.info("Opening '"+startupOptions.design_input_filename +"'..."); + DesignFile design_file = DesignFile.get_instance(startupOptions.design_input_filename, false); if (design_file == null) { System.out.print(resources.getString("message_6") + " "); - System.out.print(startupOptions.design_file_name); + System.out.print(startupOptions.design_input_filename); System.out.println(" " + resources.getString("message_7")); return; } String message = resources.getString("loading_design") + " " - + startupOptions.design_file_name; + + startupOptions.design_input_filename; WindowMessage welcome_window = WindowMessage.show(message); final BoardFrame new_frame = create_board_frame(design_file, null, board_option, diff --git a/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java b/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java index 3fd29fd..be1edd1 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java @@ -11,8 +11,11 @@ public class StartupOptions { boolean test_version_option = false; boolean session_file_option = false; boolean webstart_option = false; - String design_file_name = null; - String design_dir_name = null; + String design_input_filename = null; + String design_output_filename = null; + String design_input_directory_name = null; + int pass_number_first = 1; + int pass_number_last = Integer.MAX_VALUE; java.util.Locale current_locale = java.util.Locale.ENGLISH; private StartupOptions() { @@ -30,22 +33,42 @@ public class StartupOptions { private void process(String[] p_args) { for (int i = 0; i < p_args.length; ++i) { + if (p_args[i].startsWith("-de")) - // the design file is provided { + // the design file is provided if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { single_design_option = true; - design_file_name = p_args[i + 1]; + design_input_filename = p_args[i + 1]; } - } else if (p_args[i].startsWith("-di")) - // the design directory is provided + } + else if (p_args[i].startsWith("-di")) { + // the design directory is provided + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + design_input_directory_name = p_args[i + 1]; + } + } + else if (p_args[i].startsWith("-do")) { if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - design_dir_name = p_args[i + 1]; + design_output_filename = p_args[i + 1]; } - } else if (p_args[i].startsWith("-l")) - // the locale is provided + } + else if (p_args[i].startsWith("-pf")) { + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + pass_number_first = p_args[i + 1]; + } + } + else if (p_args[i].startsWith("-pl")) { + // the design directory is provided + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + pass_number_last = p_args[i + 1]; + } + } + else if (p_args[i].startsWith("-l")) + { + // the locale is provided if (p_args.length > i + 1 && p_args[i + 1].startsWith("d")) { current_locale = java.util.Locale.GERMAN; } @@ -68,6 +91,6 @@ public class StartupOptions { } public String getDesignDir() { - return design_dir_name; + return design_input_directory_name; } } From 457b4497c310ca0160887cf40c02ba87860d56e6 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 19:39:17 +0100 Subject: [PATCH 09/22] Completed the -pf implementation --- .../autoroute/BatchAutorouter.java | 2 +- .../specctra/AutorouteSettings.java | 4 +- .../freerouting/gui/MainApplication.java | 14 ++- .../freerouting/gui/StartupOptions.java | 89 +++++++++---------- .../gui/WindowAutorouteDetailParameter.java | 19 ++-- .../gui/WindowAutorouteParameter.java | 6 +- .../interactive/AutorouteSettings.java | 11 ++- .../interactive/BatchAutorouterThread.java | 2 +- .../interactive/BoardHandling.java | 2 +- .../interactive/ExpandTestState.java | 2 +- 10 files changed, 85 insertions(+), 66 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java index 2e43e1c..50b3f3a 100644 --- a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java +++ b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java @@ -131,7 +131,7 @@ public class BatchAutorouter break; } - Integer curr_pass_no = hdlg.get_settings().autoroute_settings.get_pass_no(); + Integer curr_pass_no = hdlg.get_settings().autoroute_settings.get_start_pass_no(); String start_message = resources.getString("batch_autorouter") + " " + resources.getString("stop_message") + " " + resources.getString("pass") + " " + curr_pass_no.toString() + ": "; hdlg.screen_messages.set_status_message(start_message); diff --git a/src/main/java/eu/mihosoft/freerouting/designforms/specctra/AutorouteSettings.java b/src/main/java/eu/mihosoft/freerouting/designforms/specctra/AutorouteSettings.java index 5e309f8..f46baef 100644 --- a/src/main/java/eu/mihosoft/freerouting/designforms/specctra/AutorouteSettings.java +++ b/src/main/java/eu/mihosoft/freerouting/designforms/specctra/AutorouteSettings.java @@ -93,7 +93,7 @@ public class AutorouteSettings } else if (next_token == Keyword.START_PASS_NO) { - result.set_pass_no(DsnFile.read_integer_scope(p_scanner)); + result.set_start_pass_no(DsnFile.read_integer_scope(p_scanner)); } else if (next_token == Keyword.LAYER_RULE) { @@ -280,7 +280,7 @@ public class AutorouteSettings p_file.new_line(); p_file.write("(start_pass_no "); { - Integer pass_no = p_settings.get_pass_no(); + Integer pass_no = p_settings.get_start_pass_no(); p_file.write(pass_no.toString()); } p_file.write(")"); diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 740208b..2f9d5cc 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -76,13 +76,11 @@ public class MainApplication extends javax.swing.JFrame board_option = BoardFrame.Option.SINGLE_FRAME; } - FRLogger.logger.info("Opening '"+startupOptions.design_input_filename +"'..."); + FRLogger.logger.info("Opening '"+startupOptions.design_input_filename+"'..."); DesignFile design_file = DesignFile.get_instance(startupOptions.design_input_filename, false); if (design_file == null) { - System.out.print(resources.getString("message_6") + " "); - System.out.print(startupOptions.design_input_filename); - System.out.println(" " + resources.getString("message_7")); + FRLogger.logger.error(resources.getString("message_6") + " " + startupOptions.design_input_filename + " " + resources.getString("message_7")); return; } String message = resources.getString("loading_design") + " " @@ -95,9 +93,17 @@ public class MainApplication extends javax.swing.JFrame welcome_window.dispose(); if (new_frame == null) { + FRLogger.logger.error("Couldn't create window frame"); System.exit(1); return; } + + if (startupOptions.pass_number_first > 0) { + new_frame.board_panel.board_handling.settings.autoroute_settings.set_start_pass_no(startupOptions.pass_number_first); + new_frame.board_panel.board_frame.autoroute_parameter_window.refresh(); + } + new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(startupOptions.pass_number_last); + new_frame.addWindowListener(new java.awt.event.WindowAdapter() { diff --git a/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java b/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java index be1edd1..218636b 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java @@ -1,5 +1,7 @@ package eu.mihosoft.freerouting.gui; +import eu.mihosoft.freerouting.logger.FRLogger; + import java.util.Locale; /** @@ -14,8 +16,8 @@ public class StartupOptions { String design_input_filename = null; String design_output_filename = null; String design_input_directory_name = null; - int pass_number_first = 1; - int pass_number_last = Integer.MAX_VALUE; + int pass_number_first = 0; + int pass_number_last = 99999; java.util.Locale current_locale = java.util.Locale.ENGLISH; private StartupOptions() { @@ -33,51 +35,46 @@ public class StartupOptions { private void process(String[] p_args) { for (int i = 0; i < p_args.length; ++i) { - - if (p_args[i].startsWith("-de")) + try { + if (p_args[i].startsWith("-de")) { + // the design file is provided + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + single_design_option = true; + design_input_filename = p_args[i + 1]; + } + } else if (p_args[i].startsWith("-di")) { + // the design directory is provided + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + design_input_directory_name = p_args[i + 1]; + } + } else if (p_args[i].startsWith("-do")) { + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + design_output_filename = p_args[i + 1]; + } + } else if (p_args[i].startsWith("-pf")) { + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + pass_number_first = Integer.decode(p_args[i + 1]); + } + } else if (p_args[i].startsWith("-pl")) { + if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { + pass_number_last = Integer.decode(p_args[i + 1]); + } + } else if (p_args[i].startsWith("-l")) { + // the locale is provided + if (p_args.length > i + 1 && p_args[i + 1].startsWith("d")) { + current_locale = java.util.Locale.GERMAN; + } + } else if (p_args[i].startsWith("-s")) { + session_file_option = true; + } else if (p_args[i].startsWith("-w")) { + webstart_option = true; + } else if (p_args[i].startsWith("-test")) { + test_version_option = true; + } + } + catch (Exception e) { - // the design file is provided - if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - single_design_option = true; - design_input_filename = p_args[i + 1]; - } - } - else if (p_args[i].startsWith("-di")) { - // the design directory is provided - if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - design_input_directory_name = p_args[i + 1]; - } - } - else if (p_args[i].startsWith("-do")) - { - if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - design_output_filename = p_args[i + 1]; - } - } - else if (p_args[i].startsWith("-pf")) - { - if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - pass_number_first = p_args[i + 1]; - } - } - else if (p_args[i].startsWith("-pl")) { - // the design directory is provided - if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - pass_number_last = p_args[i + 1]; - } - } - else if (p_args[i].startsWith("-l")) - { - // the locale is provided - if (p_args.length > i + 1 && p_args[i + 1].startsWith("d")) { - current_locale = java.util.Locale.GERMAN; - } - } else if (p_args[i].startsWith("-s")) { - session_file_option = true; - } else if (p_args[i].startsWith("-w")) { - webstart_option = true; - } else if (p_args[i].startsWith("-test")) { - test_version_option = true; + FRLogger.logger.error("There was a problem parsing the '"+p_args[i]+"' parameter", e); } } } diff --git a/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java b/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java index 0494c65..f48b90c 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteDetailParameter.java @@ -23,7 +23,6 @@ */ package eu.mihosoft.freerouting.gui; -import java.awt.*; import java.text.DecimalFormat; /** @@ -214,7 +213,7 @@ public class WindowAutorouteDetailParameter extends BoardSavableSubWindow this.via_cost_field.setValue(settings.get_via_costs()); this.plane_via_cost_field.setValue(settings.get_plane_via_costs()); this.start_ripup_costs.setValue(settings.get_start_ripup_costs()); - this.start_pass_no.setValue(settings.get_pass_no()); + this.start_pass_no.setValue(settings.get_start_pass_no()); for (int i = 0; i < preferred_direction_trace_cost_arr.length; ++i) { this.preferred_direction_trace_cost_arr[i].setValue(settings.get_preferred_direction_trace_costs(layer_structure.get_layer_no(i))); @@ -398,7 +397,7 @@ public class WindowAutorouteDetailParameter extends BoardSavableSubWindow { if (p_evt.getKeyChar() == '\n') { - int old_value = board_handling.settings.autoroute_settings.get_pass_no(); + int old_value = board_handling.settings.autoroute_settings.get_start_pass_no(); Object input = start_pass_no.getValue(); int input_value; if (input instanceof Number) @@ -416,13 +415,23 @@ public class WindowAutorouteDetailParameter extends BoardSavableSubWindow { input_value = old_value; } - board_handling.settings.autoroute_settings.set_pass_no(input_value); - start_pass_no.setValue(input_value); + set_start_pass_no(input_value); } } } + public void set_start_pass_no(int input_value) + { + board_handling.settings.autoroute_settings.set_start_pass_no(input_value); + start_pass_no.setValue(input_value); + } + + public void set_stop_pass_no(int input_value) + { + board_handling.settings.autoroute_settings.set_stop_pass_no(input_value); + } + private class StartPassFieldFocusListener implements java.awt.event.FocusListener { diff --git a/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteParameter.java b/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteParameter.java index b8e7725..6a585dc 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteParameter.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/WindowAutorouteParameter.java @@ -290,7 +290,7 @@ public class WindowAutorouteParameter extends BoardSavableSubWindow { eu.mihosoft.freerouting.interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; autoroute_settings.set_with_fanout(fanout_pass_button.isSelected()); - autoroute_settings.set_pass_no(1); + autoroute_settings.set_start_pass_no(1); } } @@ -301,7 +301,7 @@ public class WindowAutorouteParameter extends BoardSavableSubWindow { eu.mihosoft.freerouting.interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; autoroute_settings.set_with_autoroute(autoroute_pass_button.isSelected()); - autoroute_settings.set_pass_no(1); + autoroute_settings.set_start_pass_no(1); } } @@ -312,7 +312,7 @@ public class WindowAutorouteParameter extends BoardSavableSubWindow { eu.mihosoft.freerouting.interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; autoroute_settings.set_with_postroute(postroute_pass_button.isSelected()); - autoroute_settings.set_pass_no(1); + autoroute_settings.set_start_pass_no(1); } } } diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java b/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java index f48d940..2b84efe 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java @@ -135,17 +135,23 @@ public class AutorouteSettings implements java.io.Serializable return start_ripup_costs; } - public void set_pass_no(int p_value) + public void set_start_pass_no(int p_value) { start_pass_no = Math.max(p_value, 1); start_pass_no = Math.min(start_pass_no, 99999); } - public int get_pass_no() + public int get_start_pass_no() { return start_pass_no; } + public void set_stop_pass_no(int p_value) + { + stop_pass_no = Math.max(p_value, 1); + stop_pass_no = Math.min(stop_pass_no, 99999); + } + public void increment_pass_no() { ++start_pass_no; @@ -347,6 +353,7 @@ public class AutorouteSettings implements java.io.Serializable private int plane_via_costs; private int start_ripup_costs; private int start_pass_no; + private int stop_pass_no; private final boolean[] layer_active_arr; private final boolean[] preferred_direction_is_horizontal_arr; private final double[] preferred_direction_trace_cost_arr; diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java b/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java index 2612972..74ab5af 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java @@ -70,7 +70,7 @@ public class BatchAutorouterThread extends InteractiveActionThread hdlg.screen_messages.set_status_message(start_message); boolean fanout_first = hdlg.get_settings().autoroute_settings.get_with_fanout() && - hdlg.get_settings().autoroute_settings.get_pass_no() <= 1; + hdlg.get_settings().autoroute_settings.get_start_pass_no() <= 1; if (fanout_first) { BatchFanout.fanout_board(this); diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java b/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java index ad252c0..7862b3f 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java @@ -740,7 +740,7 @@ public class BoardHandling extends BoardHandlingImpl { // reset the start pass number in the autorouter in case // a batch autorouter is undone. - this.settings.autoroute_settings.set_pass_no(1); + this.settings.autoroute_settings.set_start_pass_no(1); } screen_messages.set_status_message(resources.getString("undo")); } diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/ExpandTestState.java b/src/main/java/eu/mihosoft/freerouting/interactive/ExpandTestState.java index b7a315d..55b9ee2 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/ExpandTestState.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/ExpandTestState.java @@ -205,7 +205,7 @@ public class ExpandTestState extends InteractiveState this.control_settings = new AutorouteControl(hdlg.get_routing_board(), route_net_no, hdlg.settings); // this.control_settings.ripup_allowed = true; // this.control_settings.is_fanout = true; - this.control_settings.ripup_pass_no = hdlg.settings.autoroute_settings.get_pass_no(); + this.control_settings.ripup_pass_no = hdlg.settings.autoroute_settings.get_start_pass_no(); this.control_settings.ripup_costs = this.control_settings.ripup_pass_no * hdlg.settings.autoroute_settings.get_start_ripup_costs(); this.control_settings.vias_allowed = false; this.autoroute_engine = new AutorouteEngine(board, this.control_settings.trace_clearance_class_no, false); From 625cf4e9ee14f4ff4f30ba0f413b66c5d5311c67 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 20:57:42 +0100 Subject: [PATCH 10/22] Completed the -pl implementation --- .../eu/mihosoft/freerouting/autoroute/BatchAutorouter.java | 5 +++++ .../java/eu/mihosoft/freerouting/gui/MainApplication.java | 5 +++++ .../freerouting/interactive/AutorouteSettings.java | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java index 50b3f3a..0740d15 100644 --- a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java +++ b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java @@ -132,6 +132,11 @@ public class BatchAutorouter } Integer curr_pass_no = hdlg.get_settings().autoroute_settings.get_start_pass_no(); + if (curr_pass_no > hdlg.get_settings().autoroute_settings.get_stop_pass_no()) + { + break; + } + String start_message = resources.getString("batch_autorouter") + " " + resources.getString("stop_message") + " " + resources.getString("pass") + " " + curr_pass_no.toString() + ": "; hdlg.screen_messages.set_status_message(start_message); diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 2f9d5cc..9f666ff 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -102,7 +102,12 @@ public class MainApplication extends javax.swing.JFrame new_frame.board_panel.board_handling.settings.autoroute_settings.set_start_pass_no(startupOptions.pass_number_first); new_frame.board_panel.board_frame.autoroute_parameter_window.refresh(); } + new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(startupOptions.pass_number_last); + if (startupOptions.pass_number_last < 99999) + { + new_frame.board_panel.board_handling.start_batch_autorouter(); + } new_frame.addWindowListener(new java.awt.event.WindowAdapter() { diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java b/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java index 2b84efe..cc46ebe 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/AutorouteSettings.java @@ -148,10 +148,15 @@ public class AutorouteSettings implements java.io.Serializable public void set_stop_pass_no(int p_value) { - stop_pass_no = Math.max(p_value, 1); + stop_pass_no = Math.max(p_value, start_pass_no); stop_pass_no = Math.min(stop_pass_no, 99999); } + public int get_stop_pass_no() + { + return stop_pass_no; + } + public void increment_pass_no() { ++start_pass_no; From 038f8a8626c08e966f18ac5dd91e30cdcba1276f Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 22:13:59 +0100 Subject: [PATCH 11/22] Fixed a bug that prevented the autorouter to stop if post-routing is enabled --- .../java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java index 0740d15..c3549ee 100644 --- a/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java +++ b/src/main/java/eu/mihosoft/freerouting/autoroute/BatchAutorouter.java @@ -128,12 +128,14 @@ public class BatchAutorouter if (already_checked_board_hashes.contains(current_board_hash)) { FRLogger.logger.warn("This board was already evaluated, so we stop autorouter to avoid the endless loop."); + thread.request_stop(); break; } Integer curr_pass_no = hdlg.get_settings().autoroute_settings.get_start_pass_no(); if (curr_pass_no > hdlg.get_settings().autoroute_settings.get_stop_pass_no()) { + thread.request_stop(); break; } From 085ca90a949169957fb0e6a877dd967ab242a5e9 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 22:14:56 +0100 Subject: [PATCH 12/22] Added 3 events to the InteractiveActionThread class --- .../interactive/BatchAutorouterThread.java | 13 +++++++++++++ .../interactive/InteractiveActionThread.java | 10 ++++++++++ .../interactive/ThreadActionListener.java | 7 +++++++ 3 files changed, 30 insertions(+) create mode 100644 src/main/java/eu/mihosoft/freerouting/interactive/ThreadActionListener.java diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java b/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java index 74ab5af..1ba1f7c 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/BatchAutorouterThread.java @@ -53,6 +53,9 @@ public class BatchAutorouterThread extends InteractiveActionThread protected void thread_action() { + for (ThreadActionListener hl : this.listeners) + hl.autorouterStarted(); + FRLogger.traceEntry("BatchAutorouterThread.thread_action()"); try @@ -133,6 +136,16 @@ public class BatchAutorouterThread extends InteractiveActionThread } FRLogger.traceExit("BatchAutorouterThread.thread_action()"); + + for (ThreadActionListener hl : this.listeners) + { + if (this.is_stop_requested()) { + hl.autorouterAborted(); + } + else { + hl.autorouterFinished(); + } + } } public void draw(java.awt.Graphics p_graphics) diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/InteractiveActionThread.java b/src/main/java/eu/mihosoft/freerouting/interactive/InteractiveActionThread.java index bdc7927..9a95972 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/InteractiveActionThread.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/InteractiveActionThread.java @@ -23,6 +23,10 @@ */ package eu.mihosoft.freerouting.interactive; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + /** * Used for running an eu.mihosoft.freerouting.interactive action in a seperate Thread, * that can be stopped by the user. @@ -31,6 +35,11 @@ package eu.mihosoft.freerouting.interactive; */ public abstract class InteractiveActionThread extends Thread implements eu.mihosoft.freerouting.datastructures.Stoppable { + protected List listeners = new ArrayList(); + + public void addListener(ThreadActionListener toAdd) { + listeners.add(toAdd); + } public static InteractiveActionThread get_autoroute_instance(BoardHandling p_board_handling) { @@ -234,3 +243,4 @@ public abstract class InteractiveActionThread extends Thread implements eu.mihos private final java.io.InputStream input_stream; } } + diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/ThreadActionListener.java b/src/main/java/eu/mihosoft/freerouting/interactive/ThreadActionListener.java new file mode 100644 index 0000000..1caf8a3 --- /dev/null +++ b/src/main/java/eu/mihosoft/freerouting/interactive/ThreadActionListener.java @@ -0,0 +1,7 @@ +package eu.mihosoft.freerouting.interactive; + +public interface ThreadActionListener { + void autorouterStarted(); + void autorouterAborted(); + void autorouterFinished(); +} From 27a1b07398d0c8c7ce80ebf463d1fa27e92f6047 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 22:16:07 +0100 Subject: [PATCH 13/22] Autorouter starter batch method returns the actual thread now --- .../eu/mihosoft/freerouting/interactive/BoardHandling.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java b/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java index 7862b3f..1aa3dd9 100644 --- a/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java +++ b/src/main/java/eu/mihosoft/freerouting/interactive/BoardHandling.java @@ -1468,15 +1468,18 @@ public class BoardHandling extends BoardHandlingImpl /** * Start the batch autorouter on the whole Board */ - public void start_batch_autorouter() + public InteractiveActionThread start_batch_autorouter() { if (board_is_read_only) { - return; + return null; } board.generate_snapshot(); this.interactive_action_thread = InteractiveActionThread.get_batch_autorouter_instance(this); + this.interactive_action_thread.start(); + + return this.interactive_action_thread; } /** From a8e5d14b4353241ba03b12866259f6a16f09d229 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 22:17:42 +0100 Subject: [PATCH 14/22] Added the automatic DNS file exportation after autorouting feature --- .../freerouting/gui/MainApplication.java | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 9f666ff..c413b11 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -24,6 +24,7 @@ package eu.mihosoft.freerouting.gui; import eu.mihosoft.freerouting.board.TestLevel; +import eu.mihosoft.freerouting.interactive.ThreadActionListener; import eu.mihosoft.freerouting.logger.FRLogger; import javax.swing.UIManager; @@ -106,12 +107,48 @@ public class MainApplication extends javax.swing.JFrame new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(startupOptions.pass_number_last); if (startupOptions.pass_number_last < 99999) { - new_frame.board_panel.board_handling.start_batch_autorouter(); + var thread = new_frame.board_panel.board_handling.start_batch_autorouter(); + + thread.addListener(new ThreadActionListener() { + @Override + public void autorouterStarted() { + } + + @Override + public void autorouterAborted() { + SaveDSNFile(); + } + + @Override + public void autorouterFinished() { + SaveDSNFile(); + } + + private void SaveDSNFile() + { + if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) + { + // save dsn file + FRLogger.logger.info("Saving '"+startupOptions.design_output_filename+"'..."); + try + { + java.io.OutputStream output_stream = new java.io.FileOutputStream(startupOptions.design_output_filename); + String[] file_name_parts = startupOptions.design_output_filename.split("\\.", 2); + String design_name = file_name_parts[0]; + + new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); + + } catch (Exception e) + { + FRLogger.logger.error(e); + } + } + } + }); } new_frame.addWindowListener(new java.awt.event.WindowAdapter() { - @Override public void windowClosed(java.awt.event.WindowEvent evt) { From 90839aa2aedb8439bcc065cbfac877d349829296 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 22:28:07 +0100 Subject: [PATCH 15/22] Added a logic to exit the application if the output file was set and the saving of the .dsn was successful --- src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index c413b11..62ed5d9 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -137,7 +137,7 @@ public class MainApplication extends javax.swing.JFrame String design_name = file_name_parts[0]; new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); - + Runtime.getRuntime().exit(0); } catch (Exception e) { FRLogger.logger.error(e); From cdd1a5db296d446087e99fbc0d585acba3b77af3 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Tue, 4 Feb 2020 22:40:07 +0100 Subject: [PATCH 16/22] Replaced the first and last pass parameters with the max passes parameter It makes more sense to use a single command line argument to set the maximum number of passes we are willing to make. It's now "-mp " --- .../freerouting/gui/MainApplication.java | 22 ++++++++----------- .../freerouting/gui/StartupOptions.java | 11 +++------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 62ed5d9..2ed544b 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -29,6 +29,7 @@ import eu.mihosoft.freerouting.logger.FRLogger; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import java.io.File; /** * @@ -99,13 +100,8 @@ public class MainApplication extends javax.swing.JFrame return; } - if (startupOptions.pass_number_first > 0) { - new_frame.board_panel.board_handling.settings.autoroute_settings.set_start_pass_no(startupOptions.pass_number_first); - new_frame.board_panel.board_frame.autoroute_parameter_window.refresh(); - } - - new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(startupOptions.pass_number_last); - if (startupOptions.pass_number_last < 99999) + new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(new_frame.board_panel.board_handling.settings.autoroute_settings.get_start_pass_no() + startupOptions.max_passes); + if (startupOptions.max_passes < 99999) { var thread = new_frame.board_panel.board_handling.start_batch_autorouter(); @@ -116,15 +112,15 @@ public class MainApplication extends javax.swing.JFrame @Override public void autorouterAborted() { - SaveDSNFile(); + ExportBoardToDSNFile(); } @Override public void autorouterFinished() { - SaveDSNFile(); + ExportBoardToDSNFile(); } - private void SaveDSNFile() + private void ExportBoardToDSNFile() { if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) { @@ -132,10 +128,10 @@ public class MainApplication extends javax.swing.JFrame FRLogger.logger.info("Saving '"+startupOptions.design_output_filename+"'..."); try { - java.io.OutputStream output_stream = new java.io.FileOutputStream(startupOptions.design_output_filename); - String[] file_name_parts = startupOptions.design_output_filename.split("\\.", 2); - String design_name = file_name_parts[0]; + String filename_only = new File(startupOptions.design_output_filename).getName(); + String design_name = filename_only.substring(0, filename_only.length() - 4); + java.io.OutputStream output_stream = new java.io.FileOutputStream(startupOptions.design_output_filename); new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); Runtime.getRuntime().exit(0); } catch (Exception e) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java b/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java index 218636b..b70f862 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/StartupOptions.java @@ -16,8 +16,7 @@ public class StartupOptions { String design_input_filename = null; String design_output_filename = null; String design_input_directory_name = null; - int pass_number_first = 0; - int pass_number_last = 99999; + int max_passes = 99999; java.util.Locale current_locale = java.util.Locale.ENGLISH; private StartupOptions() { @@ -51,13 +50,9 @@ public class StartupOptions { if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { design_output_filename = p_args[i + 1]; } - } else if (p_args[i].startsWith("-pf")) { + } else if (p_args[i].startsWith("-mp")) { if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - pass_number_first = Integer.decode(p_args[i + 1]); - } - } else if (p_args[i].startsWith("-pl")) { - if (p_args.length > i + 1 && !p_args[i + 1].startsWith("-")) { - pass_number_last = Integer.decode(p_args[i + 1]); + max_passes = Integer.decode(p_args[i + 1]); } } else if (p_args[i].startsWith("-l")) { // the locale is provided From 44419c9670e23d66aea8f545a6c96d3e77f7c3ca Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Wed, 5 Feb 2020 11:19:01 +0100 Subject: [PATCH 17/22] Changed the .dsn export sligthly --- .../freerouting/gui/MainApplication.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 2ed544b..672d7f3 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -112,32 +112,32 @@ public class MainApplication extends javax.swing.JFrame @Override public void autorouterAborted() { - ExportBoardToDSNFile(); + if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) { + ExportBoardToDSNFile(); + } } @Override public void autorouterFinished() { - ExportBoardToDSNFile(); + if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) { + ExportBoardToDSNFile(); + } } private void ExportBoardToDSNFile() { - if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) + FRLogger.logger.info("Saving '"+startupOptions.design_output_filename+"'..."); + try { - // save dsn file - FRLogger.logger.info("Saving '"+startupOptions.design_output_filename+"'..."); - try - { - String filename_only = new File(startupOptions.design_output_filename).getName(); - String design_name = filename_only.substring(0, filename_only.length() - 4); + String filename_only = new File(startupOptions.design_output_filename).getName(); + String design_name = filename_only.substring(0, filename_only.length() - 4); - java.io.OutputStream output_stream = new java.io.FileOutputStream(startupOptions.design_output_filename); - new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); - Runtime.getRuntime().exit(0); - } catch (Exception e) - { - FRLogger.logger.error(e); - } + java.io.OutputStream output_stream = new java.io.FileOutputStream(startupOptions.design_output_filename); + new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); + Runtime.getRuntime().exit(0); + } catch (Exception e) + { + FRLogger.logger.error(e); } } }); From 7aa430893d3a760780dcb9dab141c32d34ffa175 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Wed, 5 Feb 2020 12:34:22 +0100 Subject: [PATCH 18/22] Update the readme to reflect the changes in the command line arguments --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e393a21..65db8b8 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,10 @@ Navigate to the [Gradle](http://www.gradle.org/) project (e.g., `path/to/freerou #### Windows (CMD) gradlew assemble + +#### Generated Executables + +All four .jar files will be generated in the _build\libs_ subfolder. You would typically run the _freerouting-executable.jar_ file. ## From the original author: @@ -54,7 +58,7 @@ Java Based Printed Circuit Board Routing Software from FreeRouting.net written b http://www.freerouting.net/fen/viewtopic.php?f=4&t=255 -by alfons � Sat Mar 08, 2014 12:07 pm +by alfons © Sat Mar 08, 2014 12:07 pm Because I am no more maintaining the Freerouting project since 4 years and future Java versions may block my Freerouting Java Web Start application completely, I finally decided to open the source of the Freerouting project under the GNU public license version 3. @@ -116,3 +120,23 @@ Additional steps for users of KiCad: 5) When you're finished, export the results into a Specctra session file (File / Export Specctra Session File). The router will generate a .ses file for you. 6) Go back to KiCad's Pcbnew and import the results (File / Import Specctra Session...). + + +Using the command line arguments: +================================= + +Freerouter was designed as a GUI program, but it also can function as a command line tool. Typically you would have an input file (e.g. Specctra DSN) that you exported from you EDA (e.g. KiCad). If this file has unconnected routes, you would want to wire those with autorouter, and save the result in a format that you can then import back into your EDA. + +The following command line arguments are supported by freerouter: + +* -de [design input file]: loads up a Specctra .dsn file at startup +* -di [design input directory] +* -do [design output file]: saves a Specctra board (.dsn), a Specctra session file (.ses) or Eagle session script file (.scr) when the routing is finished +* -mp [number of passes]: sets the upper limit of the number of passes that will be performed +* -l [language]: "de" for German, otherwise it's English + +A complete command line looks something like this: + +` +freerouter-executable.jar -de MyBoard.dsn -do MyBoard.ses -mp 100 +` \ No newline at end of file From 8eabae57234b1dd72b6520866afd0006910b09b2 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Wed, 5 Feb 2020 12:54:26 +0100 Subject: [PATCH 19/22] Added support for .ses and .scr file exports with command line --- .../freerouting/gui/MainApplication.java | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index 672d7f3..cf874f8 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -29,6 +29,8 @@ import eu.mihosoft.freerouting.logger.FRLogger; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; /** @@ -112,32 +114,44 @@ public class MainApplication extends javax.swing.JFrame @Override public void autorouterAborted() { - if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) { - ExportBoardToDSNFile(); - } + ExportBoardToFile(startupOptions.design_output_filename); } @Override public void autorouterFinished() { - if ((startupOptions.design_output_filename != null) && (startupOptions.design_output_filename.toLowerCase().endsWith(".dsn"))) { - ExportBoardToDSNFile(); - } + ExportBoardToFile(startupOptions.design_output_filename); } - private void ExportBoardToDSNFile() - { - FRLogger.logger.info("Saving '"+startupOptions.design_output_filename+"'..."); - try - { - String filename_only = new File(startupOptions.design_output_filename).getName(); - String design_name = filename_only.substring(0, filename_only.length() - 4); + private void ExportBoardToFile(String filename) { + if ((filename != null) + && ((filename.toLowerCase().endsWith(".dsn")) + || (filename.toLowerCase().endsWith(".ses")) + || (filename.toLowerCase().endsWith(".scr")))) { - java.io.OutputStream output_stream = new java.io.FileOutputStream(startupOptions.design_output_filename); - new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); - Runtime.getRuntime().exit(0); - } catch (Exception e) - { - FRLogger.logger.error(e); + FRLogger.logger.info("Saving '" + filename + "'..."); + try { + String filename_only = new File(filename).getName(); + String design_name = filename_only.substring(0, filename_only.length() - 4); + + java.io.OutputStream output_stream = new java.io.FileOutputStream(filename); + + if (filename.toLowerCase().endsWith(".dsn")) { + new_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false); + } else if (filename.toLowerCase().endsWith(".ses")) { + new_frame.board_panel.board_handling.export_specctra_session_file(design_name, output_stream); + } else if (filename.toLowerCase().endsWith(".scr")) { + java.io.ByteArrayOutputStream session_output_stream = new ByteArrayOutputStream(); + new_frame.board_panel.board_handling.export_specctra_session_file(filename, session_output_stream); + java.io.InputStream input_stream = new ByteArrayInputStream(session_output_stream.toByteArray()); + new_frame.board_panel.board_handling.export_eagle_session_file(input_stream, output_stream); + } + + Runtime.getRuntime().exit(0); + } catch (Exception e) { + FRLogger.logger.error(e); + } + } else { + FRLogger.logger.error("Couldn't export board to '" + filename + "'."); } } }); From b88655de898c3e592fbbcbb4528f7f3b4cee2815 Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Wed, 5 Feb 2020 13:32:19 +0100 Subject: [PATCH 20/22] Added explanation for the -di command line argument --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65db8b8..46d5aad 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Freerouter was designed as a GUI program, but it also can function as a command The following command line arguments are supported by freerouter: * -de [design input file]: loads up a Specctra .dsn file at startup -* -di [design input directory] +* -di [design input directory]: if the GUI is used, this sets the default folder for the open design dialogs * -do [design output file]: saves a Specctra board (.dsn), a Specctra session file (.ses) or Eagle session script file (.scr) when the routing is finished * -mp [number of passes]: sets the upper limit of the number of passes that will be performed * -l [language]: "de" for German, otherwise it's English From 064c5cd6c7cae9f3bce2cacef93a4f257cf5572e Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Thu, 6 Feb 2020 13:04:41 +0100 Subject: [PATCH 21/22] Modified the command line example for users using PowerShell --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 46d5aad..928bc88 100644 --- a/README.md +++ b/README.md @@ -135,8 +135,10 @@ The following command line arguments are supported by freerouter: * -mp [number of passes]: sets the upper limit of the number of passes that will be performed * -l [language]: "de" for German, otherwise it's English -A complete command line looks something like this: +A complete command line looks something like this if your are using PowerShell on Windows: ` -freerouter-executable.jar -de MyBoard.dsn -do MyBoard.ses -mp 100 -` \ No newline at end of file +& "c:\Program Files\Java\jdk-11.0.6\bin\java.exe" -jar freerouting-executable.jar -de MyBoard.dsn -do MyBoard.ses -mp 100 +` + +This would read the _MyBoard.dsn_ file, do the auto-routing for the maximum of 100 passes, and then save the result into the _MyBoard.ses_ file. \ No newline at end of file From ef99012263f237044266b665812fd4ca031d436e Mon Sep 17 00:00:00 2001 From: Andras Fuchs Date: Thu, 6 Feb 2020 13:11:56 +0100 Subject: [PATCH 22/22] Fixed the -mp parameter calculation --- src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java index cf874f8..e606d23 100644 --- a/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java +++ b/src/main/java/eu/mihosoft/freerouting/gui/MainApplication.java @@ -102,7 +102,7 @@ public class MainApplication extends javax.swing.JFrame return; } - new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(new_frame.board_panel.board_handling.settings.autoroute_settings.get_start_pass_no() + startupOptions.max_passes); + new_frame.board_panel.board_handling.settings.autoroute_settings.set_stop_pass_no(new_frame.board_panel.board_handling.settings.autoroute_settings.get_start_pass_no() + startupOptions.max_passes - 1); if (startupOptions.max_passes < 99999) { var thread = new_frame.board_panel.board_handling.start_batch_autorouter();