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-2020 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( "Attempting to call fromTo() with non-existent from-to cache, aborting...");
63  return true;
64  }
65 
66  if( ftCache->IsOnFromToPath( static_cast<BOARD_CONNECTED_ITEM*>( item ),
67  argFrom->AsString(), argTo->AsString() ) )
68  {
69  result->Set(1.0);
70  }
71 
72  return true;
73 }
74 
75 
76 static void existsOnLayer( LIBEVAL::CONTEXT* aCtx, void *self )
77 {
78  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
79  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
80 
81  LIBEVAL::VALUE* arg = aCtx->Pop();
82  LIBEVAL::VALUE* result = aCtx->AllocValue();
83 
84  result->Set( 0.0 );
85  aCtx->Push( result );
86 
87  if( !item )
88  return;
89 
90  if( !arg )
91  {
92  if( aCtx->HasErrorCallback() )
93  {
94  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
95  wxT( "existsOnLayer()" ) ) );
96  }
97 
98  return;
99  }
100 
101  result->SetDeferredEval(
102  [item, arg, aCtx]() -> double
103  {
104  const wxString& layerName = arg->AsString();
105  wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
106 
107  if( aCtx->HasErrorCallback())
108  {
109  /*
110  * Interpreted version
111  */
112 
113  bool anyMatch = false;
114 
115  for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
116  {
117  wxPGChoiceEntry& entry = layerMap[ ii ];
118 
119  if( entry.GetText().Matches( layerName ))
120  {
121  anyMatch = true;
122 
123  if( item->IsOnLayer( ToLAYER_ID( entry.GetValue())))
124  return 1.0;
125  }
126  }
127 
128  if( !anyMatch )
129  {
130  aCtx->ReportError( wxString::Format( _( "Unrecognized layer '%s'" ),
131  layerName ) );
132  }
133  }
134  else
135  {
136  /*
137  * Compiled version
138  */
139 
140  BOARD* board = item->GetBoard();
141  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
142  auto i = board->m_LayerExpressionCache.find( layerName );
143  LSET mask;
144 
145  if( i == board->m_LayerExpressionCache.end() )
146  {
147  for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
148  {
149  wxPGChoiceEntry& entry = layerMap[ ii ];
150 
151  if( entry.GetText().Matches( layerName ) )
152  mask.set( ToLAYER_ID( entry.GetValue() ) );
153  }
154 
155  board->m_LayerExpressionCache[ layerName ] = mask;
156  }
157  else
158  {
159  mask = i->second;
160  }
161 
162  if( ( item->GetLayerSet() & mask ).any() )
163  return 1.0;
164  }
165 
166  return 0.0;
167  } );
168 }
169 
170 
171 static void isPlated( LIBEVAL::CONTEXT* aCtx, void* self )
172 {
173  LIBEVAL::VALUE* result = aCtx->AllocValue();
174 
175  result->Set( 0.0 );
176  aCtx->Push( result );
177 
178  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
179  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
180 
181  if( !item )
182  return;
183 
184  if( item->Type() == PCB_PAD_T && static_cast<PAD*>( item )->GetAttribute() == PAD_ATTRIB::PTH )
185  result->Set( 1.0 );
186  else if( item->Type() == PCB_VIA_T )
187  result->Set( 1.0 );
188 }
189 
190 
191 bool calcIsInsideCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox,
192  std::shared_ptr<SHAPE>& aItemShape, PCB_EXPR_CONTEXT* aCtx,
193  FOOTPRINT* aFootprint, PCB_LAYER_ID aSide )
194 {
195  SHAPE_POLY_SET footprintCourtyard;
196 
197  footprintCourtyard = aFootprint->GetPolyCourtyard( aSide );
198 
199  if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
200  {
201  // A zone must be entirely inside the courtyard to be considered
202  if( !aFootprint->GetBoundingBox().Contains( aItemBBox ) )
203  return false;
204  }
205  else
206  {
207  if( !aFootprint->GetBoundingBox().Intersects( aItemBBox ) )
208  return false;
209  }
210 
211  if( !aItemShape )
212  aItemShape = aItem->GetEffectiveShape( aCtx->GetLayer() );
213 
214  return footprintCourtyard.Collide( aItemShape.get() );
215 };
216 
217 
218 bool isInsideCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox,
219  std::shared_ptr<SHAPE>& aItemShape, PCB_EXPR_CONTEXT* aCtx,
220  FOOTPRINT* aFootprint, PCB_LAYER_ID aSide )
221 {
222  if( !aFootprint )
223  return false;
224 
225  BOARD* board = aItem->GetBoard();
226  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
227  std::pair<BOARD_ITEM*, BOARD_ITEM*> key( aFootprint, aItem );
228 
229  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, bool >* cache;
230 
231  switch( aSide )
232  {
233  case F_Cu: cache = &board->m_InsideFCourtyardCache; break;
234  case B_Cu: cache = &board->m_InsideBCourtyardCache; break;
235  default: cache = &board->m_InsideCourtyardCache; break;
236  }
237 
238  auto i = cache->find( key );
239 
240  if( i != cache->end() )
241  return i->second;
242 
243  bool res = calcIsInsideCourtyard( aItem, aItemBBox, aItemShape, aCtx, aFootprint, aSide );
244 
245  (*cache)[ key ] = res;
246  return res;
247 };
248 
249 
250 static void insideCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
251 {
252  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
253  LIBEVAL::VALUE* arg = aCtx->Pop();
254  LIBEVAL::VALUE* result = aCtx->AllocValue();
255 
256  result->Set( 0.0 );
257  aCtx->Push( result );
258 
259  if( !arg )
260  {
261  if( aCtx->HasErrorCallback() )
262  {
263  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
264  wxT( "insideCourtyard()" ) ) );
265  }
266 
267  return;
268  }
269 
270  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
271  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
272 
273  if( !item )
274  return;
275 
276  result->SetDeferredEval(
277  [item, arg, context]() -> double
278  {
279  BOARD* board = item->GetBoard();
280  EDA_RECT itemBBox;
281  std::shared_ptr<SHAPE> itemShape;
282 
283  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
284  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
285  else
286  itemBBox = item->GetBoundingBox();
287 
288  if( arg->AsString() == "A" )
289  {
290  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
291 
292  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, In1_Cu ) )
293  return 1.0;
294  }
295  else if( arg->AsString() == "B" )
296  {
297  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
298 
299  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, In1_Cu ) )
300  return 1.0;
301  }
302  else for( FOOTPRINT* fp : board->Footprints() )
303  {
304  if( fp->GetReference().Matches( arg->AsString() ) )
305  {
306  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, In1_Cu ) )
307  return 1.0;
308  }
309  }
310 
311  return 0.0;
312  } );
313 }
314 
315 
316 static void insideFrontCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
317 {
318  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
319  LIBEVAL::VALUE* arg = aCtx->Pop();
320  LIBEVAL::VALUE* result = aCtx->AllocValue();
321 
322  result->Set( 0.0 );
323  aCtx->Push( result );
324 
325  if( !arg )
326  {
327  if( aCtx->HasErrorCallback() )
328  {
329  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
330  wxT( "insideFrontCourtyard()" ) ) );
331  }
332 
333  return;
334  }
335 
336  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
337  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
338 
339  if( !item )
340  return;
341 
342  result->SetDeferredEval(
343  [item, arg, context]() -> double
344  {
345  BOARD* board = item->GetBoard();
346  EDA_RECT itemBBox;
347  std::shared_ptr<SHAPE> itemShape;
348 
349  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
350  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
351  else
352  itemBBox = item->GetBoundingBox();
353 
354  if( arg->AsString() == "A" )
355  {
356  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
357 
358  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, F_Cu ) )
359  return 1.0;
360  }
361  else if( arg->AsString() == "B" )
362  {
363  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
364 
365  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, F_Cu ) )
366  return 1.0;
367  }
368  else for( FOOTPRINT* fp : board->Footprints() )
369  {
370  if( fp->GetReference().Matches( arg->AsString() ) )
371  {
372  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, F_Cu ) )
373  return 1.0;
374  }
375  }
376 
377  return 0.0;
378  } );
379 }
380 
381 
382 static void insideBackCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
383 {
384  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
385  LIBEVAL::VALUE* arg = aCtx->Pop();
386  LIBEVAL::VALUE* result = aCtx->AllocValue();
387 
388  result->Set( 0.0 );
389  aCtx->Push( result );
390 
391  if( !arg )
392  {
393  if( aCtx->HasErrorCallback() )
394  {
395  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
396  wxT( "insideBackCourtyard()" ) ) );
397  }
398  return;
399  }
400 
401  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
402  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
403 
404  if( !item )
405  return;
406 
407  result->SetDeferredEval(
408  [item, arg, context]() -> double
409  {
410  BOARD* board = item->GetBoard();
411  EDA_RECT itemBBox;
412  std::shared_ptr<SHAPE> itemShape;
413 
414  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
415  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
416  else
417  itemBBox = item->GetBoundingBox();
418 
419  if( arg->AsString() == "A" )
420  {
421  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
422 
423  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, B_Cu ) )
424  return 1.0;
425  }
426  else if( arg->AsString() == "B" )
427  {
428  FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
429 
430  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, B_Cu ) )
431  return 1.0;
432  }
433  else for( FOOTPRINT* fp : board->Footprints() )
434  {
435  if( fp->GetReference().Matches( arg->AsString() ) )
436  {
437  if( isInsideCourtyard( item, itemBBox, itemShape, context, fp, B_Cu ) )
438  return 1.0;
439  }
440  }
441 
442  return 0.0;
443  } );
444 }
445 
446 
447 bool calcIsInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CONTEXT* aCtx,
448  ZONE* aArea )
449 {
450  BOARD* board = aArea->GetBoard();
451  std::shared_ptr<SHAPE> shape;
452 
453  if( !aArea->GetCachedBoundingBox().Intersects( aItemBBox ) )
454  return false;
455 
456  // Collisions include touching, so we need to deflate outline by enough to
457  // exclude touching. This is particularly important for detecting copper fills
458  // as they will be exactly touching along the entire border.
459  SHAPE_POLY_SET areaOutline = *aArea->Outline();
460  areaOutline.Deflate( board->GetDesignSettings().GetDRCEpsilon(), 0,
462 
463  if( aItem->GetFlags() & HOLE_PROXY )
464  {
465  if( aItem->Type() == PCB_PAD_T )
466  {
467  PAD* pad = static_cast<PAD*>( aItem );
468  const SHAPE_SEGMENT* holeShape = pad->GetEffectiveHoleShape();
469 
470  return areaOutline.Collide( holeShape );
471  }
472  else if( aItem->Type() == PCB_VIA_T )
473  {
474  PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
475  const SHAPE_CIRCLE holeShape( via->GetPosition(), via->GetDrillValue() );
476  LSET overlap = via->GetLayerSet() & aArea->GetLayerSet();
477 
479  if( overlap.count() > 0 )
480  {
481  if( aCtx->GetLayer() == UNDEFINED_LAYER || overlap.Contains( aCtx->GetLayer() ) )
482  return areaOutline.Collide( &holeShape );
483  }
484  }
485 
486  return false;
487  }
488 
489  if( aItem->Type() == PCB_FOOTPRINT_T )
490  {
491  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
492 
493  if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
494  {
495  if( aCtx->HasErrorCallback() )
496  {
497  aCtx->ReportError( _( "Footprint's courtyard is not a single, closed shape." ) );
498  }
499 
500  return false;
501  }
502 
503  if( ( aArea->GetLayerSet() & LSET::FrontMask() ).any() )
504  {
505  SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( F_CrtYd );
506 
507  if( courtyard.OutlineCount() == 0 )
508  {
509  if( aCtx->HasErrorCallback() )
510  aCtx->ReportError( _( "Footprint has no front courtyard." ) );
511 
512  return false;
513  }
514  else
515  {
516  return areaOutline.Collide( &courtyard.Outline( 0 ) );
517  }
518  }
519 
520  if( ( aArea->GetLayerSet() & LSET::BackMask() ).any() )
521  {
522  SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( B_CrtYd );
523 
524  if( courtyard.OutlineCount() == 0 )
525  {
526  if( aCtx->HasErrorCallback() )
527  aCtx->ReportError( _( "Footprint has no back courtyard." ) );
528 
529  return false;
530  }
531  else
532  {
533  return areaOutline.Collide( &courtyard.Outline( 0 ) );
534  }
535  }
536 
537  return false;
538  }
539 
540  if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
541  {
542  ZONE* zone = static_cast<ZONE*>( aItem );
543 
544  if( !zone->IsFilled() )
545  return false;
546 
547  DRC_RTREE* zoneRTree = board->m_CopperZoneRTrees[ zone ].get();
548 
549  std::vector<SHAPE*> shapes;
550 
551  if( zoneRTree )
552  {
553  for( PCB_LAYER_ID layer : aArea->GetLayerSet().Seq() )
554  {
555  if( aCtx->GetLayer() == layer || aCtx->GetLayer() == UNDEFINED_LAYER )
556  {
557  if( zoneRTree->QueryColliding( aItemBBox, &areaOutline, layer ) )
558  return true;
559  }
560  }
561  }
562 
563  return false;
564  }
565  else
566  {
567  if( aCtx->GetLayer() != UNDEFINED_LAYER
568  && !( aArea->GetLayerSet().Contains( aCtx->GetLayer() ) ) )
569  return false;
570 
571  if( !shape )
572  shape = aItem->GetEffectiveShape( aCtx->GetLayer() );
573 
574  return areaOutline.Collide( shape.get() );
575  }
576 }
577 
578 
579 bool isInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CONTEXT* aCtx,
580  ZONE* aArea )
581 {
582  if( !aArea || aArea == aItem || aArea->GetParent() == aItem )
583  return false;
584 
585  BOARD* board = aArea->GetBoard();
586  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
587  std::pair<BOARD_ITEM*, BOARD_ITEM*> key( aArea, aItem );
588  auto i = board->m_InsideAreaCache.find( key );
589 
590  if( i != board->m_InsideAreaCache.end() )
591  return i->second;
592 
593  bool isInside = calcIsInsideArea( aItem, aItemBBox, aCtx, aArea );
594 
595  board->m_InsideAreaCache[ key ] = isInside;
596  return isInside;
597 }
598 
599 
600 static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
601 {
602  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
603  LIBEVAL::VALUE* arg = aCtx->Pop();
604  LIBEVAL::VALUE* result = aCtx->AllocValue();
605 
606  result->Set( 0.0 );
607  aCtx->Push( result );
608 
609  if( !arg )
610  {
611  if( aCtx->HasErrorCallback() )
612  {
613  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
614  wxT( "insideArea()" ) ) );
615  }
616 
617  return;
618  }
619 
620  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
621  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
622 
623  if( !item )
624  return;
625 
626  result->SetDeferredEval(
627  [item, arg, context]() -> double
628  {
629  BOARD* board = item->GetBoard();
630  EDA_RECT itemBBox;
631 
632  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
633  itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
634  else
635  itemBBox = item->GetBoundingBox();
636 
637  if( arg->AsString() == "A" )
638  {
639  ZONE* zone = dynamic_cast<ZONE*>( context->GetItem( 0 ) );
640  return isInsideArea( item, itemBBox, context, zone ) ? 1.0 : 0.0;
641  }
642  else if( arg->AsString() == "B" )
643  {
644  ZONE* zone = dynamic_cast<ZONE*>( context->GetItem( 1 ) );
645  return isInsideArea( item, itemBBox, context, zone ) ? 1.0 : 0.0;
646  }
647  else if( KIID::SniffTest( arg->AsString() ) )
648  {
649  KIID target( arg->AsString());
650 
651  for( ZONE* area : board->Zones() )
652  {
653  // Only a single zone can match the UUID; exit once we find a match whether
654  // "inside" or not
655  if( area->m_Uuid == target )
656  return isInsideArea( item, itemBBox, context, area ) ? 1.0 : 0.0;
657  }
658 
659  for( FOOTPRINT* footprint : board->Footprints() )
660  {
661  for( ZONE* area : footprint->Zones() )
662  {
663  // Only a single zone can match the UUID; exit once we find a match
664  // whether "inside" or not
665  if( area->m_Uuid == target )
666  return isInsideArea( item, itemBBox, context, area ) ? 1.0 : 0.0;
667  }
668  }
669 
670  return 0.0;
671  }
672  else // Match on zone name
673  {
674  for( ZONE* area : board->Zones())
675  {
676  if( area->GetZoneName().Matches( arg->AsString() ) )
677  {
678  // Many zones can match the name; exit only when we find an "inside"
679  if( isInsideArea( item, itemBBox, context, area ) )
680  return 1.0;
681  }
682  }
683 
684  for( FOOTPRINT* footprint : board->Footprints() )
685  {
686  for( ZONE* area : footprint->Zones() )
687  {
688  // Many zones can match the name; exit only when we find an "inside"
689  if( area->GetZoneName().Matches( arg->AsString() ) )
690  {
691  if( isInsideArea( item, itemBBox, context, area ) )
692  return 1.0;
693  }
694  }
695  }
696 
697  return 0.0;
698  }
699  } );
700 }
701 
702 
703 static void memberOf( LIBEVAL::CONTEXT* aCtx, void* self )
704 {
705  LIBEVAL::VALUE* arg = aCtx->Pop();
706  LIBEVAL::VALUE* result = aCtx->AllocValue();
707 
708  result->Set( 0.0 );
709  aCtx->Push( result );
710 
711  if( !arg )
712  {
713  if( aCtx->HasErrorCallback() )
714  {
715  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
716  wxT( "memberOf()" ) ) );
717  }
718  return;
719  }
720 
721  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
722  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
723 
724  if( !item )
725  return;
726 
727  result->SetDeferredEval(
728  [item, arg]() -> double
729  {
730  PCB_GROUP* group = item->GetParentGroup();
731 
732  if( !group && item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T )
733  group = item->GetParent()->GetParentGroup();
734 
735  while( group )
736  {
737  if( group->GetName().Matches( arg->AsString() ) )
738  return 1.0;
739 
740  group = group->GetParentGroup();
741  }
742 
743  return 0.0;
744  } );
745 }
746 
747 
748 static void isMicroVia( LIBEVAL::CONTEXT* aCtx, void* self )
749 {
750  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
751  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
752  LIBEVAL::VALUE* result = aCtx->AllocValue();
753 
754  result->Set( 0.0 );
755  aCtx->Push( result );
756 
757  PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
758 
759  if( via && via->GetViaType() == VIATYPE::MICROVIA )
760  result->Set ( 1.0 );
761 }
762 
763 
764 static void isBlindBuriedVia( LIBEVAL::CONTEXT* aCtx, void* self )
765 {
766  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
767  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
768  LIBEVAL::VALUE* result = aCtx->AllocValue();
769 
770  result->Set( 0.0 );
771  aCtx->Push( result );
772 
773  PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
774 
775  if( via && via->GetViaType() == VIATYPE::BLIND_BURIED )
776  result->Set ( 1.0 );
777 }
778 
779 
780 static void isCoupledDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
781 {
782  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
783  BOARD_CONNECTED_ITEM* a = dynamic_cast<BOARD_CONNECTED_ITEM*>( context->GetItem( 0 ) );
784  BOARD_CONNECTED_ITEM* b = dynamic_cast<BOARD_CONNECTED_ITEM*>( context->GetItem( 1 ) );
785  LIBEVAL::VALUE* result = aCtx->AllocValue();
786 
787  result->Set( 0.0 );
788  aCtx->Push( result );
789 
790  result->SetDeferredEval(
791  [a, b]() -> double
792  {
793  if( a && b )
794  {
795  NETINFO_ITEM* netinfo = a->GetNet();
796  wxString coupledNet, dummy;
797 
798  if( netinfo
799  && DRC_ENGINE::MatchDpSuffix( netinfo->GetNetname(), coupledNet, dummy )
800  && b->GetNetname() == coupledNet )
801  {
802  return 1.0;
803  }
804  }
805 
806  return 0.0;
807  } );
808 }
809 
810 
811 static void inDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
812 {
813  LIBEVAL::VALUE* arg = aCtx->Pop();
814  PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
815  BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
816  LIBEVAL::VALUE* result = aCtx->AllocValue();
817 
818  result->Set( 0.0 );
819  aCtx->Push( result );
820 
821  if( !item || !item->GetBoard() )
822  return;
823 
824  if( !arg )
825  {
826  if( aCtx->HasErrorCallback() )
827  {
828  aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
829  wxT( "inDiffPair()" ) ) );
830  }
831 
832  return;
833  }
834 
835  result->SetDeferredEval(
836  [item, arg]() -> double
837  {
838  if( item && item->IsConnected() )
839  {
840  NETINFO_ITEM* netinfo = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNet();
841 
842  wxString refName = netinfo->GetNetname();
843  wxString baseName, coupledNet;
844  int polarity = DRC_ENGINE::MatchDpSuffix( refName, coupledNet, baseName );
845 
846  if( polarity != 0
847  && item->GetBoard()->FindNet( coupledNet )
848  && baseName.Matches( arg->AsString() ) )
849  {
850  return 1.0;
851  }
852  }
853 
854  return 0.0;
855  } );
856 }
857 
858 
860 {
862 }
863 
864 
866 {
867  m_funcs.clear();
868  RegisterFunc( "existsOnLayer('x')", existsOnLayer );
869  RegisterFunc( "isPlated()", isPlated );
870  RegisterFunc( "insideCourtyard('x')", insideCourtyard );
871  RegisterFunc( "insideFrontCourtyard('x')", insideFrontCourtyard );
872  RegisterFunc( "insideBackCourtyard('x')", insideBackCourtyard );
873  RegisterFunc( "insideArea('x')", insideArea );
874  RegisterFunc( "isMicroVia()", isMicroVia );
875  RegisterFunc( "isBlindBuriedVia()", isBlindBuriedVia );
876  RegisterFunc( "memberOf('x')", memberOf );
877  RegisterFunc( "fromTo('x','y')", exprFromTo );
878  RegisterFunc( "isCoupledDiffPair()", isCoupledDiffPair );
879  RegisterFunc( "inDiffPair('x')", inDiffPair );
880 }
881 
882 
884 {
885  wxASSERT( dynamic_cast<const PCB_EXPR_CONTEXT*>( aCtx ) );
886 
887  const PCB_EXPR_CONTEXT* ctx = static_cast<const PCB_EXPR_CONTEXT*>( aCtx );
888  BOARD_ITEM* item = ctx->GetItem( m_itemIndex );
889  return item;
890 }
891 
892 
894 {
895 public:
897  LIBEVAL::VALUE( double( aLayer ) )
898  {};
899 
900  virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
901  {
902  // For boards with user-defined layer names there will be 2 entries for each layer
903  // in the ENUM_MAP: one for the canonical layer name and one for the user layer name.
904  // We need to check against both.
905 
906  wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
907  const wxString& layerName = b->AsString();
908  BOARD* board = static_cast<PCB_EXPR_CONTEXT*>( aCtx )->GetBoard();
909  std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
910  auto i = board->m_LayerExpressionCache.find( layerName );
911  LSET mask;
912 
913  if( i == board->m_LayerExpressionCache.end() )
914  {
915  for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
916  {
917  wxPGChoiceEntry& entry = layerMap[ii];
918 
919  if( entry.GetText().Matches( layerName ) )
920  mask.set( ToLAYER_ID( entry.GetValue() ) );
921  }
922 
923  board->m_LayerExpressionCache[ layerName ] = mask;
924  }
925  else
926  {
927  mask = i->second;
928  }
929 
930  PCB_LAYER_ID layerId = ToLAYER_ID( (int) AsDouble() );
931 
932  return mask.Contains( layerId );
933  }
934 };
935 
936 
938 {
939  if( m_itemIndex == 2 )
940  {
941  PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
942  return PCB_LAYER_VALUE( context->GetLayer() );
943  }
944 
945  BOARD_ITEM* item = GetObject( aCtx );
946 
947  if( !item )
948  return LIBEVAL::VALUE();
949 
950  auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
951 
952  if( it == m_matchingTypes.end() )
953  {
954  // Don't force user to type "A.Type == 'via' && A.Via_Type == 'buried'" when the
955  // simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
956  // value when the property doesn't appear on a particular object.
957 
958  return LIBEVAL::VALUE();
959  }
960  else
961  {
962  if( m_type == LIBEVAL::VT_NUMERIC )
963  return LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
964  else
965  {
966  wxString str;
967 
968  if( !m_isEnum )
969  {
970  str = item->Get<wxString>( it->second );
971  return LIBEVAL::VALUE( str );
972  }
973  else
974  {
975  const wxAny& any = item->Get( it->second );
976  bool valid = any.GetAs<wxString>( &str );
977 
978  if( valid )
979  return LIBEVAL::VALUE( str );
980  }
981 
982  return LIBEVAL::VALUE();
983  }
984  }
985 }
986 
987 
989 {
990  BOARD_ITEM* item = GetObject( aCtx );
991 
992  if( !item )
993  return LIBEVAL::VALUE();
994 
995  if( item->IsConnected() )
996  return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetClassName() );
997  else
998  return LIBEVAL::VALUE();
999 }
1000 
1001 
1003 {
1004  BOARD_ITEM* item = GetObject( aCtx );
1005 
1006  if( !item )
1007  return LIBEVAL::VALUE();
1008 
1009  if( item->IsConnected() )
1010  return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetname() );
1011  else
1012  return LIBEVAL::VALUE();
1013 }
1014 
1015 
1017 {
1018  BOARD_ITEM* item = GetObject( aCtx );
1019 
1020  if( !item )
1021  return LIBEVAL::VALUE();
1022 
1023  return LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
1024 }
1025 
1026 
1028 {
1030 
1031  return registry.Get( aName.Lower() );
1032 }
1033 
1034 
1035 std::unique_ptr<LIBEVAL::VAR_REF> PCB_EXPR_UCODE::CreateVarRef( const wxString& aVar,
1036  const wxString& aField )
1037 {
1039  std::unique_ptr<PCB_EXPR_VAR_REF> vref;
1040 
1041  // Check for a couple of very common cases and compile them straight to "object code".
1042 
1043  if( aField.CmpNoCase( "NetClass" ) == 0 )
1044  {
1045  if( aVar == "A" )
1046  return std::make_unique<PCB_EXPR_NETCLASS_REF>( 0 );
1047  else if( aVar == "B" )
1048  return std::make_unique<PCB_EXPR_NETCLASS_REF>( 1 );
1049  else
1050  return nullptr;
1051  }
1052  else if( aField.CmpNoCase( "NetName" ) == 0 )
1053  {
1054  if( aVar == "A" )
1055  return std::make_unique<PCB_EXPR_NETNAME_REF>( 0 );
1056  else if( aVar == "B" )
1057  return std::make_unique<PCB_EXPR_NETNAME_REF>( 1 );
1058  else
1059  return nullptr;
1060  }
1061  else if( aField.CmpNoCase( "Type" ) == 0 )
1062  {
1063  if( aVar == "A" )
1064  return std::make_unique<PCB_EXPR_TYPE_REF>( 0 );
1065  else if( aVar == "B" )
1066  return std::make_unique<PCB_EXPR_TYPE_REF>( 1 );
1067  else
1068  return nullptr;
1069  }
1070 
1071  if( aVar == "A" || aVar == "AB" )
1072  vref = std::make_unique<PCB_EXPR_VAR_REF>( 0 );
1073  else if( aVar == "B" )
1074  vref = std::make_unique<PCB_EXPR_VAR_REF>( 1 );
1075  else if( aVar == "L" )
1076  vref = std::make_unique<PCB_EXPR_VAR_REF>( 2 );
1077  else
1078  return nullptr;
1079 
1080  if( aField.length() == 0 ) // return reference to base object
1081  {
1082  return std::move( vref );
1083  }
1084 
1085  wxString field( aField );
1086  field.Replace( "_", " " );
1087 
1088  for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
1089  {
1090  if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) )
1091  {
1092  PROPERTY_BASE* prop = propMgr.GetProperty( cls.type, field );
1093 
1094  if( prop )
1095  {
1096  vref->AddAllowedClass( cls.type, prop );
1097 
1098  if( prop->TypeHash() == TYPE_HASH( int ) )
1099  {
1100  vref->SetType( LIBEVAL::VT_NUMERIC );
1101  }
1102  else if( prop->TypeHash() == TYPE_HASH( wxString ) )
1103  {
1104  vref->SetType( LIBEVAL::VT_STRING );
1105  }
1106  else if ( prop->HasChoices() )
1107  { // it's an enum, we treat it as string
1108  vref->SetType( LIBEVAL::VT_STRING );
1109  vref->SetIsEnum ( true );
1110  }
1111  else
1112  {
1113  wxFAIL_MSG( "PCB_EXPR_UCODE::createVarRef: Unknown property type." );
1114  }
1115  }
1116  }
1117  }
1118 
1119  if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
1120  vref->SetType( LIBEVAL::VT_PARSE_ERROR );
1121 
1122  return std::move( vref );
1123 }
1124 
1125 
1127 {
1128  if( m_items[0] )
1129  return m_items[0]->GetBoard();
1130 
1131  return nullptr;
1132 }
1133 
1134 
1136 {
1137 public:
1139  {
1140  }
1141 
1142  virtual const std::vector<wxString>& GetSupportedUnits() const override
1143  {
1144  static const std::vector<wxString> pcbUnits = { "mil", "mm", "in" };
1145 
1146  return pcbUnits;
1147  }
1148 
1149  virtual wxString GetSupportedUnitsMessage() const override
1150  {
1151  return _( "must be mm, in, or mil" );
1152  }
1153 
1154  virtual double Convert( const wxString& aString, int unitId ) const override
1155  {
1156  double v = wxAtof( aString );
1157 
1158  switch( unitId )
1159  {
1160  case 0: return DoubleValueFromString( EDA_UNITS::MILS, aString );
1161  case 1: return DoubleValueFromString( EDA_UNITS::MILLIMETRES, aString );
1162  case 2: return DoubleValueFromString( EDA_UNITS::INCHES, aString );
1163  default: return v;
1164  }
1165  };
1166 };
1167 
1168 
1170 {
1171  m_unitResolver = std::make_unique<PCB_UNIT_RESOLVER>();
1172 }
1173 
1174 
1176  m_result( 0 ),
1177  m_compiler(),
1178  m_ucode(),
1179  m_errorStatus()
1180 {
1181 }
1182 
1183 
1185 {
1186 }
1187 
1188 
1189 bool PCB_EXPR_EVALUATOR::Evaluate( const wxString& aExpr )
1190 {
1191  PCB_EXPR_UCODE ucode;
1192  PCB_EXPR_CONTEXT preflightContext( F_Cu );
1193 
1194  if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
1195  return false;
1196 
1197  PCB_EXPR_CONTEXT evaluationContext( F_Cu );
1198  LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
1199 
1200  if( result->GetType() == LIBEVAL::VT_NUMERIC )
1201  m_result = KiROUND( result->AsDouble() );
1202 
1203  return true;
1204 }
1205 
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:1325
virtual bool Matches(const wxFindReplaceData &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:365
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:1090
ZONES & Zones()
Definition: board.h:239
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:575
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:295
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:874
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
std::mutex m_CachesMutex
Definition: board.h:1089
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:504
#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:198
static void isBlindBuriedVia(LIBEVAL::CONTEXT *aCtx, void *self)
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:145
LIBEVAL::VAR_TYPE_T m_type
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
static bool SniffTest(const wxString &aCandidate)
Definition: kiid.cpp:140
static void existsOnLayer(LIBEVAL::CONTEXT *aCtx, void *self)
FOOTPRINTS & Footprints()
Definition: board.h:233
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:344
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
const wxString & GetNetname() const
Definition: netinfo.h:119
#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:155
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:1094
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:64
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:190
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:718
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:881
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:1096
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:167
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:1092
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:44
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:135
#define MALFORMED_COURTYARDS
LIBEVAL::VALUE GetValue(LIBEVAL::CONTEXT *aCtx) override
std::map< std::pair< BOARD_ITEM *, BOARD_ITEM * >, bool > m_InsideAreaCache
Definition: board.h:1093
void Push(VALUE *v)
just inflate the polygon. Acute angles create spikes
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:905
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:145
std::unordered_map< TYPE_ID, PROPERTY_BASE * > m_matchingTypes
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
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:165
static PCB_EXPR_BUILTIN_FUNCTIONS & Instance()
std::map< std::pair< BOARD_ITEM *, BOARD_ITEM * >, bool > m_InsideFCourtyardCache
Definition: board.h:1091
LIBEVAL::VALUE GetValue(LIBEVAL::CONTEXT *aCtx) override