/*
* Copyright (C) 2014 Alfons Wirtz
* website www.freerouting.net
*
* This program 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.
*
* This program 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 at <http://www.gnu.org/licenses/>
* for more details.
*
* ExpandTestState.java
*
* Created on 23. Dezember 2003, 07:56
*/
package interactive;
import geometry.planar.FloatPoint;
import geometry.planar.TileShape;
import java.util.Collection;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Iterator;
import autoroute.AutorouteControl;
import autoroute.CompleteFreeSpaceExpansionRoom;
import autoroute.IncompleteFreeSpaceExpansionRoom;
import autoroute.InsertFoundConnectionAlgo;
import autoroute.LocateFoundConnectionAlgo;
import autoroute.MazeSearchAlgo;
import autoroute.AutorouteEngine;
import board.Item;
import board.RoutingBoard;
/**
* State for testing the expanding algorithm of the autorouter.
*
* @author Alfons Wirtz
*/
public class ExpandTestState extends InteractiveState
{
public static ExpandTestState get_instance(FloatPoint p_location, InteractiveState p_return_state, BoardHandling p_board_handling)
{
ExpandTestState result = new ExpandTestState(p_location, p_return_state, p_board_handling);
return result;
}
/** Creates a new instance of ExpandTestState */
private ExpandTestState(FloatPoint p_location, InteractiveState p_return_state, BoardHandling p_board_handling)
{
super(p_return_state, p_board_handling, null);
init(p_location);
}
public InteractiveState key_typed(char p_key_char)
{
InteractiveState result;
if (p_key_char == 'n')
{
if (in_autoroute)
{
if (!this.maze_search_algo.occupy_next_element())
{
// to display the backtack rooms
complete_autoroute();
hdlg.screen_messages.set_status_message("expansion completed");
}
}
else
{
boolean completing_succeeded = false;
while (!completing_succeeded)
{
IncompleteFreeSpaceExpansionRoom next_room = this.autoroute_engine.get_first_incomplete_expansion_room();
if (next_room == null)
{
hdlg.screen_messages.set_status_message("expansion completed");
break;
}
completing_succeeded = complete_expansion_room(next_room);
}
}
//hdlg.get_routing_board().autoroute_data().validate();
result = this;
}
else if (p_key_char == 'a')
{
if (in_autoroute)
{
complete_autoroute();
}
else
{
IncompleteFreeSpaceExpansionRoom next_room = this.autoroute_engine.get_first_incomplete_expansion_room();
while (next_room != null)
{
complete_expansion_room(next_room);
next_room = this.autoroute_engine.get_first_incomplete_expansion_room();
}
}
result = this;
//hdlg.get_routing_board().autoroute_data().validate();
}
else if (Character.isDigit(p_key_char))
{
// next 10^p_key_char expansions
int d = Character.digit(p_key_char, 10);
final int max_count = (int) Math.pow(10, d);
if (in_autoroute)
{
for (int i = 0; i < max_count; ++i)
{
if (!this.maze_search_algo.occupy_next_element())
{
// to display the backtack rooms
complete_autoroute();
hdlg.screen_messages.set_status_message("expansion completed");
break;
}
}
}
else
{
int curr_count = 0;
IncompleteFreeSpaceExpansionRoom next_room = this.autoroute_engine.get_first_incomplete_expansion_room();
while (next_room != null && curr_count < max_count)
{
complete_expansion_room(next_room);
next_room = this.autoroute_engine.get_first_incomplete_expansion_room();
++curr_count;
}
}
result = this;
//hdlg.get_routing_board().autoroute_data().validate();
}
else
{
autoroute_engine.clear();
result = super.key_typed(p_key_char);
}
hdlg.repaint();
return result;
}
public InteractiveState left_button_clicked(FloatPoint p_location)
{
return cancel();
}
public InteractiveState cancel()
{
autoroute_engine.clear();
return this.return_state;
}
public InteractiveState complete()
{
return cancel();
}
public void draw(java.awt.Graphics p_graphics)
{
autoroute_engine.draw(p_graphics, hdlg.graphics_context, 0.1);
if (this.autoroute_result != null)
{
this.autoroute_result.draw(p_graphics, hdlg.graphics_context);
}
}
private void init(FloatPoint p_location)
{
// look if an autoroute can be started at the input location
RoutingBoard board = hdlg.get_routing_board();
int layer = hdlg.settings.layer;
Collection<Item> found_items = board.pick_items(p_location.round(), layer, null);
Item route_item = null;
int route_net_no = 0;
Iterator<Item> it = found_items.iterator();
while (it.hasNext())
{
Item curr_ob = it.next();
if (curr_ob instanceof board.Connectable)
{
Item curr_item = curr_ob;
if (curr_item.net_count() == 1 && curr_item.get_net_no(0) > 0)
{
route_item = curr_item;
route_net_no = curr_item.get_net_no(0);
break;
}
}
}
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_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);
this.autoroute_engine.init_connection(route_net_no, null, null);
if (route_item == null)
{
// create an expansion room in the empty space
TileShape contained_shape = TileShape.get_instance(p_location.round());
IncompleteFreeSpaceExpansionRoom expansion_room =
autoroute_engine.add_incomplete_expansion_room(null, layer, contained_shape);
hdlg.screen_messages.set_status_message("expansion test started");
complete_expansion_room(expansion_room);
return;
}
Set<Item> route_start_set = route_item.get_connected_set(route_net_no);
Set<Item> route_dest_set = route_item.get_unconnected_set(route_net_no);
if (route_dest_set.size() > 0)
{
hdlg.screen_messages.set_status_message("autoroute test started");
this.maze_search_algo =
MazeSearchAlgo.get_instance(route_start_set, route_dest_set, autoroute_engine, control_settings);
this.in_autoroute = (this.maze_search_algo != null);
}
}
private void complete_autoroute()
{
MazeSearchAlgo.Result search_result = this.maze_search_algo.find_connection();
if (search_result != null)
{
SortedSet<Item> ripped_item_list = new TreeSet<Item>();
this.autoroute_result =
LocateFoundConnectionAlgo.get_instance(search_result, control_settings,
this.autoroute_engine.autoroute_search_tree,
hdlg.get_routing_board().rules.get_trace_angle_restriction(),
ripped_item_list, board.TestLevel.ALL_DEBUGGING_OUTPUT);
hdlg.get_routing_board().generate_snapshot();
SortedSet<Item> ripped_connections = new TreeSet<Item>();
for (Item curr_ripped_item : ripped_item_list)
{
ripped_connections.addAll(curr_ripped_item.get_connection_items(Item.StopConnectionOption.VIA));
}
hdlg.get_routing_board().remove_items(ripped_connections, false);
InsertFoundConnectionAlgo.get_instance(autoroute_result, hdlg.get_routing_board(), control_settings);
}
}
/**
* Returns true, if the completion succeeded.
*/
private boolean complete_expansion_room(IncompleteFreeSpaceExpansionRoom p_incomplete_room)
{
Collection<CompleteFreeSpaceExpansionRoom> completed_rooms = autoroute_engine.complete_expansion_room(p_incomplete_room);
return (completed_rooms.size() > 0);
}
private boolean in_autoroute = false;
private MazeSearchAlgo maze_search_algo = null;
private LocateFoundConnectionAlgo autoroute_result = null;
private AutorouteControl control_settings;
private AutorouteEngine autoroute_engine;
}