KiCad PCB EDA Suite
ar_matrix.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 Jean-Pierre Charras, [email protected]
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6  * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
7  *
8  * Copyright (C) 1992-2020 KiCad Developers, see change_log.txt for contributors.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
28 #include "ar_matrix.h"
29 #include <math/util.h> // for KiROUND
30 #include <math_for_graphics.h>
31 #include <trigo.h>
32 
33 #include <pcb_shape.h>
34 #include <pad.h>
35 
37 {
38  m_BoardSide[0] = nullptr;
39  m_BoardSide[1] = nullptr;
40  m_DistSide[0] = nullptr;
41  m_DistSide[1] = nullptr;
42  m_opWriteCell = nullptr;
43  m_Nrows = 0;
44  m_Ncols = 0;
45  m_MemSize = 0;
47  m_GridRouting = 0;
48  m_RouteCount = 0;
51 }
52 
53 
55 {
56 }
57 
58 // was: bool AR_MATRIX::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnly )
59 // aUseBoardEdgesOnly ? aPcb->GetBoardEdgesBoundingBox() : aPcb->GetBoundingBox();
60 
61 bool AR_MATRIX::ComputeMatrixSize( const EDA_RECT& aBoundingBox )
62 {
63  // The boundary box must have its start point on routing grid:
64  m_BrdBox = aBoundingBox;
65 
68 
69  // The boundary box must have its end point on routing grid:
70  wxPoint end = m_BrdBox.GetEnd();
71 
72  end.x -= end.x % m_GridRouting;
73  end.x += m_GridRouting;
74 
75  end.y -= end.y % m_GridRouting;
76  end.y += m_GridRouting;
77 
78  m_BrdBox.SetEnd( end );
79 
82 
83  // gives a small margin
84  m_Ncols += 1;
85  m_Nrows += 1;
86 
87  return true;
88 }
89 
90 
92 {
93  if( m_Nrows <= 0 || m_Ncols <= 0 )
94  return 0;
95 
96  // give a small margin for memory allocation:
97  int ii = ( m_Nrows + 1 ) * ( m_Ncols + 1 );
98 
99  int side = AR_SIDE_BOTTOM;
100  for( int jj = 0; jj < m_RoutingLayersCount; jj++ ) // m_RoutingLayersCount = 1 or 2
101  {
102  m_BoardSide[side] = nullptr;
103  m_DistSide[side] = nullptr;
104 
105  // allocate matrix & initialize everything to empty
106  m_BoardSide[side] = new MATRIX_CELL[ ii * sizeof( MATRIX_CELL ) ];
107  memset( m_BoardSide[side], 0, ii * sizeof( MATRIX_CELL ) );
108 
109  if( m_BoardSide[side] == nullptr )
110  return -1;
111 
112  // allocate Distances
113  m_DistSide[side] = new DIST_CELL[ ii * sizeof( DIST_CELL ) ];
114  memset( m_DistSide[side], 0, ii * sizeof( DIST_CELL ) );
115 
116  if( m_DistSide[side] == nullptr )
117  return -1;
118 
119  side = AR_SIDE_TOP;
120  }
121 
122  m_MemSize = m_RouteCount * ii * ( sizeof( MATRIX_CELL ) + sizeof( DIST_CELL ) );
123 
124  return m_MemSize;
125 }
126 
127 
129 {
130  int ii;
131 
132  for( ii = 0; ii < AR_MAX_ROUTING_LAYERS_COUNT; ii++ )
133  {
134  // de-allocate Distances matrix
135  if( m_DistSide[ii] )
136  {
137  delete[] m_DistSide[ii];
138  m_DistSide[ii] = nullptr;
139  }
140 
141  // de-allocate cells matrix
142  if( m_BoardSide[ii] )
143  {
144  delete[] m_BoardSide[ii];
145  m_BoardSide[ii] = nullptr;
146  }
147  }
148 
149  m_Nrows = m_Ncols = 0;
150 }
151 
152 // Initialize m_opWriteCell member to make the aLogicOp
154 {
155  switch( aLogicOp )
156  {
157  default:
163  }
164 }
165 
166 
167 /* return the value stored in a cell
168  */
169 AR_MATRIX::MATRIX_CELL AR_MATRIX::GetCell( int aRow, int aCol, int aSide )
170 {
171  MATRIX_CELL* p;
172 
173  p = m_BoardSide[aSide];
174  return p[aRow * m_Ncols + aCol];
175 }
176 
177 
178 /* basic cell operation : WRITE operation
179  */
180 void AR_MATRIX::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
181 {
182  MATRIX_CELL* p;
183 
184  p = m_BoardSide[aSide];
185  p[aRow * m_Ncols + aCol] = x;
186 }
187 
188 
189 /* basic cell operation : OR operation
190  */
191 void AR_MATRIX::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
192 {
193  MATRIX_CELL* p;
194 
195  p = m_BoardSide[aSide];
196  p[aRow * m_Ncols + aCol] |= x;
197 }
198 
199 
200 /* basic cell operation : XOR operation
201  */
202 void AR_MATRIX::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
203 {
204  MATRIX_CELL* p;
205 
206  p = m_BoardSide[aSide];
207  p[aRow * m_Ncols + aCol] ^= x;
208 }
209 
210 
211 /* basic cell operation : AND operation
212  */
213 void AR_MATRIX::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
214 {
215  MATRIX_CELL* p;
216 
217  p = m_BoardSide[aSide];
218  p[aRow * m_Ncols + aCol] &= x;
219 }
220 
221 
222 /* basic cell operation : ADD operation
223  */
224 void AR_MATRIX::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
225 {
226  MATRIX_CELL* p;
227 
228  p = m_BoardSide[aSide];
229  p[aRow * m_Ncols + aCol] += x;
230 }
231 
232 
233 // fetch distance cell
234 AR_MATRIX::DIST_CELL AR_MATRIX::GetDist( int aRow, int aCol, int aSide ) // fetch distance cell
235 {
236  DIST_CELL* p;
237 
238  p = m_DistSide[aSide];
239  return p[aRow * m_Ncols + aCol];
240 }
241 
242 
243 // store distance cell
244 void AR_MATRIX::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
245 {
246  DIST_CELL* p;
247 
248  p = m_DistSide[aSide];
249  p[aRow * m_Ncols + aCol] = x;
250 }
251 
252 
253 /*
254 ** x is the direction to enter the cell of interest.
255 ** y is the direction to exit the cell of interest.
256 ** z is the direction to really exit the cell, if y=FROM_OTHERSIDE.
257 **
258 ** return the distance of the trace through the cell of interest.
259 ** the calculation is driven by the tables above.
260 */
261 
262 
263 #define OP_CELL( layer, dy, dx ) \
264  { \
265  if( layer == UNDEFINED_LAYER ) \
266  { \
267  WriteCell( dy, dx, AR_SIDE_BOTTOM, color ); \
268  if( m_RoutingLayersCount > 1 ) \
269  WriteCell( dy, dx, AR_SIDE_TOP, color ); \
270  } \
271  else \
272  { \
273  if( layer == m_routeLayerBottom ) \
274  WriteCell( dy, dx, AR_SIDE_BOTTOM, color ); \
275  if( m_RoutingLayersCount > 1 ) \
276  if( layer == m_routeLayerTop ) \
277  WriteCell( dy, dx, AR_SIDE_TOP, color ); \
278  } \
279  }
280 
281 /* Fills all cells inside a segment
282  * half-width = lg, org = ux0,uy0 end = ux1,uy1
283  * coordinates are in PCB units
284  */
285 void AR_MATRIX::drawSegmentQcq( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
286  int color, AR_MATRIX::CELL_OP op_logic )
287 {
288  int64_t row, col;
289  int64_t inc;
290  int64_t row_max, col_max, row_min, col_min;
291  int64_t demi_pas;
292 
293  int cx, cy, dx, dy;
294 
295  SetCellOperation( op_logic );
296 
297  // Make coordinate ux1 tj > ux0 to simplify calculations
298  if( ux1 < ux0 )
299  {
300  std::swap( ux1, ux0 );
301  std::swap( uy1, uy0 );
302  }
303 
304  // Calculating the incrementing the Y axis
305  inc = 1;
306 
307  if( uy1 < uy0 )
308  inc = -1;
309 
310  demi_pas = m_GridRouting / 2;
311 
312  col_min = ( ux0 - lg ) / m_GridRouting;
313 
314  if( col_min < 0 )
315  col_min = 0;
316 
317  col_max = ( ux1 + lg + demi_pas ) / m_GridRouting;
318 
319  if( col_max > ( m_Ncols - 1 ) )
320  col_max = m_Ncols - 1;
321 
322  if( inc > 0 )
323  {
324  row_min = ( uy0 - lg ) / m_GridRouting;
325  row_max = ( uy1 + lg + demi_pas ) / m_GridRouting;
326  }
327  else
328  {
329  row_min = ( uy1 - lg ) / m_GridRouting;
330  row_max = ( uy0 + lg + demi_pas ) / m_GridRouting;
331  }
332 
333  if( row_min < 0 )
334  row_min = 0;
335 
336  if( row_min > ( m_Nrows - 1 ) )
337  row_min = m_Nrows - 1;
338 
339  if( row_max < 0 )
340  row_max = 0;
341 
342  if( row_max > ( m_Nrows - 1 ) )
343  row_max = m_Nrows - 1;
344 
345  dx = ux1 - ux0;
346  dy = uy1 - uy0;
347 
348  double angle;
349  if( dx )
350  {
351  angle = ArcTangente( dy, dx );
352  }
353  else
354  {
355  angle = 900;
356 
357  if( dy < 0 )
358  angle = -900;
359  }
360 
361  RotatePoint( &dx, &dy, angle ); // dx = length, dy = 0
362 
363  for( col = col_min; col <= col_max; col++ )
364  {
365  int64_t cxr;
366  cxr = ( col * m_GridRouting ) - ux0;
367 
368  for( row = row_min; row <= row_max; row++ )
369  {
370  cy = ( row * m_GridRouting ) - uy0;
371  cx = cxr;
372  RotatePoint( &cx, &cy, angle );
373 
374  if( abs( cy ) > lg )
375  continue; // The point is too far on the Y axis.
376 
377  /* This point a test is close to the segment: the position
378  * along the X axis must be tested.
379  */
380  if( ( cx >= 0 ) && ( cx <= dx ) )
381  {
382  OP_CELL( layer, row, col );
383  continue;
384  }
385 
386  // Examination of extremities are rounded.
387  if( ( cx < 0 ) && ( cx >= -lg ) )
388  {
389  if( ( ( cx * cx ) + ( cy * cy ) ) <= ( lg * lg ) )
390  OP_CELL( layer, row, col );
391 
392  continue;
393  }
394 
395  if( ( cx > dx ) && ( cx <= ( dx + lg ) ) )
396  {
397  if( ( ( ( cx - dx ) * ( cx - dx ) ) + ( cy * cy ) ) <= ( lg * lg ) )
398  OP_CELL( layer, row, col );
399 
400  continue;
401  }
402  }
403  }
404 }
405 
406 
407 /* Fills all cells of the routing matrix contained in the circle
408  * half-width = lg, center = ux0, uy0, ux1,uy1 is a point on the circle.
409  * coord are in PCB units.
410  */
411 void AR_MATRIX::traceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer, int color,
412  AR_MATRIX::CELL_OP op_logic )
413 {
414  int radius, nb_segm;
415  int x0, y0, // Starting point of the current segment trace.
416  x1, y1; // End point.
417  int ii;
418  int angle;
419 
420  radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
421 
422  x0 = x1 = radius;
423  y0 = y1 = 0;
424 
425  if( lg < 1 )
426  lg = 1;
427 
428  nb_segm = ( 2 * radius ) / lg;
429 
430  if( nb_segm < 5 )
431  nb_segm = 5;
432 
433  if( nb_segm > 100 )
434  nb_segm = 100;
435 
436  for( ii = 1; ii < nb_segm; ii++ )
437  {
438  angle = ( 3600 * ii ) / nb_segm;
439  x1 = KiROUND( cosdecideg( radius, angle ) );
440  y1 = KiROUND( sindecideg( radius, angle ) );
441  drawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
442  x0 = x1;
443  y0 = y1;
444  }
445 
446  drawSegmentQcq( x1 + ux0, y1 + uy0, ux0 + radius, uy0, lg, layer, color, op_logic );
447 }
448 
449 
451  int cx, int cy, int radius, LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic )
452 {
453  int row, col;
454  int ux0, uy0, ux1, uy1;
455  int row_max, col_max, row_min, col_min;
456  int trace = 0;
457  double fdistmin, fdistx, fdisty;
458  int tstwrite = 0;
459  int distmin;
460 
461  if( aLayerMask[m_routeLayerBottom] )
462  trace = 1; // Trace on BOTTOM
463 
464  if( aLayerMask[m_routeLayerTop] )
465  if( m_RoutingLayersCount > 1 )
466  trace |= 2; // Trace on TOP
467 
468  if( trace == 0 )
469  return;
470 
471  SetCellOperation( op_logic );
472 
473  cx -= GetBrdCoordOrigin().x;
474  cy -= GetBrdCoordOrigin().y;
475 
476  distmin = radius;
477 
478  // Calculate the bounding rectangle of the circle.
479  ux0 = cx - radius;
480  uy0 = cy - radius;
481  ux1 = cx + radius;
482  uy1 = cy + radius;
483 
484  // Calculate limit coordinates of cells belonging to the rectangle.
485  row_max = uy1 / m_GridRouting;
486  col_max = ux1 / m_GridRouting;
487  row_min = uy0 / m_GridRouting; // if (uy0 > row_min*Board.m_GridRouting) row_min++;
488  col_min = ux0 / m_GridRouting; // if (ux0 > col_min*Board.m_GridRouting) col_min++;
489 
490  if( row_min < 0 )
491  row_min = 0;
492 
493  if( row_max >= ( m_Nrows - 1 ) )
494  row_max = m_Nrows - 1;
495 
496  if( col_min < 0 )
497  col_min = 0;
498 
499  if( col_max >= ( m_Ncols - 1 ) )
500  col_max = m_Ncols - 1;
501 
502  // Calculate coordinate limits of cell belonging to the rectangle.
503  if( row_min > row_max )
504  row_max = row_min;
505 
506  if( col_min > col_max )
507  col_max = col_min;
508 
509  fdistmin = (double) distmin * distmin;
510 
511  for( row = row_min; row <= row_max; row++ )
512  {
513  fdisty = (double) ( cy - ( row * m_GridRouting ) );
514  fdisty *= fdisty;
515 
516  for( col = col_min; col <= col_max; col++ )
517  {
518  fdistx = (double) ( cx - ( col * m_GridRouting ) );
519  fdistx *= fdistx;
520 
521  if( fdistmin <= ( fdistx + fdisty ) )
522  continue;
523 
524  if( trace & 1 )
525  WriteCell( row, col, AR_SIDE_BOTTOM, color );
526 
527  if( trace & 2 )
528  WriteCell( row, col, AR_SIDE_TOP, color );
529 
530  tstwrite = 1;
531  }
532  }
533 
534  if( tstwrite )
535  return;
536 
537  /* If no cell has been written, it affects the 4 neighboring diagonal
538  * (Adverse event: pad off grid in the center of the 4 neighboring
539  * diagonal) */
540  distmin = m_GridRouting / 2 + 1;
541  fdistmin = ( (double) distmin * distmin ) * 2; // Distance to center point diagonally
542 
543  for( row = row_min; row <= row_max; row++ )
544  {
545  fdisty = (double) ( cy - ( row * m_GridRouting ) );
546  fdisty *= fdisty;
547 
548  for( col = col_min; col <= col_max; col++ )
549  {
550  fdistx = (double) ( cx - ( col * m_GridRouting ) );
551  fdistx *= fdistx;
552 
553  if( fdistmin <= ( fdistx + fdisty ) )
554  continue;
555 
556  if( trace & 1 )
557  WriteCell( row, col, AR_SIDE_BOTTOM, color );
558 
559  if( trace & 2 )
560  WriteCell( row, col, AR_SIDE_TOP, color );
561  }
562  }
563 }
564 
565 
566 /* Fills all routing matrix cells contained in the arc
567  * angle = ArcAngle, half-width lg
568  * center = ux0,uy0, starting at ux1, uy1. Coordinates are in
569  * PCB units.
570  */
571 void AR_MATRIX::traceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
572  LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic )
573 {
574  int radius, nb_segm;
575  int x0, y0, // Starting point of the current segment trace
576  x1, y1; // End point
577  int ii;
578  double angle, StAngle;
579 
580 
581  radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
582 
583  x0 = ux1 - ux0;
584  y0 = uy1 - uy0;
585  StAngle = ArcTangente( uy1 - uy0, ux1 - ux0 );
586 
587  if( lg < 1 )
588  lg = 1;
589 
590  nb_segm = ( 2 * radius ) / lg;
591  nb_segm = ( nb_segm * std::abs( ArcAngle ) ) / 3600;
592 
593  if( nb_segm < 5 )
594  nb_segm = 5;
595 
596  if( nb_segm > 100 )
597  nb_segm = 100;
598 
599  for( ii = 1; ii <= nb_segm; ii++ )
600  {
601  angle = ( ArcAngle * ii ) / nb_segm;
602  angle += StAngle;
603 
605 
606  x1 = KiROUND( cosdecideg( radius, angle ) );
607  y1 = KiROUND( cosdecideg( radius, angle ) );
608  drawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
609  x0 = x1;
610  y0 = y1;
611  }
612 }
613 
614 
615 void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1, double angle,
616  LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic )
617 {
618  int row, col;
619  int cx, cy; // Center of rectangle
620  int radius; // Radius of the circle
621  int row_min, row_max, col_min, col_max;
622  int rotrow, rotcol;
623  int trace = 0;
624 
625  if( aLayerMask[m_routeLayerBottom] )
626  trace = 1; // Trace on BOTTOM
627 
628  if( aLayerMask[m_routeLayerTop] )
629  {
630  if( m_RoutingLayersCount > 1 )
631  trace |= 2; // Trace on TOP
632  }
633 
634  if( trace == 0 )
635  return;
636 
637  SetCellOperation( op_logic );
638 
639  ux0 -= GetBrdCoordOrigin().x;
640  uy0 -= GetBrdCoordOrigin().y;
641  ux1 -= GetBrdCoordOrigin().x;
642  uy1 -= GetBrdCoordOrigin().y;
643 
644  cx = ( ux0 + ux1 ) / 2;
645  cy = ( uy0 + uy1 ) / 2;
646  radius = KiROUND( Distance( ux0, uy0, cx, cy ) );
647 
648  // Calculating coordinate limits belonging to the rectangle.
649  row_max = ( cy + radius ) / m_GridRouting;
650  col_max = ( cx + radius ) / m_GridRouting;
651  row_min = ( cy - radius ) / m_GridRouting;
652 
653  if( uy0 > row_min * m_GridRouting )
654  row_min++;
655 
656  col_min = ( cx - radius ) / m_GridRouting;
657 
658  if( ux0 > col_min * m_GridRouting )
659  col_min++;
660 
661  if( row_min < 0 )
662  row_min = 0;
663 
664  if( row_max >= ( m_Nrows - 1 ) )
665  row_max = m_Nrows - 1;
666 
667  if( col_min < 0 )
668  col_min = 0;
669 
670  if( col_max >= ( m_Ncols - 1 ) )
671  col_max = m_Ncols - 1;
672 
673  for( row = row_min; row <= row_max; row++ )
674  {
675  for( col = col_min; col <= col_max; col++ )
676  {
677  rotrow = row * m_GridRouting;
678  rotcol = col * m_GridRouting;
679  RotatePoint( &rotcol, &rotrow, cx, cy, -angle );
680 
681  if( rotrow <= uy0 )
682  continue;
683 
684  if( rotrow >= uy1 )
685  continue;
686 
687  if( rotcol <= ux0 )
688  continue;
689 
690  if( rotcol >= ux1 )
691  continue;
692 
693  if( trace & 1 )
694  WriteCell( row, col, AR_SIDE_BOTTOM, color );
695 
696  if( trace & 2 )
697  WriteCell( row, col, AR_SIDE_TOP, color );
698  }
699  }
700 }
701 
702 
703 void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1, LSET aLayerMask,
704  int color, AR_MATRIX::CELL_OP op_logic )
705 {
706  int row, col;
707  int row_min, row_max, col_min, col_max;
708  int trace = 0;
709 
710  if( aLayerMask[m_routeLayerBottom] )
711  trace = 1; // Trace on BOTTOM
712 
713  if( aLayerMask[m_routeLayerTop] && m_RoutingLayersCount > 1 )
714  trace |= 2; // Trace on TOP
715 
716  if( trace == 0 )
717  return;
718 
719  SetCellOperation( op_logic );
720 
721  ux0 -= GetBrdCoordOrigin().x;
722  uy0 -= GetBrdCoordOrigin().y;
723  ux1 -= GetBrdCoordOrigin().x;
724  uy1 -= GetBrdCoordOrigin().y;
725 
726  // Calculating limits coord cells belonging to the rectangle.
727  row_max = uy1 / m_GridRouting;
728  col_max = ux1 / m_GridRouting;
729  row_min = uy0 / m_GridRouting;
730 
731  if( uy0 > row_min * m_GridRouting )
732  row_min++;
733 
734  col_min = ux0 / m_GridRouting;
735 
736  if( ux0 > col_min * m_GridRouting )
737  col_min++;
738 
739  if( row_min < 0 )
740  row_min = 0;
741 
742  if( row_max >= ( m_Nrows - 1 ) )
743  row_max = m_Nrows - 1;
744 
745  if( col_min < 0 )
746  col_min = 0;
747 
748  if( col_max >= ( m_Ncols - 1 ) )
749  col_max = m_Ncols - 1;
750 
751  for( row = row_min; row <= row_max; row++ )
752  {
753  for( col = col_min; col <= col_max; col++ )
754  {
755  if( trace & 1 )
756  WriteCell( row, col, AR_SIDE_BOTTOM, color );
757 
758  if( trace & 2 )
759  WriteCell( row, col, AR_SIDE_TOP, color );
760  }
761  }
762 }
763 
764 
765 void AR_MATRIX::TraceSegmentPcb( PCB_SHAPE* aShape, int aColor, int aMargin,
766  AR_MATRIX::CELL_OP op_logic )
767 {
768  int half_width = ( aShape->GetWidth() / 2 ) + aMargin;
769 
770  // Calculate the bounding rectangle of the segment (if H, V or Via)
771  LAYER_NUM layer = UNDEFINED_LAYER; // Draw on all layers
772 
773  if( aShape->GetShape() == SHAPE_T::CIRCLE || aShape->GetShape() == SHAPE_T::SEGMENT )
774  {
775  int ux0 = aShape->GetStart().x - GetBrdCoordOrigin().x;
776  int uy0 = aShape->GetStart().y - GetBrdCoordOrigin().y;
777  int ux1 = aShape->GetEnd().x - GetBrdCoordOrigin().x;
778  int uy1 = aShape->GetEnd().y - GetBrdCoordOrigin().y;
779 
780  if( aShape->GetShape() == SHAPE_T::CIRCLE )
781  traceCircle( ux0, uy0, ux1, uy1, half_width, layer, aColor, op_logic );
782  else
783  drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, aColor, op_logic );
784  }
785  else if( aShape->GetShape() == SHAPE_T::ARC )
786  {
787  int ux0 = aShape->GetCenter().x - GetBrdCoordOrigin().x;
788  int uy0 = aShape->GetCenter().y - GetBrdCoordOrigin().y;
789  int ux1 = aShape->GetStart().x - GetBrdCoordOrigin().x;
790  int uy1 = aShape->GetStart().y - GetBrdCoordOrigin().y;
791 
792  traceArc( ux0, uy0, ux1, uy1, aShape->GetArcAngle(), half_width, layer, aColor, op_logic );
793  }
794 }
795 
796 
808  int ux0, int uy0, int ux1, int uy1, int marge, int aKeepOut, LSET aLayerMask )
809 {
810  int row, col;
811  int row_min, row_max, col_min, col_max, pmarge;
812  int trace = 0;
813  DIST_CELL data, LocalKeepOut;
814  int lgain, cgain;
815 
816  if( aLayerMask[m_routeLayerBottom] )
817  trace = 1; // Trace on bottom layer.
818 
819  if( aLayerMask[m_routeLayerTop] && m_RoutingLayersCount )
820  trace |= 2; // Trace on top layer.
821 
822  if( trace == 0 )
823  return;
824 
825  ux0 -= m_BrdBox.GetX();
826  uy0 -= m_BrdBox.GetY();
827  ux1 -= m_BrdBox.GetX();
828  uy1 -= m_BrdBox.GetY();
829 
830  ux0 -= marge;
831  ux1 += marge;
832  uy0 -= marge;
833  uy1 += marge;
834 
835  pmarge = marge / m_GridRouting;
836 
837  if( pmarge < 1 )
838  pmarge = 1;
839 
840  // Calculate the coordinate limits of the rectangle.
841  row_max = uy1 / m_GridRouting;
842  col_max = ux1 / m_GridRouting;
843  row_min = uy0 / m_GridRouting;
844 
845  if( uy0 > row_min * m_GridRouting )
846  row_min++;
847 
848  col_min = ux0 / m_GridRouting;
849 
850  if( ux0 > col_min * m_GridRouting )
851  col_min++;
852 
853  if( row_min < 0 )
854  row_min = 0;
855 
856  if( row_max >= ( m_Nrows - 1 ) )
857  row_max = m_Nrows - 1;
858 
859  if( col_min < 0 )
860  col_min = 0;
861 
862  if( col_max >= ( m_Ncols - 1 ) )
863  col_max = m_Ncols - 1;
864 
865  for( row = row_min; row <= row_max; row++ )
866  {
867  lgain = 256;
868 
869  if( row < pmarge )
870  lgain = ( 256 * row ) / pmarge;
871  else if( row > row_max - pmarge )
872  lgain = ( 256 * ( row_max - row ) ) / pmarge;
873 
874  for( col = col_min; col <= col_max; col++ )
875  {
876  // RoutingMatrix Dist map contained the "cost" of the cell
877  // at position (row, col)
878  // in autoplace this is the cost of the cell, when
879  // a footprint overlaps it, near a "master" footprint
880  // this cost is high near the "master" footprint
881  // and decrease with the distance
882  cgain = 256;
883  LocalKeepOut = aKeepOut;
884 
885  if( col < pmarge )
886  cgain = ( 256 * col ) / pmarge;
887  else if( col > col_max - pmarge )
888  cgain = ( 256 * ( col_max - col ) ) / pmarge;
889 
890  cgain = ( cgain * lgain ) / 256;
891 
892  if( cgain != 256 )
893  LocalKeepOut = ( LocalKeepOut * cgain ) / 256;
894 
895  if( trace & 1 )
896  {
897  data = GetDist( row, col, AR_SIDE_BOTTOM ) + LocalKeepOut;
898  SetDist( row, col, AR_SIDE_BOTTOM, data );
899  }
900 
901  if( trace & 2 )
902  {
903  data = GetDist( row, col, AR_SIDE_TOP );
904  data = std::max( data, LocalKeepOut );
905  SetDist( row, col, AR_SIDE_TOP, data );
906  }
907  }
908  }
909 }
910 
911 
912 void AR_MATRIX::PlacePad( PAD* aPad, int color, int marge, AR_MATRIX::CELL_OP op_logic )
913 {
914  int dx, dy;
915  wxPoint shape_pos = aPad->ShapePos();
916 
917  dx = aPad->GetSize().x / 2;
918  dx += marge;
919 
920  if( aPad->GetShape() == PAD_SHAPE::CIRCLE )
921  {
922  traceFilledCircle( shape_pos.x, shape_pos.y, dx, aPad->GetLayerSet(), color, op_logic );
923  return;
924  }
925 
926  dy = aPad->GetSize().y / 2;
927  dy += marge;
928 
929  if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
930  {
931  dx += abs( aPad->GetDelta().y ) / 2;
932  dy += abs( aPad->GetDelta().x ) / 2;
933  }
934 
935  // The pad is a rectangle ( horizontal or vertical )
936  if( int( aPad->GetOrientation() ) % 900 == 0 )
937  {
938  // Orientation turned 90 deg.
939  if( aPad->GetOrientation() == 900 || aPad->GetOrientation() == 2700 )
940  {
941  std::swap( dx, dy );
942  }
943 
944  TraceFilledRectangle( shape_pos.x - dx, shape_pos.y - dy, shape_pos.x + dx,
945  shape_pos.y + dy, aPad->GetLayerSet(), color, op_logic );
946  }
947  else
948  {
949  TraceFilledRectangle( shape_pos.x - dx, shape_pos.y - dy, shape_pos.x + dx,
950  shape_pos.y + dy, aPad->GetOrientation(), aPad->GetLayerSet(), color, op_logic );
951  }
952 }
#define AR_SIDE_BOTTOM
Definition: ar_matrix.h:42
void traceArc(int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg, LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic)
Definition: ar_matrix.cpp:571
int InitRoutingMatrix()
Initialize the data structures.
Definition: ar_matrix.cpp:91
int GetWidth() const
Definition: eda_shape.h:98
DIST_CELL * m_DistSide[AR_MAX_ROUTING_LAYERS_COUNT]
Definition: ar_matrix.h:139
int m_MemSize
Definition: ar_matrix.h:145
#define AR_SIDE_TOP
Definition: ar_matrix.h:41
int m_Ncols
Definition: ar_matrix.h:144
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:106
int GetX() const
Definition: eda_rect.h:107
int m_GridRouting
Definition: ar_matrix.h:142
int color
Definition: DXF_plotter.cpp:57
void TraceFilledRectangle(int ux0, int uy0, int ux1, int uy1, double angle, LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic)
Definition: ar_matrix.cpp:615
EDA_RECT m_BrdBox
Definition: ar_matrix.h:143
int GetWidth() const
Definition: eda_rect.h:118
double GetArcAngle() const
Definition: eda_shape.cpp:536
int LAYER_NUM
This can be replaced with int and removed.
Definition: layer_ids.h:41
void CreateKeepOutRectangle(int ux0, int uy0, int ux1, int uy1, int marge, int aKeepOut, LSET aLayerMask)
Function CreateKeepOutRectangle builds the cost map: Cells ( in Dist map ) inside the rect x0,...
Definition: ar_matrix.cpp:807
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:290
int DIST_CELL
Definition: ar_matrix.h:51
void XorCell(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.cpp:202
void PlacePad(PAD *aPad, int color, int marge, AR_MATRIX::CELL_OP op_logic)
Definition: ar_matrix.cpp:912
const wxPoint GetEnd() const
Definition: eda_rect.h:112
PCB_LAYER_ID m_routeLayerTop
Definition: ar_matrix.h:148
wxPoint ShapePos() const
Definition: pad.cpp:706
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:131
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
void WriteCell(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.h:65
double GetOrientation() const
Return the rotation angle of the pad in a variety of units (the basic call returns tenths of degrees)...
Definition: pad.h:349
void SetEnd(int x, int y)
Definition: eda_rect.h:191
void OrCell(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.cpp:191
const wxSize & GetSize() const
Definition: pad.h:233
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:79
MATRIX_CELL GetCell(int aRow, int aCol, int aSide)
Definition: ar_matrix.cpp:169
void(AR_MATRIX::* m_opWriteCell)(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.h:153
int m_Nrows
Definition: ar_matrix.h:144
PAD_SHAPE GetShape() const
Definition: pad.h:170
void SetX(int val)
Definition: eda_rect.h:167
void SetCellOperation(CELL_OP aLogicOp)
Definition: ar_matrix.cpp:153
MATRIX_CELL * m_BoardSide[AR_MAX_ROUTING_LAYERS_COUNT]
Definition: ar_matrix.h:138
void SetCell(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.cpp:180
void drawSegmentQcq(int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer, int color, CELL_OP op_logic)
Definition: ar_matrix.cpp:285
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:368
void TraceSegmentPcb(PCB_SHAPE *aShape, int aColor, int aMargin, AR_MATRIX::CELL_OP op_logic)
Definition: ar_matrix.cpp:765
void AndCell(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.cpp:213
int GetHeight() const
Definition: eda_rect.h:119
void SetY(int val)
Definition: eda_rect.h:173
void traceCircle(int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic)
Definition: ar_matrix.cpp:411
const wxSize & GetDelta() const
Definition: pad.h:240
void UnInitRoutingMatrix()
Definition: ar_matrix.cpp:128
#define OP_CELL(layer, dy, dx)
Definition: ar_matrix.cpp:263
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:452
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:443
int m_RoutingLayersCount
Definition: ar_matrix.h:141
Definition: layer_ids.h:71
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
wxPoint GetBrdCoordOrigin()
Definition: ar_matrix.h:74
Handle the component boundary box.
Definition: eda_rect.h:42
void AddCell(int aRow, int aCol, int aSide, MATRIX_CELL aCell)
Definition: ar_matrix.cpp:224
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
int GetY() const
Definition: eda_rect.h:108
void traceFilledCircle(int cx, int cy, int radius, LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic)
Definition: ar_matrix.cpp:450
unsigned char MATRIX_CELL
Definition: ar_matrix.h:50
SHAPE_T GetShape() const
Definition: eda_shape.h:101
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
void SetDist(int aRow, int aCol, int aSide, DIST_CELL)
Definition: ar_matrix.cpp:244
bool ComputeMatrixSize(const EDA_RECT &aBoundingBox)
Calculate the number of rows and columns of dimensions of aPcb for routing and automatic calculation ...
Definition: ar_matrix.cpp:61
Definition: pad.h:57
#define AR_MAX_ROUTING_LAYERS_COUNT
Definition: ar_matrix.h:39
int m_RouteCount
Definition: ar_matrix.h:146
DIST_CELL GetDist(int aRow, int aCol, int aSide)
Definition: ar_matrix.cpp:234
PCB_LAYER_ID m_routeLayerBottom
Definition: ar_matrix.h:149