EDA_RECT SCH_FIELD::GetBoundingBox() const { SCH_COMPONENT* parentComponent = (SCH_COMPONENT*) m_Parent; int linewidth = ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; // We must pass the effective text thickness to GetTextBox // when calculating the bounding box linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); // Calculate the text bounding box: EDA_RECT rect; // set USE_TEXT_JUSTIFY_INITIAL_BEHAVIOR to 0 to use // a justification relative to the text itself // i.e. justification relative to an horizontal text // or to 1 to keep the initial behavior #if (USE_TEXT_JUSTIFY_INITIAL_BEHAVIOR == 1 ) if( m_Orient == TEXT_ORIENT_VERT ) { // For vertical texts, exchange the horizontal and the vertical justification // The idea is to keep the justification always left or top for instance, // no matter the text orientation SCH_FIELD text( *this ); // Make a local copy to swap justifications // because GetBoundingBox() is const int tmp = (int)text.m_VJustify; NEGATE( tmp ); text.m_VJustify = (EDA_TEXT_VJUSTIFY_T)text.m_HJustify; text.m_HJustify = (EDA_TEXT_HJUSTIFY_T)tmp; rect = text.GetTextBox( -1, linewidth ); } else #endif rect = GetTextBox( -1, linewidth ); // Calculate the bounding box position relative to the component: wxPoint origin = parentComponent->GetPosition(); wxPoint pos = m_Pos - origin; wxPoint begin = rect.GetOrigin() - origin; wxPoint end = rect.GetEnd() - origin; RotatePoint( &begin, pos, m_Orient ); RotatePoint( &end, pos, m_Orient ); // Due to the Y axis direction, we must mirror the bounding box, // relative to the text position: begin.y -= pos.y; end.y -= pos.y; NEGATE( begin.y ); NEGATE( end.y ); begin.y += pos.y; end.y += pos.y; // Now, apply the component transform (mirror/rot) begin = parentComponent->GetTransform().TransformCoordinate( begin ); end = parentComponent->GetTransform().TransformCoordinate( end ); rect.SetOrigin( begin); rect.SetEnd( end); rect.Move( origin ); rect.Normalize(); return rect; }
const EDA_RECT SCH_TEXT::GetBoundingBox() const { // We must pass the effective text thickness to GetTextBox // when calculating the bounding box int linewidth = GetThickness() == 0 ? GetDefaultLineThickness() : GetThickness(); linewidth = Clamp_Text_PenSize( linewidth, GetTextSize(), IsBold() ); EDA_RECT rect = GetTextBox( -1, linewidth ); if( GetTextAngle() != 0 ) // Rotate rect { wxPoint pos = rect.GetOrigin(); wxPoint end = rect.GetEnd(); RotatePoint( &pos, GetTextPos(), GetTextAngle() ); RotatePoint( &end, GetTextPos(), GetTextAngle() ); rect.SetOrigin( pos ); rect.SetEnd( end ); } rect.Normalize(); return rect; }
int SCH_SCREEN::UpdatePickList() { ITEM_PICKER picker; EDA_RECT area; unsigned count; area.SetOrigin( m_BlockLocate.GetOrigin() ); area.SetSize( m_BlockLocate.GetSize() ); area.Normalize(); for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { // An item is picked if its bounding box intersects the reference area. if( item->HitTest( area ) ) { picker.SetItem( item ); m_BlockLocate.PushItem( picker ); } } // if the block is composed of one item, // select it as the current item count = m_BlockLocate.GetCount(); if( count == 1 ) { SetCurItem( (SCH_ITEM*) m_BlockLocate.GetItem( 0 ) ); } else { SetCurItem( NULL ); } return count; }
const EDA_RECT SCH_BUS_ENTRY_BASE::GetBoundingBox() const { EDA_RECT box; box.SetOrigin( m_pos ); box.SetEnd( m_End() ); box.Normalize(); box.Inflate( GetPenSize() / 2 ); return box; }
bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { EDA_RECT arect = aRect; arect.Inflate( aAccuracy ); EDA_RECT bbox = m_Poly->GetBoundingBox(); bbox.Normalize(); if( aContained ) return arect.Contains( bbox ); else // Test for intersection between aRect and the polygon // For a polygon, using its bounding box has no sense here { // Fast test: if aRect is outside the polygon bounding box, // rectangles cannot intersect if( ! bbox.Intersects( arect ) ) return false; // aRect is inside the polygon bounding box, // and can intersect the polygon: use a fine test. // aRect intersects the polygon if at least one aRect corner // is inside the polygon wxPoint corner = arect.GetOrigin(); if( HitTestInsideZone( corner ) ) return true; corner.x = arect.GetEnd().x; if( HitTestInsideZone( corner ) ) return true; corner = arect.GetEnd(); if( HitTestInsideZone( corner ) ) return true; corner.x = arect.GetOrigin().x; if( HitTestInsideZone( corner ) ) return true; // No corner inside arect, but outlines can intersect arect // if one of outline corners is inside arect int count = m_Poly->GetCornersCount(); for( int ii =0; ii < count; ii++ ) { if( arect.Contains( m_Poly->GetPos( ii ) ) ) return true; } return false; } }
EDA_RECT SCH_BUS_ENTRY::GetBoundingBox() const { EDA_RECT box; box.SetOrigin( m_pos ); box.SetEnd( m_End() ); box.Normalize(); int width = ( m_width == 0 ) ? GetDefaultLineThickness() : m_width; box.Inflate( width / 2 ); return box; }
void EDA_RECT::Merge( const EDA_RECT& aRect ) { Normalize(); // ensure width and height >= 0 EDA_RECT rect = aRect; rect.Normalize(); // ensure width and height >= 0 wxPoint end = GetEnd(); wxPoint rect_end = rect.GetEnd(); // Change origin and size in order to contain the given rect m_Pos.x = std::min( m_Pos.x, rect.m_Pos.x ); m_Pos.y = std::min( m_Pos.y, rect.m_Pos.y ); end.x = std::max( end.x, rect_end.x ); end.y = std::max( end.y, rect_end.y ); SetEnd( end ); }
const EDA_RECT SCH_FIELD::GetBoundingBox() const { SCH_COMPONENT* parentComponent = (SCH_COMPONENT*) m_Parent; int linewidth = ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; // We must pass the effective text thickness to GetTextBox // when calculating the bounding box linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); // Calculate the text bounding box: EDA_RECT rect; if( m_id == REFERENCE ) // multi units have one letter or more added to reference { SCH_FIELD text( *this ); // Make a local copy to change text // because GetBoundingBox() is const text.SetText( GetFullyQualifiedText() ); rect = text.GetTextBox( -1, linewidth ); } else rect = GetTextBox( -1, linewidth ); // Calculate the bounding box position relative to the component: wxPoint origin = parentComponent->GetPosition(); wxPoint pos = m_Pos - origin; wxPoint begin = rect.GetOrigin() - origin; wxPoint end = rect.GetEnd() - origin; RotatePoint( &begin, pos, m_Orient ); RotatePoint( &end, pos, m_Orient ); // Due to the Y axis direction, we must mirror the bounding box, // relative to the text position: begin.y -= pos.y; end.y -= pos.y; NEGATE( begin.y ); NEGATE( end.y ); begin.y += pos.y; end.y += pos.y; // Now, apply the component transform (mirror/rot) begin = parentComponent->GetTransform().TransformCoordinate( begin ); end = parentComponent->GetTransform().TransformCoordinate( end ); rect.SetOrigin( begin); rect.SetEnd( end); rect.Move( origin ); rect.Normalize(); return rect; }
const EDA_RECT DIMENSION::GetBoundingBox() const { EDA_RECT bBox; int xmin, xmax, ymin, ymax; bBox = m_Text.GetTextBox( -1 ); xmin = bBox.GetX(); xmax = bBox.GetRight(); ymin = bBox.GetY(); ymax = bBox.GetBottom(); xmin = std::min( xmin, m_crossBarO.x ); xmin = std::min( xmin, m_crossBarF.x ); ymin = std::min( ymin, m_crossBarO.y ); ymin = std::min( ymin, m_crossBarF.y ); xmax = std::max( xmax, m_crossBarO.x ); xmax = std::max( xmax, m_crossBarF.x ); ymax = std::max( ymax, m_crossBarO.y ); ymax = std::max( ymax, m_crossBarF.y ); xmin = std::min( xmin, m_featureLineGO.x ); xmin = std::min( xmin, m_featureLineGF.x ); ymin = std::min( ymin, m_featureLineGO.y ); ymin = std::min( ymin, m_featureLineGF.y ); xmax = std::max( xmax, m_featureLineGO.x ); xmax = std::max( xmax, m_featureLineGF.x ); ymax = std::max( ymax, m_featureLineGO.y ); ymax = std::max( ymax, m_featureLineGF.y ); xmin = std::min( xmin, m_featureLineDO.x ); xmin = std::min( xmin, m_featureLineDF.x ); ymin = std::min( ymin, m_featureLineDO.y ); ymin = std::min( ymin, m_featureLineDF.y ); xmax = std::max( xmax, m_featureLineDO.x ); xmax = std::max( xmax, m_featureLineDF.x ); ymax = std::max( ymax, m_featureLineDO.y ); ymax = std::max( ymax, m_featureLineDF.y ); bBox.SetX( xmin ); bBox.SetY( ymin ); bBox.SetWidth( xmax - xmin + 1 ); bBox.SetHeight( ymax - ymin + 1 ); bBox.Normalize(); return bBox; }
EDA_RECT LIB_TEXT::GetBoundingBox() const { /* Y coordinates for LIB_ITEMS are bottom to top, so we must invert the Y position when * calling GetTextBox() that works using top to bottom Y axis orientation. */ EDA_RECT rect = GetTextBox( -1, -1, true ); wxPoint orig = rect.GetOrigin(); wxPoint end = rect.GetEnd(); NEGATE( orig.y); NEGATE( end.y); RotatePoint( &orig, m_Pos, -m_Orient ); RotatePoint( &end, m_Pos, -m_Orient ); rect.SetOrigin( orig ); rect.SetEnd( end ); rect.Normalize(); return rect; }
const EDA_RECT SCH_LABEL::GetBoundingBox() const { int linewidth = GetThickness() == 0 ? GetDefaultLineThickness() : GetThickness(); EDA_RECT rect = GetTextBox( -1, linewidth ); if( GetTextAngle() != 0.0 ) { // Rotate rect wxPoint pos = rect.GetOrigin(); wxPoint end = rect.GetEnd(); RotatePoint( &pos, GetTextPos(), GetTextAngle() ); RotatePoint( &end, GetTextPos(), GetTextAngle() ); rect.SetOrigin( pos ); rect.SetEnd( end ); rect.Normalize(); } return rect; }
EDA_RECT SCH_TEXT::GetBoundingBox() const { // We must pass the effective text thickness to GetTextBox // when calculating the bounding box int linewidth = ( m_Thickness == 0 ) ? GetDefaultLineThickness() : m_Thickness; linewidth = Clamp_Text_PenSize( linewidth, m_Size, m_Bold ); EDA_RECT rect = GetTextBox( -1, linewidth ); if( m_Orient ) // Rotate rect { wxPoint pos = rect.GetOrigin(); wxPoint end = rect.GetEnd(); RotatePoint( &pos, m_Pos, m_Orient ); RotatePoint( &end, m_Pos, m_Orient ); rect.SetOrigin( pos ); rect.SetEnd( end ); } rect.Normalize(); return rect; }
EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const { EDA_RECT rect; wxPoint pos; wxArrayString strings; wxString text = GetShownText(); int thickness = ( aThickness < 0 ) ? m_Thickness : aThickness; int linecount = 1; if( m_MultilineAllowed ) { wxStringSplit( text, strings, '\n' ); if ( strings.GetCount() ) // GetCount() == 0 for void strings { if( aLine >= 0 && (aLine < (int)strings.GetCount()) ) text = strings.Item( aLine ); else text = strings.Item( 0 ); linecount = strings.GetCount(); } } // calculate the H and V size int dx = LenSize( text ); int dy = GetInterline( aThickness ); // Creates bounding box (rectangle) for an horizontal text wxSize textsize = wxSize( dx, dy ); if( aInvertY ) rect.SetOrigin( m_Pos.x, -m_Pos.y ); else rect.SetOrigin( m_Pos ); // extra dy interval for letters like j and y and ] int extra_dy = dy - m_Size.y; rect.Move( wxPoint( 0, -extra_dy / 2 ) ); // move origin by the half extra interval // for multiline texts and aLine < 0, merge all rectangles if( m_MultilineAllowed && aLine < 0 ) { for( unsigned ii = 1; ii < strings.GetCount(); ii++ ) { text = strings.Item( ii ); dx = LenSize( text ); textsize.x = std::max( textsize.x, dx ); textsize.y += dy; } } rect.SetSize( textsize ); /* Now, calculate the rect origin, according to text justification * At this point the rectangle origin is the text origin (m_Pos). * This is true only for left and top text justified texts (using top to bottom Y axis * orientation). and must be recalculated for others justifications * also, note the V justification is relative to the first line */ switch( m_HJustify ) { case GR_TEXT_HJUSTIFY_LEFT: if( m_Mirror ) rect.SetX( rect.GetX() - rect.GetWidth() ); break; case GR_TEXT_HJUSTIFY_CENTER: rect.SetX( rect.GetX() - (rect.GetWidth() / 2) ); break; case GR_TEXT_HJUSTIFY_RIGHT: if( !m_Mirror ) rect.SetX( rect.GetX() - rect.GetWidth() ); break; } dy = m_Size.y + thickness; switch( m_VJustify ) { case GR_TEXT_VJUSTIFY_TOP: break; case GR_TEXT_VJUSTIFY_CENTER: rect.SetY( rect.GetY() - ( dy / 2) ); break; case GR_TEXT_VJUSTIFY_BOTTOM: rect.SetY( rect.GetY() - dy ); break; } if( linecount > 1 ) { int yoffset; linecount -= 1; switch( m_VJustify ) { case GR_TEXT_VJUSTIFY_TOP: break; case GR_TEXT_VJUSTIFY_CENTER: yoffset = linecount * GetInterline() / 2; rect.SetY( rect.GetY() - yoffset ); break; case GR_TEXT_VJUSTIFY_BOTTOM: yoffset = linecount * GetInterline( aThickness ); rect.SetY( rect.GetY() - yoffset ); break; } } rect.Inflate( thickness / 2 ); rect.Normalize(); // Make h and v sizes always >= 0 return rect; }
bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { EDA_RECT arect = aRect; arect.Normalize(); arect.Inflate( aAccuracy ); wxPoint shapePos = ShapePos(); EDA_RECT shapeRect; int r; EDA_RECT bb = GetBoundingBox(); wxPoint endCenter; int radius; if( !arect.Intersects( bb ) ) return false; // This covers total containment for all test cases if( arect.Contains( bb ) ) return true; switch( GetShape() ) { case PAD_SHAPE_CIRCLE: return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() ); case PAD_SHAPE_RECT: shapeRect.SetOrigin( shapePos ); shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 ); return arect.Intersects( shapeRect, m_Orient ); case PAD_SHAPE_OVAL: // Circlular test if dimensions are equal if( m_Size.x == m_Size.y ) return arect.IntersectsCircle( shapePos, GetBoundingRadius() ); shapeRect.SetOrigin( shapePos ); // Horizontal dimension is greater if( m_Size.x > m_Size.y ) { radius = m_Size.y / 2; shapeRect.Inflate( m_Size.x / 2 - radius, radius ); endCenter = wxPoint( m_Size.x / 2 - radius, 0 ); RotatePoint( &endCenter, m_Orient ); // Test circular ends if( arect.IntersectsCircle( shapePos + endCenter, radius ) || arect.IntersectsCircle( shapePos - endCenter, radius ) ) { return true; } } else { radius = m_Size.x / 2; shapeRect.Inflate( radius, m_Size.y / 2 - radius ); endCenter = wxPoint( 0, m_Size.y / 2 - radius ); RotatePoint( &endCenter, m_Orient ); // Test circular ends if( arect.IntersectsCircle( shapePos + endCenter, radius ) || arect.IntersectsCircle( shapePos - endCenter, radius ) ) { return true; } } // Test rectangular portion between rounded ends if( arect.Intersects( shapeRect, m_Orient ) ) { return true; } break; case PAD_SHAPE_TRAPEZOID: /* Trapezoid intersection tests: * A) Any points of rect inside trapezoid * B) Any points of trapezoid inside rect * C) Any sides of trapezoid cross rect */ { wxPoint poly[4]; BuildPadPolygon( poly, wxSize( 0, 0 ), 0 ); wxPoint corners[4]; corners[0] = wxPoint( arect.GetLeft(), arect.GetTop() ); corners[1] = wxPoint( arect.GetRight(), arect.GetTop() ); corners[2] = wxPoint( arect.GetRight(), arect.GetBottom() ); corners[3] = wxPoint( arect.GetLeft(), arect.GetBottom() ); for( int i=0; i<4; i++ ) { RotatePoint( &poly[i], m_Orient ); poly[i] += shapePos; } for( int ii=0; ii<4; ii++ ) { if( TestPointInsidePolygon( poly, 4, corners[ii] ) ) { return true; } if( arect.Contains( poly[ii] ) ) { return true; } if( arect.Intersects( poly[ii], poly[(ii+1) % 4] ) ) { return true; } } return false; } case PAD_SHAPE_ROUNDRECT: /* RoundRect intersection can be broken up into simple tests: * a) Test intersection of horizontal rect * b) Test intersection of vertical rect * c) Test intersection of each corner */ r = GetRoundRectCornerRadius(); /* Test A - intersection of horizontal rect */ shapeRect.SetSize( 0, 0 ); shapeRect.SetOrigin( shapePos ); shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 - r ); // Short-circuit test for zero width or height if( shapeRect.GetWidth() > 0 && shapeRect.GetHeight() > 0 && arect.Intersects( shapeRect, m_Orient ) ) { return true; } /* Test B - intersection of vertical rect */ shapeRect.SetSize( 0, 0 ); shapeRect.SetOrigin( shapePos ); shapeRect.Inflate( m_Size.x / 2 - r, m_Size.y / 2 ); // Short-circuit test for zero width or height if( shapeRect.GetWidth() > 0 && shapeRect.GetHeight() > 0 && arect.Intersects( shapeRect, m_Orient ) ) { return true; } /* Test C - intersection of each corner */ endCenter = wxPoint( m_Size.x / 2 - r, m_Size.y / 2 - r ); RotatePoint( &endCenter, m_Orient ); if( arect.IntersectsCircle( shapePos + endCenter, r ) || arect.IntersectsCircle( shapePos - endCenter, r ) ) { return true; } endCenter = wxPoint( m_Size.x / 2 - r, -m_Size.y / 2 + r ); RotatePoint( &endCenter, m_Orient ); if( arect.IntersectsCircle( shapePos + endCenter, r ) || arect.IntersectsCircle( shapePos - endCenter, r ) ) { return true; } break; default: break; } return false; }
const EDA_RECT DRAWSEGMENT::GetBoundingBox() const { EDA_RECT bbox; bbox.SetOrigin( m_Start ); switch( m_Shape ) { case S_SEGMENT: bbox.SetEnd( m_End ); break; case S_CIRCLE: bbox.Inflate( GetRadius() ); break; case S_ARC: { bbox.Merge( m_End ); wxPoint end = m_End; RotatePoint( &end, m_Start, -m_Angle ); bbox.Merge( end ); } break; case S_POLYGON: { wxPoint p_end; MODULE* module = GetParentModule(); for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) { wxPoint pt = m_PolyPoints[ii]; if( module ) // Transform, if we belong to a module { RotatePoint( &pt, module->GetOrientation() ); pt += module->GetPosition(); } if( ii == 0 ) p_end = pt; bbox.SetX( std::min( bbox.GetX(), pt.x ) ); bbox.SetY( std::min( bbox.GetY(), pt.y ) ); p_end.x = std::max( p_end.x, pt.x ); p_end.y = std::max( p_end.y, pt.y ); } bbox.SetEnd( p_end ); } break; default: ; } bbox.Inflate( ((m_Width+1) / 2) + 1 ); bbox.Normalize(); return bbox; }
const EDA_RECT DRAWSEGMENT::GetBoundingBox() const { EDA_RECT bbox; bbox.SetOrigin( m_Start ); switch( m_Shape ) { case S_SEGMENT: bbox.SetEnd( m_End ); break; case S_CIRCLE: bbox.Inflate( GetRadius() ); break; case S_ARC: { bbox.Merge( m_End ); wxPoint end = m_End; RotatePoint( &end, m_Start, -m_Angle ); bbox.Merge( end ); // Determine the starting quarter // 0 right-bottom // 1 left-bottom // 2 left-top // 3 right-top unsigned int quarter = 0; // assume right-bottom if( m_End.y < m_Start.y ) // change to left-top quarter |= 3; if( m_End.x < m_Start.x ) // for left side, the LSB is 2nd bit negated quarter ^= 1; int radius = GetRadius(); int angle = (int) GetArcAngleStart() % 900 + m_Angle; bool directionCW = ( m_Angle > 0 ); // Is the direction of arc clockwise? if( !directionCW ) { angle = 900 - angle; quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic } while( angle > 900 ) { switch( quarter ) { case 0: bbox.Merge( wxPoint( m_Start.x, m_Start.y + radius ) ); // down break; case 1: bbox.Merge( wxPoint( m_Start.x - radius, m_Start.y ) ); // left break; case 2: bbox.Merge( wxPoint( m_Start.x, m_Start.y - radius ) ); // up break; case 3: bbox.Merge( wxPoint( m_Start.x + radius, m_Start.y ) ); // right break; } if( directionCW ) ++quarter; else quarter += 3; // -1 modulo arithmetic quarter %= 4; angle -= 900; } } break; case S_POLYGON: { wxPoint p_end; MODULE* module = GetParentModule(); for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) { wxPoint pt = m_PolyPoints[ii]; if( module ) // Transform, if we belong to a module { RotatePoint( &pt, module->GetOrientation() ); pt += module->GetPosition(); } if( ii == 0 ) p_end = pt; bbox.SetX( std::min( bbox.GetX(), pt.x ) ); bbox.SetY( std::min( bbox.GetY(), pt.y ) ); p_end.x = std::max( p_end.x, pt.x ); p_end.y = std::max( p_end.y, pt.y ); } bbox.SetEnd( p_end ); } break; default: ; } bbox.Inflate( ((m_Width+1) / 2) + 1 ); bbox.Normalize(); return bbox; }