void OPENGL_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList ) { if( aPointList.empty() ) return; currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); std::deque<VECTOR2D>::const_iterator it = aPointList.begin(); // Start from the second point for( ++it; it != aPointList.end(); ++it ) { const VECTOR2D startEndVector = ( *it - *( it - 1 ) ); double lineAngle = startEndVector.Angle(); drawLineQuad( *( it - 1 ), *it ); // There is no need to draw line caps on both ends of polyline's segments drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle + M_PI / 2 ); } // ..and now - draw the ending cap const VECTOR2D startEndVector = ( *( it - 1 ) - *( it - 2 ) ); double lineAngle = startEndVector.Angle(); drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle - M_PI / 2 ); }
SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool aSide ) { SHAPE_LINE_CHAIN lc; if( aDir.EuclideanNorm( ) == 0.0f ) { lc.Append( aP ); return lc; } VECTOR2D dir_u( aDir ); VECTOR2D dir_v( aDir.Perpendicular( ) ); const int ArcSegments = Settings().m_cornerArcSegments; for( int i = ArcSegments - 1; i >= 0; i-- ) { VECTOR2D p; double alpha = (double) i / (double) ( ArcSegments - 1 ) * M_PI / 2.0; p = aP + dir_u * cos( alpha ) + dir_v * ( aSide ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) ); lc.Append( ( int ) p.x, ( int ) p.y ); } return lc; }
/** * Draw simple ticks on the back of a line such that the line is * divided into n parts. * * @param aGal the GAL to draw on * @param aOrigin start of line to draw ticks on * @param aLine line vector * @param aTickLen length of ticks in IU * @param aNumDivisions number of parts to divide the line into */ void drawBacksideTicks( KIGFX::GAL& aGal, const VECTOR2D& aOrigin, const VECTOR2D& aLine, double aTickLen, int aNumDivisions ) { const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions; const auto backTickVec = aLine.Rotate( M_PI_2 ).Resize( aTickLen ); for( int i = 0; i < aNumDivisions + 1; ++i ) { const auto backTickPos = aOrigin + aLine.Resize( backTickSpace * i ); aGal.DrawLine( backTickPos, backTickPos + backTickVec ); } }
bool SHAPE_ARC::ConstructFromCorners( VECTOR2I aP0, VECTOR2I aP1, double aCenterAngle ) { VECTOR2D mid = ( VECTOR2D( aP0 ) + VECTOR2D( aP1 ) ) * 0.5; VECTOR2D chord = VECTOR2D( aP1 ) - VECTOR2D( aP0 ); double c = (aP1 - aP0).EuclideanNorm() / 2; VECTOR2D d = chord.Rotate( M_PI / 2.0 ).Resize( c ); m_pc = mid + d * ( 1.0 / tan( aCenterAngle / 2.0 * M_PI / 180.0 ) ); m_p0 = aP0; m_p1 = aP1; return true; }
/** * Draw labelled ticks on a line. Ticks are spaced according to a * maximum density. Miror ticks are not labelled. * * @param aGal the GAL to draw on * @param aOrigin start of line to draw ticks on * @param aLine line vector * @param aMinorTickLen length of minor ticks in IU */ void drawTicksAlongLine( KIGFX::GAL& aGal, const VECTOR2D& aOrigin, const VECTOR2D& aLine, double aMinorTickLen ) { VECTOR2D tickLine = aLine.Rotate( -M_PI_2 ); double tickSpace; TICK_FORMAT tickF = getTickFormatForScale( aGal.GetWorldScale(), tickSpace ); // number of ticks in whole ruler int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace ); // work out which way up the tick labels go double labelAngle = -tickLine.Angle(); if( aLine.Angle() > 0 ) { aGal.SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT ); } else { aGal.SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT ); labelAngle += M_PI; } // text and ticks are dimmed aGal.SetStrokeColor( PreviewOverlayDefaultColor().WithAlpha( PreviewOverlayDeemphAlpha( true ) ) ); const auto labelOffset = tickLine.Resize( aMinorTickLen * ( majorTickLengthFactor + 1 ) ); for( int i = 0; i < numTicks; ++i ) { const auto tickPos = aOrigin + aLine.Resize( tickSpace * i ); double length = aMinorTickLen; bool drawLabel = false; if( i % tickF.majorStep == 0) { drawLabel = true; length *= majorTickLengthFactor; } else if( tickF.midStep && i % tickF.midStep == 0 ) { drawLabel = true; length *= midTickLengthFactor; } aGal.DrawLine( tickPos, tickPos + tickLine.Resize( length ) ); if( drawLabel ) { wxString label = DimensionLabel( "", tickSpace * i, g_UserUnit ); // FIXME: spaces choke OpenGL lp:1668455 label.erase( std::remove( label.begin(), label.end(), ' ' ), label.end() ); aGal.BitmapText( label, tickPos + labelOffset, labelAngle ); } } }
void PNS_MEANDER_SHAPE::arc( int aRadius, bool aSide ) { if( aRadius <= 0 ) { turn( aSide ? -90 : 90 ); return; } VECTOR2D dir = m_currentDir.Resize( (double) aRadius ); SHAPE_LINE_CHAIN arc = circleQuad( m_currentPos, dir, aSide ); m_currentPos = arc.CPoint( -1 ); m_currentDir = dir.Rotate( aSide ? -M_PI / 2.0 : M_PI / 2.0 ); m_currentTarget->Append ( arc ); }
void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { /* Helper drawing: ____--- v3 ^ * ____---- ... \ \ * ____---- ... \ end \ * v1 ____---- ... ____---- \ width * ---- ...___---- \ \ * \ ___...-- \ v * \ ____----... ____---- v2 * ---- ... ____---- * start \ ... ____---- * \... ____---- * ---- * v0 * dots mark triangles' hypotenuses */ VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineLength = startEndVector.EuclideanNorm(); if( lineLength <= 0.0 ) return; double scale = 0.5 * lineWidth / lineLength; // The perpendicular vector also needs transformations glm::vec4 vector = currentManager->GetTransformation() * glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 ); // Line width is maintained by the vertex shader currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1 currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2 }
void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { const VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineAngle = startEndVector.Angle(); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); drawLineQuad( aStartPoint, aEndPoint ); // Line caps if( lineWidth > 1.0 ) { drawFilledSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2 ); drawFilledSemiCircle( aEndPoint, lineWidth / 2, lineAngle - M_PI / 2 ); } }
SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool aSide ) { SHAPE_LINE_CHAIN lc; if( aDir.EuclideanNorm( ) == 0.0f ) { lc.Append( aP ); return lc; } VECTOR2D dir_u( aDir ); VECTOR2D dir_v( aDir.Perpendicular( ) ); const int ArcSegments = Settings().m_cornerArcSegments; double radius = (double) aDir.EuclideanNorm(); double angleStep = M_PI / 2.0 / (double) ArcSegments; double correction = 12.0 * radius * ( 1.0 - cos( angleStep / 2.0 ) ); if( !m_dual ) correction = 0.0; else if( radius < m_meanCornerRadius ) correction = 0.0; VECTOR2D p = aP; lc.Append( ( int ) p.x, ( int ) p.y ); VECTOR2D dir_uu = dir_u.Resize( radius - correction ); VECTOR2D dir_vv = dir_v.Resize( radius - correction ); VECTOR2D shift = dir_u.Resize( correction ); for( int i = ArcSegments - 1; i >= 0; i-- ) { double alpha = (double) i / (double) ( ArcSegments - 1 ) * M_PI / 2.0; p = aP + shift + dir_uu * cos( alpha ) + dir_vv * ( aSide ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) ); lc.Append( ( int ) p.x, ( int ) p.y ); } p = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 ); lc.Append( ( int ) p.x, ( int ) p.y ); return lc; }
void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) { VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineAngle = startEndVector.Angle(); if( isFillEnabled ) { // Filled tracks currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); SetLineWidth( aWidth ); drawLineQuad( aStartPoint, aEndPoint ); // Draw line caps drawFilledSemiCircle( aStartPoint, aWidth / 2, lineAngle + M_PI / 2 ); drawFilledSemiCircle( aEndPoint, aWidth / 2, lineAngle - M_PI / 2 ); } else { // Outlined tracks double lineLength = startEndVector.EuclideanNorm(); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); Save(); currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 ); currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f ); drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ), VECTOR2D( lineLength, aWidth / 2.0 ) ); drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ), VECTOR2D( lineLength, -aWidth / 2.0 ) ); // Draw line caps drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 ); drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 ); Restore(); } }
static void drawCursorStrings( KIGFX::GAL& aGal, const VECTOR2D& aCursor, const VECTOR2D& aRulerVec ) { // draw the cursor labels std::vector<wxString> cursorStrings; cursorStrings.push_back( DimensionLabel( "r", aRulerVec.EuclideanNorm(), g_UserUnit ) ); double degs = RAD2DECIDEG( -aRulerVec.Angle() ); cursorStrings.push_back( DimensionLabel( "θ", degs, DEGREES ) ); for( auto& str: cursorStrings ) { // FIXME: remove spaces that choke OpenGL lp:1668455 str.erase( std::remove( str.begin(), str.end(), ' ' ), str.end() ); } auto temp = aRulerVec; DrawTextNextToCursor( aGal, aCursor, -temp, cursorStrings ); }
void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) { if( isFillEnabled ) { // Filled tracks mode SetLineWidth( aWidth ); cairo_move_to( currentContext, (double) aStartPoint.x, (double) aStartPoint.y ); cairo_line_to( currentContext, (double) aEndPoint.x, (double) aEndPoint.y ); } else { // Outline mode for tracks VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineAngle = atan2( startEndVector.y, startEndVector.x ); double lineLength = startEndVector.EuclideanNorm(); cairo_save( currentContext ); cairo_translate( currentContext, aStartPoint.x, aStartPoint.y ); cairo_rotate( currentContext, lineAngle ); cairo_arc( currentContext, 0.0, 0.0, aWidth / 2.0, M_PI / 2.0, 3.0 * M_PI / 2.0 ); cairo_arc( currentContext, lineLength, 0.0, aWidth / 2.0, -M_PI / 2.0, M_PI / 2.0 ); cairo_move_to( currentContext, 0.0, aWidth / 2.0 ); cairo_line_to( currentContext, lineLength, aWidth / 2.0 ); cairo_move_to( currentContext, 0.0, -aWidth / 2.0 ); cairo_line_to( currentContext, lineLength, -aWidth / 2.0 ); cairo_restore( currentContext ); } isElementAdded = true; }
void POINT_EDITOR::updateItem() const { EDA_ITEM* item = m_editPoints->GetParent(); switch( item->Type() ) { case PCB_LINE_T: case PCB_MODULE_EDGE_T: { DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item ); switch( segment->GetShape() ) { case S_SEGMENT: if( isModified( m_editPoints->Point( SEG_START ) ) ) segment->SetStart( wxPoint( m_editPoints->Point( SEG_START ).GetPosition().x, m_editPoints->Point( SEG_START ).GetPosition().y ) ); else if( isModified( m_editPoints->Point( SEG_END ) ) ) segment->SetEnd( wxPoint( m_editPoints->Point( SEG_END ).GetPosition().x, m_editPoints->Point( SEG_END ).GetPosition().y ) ); break; case S_ARC: { const VECTOR2I& center = m_editPoints->Point( ARC_CENTER ).GetPosition(); const VECTOR2I& start = m_editPoints->Point( ARC_START ).GetPosition(); const VECTOR2I& end = m_editPoints->Point( ARC_END ).GetPosition(); if( center != segment->GetCenter() ) { wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter(); segment->Move( moveVector ); m_editPoints->Point( ARC_START ).SetPosition( segment->GetArcStart() ); m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() ); } else { segment->SetArcStart( wxPoint( start.x, start.y ) ); VECTOR2D startLine = start - center; VECTOR2I endLine = end - center; double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() ); // Adjust the new angle to (counter)clockwise setting bool clockwise = ( segment->GetAngle() > 0 ); if( clockwise && newAngle < 0.0 ) newAngle += 3600.0; else if( !clockwise && newAngle > 0.0 ) newAngle -= 3600.0; segment->SetAngle( newAngle ); } break; } case S_CIRCLE: { const VECTOR2I& center = m_editPoints->Point( CIRC_CENTER ).GetPosition(); const VECTOR2I& end = m_editPoints->Point( CIRC_END ).GetPosition(); if( isModified( m_editPoints->Point( CIRC_CENTER ) ) ) { wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter(); segment->Move( moveVector ); } else { segment->SetEnd( wxPoint( end.x, end.y ) ); } break; } default: // suppress warnings break; } // Update relative coordinates for module edges if( EDGE_MODULE* edge = dyn_cast<EDGE_MODULE*>( item ) ) edge->SetLocalCoord(); break; } case PCB_ZONE_AREA_T: { ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); zone->ClearFilledPolysList(); CPolyLine* outline = zone->Outline(); for( int i = 0; i < outline->GetCornersCount(); ++i ) { VECTOR2I point = m_editPoints->Point( i ).GetPosition(); outline->SetX( i, point.x ); outline->SetY( i, point.y ); } break; } case PCB_DIMENSION_T: { DIMENSION* dimension = static_cast<DIMENSION*>( item ); // Check which point is currently modified and updated dimension's points respectively if( isModified( m_editPoints->Point( DIM_CROSSBARO ) ) ) { VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetOrigin() ); VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() ); if( featureLine.Cross( crossBar ) > 0 ) dimension->SetHeight( -featureLine.EuclideanNorm() ); else dimension->SetHeight( featureLine.EuclideanNorm() ); } else if( isModified( m_editPoints->Point( DIM_CROSSBARF ) ) ) { VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetEnd() ); VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() ); if( featureLine.Cross( crossBar ) > 0 ) dimension->SetHeight( -featureLine.EuclideanNorm() ); else dimension->SetHeight( featureLine.EuclideanNorm() ); } else if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) ) { dimension->SetOrigin( wxPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y ) ); m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ), m_editPoints->Point( DIM_FEATUREGO ) ) ); m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ), m_editPoints->Point( DIM_FEATUREDO ) ) ); } else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) ) { dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y ) ); m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ), m_editPoints->Point( DIM_FEATUREGO ) ) ); m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ), m_editPoints->Point( DIM_FEATUREDO ) ) ); } break; } default: break; } }
void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer ) { VECTOR2D start( aTrack->GetStart() ); VECTOR2D end( aTrack->GetEnd() ); int width = aTrack->GetWidth(); if( m_pcbSettings.m_netNamesOnTracks && IsNetnameLayer( aLayer ) ) { // If there is a net name - display it on the track if( aTrack->GetNetCode() > NETINFO_LIST::UNCONNECTED ) { VECTOR2D line = ( end - start ); double length = line.EuclideanNorm(); // Check if the track is long enough to have a netname displayed if( length < 10 * width ) return; const wxString& netName = aTrack->GetShortNetname(); VECTOR2D textPosition = start + line / 2.0; // center of the track double textOrientation; if( end.y == start.y ) // horizontal textOrientation = 0; else if( end.x == start.x ) // vertical textOrientation = M_PI / 2; else textOrientation = -atan( line.y / line.x ); double textSize = width; m_gal->SetIsStroke( true ); m_gal->SetIsFill( false ); m_gal->SetStrokeColor( m_pcbSettings.GetColor( NULL, aLayer ) ); m_gal->SetLineWidth( width / 10.0 ); m_gal->SetFontBold( false ); m_gal->SetFontItalic( false ); m_gal->SetTextMirrored( false ); m_gal->SetGlyphSize( VECTOR2D( textSize * 0.7, textSize * 0.7 ) ); m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER ); m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER ); m_gal->BitmapText( netName, textPosition, textOrientation ); } } else if( IsCopperLayer( aLayer ) ) { // Draw a regular track const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aLayer ); bool outline_mode = m_pcbSettings.m_sketchMode[LAYER_TRACKS]; m_gal->SetStrokeColor( color ); m_gal->SetFillColor( color ); m_gal->SetIsStroke( outline_mode ); m_gal->SetIsFill( not outline_mode ); m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth ); m_gal->DrawSegment( start, end, width ); // Clearance lines constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_EXISTING | PCB_RENDER_SETTINGS::CL_TRACKS; if( ( m_pcbSettings.m_clearance & clearanceFlags ) == clearanceFlags ) { m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth ); m_gal->SetIsFill( false ); m_gal->SetIsStroke( true ); m_gal->SetStrokeColor( color ); m_gal->DrawSegment( start, end, width + aTrack->GetClearance() * 2 ); } } }
void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer ) { VECTOR2D start( aTrack->GetStart() ); VECTOR2D end( aTrack->GetEnd() ); int width = aTrack->GetWidth(); if( m_pcbSettings.m_netNamesOnTracks && IsNetnameLayer( aLayer ) ) { // If there is a net name - display it on the track if( aTrack->GetNetCode() > NETINFO_LIST::UNCONNECTED ) { VECTOR2D line = ( end - start ); double length = line.EuclideanNorm(); // Check if the track is long enough to have a netname displayed if( length < 10 * width ) return; const wxString& netName = aTrack->GetShortNetname(); VECTOR2D textPosition = start + line / 2.0; // center of the track double textOrientation = -atan( line.y / line.x ); double textSize = std::min( static_cast<double>( width ), length / netName.length() ); // Set a proper color for the label const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aTrack->GetLayer() ); COLOR4D labelColor = m_pcbSettings.GetColor( NULL, aLayer ); if( color.GetBrightness() > 0.5 ) m_gal->SetStrokeColor( labelColor.Inverted() ); else m_gal->SetStrokeColor( labelColor ); m_gal->SetLineWidth( width / 10.0 ); m_gal->SetBold( false ); m_gal->SetItalic( false ); m_gal->SetMirrored( false ); m_gal->SetGlyphSize( VECTOR2D( textSize * 0.7, textSize * 0.7 ) ); m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER ); m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER ); m_gal->StrokeText( netName, textPosition, textOrientation ); } } else if( IsCopperLayer( aLayer ) ) { // Draw a regular track const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aLayer ); m_gal->SetStrokeColor( color ); m_gal->SetIsStroke( true ); if( m_pcbSettings.m_sketchMode[TRACKS_VISIBLE] ) { // Outline mode m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth ); m_gal->SetIsFill( false ); } else { // Filled mode m_gal->SetFillColor( color ); m_gal->SetIsFill( true ); } m_gal->DrawSegment( start, end, width ); } }
bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos ) const { // In case the item has a very tiny width defined, allow it to be selected const int MIN_HIT_TEST_RADIUS = Millimeter2iu( 0.01 ); // calculate aRefPos in XY gerber axis: wxPoint ref_pos = GetXYPosition( aRefPos ); SHAPE_POLY_SET poly; switch( m_Shape ) { case GBR_POLYGON: poly = m_Polygon; return poly.Contains( VECTOR2I( ref_pos ), 0 ); case GBR_SPOT_POLY: poly = GetDcodeDescr()->m_Polygon; poly.Move( m_Start ); return poly.Contains( VECTOR2I( ref_pos ), 0 ); case GBR_SPOT_RECT: return GetBoundingBox().Contains( aRefPos ); case GBR_ARC: { double radius = GetLineLength( m_Start, m_ArcCentre ); VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre ); int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x ); // Are we close enough to the radius? bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size ); if( radius_hit ) { // Now check that we are within the arc angle VECTOR2D start = VECTOR2D( m_Start ) - VECTOR2D( m_ArcCentre ); VECTOR2D end = VECTOR2D( m_End ) - VECTOR2D( m_ArcCentre ); double start_angle = NormalizeAngleRadiansPos( start.Angle() ); double end_angle = NormalizeAngleRadiansPos( end.Angle() ); if( m_Start == m_End ) { start_angle = 0; end_angle = 2 * M_PI; } else if( end_angle < start_angle ) { end_angle += 2 * M_PI; } double test_angle = NormalizeAngleRadiansPos( test_radius.Angle() ); return ( test_angle > start_angle && test_angle < end_angle ); } return false; } case GBR_SPOT_MACRO: // Aperture macro polygons are already in absolute coordinates auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start ); for( int i = 0; i < p->OutlineCount(); ++i ) { if( p->Contains( VECTOR2I( aRefPos ), i ) ) return true; } return false; } // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items) int radius = std::min( m_Size.x, m_Size.y ) >> 1; if( radius < MIN_HIT_TEST_RADIUS ) radius = MIN_HIT_TEST_RADIUS; if( m_Flashed ) return HitTestPoints( m_Start, ref_pos, radius ); else return TestSegmentHit( ref_pos, m_Start, m_End, radius ); }
SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape( VECTOR2D aP, VECTOR2D aDir, bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset ) { const PNS_MEANDER_SETTINGS& st = Settings(); int cr = cornerRadius(); int offset = aBaselineOffset; int spc = spacing(); if( aSide ) offset *= -1; VECTOR2D dir_u_b( aDir.Resize( offset ) ); VECTOR2D dir_v_b( dir_u_b.Perpendicular() ); if( 2 * cr > aAmpl ) { cr = aAmpl / 2; } if( 2 * cr > spc ) { cr = spc / 2; } SHAPE_LINE_CHAIN lc; start( &lc, aP + dir_v_b, aDir ); switch( aType ) { case MT_EMPTY: { lc.Append( aP + dir_v_b + aDir ); break; } case MT_START: { arc( cr - offset, false ); uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); forward( std::min( cr - offset, cr + offset ) ); forward( std::abs( offset ) ); break; } case MT_FINISH: { start( &lc, aP - dir_u_b, aDir ); turn ( 90 ); forward( std::min( cr - offset, cr + offset ) ); forward( std::abs( offset ) ); uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); arc( cr - offset, false ); break; } case MT_TURN: { start( &lc, aP - dir_u_b, aDir ); turn( 90 ); forward( std::abs( offset ) ); uShape ( aAmpl - cr, cr + offset, spc - 2 * cr ); forward( std::abs( offset ) ); break; } case MT_SINGLE: { arc( cr - offset, false ); uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); arc( cr - offset, false ); lc.Append( aP + dir_v_b + aDir.Resize ( 2 * st.m_spacing ) ); break; } default: break; } if( aSide ) { SEG axis ( aP, aP + aDir ); for( int i = 0; i < lc.PointCount(); i++ ) lc.Point( i ) = reflect( lc.CPoint( i ), axis ); } return lc; }