forked from nikropht/FreeRouting
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMoveDrillItemAlgo.java
More file actions
344 lines (327 loc) · 13.6 KB
/
Copy pathMoveDrillItemAlgo.java
File metadata and controls
344 lines (327 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*
* 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.
*
* ShoveViaAlgo.java
*
* Created on 12. Dezember 2005, 06:48
*
*/
package board;
import java.util.Collection;
import datastructures.TimeLimit;
import geometry.planar.TileShape;
import geometry.planar.ConvexShape;
import geometry.planar.IntOctagon;
import geometry.planar.IntBox;
import geometry.planar.IntPoint;
import geometry.planar.Point;
import geometry.planar.Vector;
import geometry.planar.FloatPoint;
/**
*
* Contains internal auxiliary functions of class RoutingBoard
* for shoving vias and pins
*
* @author Alfons Wirtz
*/
public class MoveDrillItemAlgo
{
/**
* checks, if p_drill_item can be translated by p_vector by shoving obstacle
* traces and vias aside, so that no clearance violations occur.
*/
public static boolean check(DrillItem p_drill_item, Vector p_vector, int p_max_recursion_depth,
int p_max_via_recursion_depth, Collection<Item> p_ignore_items,
RoutingBoard p_board, TimeLimit p_time_limit)
{
if (p_time_limit != null && p_time_limit.limit_exceeded())
{
return false;
}
if (p_drill_item.is_shove_fixed())
{
return false;
}
// Check, that p_drillitem is only connected to traces.
Collection<Item> contact_list = p_drill_item.get_normal_contacts();
for (Item curr_contact : contact_list)
{
if (!(curr_contact instanceof Trace || curr_contact instanceof ConductionArea))
{
return false;
}
}
Collection<Item> ignore_items;
if (p_ignore_items == null)
{
ignore_items = new java.util.LinkedList<Item>();
}
else
{
ignore_items = p_ignore_items;
}
ignore_items.add(p_drill_item);
ForcedPadAlgo forced_pad_algo = new ForcedPadAlgo(p_board);
boolean attach_allowed = false;
if (p_drill_item instanceof Via)
{
attach_allowed = ((Via)p_drill_item).attach_allowed;
}
ShapeSearchTree search_tree = p_board.search_tree_manager.get_default_tree();
for (int curr_layer = p_drill_item.first_layer(); curr_layer <= p_drill_item.last_layer(); ++curr_layer)
{
int curr_ind = curr_layer - p_drill_item.first_layer();
TileShape curr_shape = p_drill_item.get_tree_shape(search_tree, curr_ind);
if (curr_shape == null)
{
continue;
}
ConvexShape new_shape = (ConvexShape) curr_shape.translate_by(p_vector);
TileShape curr_tile_shape;
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
{
curr_tile_shape = new_shape.bounding_box();
}
else
{
curr_tile_shape = new_shape.bounding_octagon();
}
CalcFromSide from_side = new CalcFromSide(p_drill_item.get_center(), curr_tile_shape);
if (forced_pad_algo.check_forced_pad(curr_tile_shape, from_side, curr_layer,
p_drill_item.net_no_arr, p_drill_item.clearance_class_no(), attach_allowed,
ignore_items, p_max_recursion_depth, p_max_via_recursion_depth, true, p_time_limit)
== ForcedPadAlgo.CheckDrillResult.NOT_DRILLABLE)
{
return false;
}
}
return true;
}
/**
* Translates p_drill_item by p_vector by shoving obstacle
* traces and vias aside, so that no clearance violations occur.
* If p_tidy_region != null, it will be joined by the bounding octagons of the translated shapes.
*/
static boolean insert(DrillItem p_drill_item, Vector p_vector,
int p_max_recursion_depth, int p_max_via_recursion_depth, IntOctagon p_tidy_region,
RoutingBoard p_board)
{
if (p_drill_item.is_shove_fixed())
{
return false;
}
boolean attach_allowed = false;
if (p_drill_item instanceof Via)
{
attach_allowed = ((Via)p_drill_item).attach_allowed;
}
ForcedPadAlgo forced_pad_algo = new ForcedPadAlgo(p_board);
Collection<Item> ignore_items = new java.util.LinkedList<Item>();
ignore_items.add(p_drill_item);
ShapeSearchTree search_tree = p_board.search_tree_manager.get_default_tree();
for (int curr_layer = p_drill_item.first_layer(); curr_layer <= p_drill_item.last_layer(); ++curr_layer)
{
int curr_ind = curr_layer - p_drill_item.first_layer();
TileShape curr_shape = p_drill_item.get_tree_shape(search_tree, curr_ind);
if (curr_shape == null)
{
continue;
}
ConvexShape new_shape = (ConvexShape) curr_shape.translate_by(p_vector);
TileShape curr_tile_shape;
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
{
curr_tile_shape = new_shape.bounding_box();
}
else
{
curr_tile_shape = new_shape.bounding_octagon();
}
if (p_tidy_region != null)
{
p_tidy_region = p_tidy_region.union(curr_tile_shape.bounding_octagon());
}
CalcFromSide from_side = new CalcFromSide(p_drill_item.get_center(), curr_tile_shape);
if (!forced_pad_algo.forced_pad(curr_tile_shape, from_side, curr_layer, p_drill_item.net_no_arr,
p_drill_item.clearance_class_no(), attach_allowed,
ignore_items, p_max_recursion_depth, p_max_via_recursion_depth))
{
return false;
}
IntBox curr_bounding_box = curr_shape.bounding_box();
for (int j = 0; j < 4; ++j)
{
p_board.join_changed_area( curr_bounding_box.corner_approx(j), curr_layer);
}
}
p_drill_item.move_by(p_vector);
return true;
}
/**
* Shoves vias out of p_obstacle_shape. Returns false, if the database is damaged, so that an undo is necessary afterwards.
*/
static boolean shove_vias(TileShape p_obstacle_shape, CalcFromSide p_from_side, int p_layer, int[] p_net_no_arr,
int p_cl_type, Collection<Item> p_ignore_items, int p_max_recursion_depth,
int p_max_via_recursion_depth, boolean p_copper_sharing_allowed,
RoutingBoard p_board)
{
ShapeSearchTree search_tree = p_board.search_tree_manager.get_default_tree();
ShapeTraceEntries shape_entries =
new ShapeTraceEntries(p_obstacle_shape, p_layer, p_net_no_arr, p_cl_type, p_from_side, p_board);
Collection<Item> obstacles =
search_tree.overlapping_items_with_clearance(p_obstacle_shape, p_layer, new int[0], p_cl_type);
if (!shape_entries.store_items(obstacles, false, p_copper_sharing_allowed))
{
return true;
}
if (p_ignore_items != null)
{
shape_entries.shove_via_list.removeAll(p_ignore_items);
}
if (shape_entries.shove_via_list.isEmpty())
{
return true;
}
double shape_radius = 0.5 * p_obstacle_shape.bounding_box().min_width();
for (Via curr_via : shape_entries.shove_via_list)
{
if (curr_via.shares_net_no(p_net_no_arr))
{
continue;
}
if (p_max_via_recursion_depth <= 0)
{
return true;
}
IntPoint [] try_via_centers =
try_shove_via_points(p_obstacle_shape, p_layer, curr_via, p_cl_type, true, p_board);
IntPoint new_via_center = null;
double max_dist = 0.5 * curr_via.get_shape_on_layer(p_layer).bounding_box().max_width() + shape_radius;
double max_dist_square = max_dist * max_dist;
IntPoint curr_via_center = (IntPoint) curr_via.get_center();
FloatPoint check_via_center = curr_via_center.to_float();
Vector rel_coor = null;
for (int i = 0; i < try_via_centers.length; ++i)
{
if (i == 0 || check_via_center.distance_square(try_via_centers[i].to_float()) <= max_dist_square)
{
Collection<Item> ignore_items = new java.util.LinkedList<Item>();
if (p_ignore_items != null)
{
ignore_items.addAll(p_ignore_items);
}
rel_coor = try_via_centers[i].difference_by(curr_via_center);
// No time limit here because the item database is already changed.
boolean shove_ok = check(curr_via, rel_coor, p_max_recursion_depth,
p_max_via_recursion_depth - 1, ignore_items, p_board, null);
if (shove_ok)
{
new_via_center = try_via_centers[i];
break;
}
}
}
if (new_via_center == null)
{
continue;
}
if (!insert(curr_via, rel_coor, p_max_recursion_depth, p_max_via_recursion_depth - 1, null, p_board))
{
return false;
}
}
return true;
}
/**
* Calculates possible new location for a via to shove outside p_obstacle_shape.
* if p_extended_check is true, more than 1 possible new locations are calculated.
* The function isused here and in ShoveTraceAlgo.check.
*/
static IntPoint[] try_shove_via_points(TileShape p_obstacle_shape, int p_layer, Via p_via, int p_cl_class_no,
boolean p_extended_check, RoutingBoard p_board)
{
ShapeSearchTree search_tree = p_board.search_tree_manager.get_default_tree();
TileShape curr_via_shape = p_via.get_tree_shape_on_layer(search_tree, p_layer);
if (curr_via_shape == null)
{
return new IntPoint [0];
}
boolean is_int_octagon = p_obstacle_shape.is_IntOctagon();
double clearance_value = p_board.clearance_value(p_cl_class_no, p_via.clearance_class_no(), p_layer);
double shove_distance;
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE ||is_int_octagon )
{
shove_distance = 0.5 * curr_via_shape.bounding_box().max_width();
if (!search_tree.is_clearance_compensation_used())
{
shove_distance += clearance_value;
}
}
else
{
// a different algorithm is used for calculating the new via centers
shove_distance = 0;
if (!search_tree.is_clearance_compensation_used())
{
// enlarge p_obstacle_shape and curr_via_shape by half of the clearance value to syncronize
// with the check algorithm in ShapeSearchTree.overlapping_tree_entries_with_clearance
shove_distance += 0.5 * clearance_value;
}
}
// The additional constant 2 is an empirical value for the tolerance in case of diagonal shoving.
shove_distance += 2;
IntPoint curr_via_center = (IntPoint) p_via.get_center();
IntPoint [] try_via_centers;
int try_count = 1;
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
{
IntBox curr_offset_box = p_obstacle_shape.bounding_box().offset(shove_distance);
if (p_extended_check)
{
try_count = 2;
}
try_via_centers = curr_offset_box.nearest_border_projections(curr_via_center, try_count);
}
else if (is_int_octagon)
{
IntOctagon curr_offset_octagon = p_obstacle_shape.bounding_octagon().enlarge(shove_distance);
if (p_extended_check)
{
try_count = 4;
}
try_via_centers = curr_offset_octagon.nearest_border_projections(curr_via_center, try_count);
}
else
{
TileShape curr_offset_shape = (TileShape) p_obstacle_shape.enlarge(shove_distance);
if (!search_tree.is_clearance_compensation_used())
{
curr_via_shape = (TileShape) curr_via_shape.enlarge(0.5 * clearance_value);
}
if (p_extended_check)
{
try_count = 4;
}
FloatPoint[] shove_deltas = curr_offset_shape.nearest_relative_outside_locations(curr_via_shape, try_count);
try_via_centers = new IntPoint[shove_deltas.length];
for (int i = 0; i < try_via_centers.length; ++i)
{
Vector curr_delta = shove_deltas[i].round().difference_by(Point.ZERO);
try_via_centers[i] = (IntPoint) curr_via_center.translate_by(curr_delta);
}
}
return try_via_centers;
}
}