KiCad PCB EDA Suite
pcb_expr_evaluator.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) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <cstdio>
26 #include <memory>
27 #include <board.h>
28 #include <board_design_settings.h>
29 #include <drc/drc_rtree.h>
30 #include <pcb_track.h>
31 #include <pcb_group.h>
32 #include <geometry/shape_segment.h>
33 #include <pcb_expr_evaluator.h>
34 #include <wx/log.h>
35 
39 
40 #include <drc/drc_engine.h>
41 #include <geometry/shape_circle.h>
42 
43 bool exprFromTo( LIBEVAL::CONTEXT* aCtx, void* self )
44 {
45  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
46  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
47  LIBEVAL::VALUE* result = aCtx->AllocValue();
48 
49  LIBEVAL::VALUE* argTo = aCtx->Pop();
50  LIBEVAL::VALUE* argFrom = aCtx->Pop();
51 
52  result->Set(0.0);
53  aCtx->Push( result );
54 
55  if(!item)
56  return false;
57 
58  auto ftCache = item->GetBoard()->GetConnectivity()->GetFromToCache();
59 
60  if( !ftCache )
61  {
62  wxLogWarning( wxT( "Attempting to call fromTo() with non-existent from-to cache, "
63  "aborting..." ));
64  return true;
65  }
66 
67  if( ftCache->IsOnFromToPath( static_cast<BOARD_CONNECTED_ITEM*>( item ),
68  argFrom->AsString(), argTo->AsString() ) )
69  {
70  result->Set(1.0);
71  }
72 
73  return true;
74 }
75 
76 
77 static void existsOnLayer( LIBEVAL::CONTEXT* aCtx, void *self )
78 {
79  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
80  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
81 
82  LIBEVAL::VALUE* arg = aCtx->Pop();
83  LIBEVAL::VALUE* result = aCtx->AllocValue();
84 
85  result->Set( 0.0 );
86  aCtx->Push( result );
87 
88  if( !item )
89  return;
90 
91  if( !arg )
92  {
93  if( aCtx->HasErrorCallback() )
94  {
95  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
96  wxT( "existsOnLayer()" ) ) );
97  }
98 
99  return;
100  }
101 
102  result->SetDeferredEval(
103  [item, arg, aCtx]() -> double
104  {
105  const wxString& layerName = arg->AsString();
106  wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
107 
108  if( aCtx->HasErrorCallback())
109  {
110  /*
111  * Interpreted version
112  */
113 
114  bool anyMatch = false;
115 
116  for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
117  {
118  wxPGChoiceEntry& entry = layerMap[ ii ];
119 
120  if( entry.GetText().Matches( layerName ))
121  {
122  anyMatch = true;
123 
124  if( item->IsOnLayer( ToLAYER_ID( entry.GetValue())))
125  return 1.0;
126  }
127  }
128 
129  if( !anyMatch )
130  {
131  aCtx->ReportError( wxString::Format( _( "Unrecognized layer '%s'" ),
132  layerName ) );
133  }
134  }
135  else
136  {
137  /*
138  * Compiled version
139  */
140 
141  BOARD* board = item->GetBoard();
142  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
143  auto i = board->m_LayerExpressionCache.find( layerName );
144  LSET mask;
145 
146  if( i == board->m_LayerExpressionCache.end() )
147  {
148  for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
149  {
150  wxPGChoiceEntry& entry = layerMap[ ii ];
151 
152  if( entry.GetText().Matches( layerName ) )
153  mask.set( ToLAYER_ID( entry.GetValue() ) );
154  }
155 
156  board->m_LayerExpressionCache[ layerName ] = mask;
157  }
158  else
159  {
160  mask = i->second;
161  }
162 
163  if( ( item->GetLayerSet() & mask ).any() )
164  return 1.0;
165  }
166 
167  return 0.0;
168  } );
169 }
170 
171 
172 static void isPlated( LIBEVAL::CONTEXT* aCtx, void* self )
173 {
174  LIBEVAL::VALUE* result = aCtx->AllocValue();
175 
176  result->Set( 0.0 );
177  aCtx->Push( result );
178 
179  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
180  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
181 
182  if( !item )
183  return;
184 
185  if( item->Type() == PCB_PAD_T && static_cast<PAD*>( item )->GetAttribute() == PAD_ATTRIB::PTH )
186  result->Set( 1.0 );
187  else if( item->Type() == PCB_VIA_T )
188  result->Set( 1.0 );
189 }
190 
191 
192 bool calcIsInsideCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox,
193  std::shared_ptr<SHAPE>& aItemShape, PCB_EXPR_CONTEXT* aCtx,
194  FOOTPRINT* aFootprint, PCB_LAYER_ID aSide )
195 {
196  SHAPE_POLY_SET footprintCourtyard;
197 
198  footprintCourtyard = aFootprint->GetPolyCourtyard( aSide );
199 
200  if( !aFootprint->GetBoundingBox().Intersects( aItemBBox ) )
201  return false;
202 
203  if( !aItemShape )
204  aItemShape = aItem->GetEffectiveShape( aCtx->GetLayer() );
205 
206  return footprintCourtyard.Collide( aItemShape.get() );
207 };
208 
209 
210 bool isInsideCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox,
211  std::shared_ptr<SHAPE>& aItemShape, PCB_EXPR_CONTEXT* aCtx,
212  FOOTPRINT* aFootprint, PCB_LAYER_ID aSide )
213 {
214  if( !aFootprint )
215  return false;
216 
217  BOARD* board = aItem->GetBoard();
218  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
219  std::pair<BOARD_ITEM*, BOARD_ITEM*> key( aFootprint, aItem );
220 
221  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, bool >* cache;
222 
223  switch( aSide )
224  {
225  case F_Cu: cache = &board->m_InsideFCourtyardCache; break;
226  case B_Cu: cache = &board->m_InsideBCourtyardCache; break;
227  default: cache = &board->m_InsideCourtyardCache; break;
228  }
229 
230  auto i = cache->find( key );
231 
232  if( i != cache->end() )
233  return i->second;
234 
235  bool res = calcIsInsideCourtyard( aItem, aItemBBox, aItemShape, aCtx, aFootprint, aSide );
236 
237  (*cache)[ key ] = res;
238  return res;
239 };
240 
241 
242 static void insideCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
243 {
244  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
245  LIBEVAL::VALUE* arg = aCtx->Pop();
246  LIBEVAL::VALUE* result = aCtx->AllocValue();
247 
248  result->Set( 0.0 );
249  aCtx->Push( result );
250 
251  if( !arg )
252  {
253  if( aCtx->HasErrorCallback() )
254  {
255  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
256  wxT( "insideCourtyard()" ) ) );
257  }
258 
259  return;
260  }
261 
262  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
263  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
264 
265  if( !item )
266  return;
267 
268  result->SetDeferredEval(
269  [item, arg, context]() -> double
270  {
271  BOARD* board = item->GetBoard();
272  EDA_RECT itemBBox;
273  std::shared_ptr<SHAPE> itemShape;
274 
275  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
276  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
277  else
278  itemBBox = item->GetBoundingBox();
279 
280  if( arg->AsString() == wxT( "A" ) )
281  {
282  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
283 
284  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, In1_Cu ) )
285  return 1.0;
286  }
287  else if( arg->AsString() == wxT( "B" ) )
288  {
289  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
290 
291  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, In1_Cu ) )
292  return 1.0;
293  }
294  else for( FOOTPRINT* fp : board->Footprints() )
295  {
296  if( fp->GetReference().Matches( arg->AsString() ) )
297  {
298  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, In1_Cu ) )
299  return 1.0;
300  }
301  }
302 
303  return 0.0;
304  } );
305 }
306 
307 
308 static void insideFrontCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
309 {
310  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
311  LIBEVAL::VALUE* arg = aCtx->Pop();
312  LIBEVAL::VALUE* result = aCtx->AllocValue();
313 
314  result->Set( 0.0 );
315  aCtx->Push( result );
316 
317  if( !arg )
318  {
319  if( aCtx->HasErrorCallback() )
320  {
321  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
322  wxT( "insideFrontCourtyard()" ) ) );
323  }
324 
325  return;
326  }
327 
328  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
329  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
330 
331  if( !item )
332  return;
333 
334  result->SetDeferredEval(
335  [item, arg, context]() -> double
336  {
337  BOARD* board = item->GetBoard();
338  EDA_RECT itemBBox;
339  std::shared_ptr<SHAPE> itemShape;
340 
341  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
342  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
343  else
344  itemBBox = item->GetBoundingBox();
345 
346  if( arg->AsString() == wxT( "A" ) )
347  {
348  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
349 
350  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, F_Cu ) )
351  return 1.0;
352  }
353  else if( arg->AsString() == wxT( "B" ) )
354  {
355  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
356 
357  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, F_Cu ) )
358  return 1.0;
359  }
360  else for( FOOTPRINT* fp : board->Footprints() )
361  {
362  if( fp->GetReference().Matches( arg->AsString() ) )
363  {
364  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, F_Cu ) )
365  return 1.0;
366  }
367  }
368 
369  return 0.0;
370  } );
371 }
372 
373 
374 static void insideBackCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
375 {
376  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
377  LIBEVAL::VALUE* arg = aCtx->Pop();
378  LIBEVAL::VALUE* result = aCtx->AllocValue();
379 
380  result->Set( 0.0 );
381  aCtx->Push( result );
382 
383  if( !arg )
384  {
385  if( aCtx->HasErrorCallback() )
386  {
387  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
388  wxT( "insideBackCourtyard()" ) ) );
389  }
390  return;
391  }
392 
393  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
394  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
395 
396  if( !item )
397  return;
398 
399  result->SetDeferredEval(
400  [item, arg, context]() -> double
401  {
402  BOARD* board = item->GetBoard();
403  EDA_RECT itemBBox;
404  std::shared_ptr<SHAPE> itemShape;
405 
406  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
407  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
408  else
409  itemBBox = item->GetBoundingBox();
410 
411  if( arg->AsString() == wxT( "A" ) )
412  {
413  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
414 
415  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, B_Cu ) )
416  return 1.0;
417  }
418  else if( arg->AsString() == wxT( "B" ) )
419  {
420  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
421 
422  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, B_Cu ) )
423  return 1.0;
424  }
425  else for( FOOTPRINT* fp : board->Footprints() )
426  {
427  if( fp->GetReference().Matches( arg->AsString() ) )
428  {
429  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, B_Cu ) )
430  return 1.0;
431  }
432  }
433 
434  return 0.0;
435  } );
436 }
437 
438 
439 bool calcIsInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CONTEXT* aCtx,
440  ZONE* aArea )
441 {
442  BOARD* board = aArea->GetBoard();
443  EDA_RECT areaBBox = aArea->GetBoundingBox();
444  std::shared_ptr<SHAPE> shape;
445 
446  if( !areaBBox.Intersects( aItemBBox ) )
447  return false;
448 
449  // Collisions include touching, so we need to deflate outline by enough to exclude it.
450  // This is particularly important for detecting copper fills as they will be exactly
451  // touching along the entire exclusion border.
452  SHAPE_POLY_SET areaOutline = *aArea->Outline();
453  areaOutline.Deflate( board->GetDesignSettings().GetDRCEpsilon(), 0,
455 
456  if( aItem->GetFlags() & HOLE_PROXY )
457  {
458  if( aItem->Type() == PCB_PAD_T )
459  {
460  PAD* pad = static_cast<PAD*>( aItem );
461  const SHAPE_SEGMENT* holeShape = pad->GetEffectiveHoleShape();
462 
463  return areaOutline.Collide( holeShape );
464  }
465  else if( aItem->Type() == PCB_VIA_T )
466  {
467  PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
468  const SHAPE_CIRCLE holeShape( via->GetPosition(), via->GetDrillValue() );
469  LSET overlap = via->GetLayerSet() & aArea->GetLayerSet();
470 
472  if( overlap.count() > 0 )
473  {
474  if( aCtx->GetLayer() == UNDEFINED_LAYER || overlap.Contains( aCtx->GetLayer() ) )
475  return areaOutline.Collide( &holeShape );
476  }
477  }
478 
479  return false;
480  }
481 
482  if( aItem->Type() == PCB_FOOTPRINT_T )
483  {
484  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
485 
486  if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
487  {
488  if( aCtx->HasErrorCallback() )
489  {
490  aCtx->ReportError( _( "Footprint's courtyard is not a single, closed shape." ) );
491  }
492 
493  return false;
494  }
495 
496  if( ( aArea->GetLayerSet() & LSET::FrontMask() ).any() )
497  {
498  SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( F_CrtYd );
499 
500  if( courtyard.OutlineCount() == 0 )
501  {
502  if( aCtx->HasErrorCallback() )
503  aCtx->ReportError( _( "Footprint has no front courtyard." ) );
504 
505  return false;
506  }
507  else
508  {
509  return areaOutline.Collide( &courtyard.Outline( 0 ) );
510  }
511  }
512 
513  if( ( aArea->GetLayerSet() & LSET::BackMask() ).any() )
514  {
515  SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( B_CrtYd );
516 
517  if( courtyard.OutlineCount() == 0 )
518  {
519  if( aCtx->HasErrorCallback() )
520  aCtx->ReportError( _( "Footprint has no back courtyard." ) );
521 
522  return false;
523  }
524  else
525  {
526  return areaOutline.Collide( &courtyard.Outline( 0 ) );
527  }
528  }
529 
530  return false;
531  }
532 
533  if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
534  {
535  ZONE* zone = static_cast<ZONE*>( aItem );
536 
537  if( !zone->IsFilled() )
538  return false;
539 
540  DRC_RTREE* zoneRTree = board->m_CopperZoneRTrees[ zone ].get();
541 
542  std::vector<SHAPE*> shapes;
543 
544  if( zoneRTree )
545  {
546  for( PCB_LAYER_ID layer : aArea->GetLayerSet().Seq() )
547  {
548  if( aCtx->GetLayer() == layer || aCtx->GetLayer() == UNDEFINED_LAYER )
549  {
550  if( zoneRTree->QueryColliding( areaBBox, &areaOutline, layer ) )
551  return true;
552  }
553  }
554  }
555 
556  return false;
557  }
558  else
559  {
560  PCB_LAYER_ID layer = aCtx->GetLayer();
561 
562  if( layer != UNDEFINED_LAYER && !( aArea->GetLayerSet().Contains( layer ) ) )
563  return false;
564 
565  if( !shape )
566  shape = aItem->GetEffectiveShape( layer );
567 
568  return areaOutline.Collide( shape.get() );
569  }
570 }
571 
572 
573 bool isInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CONTEXT* aCtx,
574  ZONE* aArea )
575 {
576  if( !aArea || aArea == aItem || aArea->GetParent() == aItem )
577  return false;
578 
579  BOARD* board = aArea->GetBoard();
580  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
581  std::pair<BOARD_ITEM*, BOARD_ITEM*> key( aArea, aItem );
582  auto i = board->m_InsideAreaCache.find( key );
583 
584  if( i != board->m_InsideAreaCache.end() )
585  return i->second;
586 
587  bool isInside = calcIsInsideArea( aItem, aItemBBox, aCtx, aArea );
588 
589  board->m_InsideAreaCache[ key ] = isInside;
590  return isInside;
591 }
592 
593 
594 static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
595 {
596  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
597  LIBEVAL::VALUE* arg = aCtx->Pop();
598  LIBEVAL::VALUE* result = aCtx->AllocValue();
599 
600  result->Set( 0.0 );
601  aCtx->Push( result );
602 
603  if( !arg )
604  {
605  if( aCtx->HasErrorCallback() )
606  {
607  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
608  wxT( "insideArea()" ) ) );
609  }
610 
611  return;
612  }
613 
614  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
615  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
616 
617  if( !item )
618  return;
619 
620  result->SetDeferredEval(
621  [item, arg, context]() -> double
622  {
623  BOARD* board = item->GetBoard();
624  EDA_RECT itemBBox;
625 
626  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
627  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
628  else
629  itemBBox = item->GetBoundingBox();
630 
631  if( arg->AsString() == wxT( "A" ) )
632  {
633  ZONE* zone = dynamic_cast<ZONE*>( context->GetItem( 0 ) );
634  return isInsideArea( item, itemBBox, context, zone ) ? 1.0 : 0.0;
635  }
636  else if( arg->AsString() == wxT( "B" ) )
637  {
638  ZONE* zone = dynamic_cast<ZONE*>( context->GetItem( 1 ) );
639  return isInsideArea( item, itemBBox, context, zone ) ? 1.0 : 0.0;
640  }
641  else if( KIID::SniffTest( arg->AsString() ) )
642  {
643  KIID target( arg->AsString());
644 
645  for( ZONE* area : board->Zones() )
646  {
647  // Only a single zone can match the UUID; exit once we find a match whether
648  // "inside" or not
649  if( area->m_Uuid == target )
650  return isInsideArea( item, itemBBox, context, area ) ? 1.0 : 0.0;
651  }
652 
653  for( FOOTPRINT* footprint : board->Footprints() )
654  {
655  for( ZONE* area : footprint->Zones() )
656  {
657  // Only a single zone can match the UUID; exit once we find a match
658  // whether "inside" or not
659  if( area->m_Uuid == target )
660  return isInsideArea( item, itemBBox, context, area ) ? 1.0 : 0.0;
661  }
662  }
663 
664  return 0.0;
665  }
666  else // Match on zone name
667  {
668  for( ZONE* area : board->Zones())
669  {
670  if( area->GetZoneName().Matches( arg->AsString() ) )
671  {
672  // Many zones can match the name; exit only when we find an "inside"
673  if( isInsideArea( item, itemBBox, context, area ) )
674  return 1.0;
675  }
676  }
677 
678  for( FOOTPRINT* footprint : board->Footprints() )
679  {
680  for( ZONE* area : footprint->Zones() )
681  {
682  // Many zones can match the name; exit only when we find an "inside"
683  if( area->GetZoneName().Matches( arg->AsString() ) )
684  {
685  if( isInsideArea( item, itemBBox, context, area ) )
686  return 1.0;
687  }
688  }
689  }
690 
691  return 0.0;
692  }
693  } );
694 }
695 
696 
697 static void memberOf( LIBEVAL::CONTEXT* aCtx, void* self )
698 {
699  LIBEVAL::VALUE* arg = aCtx->Pop();
700  LIBEVAL::VALUE* result = aCtx->AllocValue();
701 
702  result->Set( 0.0 );
703  aCtx->Push( result );
704 
705  if( !arg )
706  {
707  if( aCtx->HasErrorCallback() )
708  {
709  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
710  wxT( "memberOf()" ) ) );
711  }
712  return;
713  }
714 
715  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
716  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
717 
718  if( !item )
719  return;
720 
721  result->SetDeferredEval(
722  [item, arg]() -> double
723  {
724  PCB_GROUP* group = item->GetParentGroup();
725 
726  if( !group && item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T )
727  group = item->GetParent()->GetParentGroup();
728 
729  while( group )
730  {
731  if( group->GetName().Matches( arg->AsString() ) )
732  return 1.0;
733 
734  group = group->GetParentGroup();
735  }
736 
737  return 0.0;
738  } );
739 }
740 
741 
742 static void isMicroVia( LIBEVAL::CONTEXT* aCtx, void* self )
743 {
744  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
745  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
746  LIBEVAL::VALUE* result = aCtx->AllocValue();
747 
748  result->Set( 0.0 );
749  aCtx->Push( result );
750 
751  PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
752 
753  if( via && via->GetViaType() == VIATYPE::MICROVIA )
754  result->Set ( 1.0 );
755 }
756 
757 
758 static void isBlindBuriedVia( LIBEVAL::CONTEXT* aCtx, void* self )
759 {
760  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
761  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
762  LIBEVAL::VALUE* result = aCtx->AllocValue();
763 
764  result->Set( 0.0 );
765  aCtx->Push( result );
766 
767  PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
768 
769  if( via && via->GetViaType() == VIATYPE::BLIND_BURIED )
770  result->Set ( 1.0 );
771 }
772 
773 
774 static void isCoupledDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
775 {
776  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
777  BOARD_CONNECTED_ITEM* a = dynamic_cast<BOARD_CONNECTED_ITEM*>( context->GetItem( 0 ) );
778  BOARD_CONNECTED_ITEM* b = dynamic_cast<BOARD_CONNECTED_ITEM*>( context->GetItem( 1 ) );
779  LIBEVAL::VALUE* result = aCtx->AllocValue();
780 
781  result->Set( 0.0 );
782  aCtx->Push( result );
783 
784  result->SetDeferredEval(
785  [a, b, context]() -> double
786  {
787  NETINFO_ITEM* netinfo = a ? a->GetNet() : nullptr;
788 
789  if( !netinfo )
790  return 0.0;
791 
792  wxString coupledNet;
793  wxString dummy;
794 
795  if( !DRC_ENGINE::MatchDpSuffix( netinfo->GetNetname(), coupledNet, dummy ) )
796  return 0.0;
797 
800  {
801  // DRC engine evaluates these singly, so we won't have a B item
802  return 1.0;
803  }
804 
805  return b && b->GetNetname() == coupledNet;
806  } );
807 }
808 
809 
810 static void inDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
811 {
812  LIBEVAL::VALUE* argv = aCtx->Pop();
813  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
814  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
815  LIBEVAL::VALUE* result = aCtx->AllocValue();
816 
817  result->Set( 0.0 );
818  aCtx->Push( result );
819 
820  if( !argv )
821  {
822  if( aCtx->HasErrorCallback() )
823  {
824  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
825  wxT( "inDiffPair()" ) ) );
826  }
827 
828  return;
829  }
830 
831  if( !item || !item->GetBoard() )
832  return;
833 
834  result->SetDeferredEval(
835  [item, argv]() -> double
836  {
837  if( item && item->IsConnected() )
838  {
839  NETINFO_ITEM* netinfo = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNet();
840 
841  wxString refName = netinfo->GetNetname();
842  wxString arg = argv->AsString();
843  wxString baseName, coupledNet;
844  int polarity = DRC_ENGINE::MatchDpSuffix( refName, coupledNet, baseName );
845 
846  if( polarity != 0 && item->GetBoard()->FindNet( coupledNet ) )
847  {
848  if( baseName.Matches( arg ) )
849  return 1.0;
850 
851  if( baseName.EndsWith( "_" ) && baseName.BeforeLast( '_' ).Matches( arg ) )
852  return 1.0;
853  }
854  }
855 
856  return 0.0;
857  } );
858 }
859 
860 
862 {
864 }
865 
866 
868 {
869  m_funcs.clear();
870  RegisterFunc( wxT( "existsOnLayer('x')" ), existsOnLayer );
871  RegisterFunc( wxT( "isPlated()" ), isPlated );
872  RegisterFunc( wxT( "insideCourtyard('x')" ), insideCourtyard );
873  RegisterFunc( wxT( "insideFrontCourtyard('x')" ), insideFrontCourtyard );
874  RegisterFunc( wxT( "insideBackCourtyard('x')" ), insideBackCourtyard );
875  RegisterFunc( wxT( "insideArea('x')" ), insideArea );
876  RegisterFunc( wxT( "isMicroVia()" ), isMicroVia );
877  RegisterFunc( wxT( "isBlindBuriedVia()" ), isBlindBuriedVia );
878  RegisterFunc( wxT( "memberOf('x')" ), memberOf );
879  RegisterFunc( wxT( "fromTo('x','y')" ), exprFromTo );
880  RegisterFunc( wxT( "isCoupledDiffPair()" ), isCoupledDiffPair );
881  RegisterFunc( wxT( "inDiffPair('x')" ), inDiffPair );
882 }
883 
884 
886 {
887  wxASSERT( dynamic_cast<const PCB_EXPR_CONTEXT*>( aCtx ) );
888 
889  const PCB_EXPR_CONTEXT* ctx = static_cast<const PCB_EXPR_CONTEXT*>( aCtx );
890  BOARD_ITEM* item = ctx->GetItem( m_itemIndex );
891  return item;
892 }
893 
894 
896 {
897 public:
899  LIBEVAL::VALUE( double( aLayer ) )
900  {};
901 
902  virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
903  {
904  // For boards with user-defined layer names there will be 2 entries for each layer
905  // in the ENUM_MAP: one for the canonical layer name and one for the user layer name.
906  // We need to check against both.
907 
908  wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
909  const wxString& layerName = b->AsString();
910  BOARD* board = static_cast<PCB_EXPR_CONTEXT*>( aCtx )->GetBoard();
911  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
912  auto i = board->m_LayerExpressionCache.find( layerName );
913  LSET mask;
914 
915  if( i == board->m_LayerExpressionCache.end() )
916  {
917  for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
918  {
919  wxPGChoiceEntry& entry = layerMap[ii];
920 
921  if( entry.GetText().Matches( layerName ) )
922  mask.set( ToLAYER_ID( entry.GetValue() ) );
923  }
924 
925  board->m_LayerExpressionCache[ layerName ] = mask;
926  }
927  else
928  {
929  mask = i->second;
930  }
931 
932  PCB_LAYER_ID layerId = ToLAYER_ID( (int) AsDouble() );
933 
934  return mask.Contains( layerId );
935  }
936 };
937 
938 
940 {
941  if( m_itemIndex == 2 )
942  {
943  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
944  return PCB_LAYER_VALUE( context->GetLayer() );
945  }
946 
947  BOARD_ITEM* item = GetObject( aCtx );
948 
949  if( !item )
950  return LIBEVAL::VALUE();
951 
952  auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
953 
954  if( it == m_matchingTypes.end() )
955  {
956  // Don't force user to type "A.Type == 'via' && A.Via_Type == 'buried'" when the
957  // simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
958  // value when the property doesn't appear on a particular object.
959 
960  return LIBEVAL::VALUE();
961  }
962  else
963  {
964  if( m_type == LIBEVAL::VT_NUMERIC )
965  return LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
966  else
967  {
968  wxString str;
969 
970  if( !m_isEnum )
971  {
972  str = item->Get<wxString>( it->second );
973  return LIBEVAL::VALUE( str );
974  }
975  else
976  {
977  const wxAny& any = item->Get( it->second );
978  bool valid = any.GetAs<wxString>( &str );
979 
980  if( valid )
981  return LIBEVAL::VALUE( str );
982  }
983 
984  return LIBEVAL::VALUE();
985  }
986  }
987 }
988 
989 
991 {
992  BOARD_ITEM* item = GetObject( aCtx );
993 
994  if( !item )
995  return LIBEVAL::VALUE();
996 
997  if( item->IsConnected() )
998  return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetClassName() );
999  else
1000  return LIBEVAL::VALUE();
1001 }
1002 
1003 
1005 {
1006  BOARD_ITEM* item = GetObject( aCtx );
1007 
1008  if( !item )
1009  return LIBEVAL::VALUE();
1010 
1011  if( item->IsConnected() )
1012  return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetname() );
1013  else
1014  return LIBEVAL::VALUE();
1015 }
1016 
1017 
1019 {
1020  BOARD_ITEM* item = GetObject( aCtx );
1021 
1022  if( !item )
1023  return LIBEVAL::VALUE();
1024 
1025  return LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
1026 }
1027 
1028 
1030 {
1032 
1033  return registry.Get( aName.Lower() );
1034 }
1035 
1036 
1037 std::unique_ptr<LIBEVAL::VAR_REF> PCB_EXPR_UCODE::CreateVarRef( const wxString& aVar,
1038  const wxString& aField )
1039 {
1041  std::unique_ptr<PCB_EXPR_VAR_REF> vref;
1042 
1043  // Check for a couple of very common cases and compile them straight to "object code".
1044 
1045  if( aField.CmpNoCase( wxT( "NetClass" ) ) == 0 )
1046  {
1047  if( aVar == wxT( "A" ) )
1048  return std::make_unique<PCB_EXPR_NETCLASS_REF>( 0 );
1049  else if( aVar == wxT( "B" ) )
1050  return std::make_unique<PCB_EXPR_NETCLASS_REF>( 1 );
1051  else
1052  return nullptr;
1053  }
1054  else if( aField.CmpNoCase( wxT( "NetName" ) ) == 0 )
1055  {
1056  if( aVar == wxT( "A" ) )
1057  return std::make_unique<PCB_EXPR_NETNAME_REF>( 0 );
1058  else if( aVar == wxT( "B" ) )
1059  return std::make_unique<PCB_EXPR_NETNAME_REF>( 1 );
1060  else
1061  return nullptr;
1062  }
1063  else if( aField.CmpNoCase( wxT( "Type" ) ) == 0 )
1064  {
1065  if( aVar == wxT( "A" ) )
1066  return std::make_unique<PCB_EXPR_TYPE_REF>( 0 );
1067  else if( aVar == wxT( "B" ) )
1068  return std::make_unique<PCB_EXPR_TYPE_REF>( 1 );
1069  else
1070  return nullptr;
1071  }
1072 
1073  if( aVar == wxT( "A" ) || aVar == wxT( "AB" ) )
1074  vref = std::make_unique<PCB_EXPR_VAR_REF>( 0 );
1075  else if( aVar == wxT( "B" ) )
1076  vref = std::make_unique<PCB_EXPR_VAR_REF>( 1 );
1077  else if( aVar == wxT( "L" ) )
1078  vref = std::make_unique<PCB_EXPR_VAR_REF>( 2 );
1079  else
1080  return nullptr;
1081 
1082  if( aField.length() == 0 ) // return reference to base object
1083  {
1084  return std::move( vref );
1085  }
1086 
1087  wxString field( aField );
1088  field.Replace( wxT( "_" ), wxT( " " ) );
1089 
1090  for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
1091  {
1092  if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) )
1093  {
1094  PROPERTY_BASE* prop = propMgr.GetProperty( cls.type, field );
1095 
1096  if( prop )
1097  {
1098  vref->AddAllowedClass( cls.type, prop );
1099 
1100  if( prop->TypeHash() == TYPE_HASH( int ) )
1101  {
1102  vref->SetType( LIBEVAL::VT_NUMERIC );
1103  }
1104  else if( prop->TypeHash() == TYPE_HASH( wxString ) )
1105  {
1106  vref->SetType( LIBEVAL::VT_STRING );
1107  }
1108  else if ( prop->HasChoices() )
1109  { // it's an enum, we treat it as string
1110  vref->SetType( LIBEVAL::VT_STRING );
1111  vref->SetIsEnum ( true );
1112  }
1113  else
1114  {
1115  wxFAIL_MSG( wxT( "PCB_EXPR_UCODE::createVarRef: Unknown property type." ) );
1116  }
1117  }
1118  }
1119  }
1120 
1121  if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
1122  vref->SetType( LIBEVAL::VT_PARSE_ERROR );
1123 
1124  return std::move( vref );
1125 }
1126 
1127 
1129 {
1130  if( m_items[0] )
1131  return m_items[0]->GetBoard();
1132 
1133  return nullptr;
1134 }
1135 
1136 
1138 {
1139 public:
1141  {
1142  }
1143 
1144  virtual const std::vector<wxString>& GetSupportedUnits() const override
1145  {
1146  static const std::vector<wxString> pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ) };
1147 
1148  return pcbUnits;
1149  }
1150 
1151  virtual wxString GetSupportedUnitsMessage() const override
1152  {
1153  return _( "must be mm, in, or mil" );
1154  }
1155 
1156  virtual double Convert( const wxString& aString, int unitId ) const override
1157  {
1158  double v = wxAtof( aString );
1159 
1160  switch( unitId )
1161  {
1162  case 0: return DoubleValueFromString( EDA_UNITS::MILS, aString );
1163  case 1: return DoubleValueFromString( EDA_UNITS::MILLIMETRES, aString );
1164  case 2: return DoubleValueFromString( EDA_UNITS::INCHES, aString );
1165  default: return v;
1166  }
1167  };
1168 };
1169 
1170 
1172 {
1173  m_unitResolver = std::make_unique<PCB_UNIT_RESOLVER>();
1174 }
1175 
1176 
1178  m_result( 0 ),
1179  m_compiler(),
1180  m_ucode(),
1181  m_errorStatus()
1182 {
1183 }
1184 
1185 
1187 {
1188 }
1189 
1190 
1191 bool PCB_EXPR_EVALUATOR::Evaluate( const wxString& aExpr )
1192 {
1193  PCB_EXPR_UCODE ucode;
1194  PCB_EXPR_CONTEXT preflightContext( NULL_CONSTRAINT, F_Cu );
1195 
1196  if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
1197  return false;
1198 
1199  PCB_EXPR_CONTEXT evaluationContext( NULL_CONSTRAINT, F_Cu );
1200  LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
1201 
1202  if( result->GetType() == LIBEVAL::VT_NUMERIC )
1203  m_result = KiROUND( result->AsDouble() );
1204 
1205  return true;
1206 }
1207 
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:60
BOARD_ITEM * GetItem(int index) const
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1328
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition: property.h:216
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:65
#define TYPE_HASH(x)
Definition: property.h:59
bool isInsideCourtyard(BOARD_ITEM *aItem, const EDA_RECT &aItemBBox, std::shared_ptr< SHAPE > &aItemShape, PCB_EXPR_CONTEXT *aCtx, FOOTPRINT *aFootprint, PCB_LAYER_ID aSide)
int OutlineCount() const
Return the number of vertices in a given outline/hole.
std::unique_ptr< UNIT_RESOLVER > m_unitResolver
std::map< std::pair< BOARD_ITEM *, BOARD_ITEM * >, bool > m_InsideCourtyardCache
Definition: board.h:1066
ZONES & Zones()
Definition: board.h:240
void SetDeferredEval(std::function< double()> aLambda)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
bool calcIsInsideArea(BOARD_ITEM *aItem, const EDA_RECT &aItemBBox, PCB_EXPR_CONTEXT *aCtx, ZONE *aArea)
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
virtual LIBEVAL::FUNC_CALL_REF CreateFuncCall(const wxString &aName) override
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
virtual bool EqualTo(LIBEVAL::CONTEXT *aCtx, const VALUE *b) const override
void RegisterFunc(const wxString &funcSignature, LIBEVAL::FUNC_CALL_REF funcPtr)
SHAPE_POLY_SET * Outline()
Definition: zone.h:320
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
Definition: layer_ids.h:587
LIBEVAL::FUNC_CALL_REF Get(const wxString &name)
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:289
virtual size_t TypeHash() const =0
Return type-id of the property type.
static ENUM_MAP< T > & Instance()
Definition: property.h:510
BOARD * GetBoard() const
static void isPlated(LIBEVAL::CONTEXT *aCtx, void *self)
bool exprFromTo(LIBEVAL::CONTEXT *aCtx, void *self)
class PAD, a pad in a footprint
Definition: typeinfo.h:89
bool IsFilled() const
Definition: zone.h:234
static void inDiffPair(LIBEVAL::CONTEXT *aCtx, void *self)
static int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet, wxString &aBaseDpName)
Check if the given net is a diff pair, returning its polarity and complement if so.
static void insideFrontCourtyard(LIBEVAL::CONTEXT *aCtx, void *self)
virtual wxString GetSupportedUnitsMessage() const override
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:883
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:181
std::mutex m_CachesMutex
Definition: board.h:1065
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
bool isInsideArea(BOARD_ITEM *aItem, const EDA_RECT &aItemBBox, PCB_EXPR_CONTEXT *aCtx, ZONE *aArea)
std::map< wxString, LIBEVAL::FUNC_CALL_REF > m_funcs
Plated through hole pad.
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
Definition: kiid.h:44
PCB_EXPR_COMPILER m_compiler
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
#define HOLE_PROXY
Indicates the BOARD_ITEM is a proxy for its hole.
VAR_TYPE_T GetType() const
std::function< void(CONTEXT *, void *)> FUNC_CALL_REF
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:195
const EDA_RECT GetBoundingBox() const override
Definition: zone.cpp:320
static void isBlindBuriedVia(LIBEVAL::CONTEXT *aCtx, void *self)
LIBEVAL::VAR_TYPE_T m_type
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
static bool SniffTest(const wxString &aCandidate)
Returns true if a string has the correct formatting to be a KIID.
Definition: kiid.cpp:158
static void existsOnLayer(LIBEVAL::CONTEXT *aCtx, void *self)
FOOTPRINTS & Footprints()
Definition: board.h:234
wxAny Get(PROPERTY_BASE *aProperty)
Definition: inspectable.h:86
virtual std::unique_ptr< LIBEVAL::VAR_REF > CreateVarRef(const wxString &aVar, const wxString &aField) override
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:345
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
const wxString & GetNetname() const
Definition: netinfo.h:126
#define _(s)
BOARD_ITEM * m_items[2]
const SHAPE_POLY_SET & GetPolyCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.h:695
bool calcIsInsideCourtyard(BOARD_ITEM *aItem, const EDA_RECT &aItemBBox, std::shared_ptr< SHAPE > &aItemShape, PCB_EXPR_CONTEXT *aCtx, FOOTPRINT *aFootprint, PCB_LAYER_ID aSide)
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
PCB_LAYER_VALUE(PCB_LAYER_ID aLayer)
static void insideArea(LIBEVAL::CONTEXT *aCtx, void *self)
static void insideBackCourtyard(LIBEVAL::CONTEXT *aCtx, void *self)
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:154
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
LIBEVAL::VALUE GetValue(LIBEVAL::CONTEXT *aCtx) override
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
std::map< wxString, LSET > m_LayerExpressionCache
Definition: board.h:1070
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
virtual LIBEVAL::VALUE GetValue(LIBEVAL::CONTEXT *aCtx) override
void ReportError(const wxString &aErrorMsg)
Handle the data for a net.
Definition: netinfo.h:66
bool IsOfType(TYPE_ID aDerived, TYPE_ID aBase) const
Return true if aDerived is inherited from aBase.
virtual double AsDouble() const
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
static void memberOf(LIBEVAL::CONTEXT *aCtx, void *self)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:736
Definition: layer_ids.h:71
virtual const wxString & AsString() const
class ZONE, managed by a footprint
Definition: typeinfo.h:94
static void insideCourtyard(LIBEVAL::CONTEXT *aCtx, void *self)
Handle the component boundary box.
Definition: eda_rect.h:42
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
bool Evaluate(const wxString &aExpr)
static void isMicroVia(LIBEVAL::CONTEXT *aCtx, void *self)
virtual double Convert(const wxString &aString, int unitId) const override
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:890
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
std::map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTrees
Definition: board.h:1072
virtual const std::vector< wxString > & GetSupportedUnits() const override
CLASSES_INFO GetAllClasses()
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:103
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:36
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:62
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
static void isCoupledDiffPair(LIBEVAL::CONTEXT *aCtx, void *self)
VALUE * Run(CONTEXT *ctx)
virtual const EDA_RECT GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:75
std::map< std::pair< BOARD_ITEM *, BOARD_ITEM * >, bool > m_InsideBCourtyardCache
Definition: board.h:1068
Definition: pad.h:57
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:307
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:46
int GetConstraint() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:136
#define MALFORMED_COURTYARDS
LIBEVAL::VALUE GetValue(LIBEVAL::CONTEXT *aCtx) override
std::map< std::pair< BOARD_ITEM *, BOARD_ITEM * >, bool > m_InsideAreaCache
Definition: board.h:1069
void Push(VALUE *v)
just inflate the polygon. Acute angles create spikes
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:914
void Set(double aValue)
BOARD_ITEM * GetObject(const LIBEVAL::CONTEXT *aCtx) const
PCB_LAYER_ID GetLayer() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:148
std::unordered_map< TYPE_ID, PROPERTY_BASE * > m_matchingTypes
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
int QueryColliding(BOARD_ITEM *aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter=nullptr, std::function< bool(BOARD_ITEM *)> aVisitor=nullptr, int aClearance=0) const
This is a fast test which essentially does bounding-box overlap given a worst-case clearance.
Definition: drc_rtree.h:183
static PCB_EXPR_BUILTIN_FUNCTIONS & Instance()
std::map< std::pair< BOARD_ITEM *, BOARD_ITEM * >, bool > m_InsideFCourtyardCache
Definition: board.h:1067
LIBEVAL::VALUE GetValue(LIBEVAL::CONTEXT *aCtx) override