示例#1
0
DRAWSEGMENT * Locate_Segment_Pcb(BOARD * Pcb, int typeloc)
/********************************************************/
/* Localisation de segments de contour du type edge pcb ou draw
	(selon couche active)
	Retourne:
		Pointeur sur DEBUT du segment localise
		NULL si rien trouve
*/
{
EDA_BaseStruct * PtStruct;
DRAWSEGMENT * pts;
wxPoint ref;

	SET_REF_POS(ref);

	PtStruct = Pcb->m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{	
		if( PtStruct->m_StructType != TYPEDRAWSEGMENT ) continue;
		pts = ( DRAWSEGMENT * ) PtStruct;
		ux0 = pts->m_Start.x ; uy0 = pts->m_Start.y;
		/* recalcul des coordonnees avec ux0, uy0 = origine des coordonnees */
		dx = pts->m_End.x - ux0 ; dy = pts->m_End.y - uy0 ;
		spot_cX = ref.x - ux0; spot_cY = ref.y - uy0 ;

		/* detection : */
		if(pts->m_Layer != ActiveScreen->m_Active_Layer) continue;

		if( (pts->m_Shape == S_CIRCLE) || (pts->m_Shape == S_ARC) )
			{
			int rayon, dist, StAngle, EndAngle, MouseAngle;
			rayon = (int) hypot((double)(dx),(double)(dy) );
			dist = (int) hypot((double)(spot_cX),(double)(spot_cY) );
			if( abs(rayon-dist) <= (pts->m_Width/2) )
				{
				if(pts->m_Shape == S_CIRCLE) return(pts);
				/* pour un arc, controle complementaire */
				MouseAngle = (int) ArcTangente(spot_cY, spot_cX);
				StAngle = (int) ArcTangente(dy, dx);
				EndAngle = StAngle + pts->m_Angle;

				if( EndAngle > 3600 )
					{
					StAngle -= 3600; EndAngle -= 3600;
					}
				if( (MouseAngle >= StAngle) && (MouseAngle <= EndAngle) )
					return(pts);
				}
			}

		else
			{
			if( distance( pts->m_Width /2 ) ) return( pts ) ;
			}
		}
	return(NULL) ;
}
示例#2
0
/* This function shows on screen the bounding box of the inductor that will be
 * created at the end of the build inductor process
 */
static void ShowBoundingBoxMicroWaveInductor( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                              const wxPoint& aPosition, bool aErase )
{
    /* Calculate the orientation and size of the box containing the inductor:
     * the box is a rectangle with height = lenght/2
     * the shape is defined by a rectangle, nor necessary horizontal or vertical
     */
    GRSetDrawMode( aDC, GR_XOR );

    wxPoint poly[5];
    wxPoint pt    = s_inductor_pattern.m_End - s_inductor_pattern.m_Start;
    double  angle = -ArcTangente( pt.y, pt.x );
    int     len   = KiROUND( EuclideanNorm( pt ) );

    // calculate corners
    pt.x = 0; pt.y = len / 4;
    RotatePoint( &pt, angle );
    poly[0] = s_inductor_pattern.m_Start + pt;
    poly[1] = s_inductor_pattern.m_End + pt;
    pt.x    = 0; pt.y = -len / 4;
    RotatePoint( &pt, angle );
    poly[2] = s_inductor_pattern.m_End + pt;
    poly[3] = s_inductor_pattern.m_Start + pt;
    poly[4] = poly[0];

    if( aErase )
    {
        GRPoly( aPanel->GetClipBox(), aDC, 5, poly, false, 0, YELLOW, YELLOW );
    }

    s_inductor_pattern.m_End = aPanel->GetParent()->GetCrossHairPosition();
    pt    = s_inductor_pattern.m_End - s_inductor_pattern.m_Start;
    angle = -ArcTangente( pt.y, pt.x );
    len   = KiROUND( EuclideanNorm( pt ) );

    // calculate new corners
    pt.x = 0; pt.y = len / 4;
    RotatePoint( &pt, angle );
    poly[0] = s_inductor_pattern.m_Start + pt;
    poly[1] = s_inductor_pattern.m_End + pt;
    pt.x    = 0; pt.y = -len / 4;
    RotatePoint( &pt, angle );
    poly[2] = s_inductor_pattern.m_End + pt;
    poly[3] = s_inductor_pattern.m_Start + pt;
    poly[4] = poly[0];

    GRPoly( aPanel->GetClipBox(), aDC, 5, poly, false, 0, YELLOW, YELLOW );
}
const double DRAWSEGMENT::GetArcAngleStart() const
{
    // due to the Y axis orient atan2 needs - y value
    double angleStart = ArcTangente( GetArcStart().y - GetCenter().y,
                                     GetArcStart().x - GetCenter().x );

    // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
    // because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
    // and this is not easy to handle in calculations
    NORMALIZE_ANGLE_POS( angleStart );

    return angleStart;
}
/* Plot items type DRAWSEGMENT on layers allowed by aLayerMask
 */
void BRDITEMS_PLOTTER::PlotDrawSegment( DRAWSEGMENT* aSeg )
{
    int     thickness;
    int     radius = 0;
    double  StAngle = 0, EndAngle = 0;

    if( !m_layerMask[aSeg->GetLayer()] )
        return;

    if( GetMode() == LINE )
        thickness = GetLineWidth();
    else
        thickness = aSeg->GetWidth();

    m_plotter->SetColor( getColor( aSeg->GetLayer() ) );

    wxPoint start( aSeg->GetStart() );
    wxPoint end(   aSeg->GetEnd() );

    m_plotter->SetCurrentLineWidth( thickness );

    switch( aSeg->GetShape() )
    {
    case S_CIRCLE:
        radius = KiROUND( GetLineLength( end, start ) );
        m_plotter->ThickCircle( start, radius * 2, thickness, GetMode() );
        break;

    case S_ARC:
        radius = KiROUND( GetLineLength( end, start ) );
        StAngle  = ArcTangente( end.y - start.y, end.x - start.x );
        EndAngle = StAngle + aSeg->GetAngle();
        m_plotter->ThickArc( start, -EndAngle, -StAngle, radius, thickness, GetMode() );
        break;

    case S_CURVE:
        {
            const std::vector<wxPoint>& bezierPoints = aSeg->GetBezierPoints();

            for( unsigned i = 1; i < bezierPoints.size(); i++ )
                m_plotter->ThickSegment( bezierPoints[i - 1],
                                         bezierPoints[i],
                                         thickness, GetMode() );
        }
        break;

    default:
        m_plotter->ThickSegment( start, end, thickness, GetMode() );
    }
}
void PLOTTER::segmentAsOval( const wxPoint& start, const wxPoint& end, int width,
                             EDA_DRAW_MODE_T tracemode )
{
    wxPoint center( (start.x + end.x) / 2, (start.y + end.y) / 2 );
    wxSize  size( end.x - start.x, end.y - start.y );
    double  orient;

    if( size.y == 0 )
        orient = 0;
    else if( size.x == 0 )
        orient = 900;
    else
        orient = -ArcTangente( size.y, size.x );

    size.x = KiROUND( EuclideanNorm( size ) ) + width;
    size.y = width;

    FlashPadOval( center, size, orient, tracemode );
}
示例#6
0
void EDGE_MODULE::Draw3D(Pcb3D_GLCanvas * glcanvas)
/***************************************************/
{
int ux0, uy0, dx, dy,rayon, StAngle, EndAngle;
double scale, x, y, fx, fy, w, zpos ;
int color = g_Parm_3D_Visu.m_BoardSettings->m_LayerColor[m_Layer];

	if ( color & ITEM_NOT_SHOW ) return;

	SetGLColor(color);
	glNormal3f( 0.0, 0.0, (m_Layer == CUIVRE_N) ? -1.0 : 1.0);
	scale = g_Parm_3D_Visu.m_BoardScale;

	ux0 = m_Start.x;
	uy0 = m_Start.y;
	dx = m_End.x;
	dy = m_End.y;
	zpos = g_Parm_3D_Visu.m_LayerZcoord[m_Layer];
	w = m_Width * g_Parm_3D_Visu.m_BoardScale;
	switch (m_Shape )
		{
		case S_SEGMENT:
			x = m_Start.x * g_Parm_3D_Visu.m_BoardScale;
			y = m_Start.y * g_Parm_3D_Visu.m_BoardScale;
			fx = dx * g_Parm_3D_Visu.m_BoardScale;
			fy = dy * g_Parm_3D_Visu.m_BoardScale;
			Draw3D_FilledSegment(x, -y, fx, -fy, w, zpos);
			break ;

		case S_CIRCLE:
			rayon = (int)hypot((double)(dx-ux0),(double)(dy-uy0) );
			/* TO DO */
			break;

		case S_ARC:
			rayon = (int)hypot((double)(dx-ux0),(double)(dy-uy0) );
			StAngle = (int)ArcTangente( dy-uy0, dx-ux0 );
			EndAngle = StAngle + m_Angle;
			/* TO DO */
			break;
		}
}
示例#7
0
/* Fills all routing matrix cells contained in the arc
 * angle = ArcAngle, half-width lg
 * center = ux0,uy0, starting at ux1, uy1.  Coordinates are in
 * PCB units.
 */
void TraceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
               LAYER_NUM layer, int color, int op_logic )
{
    int radius, nb_segm;
    int x0, y0,             // Starting point of the current segment trace
        x1, y1;             // End point
    int ii;
    double angle, StAngle;


    radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );

    x0 = ux1 - ux0;
    y0 = uy1 - uy0;
    StAngle = ArcTangente( uy1 - uy0, ux1 - ux0 );

    if( lg < 1 )
        lg = 1;

    nb_segm = ( 2 * radius ) / lg;
    nb_segm = ( nb_segm * std::abs( ArcAngle ) ) / 3600;

    if( nb_segm < 5 )
        nb_segm = 5;

    if( nb_segm > 100 )
        nb_segm = 100;

    for( ii = 1; ii <= nb_segm; ii++ )
    {
        angle  = ( ArcAngle * ii ) / nb_segm;
        angle += StAngle;

        NORMALIZE_ANGLE_POS( angle );

        x1 = KiROUND( cosdecideg( radius, angle ) );
        y1 = KiROUND( cosdecideg( radius, angle ) );
        DrawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
        x0 = x1;
        y0 = y1;
    }
}
/* test DRC between 2 pads.
 * this function can be also used to test DRC between a pas and a hole,
 * because a hole is like a round pad.
 */
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{
    int     dist;

    double  pad_angle;

    // Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
    int     dist_min = aRefPad->GetClearance( aPad );

    // relativePadPos is the aPad shape position relative to the aRefPad shape position
    wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos();

    dist = KiROUND( EuclideanNorm( relativePadPos ) );

    // Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
    if( (dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius()) >= dist_min )
        return true;

    /* Here, pads are near and DRC depend on the pad shapes
     * We must compare distance using a fine shape analysis
     * Because a circle or oval shape is the easier shape to test, try to have
     * aRefPad shape type = PAD_CIRCLE or PAD_OVAL.
     * if aRefPad = TRAP. and aPad = RECT, also swap pads
     * Swap aRefPad and aPad if needed
     */
    bool swap_pads;
    swap_pads = false;

    // swap pads to make comparisons easier
    // priority is aRefPad = ROUND then OVAL then RECT then other
    if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_CIRCLE )
    {
        // pad ref shape is here oval, rect or trapezoid
        switch( aPad->GetShape() )
        {
            case PAD_CIRCLE:
                swap_pads = true;
                break;

            case PAD_OVAL:
                swap_pads = true;
                break;

            case PAD_RECT:
                if( aRefPad->GetShape() != PAD_OVAL )
                    swap_pads = true;
                break;

            default:
                break;
        }
    }

    if( swap_pads )
    {
        EXCHG( aRefPad, aPad );
        relativePadPos = -relativePadPos;
    }

    /* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL,
     * if one of the 2 pads was a PAD_CIRCLE or PAD_OVAL.
     * Therefore, if aRefPad is a PAD_RECT or a PAD_TRAPEZOID,
     * aPad is also a PAD_RECT or a PAD_TRAPEZOID
     */
    bool diag = true;

    switch( aRefPad->GetShape() )
    {
    case PAD_CIRCLE:

        /* One can use checkClearanceSegmToPad to test clearance
         * aRefPad is like a track segment with a null length and a witdth = GetSize().x
         */
        m_segmLength = 0;
        m_segmAngle  = 0;

        m_segmEnd.x = m_segmEnd.y = 0;

        m_padToTestPos = relativePadPos;
        diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
        break;

    case PAD_RECT:
        // pad_angle = pad orient relative to the aRefPad orient
        pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
        NORMALIZE_ANGLE_POS( pad_angle );

        if( aPad->GetShape() == PAD_RECT )
        {
            wxSize size = aPad->GetSize();

            // The trivial case is if both rects are rotated by multiple of 90 deg
            // Most of time this is the case, and the test is fast
            if( ( (aRefPad->GetOrientation() == 0) || (aRefPad->GetOrientation() == 900)
                 || (aRefPad->GetOrientation() == 1800) || (aRefPad->GetOrientation() == 2700) )
               && ( (aPad->GetOrientation() == 0) || (aPad->GetOrientation() == 900) || (aPad->GetOrientation() == 1800)
                   || (aPad->GetOrientation() == 2700) ) )
            {
                if( (pad_angle == 900) || (pad_angle == 2700) )
                {
                    EXCHG( size.x, size.y );
                }

                // Test DRC:
                diag = false;
                RotatePoint( &relativePadPos, aRefPad->GetOrientation() );
                relativePadPos.x = std::abs( relativePadPos.x );
                relativePadPos.y = std::abs( relativePadPos.y );

                if( ( relativePadPos.x - ( (size.x + aRefPad->GetSize().x) / 2 ) ) >= dist_min )
                    diag = true;

                if( ( relativePadPos.y - ( (size.y + aRefPad->GetSize().y) / 2 ) ) >= dist_min )
                    diag = true;
            }
            else    // at least one pad has any other orient. Test is more tricky
            {   // Use the trapezoid2trapezoidDRC which also compare 2 rectangles with any orientation
                wxPoint polyref[4];         // Shape of aRefPad
                wxPoint polycompare[4];     // Shape of aPad
                aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
                aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

                // Move aPad shape to relativePadPos
                for( int ii = 0; ii < 4; ii++ )
                    polycompare[ii] += relativePadPos;

                // And now test polygons:
                if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
                    diag = false;
            }
        }
        else if( aPad->GetShape() == PAD_TRAPEZOID )
        {
            wxPoint polyref[4];         // Shape of aRefPad
            wxPoint polycompare[4];     // Shape of aPad
            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
            aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

            // Move aPad shape to relativePadPos
            for( int ii = 0; ii < 4; ii++ )
                polycompare[ii] += relativePadPos;

            // And now test polygons:
            if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
                diag = false;
        }
        else
        {
            // Should not occur, because aPad and aRefPad are swapped
            // to have only aPad shape RECT or TRAP and aRefPad shape TRAP or RECT.
            wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad ref RECT @ %d, %d to pad shape %d @ %d, %d"),
                aRefPad->GetPosition().x, aRefPad->GetPosition().y,
                aPad->GetShape(), aPad->GetPosition().x, aPad->GetPosition().y );
        }
        break;

    case PAD_OVAL:     /* an oval pad is like a track segment */
    {
        /* Create a track segment with same dimensions as the oval aRefPad
         * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
         */
        int segm_width;
        m_segmAngle = aRefPad->GetOrientation();                // Segment orient.

        if( aRefPad->GetSize().y < aRefPad->GetSize().x )     // Build an horizontal equiv segment
        {
            segm_width   = aRefPad->GetSize().y;
            m_segmLength = aRefPad->GetSize().x - aRefPad->GetSize().y;
        }
        else        // Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
        {
            segm_width   = aRefPad->GetSize().x;
            m_segmLength = aRefPad->GetSize().y - aRefPad->GetSize().x;
            m_segmAngle += 900;
        }

        /* the start point must be 0,0 and currently relativePadPos
         * is relative the center of pad coordinate */
        wxPoint segstart;
        segstart.x = -m_segmLength / 2;                 // Start point coordinate of the horizontal equivalent segment

        RotatePoint( &segstart, m_segmAngle );          // actual start point coordinate of the equivalent segment
        // Calculate segment end position relative to the segment origin
        m_segmEnd.x = -2 * segstart.x;
        m_segmEnd.y = -2 * segstart.y;

        // Recalculate the equivalent segment angle in 0,1 degrees
        // to prepare a call to checkClearanceSegmToPad()
        m_segmAngle = ArcTangente( m_segmEnd.y, m_segmEnd.x );

        // move pad position relative to the segment origin
        m_padToTestPos = relativePadPos - segstart;

        // Use segment to pad check to test the second pad:
        diag = checkClearanceSegmToPad( aPad, segm_width, dist_min );
        break;
    }

    case PAD_TRAPEZOID:

        // at this point, aPad is also a trapezoid, because all other shapes
        // have priority, and are already tested
        wxASSERT( aPad->GetShape() == PAD_TRAPEZOID );
        {
            wxPoint polyref[4];         // Shape of aRefPad
            wxPoint polycompare[4];     // Shape of aPad
            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
            aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

            // Move aPad shape to relativePadPos
            for( int ii = 0; ii < 4; ii++ )
                polycompare[ii] += relativePadPos;

            // And now test polygons:
            if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
                diag = false;
        }
        break;

    default:
        wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape" ) );
        break;
    }

    return diag;
}
//* Plot a graphic item (outline) relative to a footprint
void BRDITEMS_PLOTTER::Plot_1_EdgeModule( EDGE_MODULE* aEdge )
{
    int     type_trace;         // Type of item to plot.
    int     thickness;          // Segment thickness.
    int     radius;             // Circle radius.

    if( aEdge->Type() != PCB_MODULE_EDGE_T )
        return;

    m_plotter->SetColor( getColor( aEdge->GetLayer() ) );

    type_trace = aEdge->GetShape();
    thickness  = aEdge->GetWidth();

    wxPoint pos( aEdge->GetStart() );
    wxPoint end( aEdge->GetEnd() );

    switch( type_trace )
    {
    case S_SEGMENT:
        m_plotter->ThickSegment( pos, end, thickness, GetMode() );
        break;

    case S_CIRCLE:
        radius = KiROUND( GetLineLength( end, pos ) );
        m_plotter->ThickCircle( pos, radius * 2, thickness, GetMode() );
        break;

    case S_ARC:
    {
        radius = KiROUND( GetLineLength( end, pos ) );
        double startAngle  = ArcTangente( end.y - pos.y, end.x - pos.x );
        double endAngle = startAngle + aEdge->GetAngle();

        m_plotter->ThickArc( pos, -endAngle, -startAngle, radius, thickness, GetMode() );
    }
    break;

    case S_POLYGON:
    {
        const std::vector<wxPoint>& polyPoints = aEdge->GetPolyPoints();

        if( polyPoints.size() <= 1 )  // Malformed polygon
            break;

        // We must compute true coordinates from m_PolyList
        // which are relative to module position, orientation 0
        MODULE* module = aEdge->GetParentModule();

        std::vector< wxPoint > cornerList;

        cornerList.reserve( polyPoints.size() );

        for( unsigned ii = 0; ii < polyPoints.size(); ii++ )
        {
            wxPoint corner = polyPoints[ii];

            if( module )
            {
                RotatePoint( &corner, module->GetOrientation() );
                corner += module->GetPosition();
            }

            cornerList.push_back( corner );
        }

        m_plotter->PlotPoly( cornerList, FILLED_SHAPE, thickness );
    }
    break;
    }
}
/* test DRC between 2 pads.
 * this function can be also used to test DRC between a pad and a hole,
 * because a hole is like a round or oval pad.
 */
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{
    int     dist;
    double pad_angle;

    // Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad
    int     dist_min = aRefPad->GetClearance( aPad );

    // relativePadPos is the aPad shape position relative to the aRefPad shape position
    wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos();

    dist = KiROUND( EuclideanNorm( relativePadPos ) );

    // Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
    if( (dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius()) >= dist_min )
        return true;

    /* Here, pads are near and DRC depend on the pad shapes
     * We must compare distance using a fine shape analysis
     * Because a circle or oval shape is the easier shape to test, try to have
     * aRefPad shape type = PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
     * if aRefPad = TRAP. and aPad = RECT, also swap pads
     * Swap aRefPad and aPad if needed
     */
    bool swap_pads;
    swap_pads = false;

    // swap pads to make comparisons easier
    // Note also a ROUNDRECT pad with a corner radius = r can be considered as
    // a smaller RECT (size - 2*r) with a clearance increased by r
    // priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other
    if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_CIRCLE )
    {
        // pad ref shape is here oval, rect, roundrect, trapezoid or custom
        switch( aPad->GetShape() )
        {
            case PAD_SHAPE_CIRCLE:
                swap_pads = true;
                break;

            case PAD_SHAPE_OVAL:
                swap_pads = true;
                break;

            case PAD_SHAPE_RECT:
            case PAD_SHAPE_ROUNDRECT:
                if( aRefPad->GetShape() != PAD_SHAPE_OVAL )
                    swap_pads = true;
                break;

            default:
                break;
        }
    }

    if( swap_pads )
    {
        std::swap( aRefPad, aPad );
        relativePadPos = -relativePadPos;
    }

    // corners of aRefPad (used only for rect/roundrect/trap pad)
    wxPoint polyref[4];
    // corners of aRefPad (used only for custom pad)
    SHAPE_POLY_SET polysetref;

    // corners of aPad (used only for rect/roundrect/trap pad)
    wxPoint polycompare[4];
    // corners of aPad (used only custom pad)
    SHAPE_POLY_SET polysetcompare;

    /* Because pad exchange, aRefPad shape is PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL,
     * if one of the 2 pads was a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
     * Therefore, if aRefPad is a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID,
     * aPad is also a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID
     */
    bool diag = true;

    switch( aRefPad->GetShape() )
    {
    case PAD_SHAPE_CIRCLE:

        /* One can use checkClearanceSegmToPad to test clearance
         * aRefPad is like a track segment with a null length and a witdth = GetSize().x
         */
        m_segmLength = 0;
        m_segmAngle  = 0;

        m_segmEnd.x = m_segmEnd.y = 0;

        m_padToTestPos = relativePadPos;
        diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
        break;

    case PAD_SHAPE_TRAPEZOID:
    case PAD_SHAPE_ROUNDRECT:
    case PAD_SHAPE_RECT:
        // pad_angle = pad orient relative to the aRefPad orient
        pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
        NORMALIZE_ANGLE_POS( pad_angle );

        if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT )
        {
            int padRadius = aRefPad->GetRoundRectCornerRadius();
            dist_min += padRadius;
            GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
                                aRefPad->GetSize(), aRefPad->GetOrientation() );
        }
        else
            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );

        switch( aPad->GetShape() )
        {
        case PAD_SHAPE_ROUNDRECT:
        case PAD_SHAPE_RECT:
        case PAD_SHAPE_TRAPEZOID:
            if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
            {
                int padRadius = aPad->GetRoundRectCornerRadius();
                dist_min += padRadius;
                GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos,
                                    aPad->GetSize(), aPad->GetOrientation() );
            }
            else
            {
                aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

                // Move aPad shape to relativePadPos
                for( int ii = 0; ii < 4; ii++ )
                    polycompare[ii] += relativePadPos;
            }

            // And now test polygons:
            if( polysetref.OutlineCount() )
            {
                const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
                // And now test polygons:
                if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
                            polycompare, 4, dist_min ) )
                    diag = false;
            }
            else if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) )
                diag = false;
            break;

        default:
            wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() );
            break;
        }
        break;

    case PAD_SHAPE_OVAL:     /* an oval pad is like a track segment */
    {
        /* Create a track segment with same dimensions as the oval aRefPad
         * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
         */
        int segm_width;
        m_segmAngle = aRefPad->GetOrientation();                // Segment orient.

        if( aRefPad->GetSize().y < aRefPad->GetSize().x )     // Build an horizontal equiv segment
        {
            segm_width   = aRefPad->GetSize().y;
            m_segmLength = aRefPad->GetSize().x - aRefPad->GetSize().y;
        }
        else        // Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
        {
            segm_width   = aRefPad->GetSize().x;
            m_segmLength = aRefPad->GetSize().y - aRefPad->GetSize().x;
            m_segmAngle += 900;
        }

        /* the start point must be 0,0 and currently relativePadPos
         * is relative the center of pad coordinate */
        wxPoint segstart;
        segstart.x = -m_segmLength / 2;                 // Start point coordinate of the horizontal equivalent segment

        RotatePoint( &segstart, m_segmAngle );          // actual start point coordinate of the equivalent segment
        // Calculate segment end position relative to the segment origin
        m_segmEnd.x = -2 * segstart.x;
        m_segmEnd.y = -2 * segstart.y;

        // Recalculate the equivalent segment angle in 0,1 degrees
        // to prepare a call to checkClearanceSegmToPad()
        m_segmAngle = ArcTangente( m_segmEnd.y, m_segmEnd.x );

        // move pad position relative to the segment origin
        m_padToTestPos = relativePadPos - segstart;

        // Use segment to pad check to test the second pad:
        diag = checkClearanceSegmToPad( aPad, segm_width, dist_min );
        break;
    }

    default:
        wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
        break;
    }

    return diag;
}
bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{
    TRACK*    track;
    wxPoint   delta;           // length on X and Y axis of segments
    LSET layerMask;
    int       net_code_ref;
    wxPoint   shape_pos;

    NETCLASSPTR netclass = aRefSeg->GetNetClass();
    BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings();

    /* In order to make some calculations more easier or faster,
     * pads and tracks coordinates will be made relative to the reference segment origin
     */
    wxPoint origin = aRefSeg->GetStart();  // origin will be the origin of other coordinates

    m_segmEnd   = delta = aRefSeg->GetEnd() - origin;
    m_segmAngle = 0;

    layerMask    = aRefSeg->GetLayerSet();
    net_code_ref = aRefSeg->GetNetCode();

    // Phase 0 : Test vias
    if( aRefSeg->Type() == PCB_VIA_T )
    {
        const VIA *refvia = static_cast<const VIA*>( aRefSeg );
        // test if the via size is smaller than minimum
        if( refvia->GetViaType() == VIA_MICROVIA )
        {
            if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_TOO_SMALL_MICROVIA, m_currentMarker );
                return false;
            }
            if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_TOO_SMALL_MICROVIA_DRILL, m_currentMarker );
                return false;
            }
        }
        else
        {
            if( refvia->GetWidth() < dsnSettings.m_ViasMinSize )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_TOO_SMALL_VIA, m_currentMarker );
                return false;
            }
            if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_TOO_SMALL_VIA_DRILL, m_currentMarker );
                return false;
            }
        }

        // test if via's hole is bigger than its diameter
        // This test is necessary since the via hole size and width can be modified
        // and a default via hole can be bigger than some vias sizes
        if( refvia->GetDrillValue() > refvia->GetWidth() )
        {
            m_currentMarker = fillMarker( refvia, NULL,
                                          DRCE_VIA_HOLE_BIGGER, m_currentMarker );
            return false;
        }

        // For microvias: test if they are blind vias and only between 2 layers
        // because they are used for very small drill size and are drill by laser
        // and **only one layer** can be drilled
        if( refvia->GetViaType() == VIA_MICROVIA )
        {
            LAYER_ID    layer1, layer2;
            bool        err = true;

            refvia->LayerPair( &layer1, &layer2 );

            if( layer1 > layer2 )
                std::swap( layer1, layer2 );

            if( layer2 == B_Cu && layer1 == m_pcb->GetDesignSettings().GetCopperLayerCount() - 2 )
                err = false;
            else if( layer1 == F_Cu  &&  layer2 == In1_Cu  )
                err = false;

            if( err )
            {
                m_currentMarker = fillMarker( refvia, NULL,
                                              DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, m_currentMarker );
                return false;
            }
        }
    }
    else    // This is a track segment
    {
        if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth )
        {
            m_currentMarker = fillMarker( aRefSeg, NULL,
                                          DRCE_TOO_SMALL_TRACK_WIDTH, m_currentMarker );
            return false;
        }
    }

    // for a non horizontal or vertical segment Compute the segment angle
    // in tenths of degrees and its length
    if( delta.x || delta.y )
    {
        // Compute the segment angle in 0,1 degrees
        m_segmAngle = ArcTangente( delta.y, delta.x );

        // Compute the segment length: we build an equivalent rotated segment,
        // this segment is horizontal, therefore dx = length
        RotatePoint( &delta, m_segmAngle );    // delta.x = length, delta.y = 0
    }

    m_segmLength = delta.x;

    /******************************************/
    /* Phase 1 : test DRC track to pads :     */
    /******************************************/

    /* Use a dummy pad to test DRC tracks versus holes, for pads not on all copper layers
     * but having a hole
     * This dummy pad has the size and shape of the hole
     * to test tracks to pad hole DRC, using checkClearanceSegmToPad test function.
     * Therefore, this dummy pad is a circle or an oval.
     * A pad must have a parent because some functions expect a non null parent
     * to find the parent board, and some other data
     */
    MODULE  dummymodule( m_pcb );    // Creates a dummy parent
    D_PAD   dummypad( &dummymodule );

    dummypad.SetLayerSet( LSET::AllCuMask() );     // Ensure the hole is on all layers

    // Compute the min distance to pads
    if( testPads )
    {
        unsigned pad_count = m_pcb->GetPadCount();

        for( unsigned ii = 0;  ii<pad_count;  ++ii )
        {
            D_PAD* pad = m_pcb->GetPad( ii );

            /* No problem if pads are on an other layer,
             * But if a drill hole exists	(a pad on a single layer can have a hole!)
             * we must test the hole
             */
            if( !( pad->GetLayerSet() & layerMask ).any() )
            {
                /* We must test the pad hole. In order to use the function
                 * checkClearanceSegmToPad(),a pseudo pad is used, with a shape and a
                 * size like the hole
                 */
                if( pad->GetDrillSize().x == 0 )
                    continue;

                dummypad.SetSize( pad->GetDrillSize() );
                dummypad.SetPosition( pad->GetPosition() );
                dummypad.SetShape( pad->GetDrillShape()  == PAD_DRILL_SHAPE_OBLONG ?
                                   PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
                dummypad.SetOrientation( pad->GetOrientation() );

                m_padToTestPos = dummypad.GetPosition() - origin;

                if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(),
                                              netclass->GetClearance() ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, pad,
                                                  DRCE_TRACK_NEAR_THROUGH_HOLE, m_currentMarker );
                    return false;
                }

                continue;
            }

            // The pad must be in a net (i.e pt_pad->GetNet() != 0 )
            // but no problem if the pad netcode is the current netcode (same net)
            if( pad->GetNetCode()                       // the pad must be connected
               && net_code_ref == pad->GetNetCode() )   // the pad net is the same as current net -> Ok
                continue;

            // DRC for the pad
            shape_pos = pad->ShapePos();
            m_padToTestPos = shape_pos - origin;

            if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) )
            {
                m_currentMarker = fillMarker( aRefSeg, pad,
                                              DRCE_TRACK_NEAR_PAD, m_currentMarker );
                return false;
            }
        }
    }

    /***********************************************/
    /* Phase 2: test DRC with other track segments */
    /***********************************************/

    // At this point the reference segment is the X axis

    // Test the reference segment with other track segments
    wxPoint segStartPoint;
    wxPoint segEndPoint;
    for( track = aStart; track; track = track->Next() )
    {
        // No problem if segments have the same net code:
        if( net_code_ref == track->GetNetCode() )
            continue;

        // No problem if segment are on different layers :
        if( !( layerMask & track->GetLayerSet() ).any() )
            continue;

        // the minimum distance = clearance plus half the reference track
        // width plus half the other track's width
        int w_dist = aRefSeg->GetClearance( track );
        w_dist += (aRefSeg->GetWidth() + track->GetWidth()) / 2;

        // Due to many double to int conversions during calculations, which
        // create rounding issues,
        // the exact clearance margin cannot be really known.
        // To avoid false bad DRC detection due to these rounding issues,
        // slightly decrease the w_dist (remove one nanometer is enough !)
        w_dist -= 1;

        // If the reference segment is a via, we test it here
        if( aRefSeg->Type() == PCB_VIA_T )
        {
            delta = track->GetEnd() - track->GetStart();
            segStartPoint = aRefSeg->GetStart() - track->GetStart();

            if( track->Type() == PCB_VIA_T )
            {
                // Test distance between two vias, i.e. two circles, trivial case
                if( EuclideanNorm( segStartPoint ) < w_dist )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_VIA_NEAR_VIA, m_currentMarker );
                    return false;
                }
            }
            else    // test via to segment
            {
                // Compute l'angle du segment a tester;
                double angle = ArcTangente( delta.y, delta.x );

                // Compute new coordinates ( the segment become horizontal)
                RotatePoint( &delta, angle );
                RotatePoint( &segStartPoint, angle );

                if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) )
                {
                    m_currentMarker = fillMarker( track, aRefSeg,
                                                  DRCE_VIA_NEAR_TRACK, m_currentMarker );
                    return false;
                }
            }

            continue;
        }

        /* We compute segStartPoint, segEndPoint = starting and ending point coordinates for
         * the segment to test in the new axis : the new X axis is the
         * reference segment.  We must translate and rotate the segment to test
         */
        segStartPoint = track->GetStart() - origin;
        segEndPoint   = track->GetEnd() - origin;
        RotatePoint( &segStartPoint, m_segmAngle );
        RotatePoint( &segEndPoint, m_segmAngle );
        if( track->Type() == PCB_VIA_T )
        {
            if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
                continue;

            m_currentMarker = fillMarker( aRefSeg, track,
                                          DRCE_TRACK_NEAR_VIA, m_currentMarker );
            return false;
        }

        /*	We have changed axis:
         *  the reference segment is Horizontal.
         *  3 cases : the segment to test can be parallel, perpendicular or have an other direction
         */
        if( segStartPoint.y == segEndPoint.y ) // parallel segments
        {
            if( abs( segStartPoint.y ) >= w_dist )
                continue;

            // Ensure segStartPoint.x <= segEndPoint.x
            if( segStartPoint.x > segEndPoint.x )
                std::swap( segStartPoint.x, segEndPoint.x );

            if( segStartPoint.x > (-w_dist) && segStartPoint.x < (m_segmLength + w_dist) )    /* possible error drc */
            {
                // the start point is inside the reference range
                //      X........
                //    O--REF--+

                // Fine test : we consider the rounded shape of each end of the track segment:
                if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS1, m_currentMarker );
                    return false;
                }

                if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS2, m_currentMarker );
                    return false;
                }
            }

            if( segEndPoint.x > (-w_dist) && segEndPoint.x < (m_segmLength + w_dist) )
            {
                // the end point is inside the reference range
                //  .....X
                //    O--REF--+
                // Fine test : we consider the rounded shape of the ends
                if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS3, m_currentMarker );
                    return false;
                }

                if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_TRACK_ENDS4, m_currentMarker );
                    return false;
                }
            }

            if( segStartPoint.x <=0 && segEndPoint.x >= 0 )
            {
            // the segment straddles the reference range (this actually only
            // checks if it straddles the origin, because the other cases where already
            // handled)
            //  X.............X
            //    O--REF--+
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_TRACK_SEGMENTS_TOO_CLOSE, m_currentMarker );
                return false;
            }
        }
        else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments
        {
            if( ( segStartPoint.x <= (-w_dist) ) || ( segStartPoint.x >= (m_segmLength + w_dist) ) )
                continue;

            // Test if segments are crossing
            if( segStartPoint.y > segEndPoint.y )
                std::swap( segStartPoint.y, segEndPoint.y );

            if( (segStartPoint.y < 0) && (segEndPoint.y > 0) )
            {
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_TRACKS_CROSSING, m_currentMarker );
                return false;
            }

            // At this point the drc error is due to an end near a reference segm end
            if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
            {
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_ENDS_PROBLEM1, m_currentMarker );
                return false;
            }
            if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
            {
                m_currentMarker = fillMarker( aRefSeg, track,
                                              DRCE_ENDS_PROBLEM2, m_currentMarker );
                return false;
            }
        }
        else    // segments quelconques entre eux
        {
            // calcul de la "surface de securite du segment de reference
            // First rought 'and fast) test : the track segment is like a rectangle

            m_xcliplo = m_ycliplo = -w_dist;
            m_xcliphi = m_segmLength + w_dist;
            m_ycliphi = w_dist;

            // A fine test is needed because a serment is not exactly a
            // rectangle, it has rounded ends
            if( !checkLine( segStartPoint, segEndPoint ) )
            {
                /* 2eme passe : the track has rounded ends.
                 * we must a fine test for each rounded end and the
                 * rectangular zone
                 */

                m_xcliplo = 0;
                m_xcliphi = m_segmLength;

                if( !checkLine( segStartPoint, segEndPoint ) )
                {
                    m_currentMarker = fillMarker( aRefSeg, track,
                                                  DRCE_ENDS_PROBLEM3, m_currentMarker );
                    return false;
                }
                else    // The drc error is due to the starting or the ending point of the reference segment
                {
                    // Test the starting and the ending point
                    segStartPoint = track->GetStart();
                    segEndPoint   = track->GetEnd();
                    delta = segEndPoint - segStartPoint;

                    // Compute the segment orientation (angle) en 0,1 degre
                    double angle = ArcTangente( delta.y, delta.x );

                    // Compute the segment length: delta.x = length after rotation
                    RotatePoint( &delta, angle );

                    /* Comute the reference segment coordinates relatives to a
                     *  X axis = current tested segment
                     */
                    wxPoint relStartPos = aRefSeg->GetStart() - segStartPoint;
                    wxPoint relEndPos   = aRefSeg->GetEnd() - segStartPoint;

                    RotatePoint( &relStartPos, angle );
                    RotatePoint( &relEndPos, angle );

                    if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) )
                    {
                        m_currentMarker = fillMarker( aRefSeg, track,
                                                      DRCE_ENDS_PROBLEM4, m_currentMarker );
                        return false;
                    }

                    if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) )
                    {
                        m_currentMarker = fillMarker( aRefSeg, track,
                                                      DRCE_ENDS_PROBLEM5, m_currentMarker );
                        return false;
                    }
                }
            }
        }
    }

    return true;
}
/**
 * Function ConvertShapeToPolygon (virtual)
 * convert a shape to an equivalent polygon.
 * Arcs and circles are approximated by segments
 * Useful when a shape is not a graphic primitive (shape with hole,
 * rotated shape ... ) and cannot be easily drawn.
 * note for some schapes conbining circles and solid lines (rectangles), only rectangles are converted
 * because circles are very easy to draw (no rotation problem) so convert them in polygons,
 * and draw them as polygons is not a good idea.
 */
void AM_PRIMITIVE::ConvertShapeToPolygon( const GERBER_DRAW_ITEM* aParent,
                                          std::vector<wxPoint>& aBuffer )
{
    D_CODE* tool = aParent->GetDcodeDescr();

    switch( primitive_id )
    {
    case AMP_CIRCLE:
    {
        /* Generated by an aperture macro declaration like:
         * "1,1,0.3,0.5, 1.0*"
         * type (1), exposure, diameter, pos.x, pos.y, <rotation>
         * <rotation> is a optional parameter: rotation from origin.
         * type is not stored in parameters list, so the first parameter is exposure
         */
        wxPoint center = mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
        int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2;
        wxPoint corner;
        const int delta = 3600 / seg_per_circle;    // rot angle in 0.1 degree

        for( int angle = 0; angle < 3600; angle += delta )
        {
            corner.x   = radius;
            corner.y   = 0;
            RotatePoint( &corner, angle );
            corner += center;
            aBuffer.push_back( corner );
        }
    }
        break;

    case AMP_LINE2:
    case AMP_LINE20:        // Line with rectangle ends. (Width, start and end pos + rotation)
    {
        int     width = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );
        wxPoint start = mapPt( params[2].GetValue( tool ),
                               params[3].GetValue( tool ), m_GerbMetric );
        wxPoint end = mapPt( params[4].GetValue( tool ),
                             params[5].GetValue( tool ), m_GerbMetric );
        wxPoint delta = end - start;
        int     len   = KiROUND( EuclideanNorm( delta ) );

        // To build the polygon, we must create a horizontal polygon starting to "start"
        // and rotate it to have the end point to "end"
        wxPoint currpt;
        currpt.y += width / 2;          // Upper left
        aBuffer.push_back( currpt );
        currpt.x = len;                 // Upper right
        aBuffer.push_back( currpt );
        currpt.y -= width;              // lower right
        aBuffer.push_back( currpt );
        currpt.x = 0;                   // lower left
        aBuffer.push_back( currpt );

        // Rotate rectangle and move it to the actual start point
        double angle = ArcTangente( delta.y, delta.x );

        for( unsigned ii = 0; ii < 4; ii++ )
        {
            RotatePoint( &aBuffer[ii], -angle );
            aBuffer[ii] += start;
        }
    }
        break;

    case AMP_LINE_CENTER:
    {
        wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
        wxPoint pos  = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), m_GerbMetric );

        // Build poly:
        pos.x -= size.x / 2;
        pos.y -= size.y / 2;        // Lower left
        aBuffer.push_back( pos );
        pos.y += size.y;            // Upper left
        aBuffer.push_back( pos );
        pos.x += size.x;            // Upper right
        aBuffer.push_back( pos );
        pos.y -= size.y;            // lower right
        aBuffer.push_back( pos );
    }
    break;

    case AMP_LINE_LOWER_LEFT:
    {
        wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
        wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue(
                                       tool ), m_GerbMetric );

        // Build poly:
        aBuffer.push_back( lowerLeft );
        lowerLeft.y += size.y;          // Upper left
        aBuffer.push_back( lowerLeft );
        lowerLeft.x += size.x;          // Upper right
        aBuffer.push_back( lowerLeft );
        lowerLeft.y -= size.y;          // lower right
        aBuffer.push_back( lowerLeft );
    }
    break;

    case AMP_THERMAL:
    {
        // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
        // rotated by 90, 180 and 270 deg.
        // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
        int outerRadius   = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2;
        int innerRadius   = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ) / 2;
        int halfthickness = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
        double angle_start = RAD2DECIDEG( asin( (double) halfthickness / innerRadius ) );

        // Draw shape in the first cadrant (X and Y > 0)
        wxPoint pos, startpos;

        // Inner arc
        startpos.x = innerRadius;
        double angle_end = 900 - angle_start;
        for( double angle = angle_start; angle < angle_end; angle += 100 )
        {
            pos = startpos;
            RotatePoint( &pos, angle );
            aBuffer.push_back( pos );
        }

        // Last point
        pos = startpos;
        RotatePoint( &pos, angle_end );
        aBuffer.push_back( pos );

        // outer arc
        startpos.x  = outerRadius;
        startpos.y  = 0;
        angle_start = RAD2DECIDEG( asin( (double) halfthickness / outerRadius ) );
        angle_end   = 900 - angle_start;

        // First point, near Y axis, outer arc
        for( double angle = angle_end; angle > angle_start; angle -= 100 )
        {
            pos = startpos;
            RotatePoint( &pos, angle );
            aBuffer.push_back( pos );
        }

        // last point
        pos = startpos;
        RotatePoint( &pos, angle_start );
        aBuffer.push_back( pos );

        aBuffer.push_back( aBuffer[0] );  // Close poly
    }
    break;

    case AMP_MOIRE:     // A cross hair with n concentric circles. Only the cros is build as polygon
                        // because circles can be drawn easily
    {
        int crossHairThickness = scaletoIU( params[6].GetValue( tool ), m_GerbMetric );
        int crossHairLength    = scaletoIU( params[7].GetValue( tool ), m_GerbMetric );

        // Create cross. First create 1/4 of the shape.
        // Others point are the same, totated by 90, 180 and 270 deg
        wxPoint pos( crossHairThickness / 2, crossHairLength / 2 );
        aBuffer.push_back( pos );
        pos.y = crossHairThickness / 2;
        aBuffer.push_back( pos );
        pos.x = -crossHairLength / 2;
        aBuffer.push_back( pos );
        pos.y = -crossHairThickness / 2;
        aBuffer.push_back( pos );

        // Copy the 4 shape, rotated by 90, 180 and 270 deg
        for( int jj = 1; jj <= 3; jj ++ )
        {
            for( int ii = 0; ii < 4; ii++ )
            {
                pos = aBuffer[ii];
                RotatePoint( &pos, jj*900 );
                aBuffer.push_back( pos );
            }
        }
    }
    break;

    case AMP_OUTLINE:
        // already is a polygon. Do nothing
        break;

    case AMP_POLYGON:   // Creates a regular polygon
    {
        int vertexcount = KiROUND( params[1].GetValue( tool ) );
        int radius    = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
        // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis
        if( vertexcount < 3 )
            vertexcount = 3;
        if( vertexcount > 10 )
            vertexcount = 10;
        for( int ii = 0; ii <= vertexcount; ii++ )
        {
            wxPoint pos( radius, 0);
            RotatePoint( &pos, ii * 3600 / vertexcount );
            aBuffer.push_back( pos );
        }
    }
        break;

    case AMP_COMMENT:
    case AMP_UNKNOWN:
    case AMP_EOF:
        break;
    }
}
示例#13
0
void Trace_DrawSegmentPcb(WinEDA_DrawPanel * panel, wxDC * DC,
		DRAWSEGMENT * PtDrawSegment, int draw_mode)
/**************************************************************************/
/* Affichage d'un segment type drawing PCB:
	Entree : ox, oy = offset de trace
	draw_mode = mode de trace ( GR_OR, GR_XOR, GrAND)
		Les contours sont de differents type:
		segment
		cercle
		arc
*/
{
int ux0, uy0, dx, dy;
int l_piste;
int color, mode;
int zoom = panel->GetZoom();
int rayon;

	color = g_DesignSettings.m_LayerColor[PtDrawSegment->m_Layer];
	if(color & ITEM_NOT_SHOW ) return ;

	GRSetDrawMode(DC, draw_mode);
	l_piste = PtDrawSegment->m_Width >> 1;  /* l_piste = demi largeur piste */

	/* coord de depart */
	ux0 = PtDrawSegment->m_Start.x;
	uy0 = PtDrawSegment->m_Start.y;
	/* coord d'arrivee */
	dx = PtDrawSegment->m_End.x;
	dy = PtDrawSegment->m_End.y;


	mode = DisplayOpt.DisplayPcbTrackFill ? FILLED : SKETCH;
	if(PtDrawSegment->m_Flags & FORCE_SKETCH) mode = SKETCH;
	if ( l_piste < (L_MIN_DESSIN * zoom) ) mode = FILAIRE;

	switch (PtDrawSegment->m_Shape)
		{
		case S_CIRCLE:
			rayon = (int)hypot((double)(dx-ux0),(double)(dy-uy0) );
			if ( mode == FILAIRE)
				{
				GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon, color) ;
				}
			else if( mode == SKETCH)
				{
				GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon-l_piste, color);
				GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon+l_piste, color);
				}
			else
				{
				GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon, PtDrawSegment->m_Width,color);
				}
			break;

		case S_ARC:
			{
			int StAngle, EndAngle;
			rayon = (int)hypot((double)(dx-ux0),(double)(dy-uy0) );
			StAngle = (int) ArcTangente(dy-uy0, dx-ux0);
			EndAngle = StAngle + PtDrawSegment->m_Angle;
			if ( mode == FILAIRE)
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle, rayon, color);
			else if( mode == SKETCH)
				{
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
					rayon - l_piste, color);
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
					rayon + l_piste, color);
				}
			else
				{
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
						rayon, PtDrawSegment->m_Width,color);
				}
			}
			break;


		default:
			if( mode == FILAIRE)
				GRLine(&panel->m_ClipBox, DC, ux0, uy0, dx, dy, color) ;
			else if( mode == SKETCH)
				{
				GRCSegm(&panel->m_ClipBox, DC, ux0, uy0, dx, dy,
						PtDrawSegment->m_Width, color) ;
				}
			else
				{
				GRFillCSegm(&panel->m_ClipBox, DC, ux0, uy0, dx, dy,
						 PtDrawSegment->m_Width, color) ;
				}
			break;
		}
}
void EDGE_MODULE::Draw(WinEDA_DrawPanel * panel, wxDC * DC,
						const wxPoint & offset, int draw_mode)
/********************************************************************************/

/* Affichage d'un segment contour de module :
	Entree : ox, oy = offset de trace
	draw_mode = mode de trace ( GR_OR, GR_XOR, GR_AND)
		Les contours sont de differents type:
		- Segment
		- Cercles
		- Arcs
*/
{
int ux0, uy0, dx, dy,rayon, StAngle, EndAngle;
int color , type_trace;
int zoom;
int typeaff;
PCB_SCREEN * screen;
WinEDA_BasePcbFrame * frame;
MODULE * Module = NULL;

	if ( m_Parent && (m_Parent->m_StructType == TYPEMODULE) )
		Module = (MODULE*) m_Parent;

	GRSetDrawMode(DC, draw_mode);
	color = g_DesignSettings.m_LayerColor[m_Layer];

	if ( panel ) screen = (PCB_SCREEN *) panel->m_Parent->m_CurrentScreen;
	else screen = ActiveScreen;

	frame = screen->GetParentPcbFrame();

	zoom = screen->GetZoom();

	type_trace = m_Shape;
	ux0 = m_Start.x - offset.x; uy0 = m_Start.y - offset.y;
	dx = m_End.x - offset.x ;
	dy = m_End.y - offset.y ;

	typeaff = frame->m_DisplayModEdge;
	if( m_Layer <= CMP_N )
		typeaff = frame->m_DisplayPcbTrackFill;
	if( (m_Width /zoom) < L_MIN_DESSIN ) typeaff = FILAIRE;

	switch (type_trace )
	{
		case S_SEGMENT:
			if( typeaff == FILAIRE)
				GRLine(&panel->m_ClipBox, DC,  ux0, uy0, dx, dy, color);
			else Affiche_1_Segment(panel, DC, ux0,uy0,dx,dy,m_Width,
									typeaff,color);
			break ;

		case S_CIRCLE:
			rayon = (int)hypot((double)(dx-ux0),(double)(dy-uy0) );
			if( typeaff == FILAIRE)
			{
				GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon, color) ;
			}
			else
			{
				if(typeaff == FILLED )
				{
					GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon, m_Width, color);
				}
				else
				{
					GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon + (m_Width/2), color) ;
					GRCircle(&panel->m_ClipBox, DC, ux0, uy0, rayon - (m_Width/2), color) ;
				}
			}
			break;

		case S_ARC:
			rayon = (int)hypot((double)(dx-ux0),(double)(dy-uy0) );
			StAngle = (int)ArcTangente( dy-uy0, dx-ux0 );
			EndAngle = StAngle + m_Angle;
			if ( StAngle > EndAngle) EXCHG (StAngle, EndAngle);
			if( typeaff == FILAIRE)
			{
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle, rayon, color) ;
			}
			else if(typeaff == FILLED )
				{
					GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle, rayon,
								m_Width, color);
				}
			else
			{
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
						rayon + (m_Width/2), color) ;
				GRArc(&panel->m_ClipBox, DC, ux0, uy0, StAngle, EndAngle,
						rayon - (m_Width/2), color) ;
			}
			break;

		case S_POLYGON:
		{
			// We must compute true coordinates from m_PolyList
			// which are relative to module position, orientation 0
			int ii, * source, * ptr, * ptr_base;
			ptr = ptr_base = (int*) MyMalloc( 2 * m_PolyCount * sizeof(int) );
			source = m_PolyList;
			for (ii = 0; ii < m_PolyCount; ii++ )
			{
				int x, y;
				x = *source; source++; y = *source; source++;
				if ( Module )
				{
					RotatePoint (&x, &y, Module->m_Orient);
					x += Module->m_Pos.x;
					y += Module->m_Pos.y;
				}
				x +=  m_Start0.x - offset.x;
				y +=  m_Start0.y - offset.y;
				*ptr = x; ptr++; *ptr = y; ptr++;
			}
			GRPoly(&panel->m_ClipBox, DC, m_PolyCount, ptr_base,
				TRUE, color, color);
			free ( ptr_base);
			break;
		}
	}
}
/**
 * Function TransformRoundedEndsSegmentToPolygon
 * convert a segment with rounded ends to a polygon
 * Convert arcs to multiple straight lines
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aStart = the segment start point coordinate
 * @param aEnd = the segment end point coordinate
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 * @param aWidth = the segment width
 * Note: the polygon is inside the arc ends, so if you want to have the polygon
 * outside the circle, you should give aStart and aEnd calculated with a correction factor
 */
void TransformRoundedEndsSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                                           wxPoint aStart, wxPoint aEnd,
                                           int aCircleToSegmentsCount,
                                           int aWidth )
{
    int     radius  = aWidth / 2;
    wxPoint endp    = aEnd - aStart; // end point coordinate for the same segment starting at (0,0)
    wxPoint startp  = aStart;
    wxPoint corner;
    VECTOR2I polypoint;

    aCornerBuffer.NewOutline();

    // normalize the position in order to have endp.x >= 0;
    if( endp.x < 0 )
    {
        endp    = aStart - aEnd;
        startp  = aEnd;
    }

    double delta_angle = ArcTangente( endp.y, endp.x ); // delta_angle is in 0.1 degrees
    int seg_len        = KiROUND( EuclideanNorm( endp ) );

    int delta = 3600 / aCircleToSegmentsCount;    // rot angle in 0.1 degree

    // Compute the outlines of the segment, and creates a polygon
    // add right rounded end:
    for( int ii = 0; ii < 1800; ii += delta )
    {
        corner = wxPoint( 0, radius );
        RotatePoint( &corner, ii );
        corner.x += seg_len;
        RotatePoint( &corner, -delta_angle );
        corner += startp;
        polypoint.x = corner.x;
        polypoint.y = corner.y;
        aCornerBuffer.Append( polypoint.x, polypoint.y );
    }

    // Finish arc:
    corner = wxPoint( seg_len, -radius );
    RotatePoint( &corner, -delta_angle );
    corner += startp;
    polypoint.x = corner.x;
    polypoint.y = corner.y;
    aCornerBuffer.Append( polypoint.x, polypoint.y );

    // add left rounded end:
    for( int ii = 0; ii < 1800; ii += delta )
    {
        corner = wxPoint( 0, -radius );
        RotatePoint( &corner, ii );
        RotatePoint( &corner, -delta_angle );
        corner += startp;
        polypoint.x = corner.x;
        polypoint.y = corner.y;
        aCornerBuffer.Append( polypoint.x, polypoint.y );
    }

    // Finish arc:
    corner = wxPoint( 0, radius );
    RotatePoint( &corner, -delta_angle );
    corner += startp;
    polypoint.x = corner.x;
    polypoint.y = corner.y;
    aCornerBuffer.Append( polypoint.x, polypoint.y );
}
示例#16
0
void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
                        const wxPoint& offset )
{
    int         ux0, uy0, dx, dy, radius, StAngle, EndAngle;
    PCB_LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;

    MODULE* module = (MODULE*) m_Parent;

    if( !module )
        return;

    BOARD* brd = GetBoard( );

    if( brd->IsLayerVisible( m_Layer ) == false )
        return;


    auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );

    auto displ_opts = (PCB_DISPLAY_OPTIONS*)( panel->GetDisplayOptions() );

    if(( draw_mode & GR_ALLOW_HIGHCONTRAST ) && displ_opts && displ_opts->m_ContrastModeDisplay )
    {
        if( !IsOnLayer( curr_layer ) )
            color = COLOR4D( DARKDARKGRAY );
    }

    ux0 = m_Start.x - offset.x;
    uy0 = m_Start.y - offset.y;

    dx = m_End.x - offset.x;
    dy = m_End.y - offset.y;

    GRSetDrawMode( DC, draw_mode );
    bool filled = displ_opts ? displ_opts->m_DisplayModEdgeFill : FILLED;

    if( IsCopperLayer( m_Layer ) )
        filled = displ_opts ? displ_opts->m_DisplayPcbTrackFill : FILLED;

    switch( m_Shape )
    {
    case S_SEGMENT:
        if( filled )
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
        else
            // SKETCH Mode
            GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );

        break;

    case S_CIRCLE:
        radius = KiROUND( Distance( ux0, uy0, dx, dy ) );

        if( filled )
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + (m_Width / 2), color );
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - (m_Width / 2), color );
        }

        break;

    case S_ARC:
        radius   = KiROUND( Distance( ux0, uy0, dx, dy ) );
        StAngle  = ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;

        if( !panel->GetPrintMirrored() )
        {
            if( StAngle > EndAngle )
                std::swap( StAngle, EndAngle );
        }
        else    // Mirrored mode: arc orientation is reversed
        {
            if( StAngle < EndAngle )
                std::swap( StAngle, EndAngle );
        }

        if( filled )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius + (m_Width / 2), color );
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius - (m_Width / 2), color );
        }
        break;

    case S_POLYGON:
        if( m_Poly.IsEmpty() )
            break;

        {
        // We must compute absolute coordinates from m_PolyPoints
        // which are relative to module position, orientation 0
        std::vector<wxPoint> points;

        for( auto iter = m_Poly.CIterate(); iter; iter++ )
        {
            points.push_back( wxPoint( iter->x,iter->y ) );
        }

        for( unsigned ii = 0; ii < points.size(); ii++ )
        {
            wxPoint& pt = points[ii];

            RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
            pt += module->GetPosition() - offset;
        }

        GRPoly( panel->GetClipBox(), DC, points.size(), &points[0], true, m_Width, color, color );
        }
        break;

    default:
        break;
    }
}
示例#17
0
/* Fills all cells inside a segment
 * half-width = lg, org = ux0,uy0 end = ux1,uy1
 * coordinates are in PCB units
 */
void DrawSegmentQcq( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
                     int color, int op_logic )
{
    int  row, col;
    int  inc;
    int  row_max, col_max, row_min, col_min;
    int  demi_pas;

    int  cx, cy, dx, dy;

    RoutingMatrix.SetCellOperation( op_logic );

    // Make coordinate ux1 tj > ux0 to simplify calculations
    if( ux1 < ux0 )
    {
        EXCHG( ux1, ux0 );
        EXCHG( uy1, uy0 );
    }

    // Calculating the incrementing the Y axis
    inc = 1;

    if( uy1 < uy0 )
        inc = -1;

    demi_pas = RoutingMatrix.m_GridRouting / 2;

    col_min = ( ux0 - lg ) / RoutingMatrix.m_GridRouting;

    if( col_min < 0 )
        col_min = 0;

    col_max = ( ux1 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;

    if( col_max > ( RoutingMatrix.m_Ncols - 1 ) )
        col_max = RoutingMatrix.m_Ncols - 1;

    if( inc > 0 )
    {
        row_min = ( uy0 - lg ) / RoutingMatrix.m_GridRouting;
        row_max = ( uy1 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
    }
    else
    {
        row_min = ( uy1 - lg ) / RoutingMatrix.m_GridRouting;
        row_max = ( uy0 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
    }

    if( row_min < 0 )
        row_min = 0;

    if( row_min > ( RoutingMatrix.m_Nrows - 1 ) )
        row_min = RoutingMatrix.m_Nrows - 1;

    if( row_max < 0 )
        row_max = 0;

    if( row_max > ( RoutingMatrix.m_Nrows - 1 ) )
        row_max = RoutingMatrix.m_Nrows - 1;

    dx = ux1 - ux0;
    dy = uy1 - uy0;

    double angle;
    if( dx )
    {
        angle = ArcTangente( dy, dx );
    }
    else
    {
        angle = 900;

        if( dy < 0 )
            angle = -900;
    }

    RotatePoint( &dx, &dy, angle );   // dx = length, dy = 0

    for( col = col_min; col <= col_max; col++ )
    {
        int cxr;
        cxr = ( col * RoutingMatrix.m_GridRouting ) - ux0;

        for( row = row_min; row <= row_max; row++ )
        {
            cy = (row * RoutingMatrix.m_GridRouting) - uy0;
            cx = cxr;
            RotatePoint( &cx, &cy, angle );

            if( abs( cy ) > lg )
                continue;             // The point is too far on the Y axis.

            /* This point a test is close to the segment: the position
             * along the X axis must be tested.
             */
            if( ( cx >= 0 ) && ( cx <= dx ) )
            {
                OP_CELL( layer, row, col );
                continue;
            }

            // Examination of extremities are rounded.
            if( ( cx < 0 ) && ( cx >= -lg ) )
            {
                if( ( ( cx * cx ) + ( cy * cy ) ) <= ( lg * lg ) )
                    OP_CELL( layer, row, col );

                continue;
            }

            if( ( cx > dx ) && ( cx <= ( dx + lg ) ) )
            {
                if( ( ( ( cx - dx ) * ( cx - dx ) ) + ( cy * cy ) ) <= ( lg * lg ) )
                    OP_CELL( layer, row, col );

                continue;
            }
        }
    }
}
/*
 * Update the status bar information.
 */
void PCB_BASE_FRAME::UpdateStatusBar()
{
    PCB_SCREEN* screen = GetScreen();

    if( !screen )
        return;

    wxString line;
    wxString locformatter;

    EDA_DRAW_FRAME::UpdateStatusBar();

    if( GetShowPolarCoords() )  // display polar coordinates
    {
        double dx = (double)GetCrossHairPosition().x - (double)screen->m_O_Curseur.x;
        double dy = (double)GetCrossHairPosition().y - (double)screen->m_O_Curseur.y;

        double theta = ArcTangente( -dy, dx ) / 10;
        double ro = hypot( dx, dy );

        wxString formatter;
        switch( GetUserUnits() )
        {
        case INCHES:
            formatter = "r %.6f  theta %.1f";
            break;

        case MILLIMETRES:
            formatter = "r %.6f  theta %.1f";
            break;

        case UNSCALED_UNITS:
            formatter = "r %f  theta %f";
            break;

        case DEGREES:
            wxASSERT( false );
            break;
        }

        line.Printf( formatter, To_User_Unit( GetUserUnits(), ro ), theta );

        SetStatusText( line, 3 );
    }

    // Display absolute coordinates:
    double dXpos = To_User_Unit( GetUserUnits(), GetCrossHairPosition().x );
    double dYpos = To_User_Unit( GetUserUnits(), GetCrossHairPosition().y );

    // The following sadly is an if Eeschema/if Pcbnew
    wxString absformatter;

    switch( GetUserUnits() )
    {
    case INCHES:
        absformatter = "X %.6f  Y %.6f";
        locformatter = "dx %.6f  dy %.6f  dist %.4f";
        break;

    case MILLIMETRES:
        absformatter = "X %.6f  Y %.6f";
        locformatter = "dx %.6f  dy %.6f  dist %.3f";
        break;

    case UNSCALED_UNITS:
        absformatter = "X %f  Y %f";
        locformatter = "dx %f  dy %f  dist %f";
        break;

    case DEGREES:
        wxASSERT( false );
        break;
    }

    line.Printf( absformatter, dXpos, dYpos );
    SetStatusText( line, 2 );

    if( !GetShowPolarCoords() )  // display relative cartesian coordinates
    {
        // Display relative coordinates:
        double dx = (double)GetCrossHairPosition().x - (double)screen->m_O_Curseur.x;
        double dy = (double)GetCrossHairPosition().y - (double)screen->m_O_Curseur.y;
        dXpos = To_User_Unit( GetUserUnits(), dx );
        dYpos = To_User_Unit( GetUserUnits(), dy );

        // We already decided the formatter above
        line.Printf( locformatter, dXpos, dYpos, hypot( dXpos, dYpos ) );
        SetStatusText( line, 3 );
    }
}
示例#19
0
/**
 * Function BuildCornersList_S_Shape
 * Create a path like a S-shaped coil
 * @param  aBuffer =  a buffer where to store points (ends of segments)
 * @param  aStartPoint = starting point of the path
 * @param  aEndPoint = ending point of the path
 * @param  aLength = full lenght of the path
 * @param  aWidth = segment width
 */
int BuildCornersList_S_Shape( std::vector <wxPoint>& aBuffer,
                              wxPoint aStartPoint, wxPoint aEndPoint,
                              int aLength, int aWidth )
{
/* We must determine:
 * segm_count = number of segments perpendicular to the direction
 * segm_len = length of a strand
 * radius = radius of rounded parts of the coil
 * stubs_len = length of the 2 stubs( segments parallel to the direction)
 *         connecting the start point to the start point of the S shape
 *         and the ending point to the end point of the S shape
 * The equations are (assuming the area size of the entire shape is Size:
 * Size.x = 2 * radius + segm_len
 * Size.y = (segm_count + 2 ) * 2 * radius + 2 * stubs_len
 * s_inductor_pattern.m_lenght = 2 * delta // connections to the coil
 *             + (segm_count-2) * segm_len      // length of the strands except 1st and last
 *             + (segm_count) * (PI * radius)   // length of rounded
 * segm_len + / 2 - radius * 2)                 // length of 1st and last bit
 *
 * The constraints are:
 * segm_count >= 2
 * radius < m_Size.x
 * Size.y = (radius * 4) + (2 * stubs_len)
 * segm_len > radius * 2
 *
 * The calculation is conducted in the following way:
 * first:
 * segm_count = 2
 * radius = 4 * Size.x (arbitrarily fixed value)
 * Then:
 * Increasing the number of segments to the desired length
 * (radius decreases if necessary)
 */
    wxSize size;

    // This scale factor adjusts the arc length to handle
    // the arc to segment approximation.
    // because we use SEGM_COUNT_PER_360DEG segment to approximate a circle,
    // the trace len must be corrected when calculated using arcs
    // this factor adjust calculations and must be changed if SEGM_COUNT_PER_360DEG is modified
    // because trace using segment is shorter the corresponding arc
    // ADJUST_SIZE is the ratio between tline len and the arc len for an arc
    // of 360/ADJUST_SIZE angle
    #define ADJUST_SIZE 0.988

    wxPoint pt       = aEndPoint - aStartPoint;
    double  angle    = -ArcTangente( pt.y, pt.x );
    int     min_len  = KiROUND( EuclideanNorm( pt ) );
    int     segm_len = 0;           // length of segments
    int     full_len;               // full len of shape (sum of lenght of all segments + arcs)


    /* Note: calculations are made for a vertical coil (more easy calculations)
     * and after points are rotated to their actual position
     * So the main direction is the Y axis.
     * the 2 stubs are on the Y axis
     * the others segments are parallel to the X axis.
     */

    // Calculate the size of area (for a vertical shape)
    size.x = min_len / 2;
    size.y = min_len;

    // Choose a reasonable starting value for the radius of the arcs.
    int radius = std::min( aWidth * 5, size.x / 4 );

    int segm_count;     // number of full len segments
                        // the half size segments (first and last segment) are not counted here
    int stubs_len = 0;  // lenght of first or last segment (half size of others segments)

    for( segm_count = 0; ; segm_count++ )
    {
        stubs_len = ( size.y - ( radius * 2 * (segm_count + 2 ) ) ) / 2;

        if( stubs_len < size.y / 10 ) // Reduce radius.
        {
            stubs_len = size.y / 10;
            radius    = ( size.y - (2 * stubs_len) ) / ( 2 * (segm_count + 2) );

            if( radius < aWidth ) // Radius too small.
            {
                // Unable to create line: Requested length value is too large for room
                return 0;
            }
        }

        segm_len  = size.x - ( radius * 2 );
        full_len  = 2 * stubs_len;               // Length of coil connections.
        full_len += segm_len * segm_count;       // Length of full length segments.
        full_len += KiROUND( ( segm_count + 2 ) * M_PI * ADJUST_SIZE * radius );    // Ard arcs len
        full_len += segm_len - (2 * radius);     // Length of first and last segments
                                                 // (half size segments len = segm_len/2 - radius).

        if( full_len >= aLength )
            break;
    }

    // Adjust len by adjusting segm_len:
    int delta_size = full_len - aLength;

    // reduce len of the segm_count segments + 2 half size segments (= 1 full size segment)
    segm_len -= delta_size / (segm_count + 1);

    // Generate first line (the first stub) and first arc (90 deg arc)
    pt = aStartPoint;
    aBuffer.push_back( pt );
    pt.y += stubs_len;
    aBuffer.push_back( pt );

    wxPoint centre = pt;
    centre.x -= radius;
    gen_arc( aBuffer, pt, centre, -900 );
    pt = aBuffer.back();

    int half_size_seg_len = segm_len / 2 - radius;

    if( half_size_seg_len )
    {
        pt.x -= half_size_seg_len;
        aBuffer.push_back( pt );
    }

    // Create shape.
    int ii;
    int sign = 1;
    segm_count += 1;    // increase segm_count to create the last half_size segment

    for( ii = 0; ii < segm_count; ii++ )
    {
        int arc_angle;

        if( ii & 1 ) // odd order arcs are greater than 0
            sign = -1;
        else
            sign = 1;

        arc_angle = 1800 * sign;
        centre    = pt;
        centre.y += radius;
        gen_arc( aBuffer, pt, centre, arc_angle );
        pt    = aBuffer.back();
        pt.x += segm_len * sign;
        aBuffer.push_back( pt );
    }

    // The last point is false:
    // it is the end of a full size segment, but must be
    // the end of the second half_size segment. Change it.
    sign *= -1;
    aBuffer.back().x = aStartPoint.x + radius * sign;

    // create last arc
    pt        = aBuffer.back();
    centre    = pt;
    centre.y += radius;
    gen_arc( aBuffer, pt, centre, 900 * sign );    pt = aBuffer.back();

    // Rotate point
    angle += 900;

    for( unsigned jj = 0; jj < aBuffer.size(); jj++ )
    {
        RotatePoint( &aBuffer[jj].x, &aBuffer[jj].y, aStartPoint.x, aStartPoint.y, angle );
    }

    // push last point (end point)
    aBuffer.push_back( aEndPoint );

    return 1;
}
void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
                        const wxPoint& offset )
{
    int         ux0, uy0, dx, dy, radius, StAngle, EndAngle;
    int         typeaff;
    LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;

    MODULE* module = (MODULE*) m_Parent;

    if( !module )
        return;

    BOARD* brd = GetBoard( );

    if( brd->IsLayerVisible( m_Layer ) == false )
        return;

    EDA_COLOR_T color = brd->GetLayerColor( m_Layer );

    if(( draw_mode & GR_ALLOW_HIGHCONTRAST ) && DisplayOpt.ContrastModeDisplay )
    {
        if( !IsOnLayer( curr_layer ) )
            ColorTurnToDarkDarkGray( &color );
    }

    PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();

    ux0 = m_Start.x - offset.x;
    uy0 = m_Start.y - offset.y;

    dx = m_End.x - offset.x;
    dy = m_End.y - offset.y;

    GRSetDrawMode( DC, draw_mode );
    typeaff = frame->m_DisplayModEdge;

    if( IsCopperLayer( m_Layer ) )
    {
        typeaff = frame->m_DisplayPcbTrackFill;

        if( !typeaff )
            typeaff = SKETCH;
    }

    if( DC->LogicalToDeviceXRel( m_Width ) <= MIN_DRAW_WIDTH )
        typeaff = LINE;

    switch( m_Shape )
    {
    case S_SEGMENT:
        if( typeaff == LINE )
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, 0, color );
        else if( typeaff == FILLED )
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
        else
            // SKETCH Mode
            GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );

        break;

    case S_CIRCLE:
        radius = KiROUND( Distance( ux0, uy0, dx, dy ) );

        if( typeaff == LINE )
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, color );
        }
        else
        {
            if( typeaff == FILLED )
            {
                GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color );
            }
            else        // SKETCH Mode
            {
                GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + (m_Width / 2), color );
                GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - (m_Width / 2), color );
            }
        }

        break;

    case S_ARC:
        radius   = KiROUND( Distance( ux0, uy0, dx, dy ) );
        StAngle  = ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;

        if( !panel->GetPrintMirrored() )
        {
            if( StAngle > EndAngle )
                EXCHG( StAngle, EndAngle );
        }
        else    // Mirrored mode: arc orientation is reversed
        {
            if( StAngle < EndAngle )
                EXCHG( StAngle, EndAngle );
        }

        if( typeaff == LINE )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, color );
        }
        else if( typeaff == FILLED )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius + (m_Width / 2), color );
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius - (m_Width / 2), color );
        }
        break;

    case S_POLYGON:
        {
        // We must compute true coordinates from m_PolyPoints
        // which are relative to module position, orientation 0
        std::vector<wxPoint> points = m_PolyPoints;

        for( unsigned ii = 0; ii < points.size(); ii++ )
        {
            wxPoint& pt = points[ii];

            RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
            pt += module->GetPosition() - offset;
        }

        GRPoly( panel->GetClipBox(), DC, points.size(), &points[0], true, m_Width, color, color );
        }
        break;

    default:
        break;
    }
}
void DRAWSEGMENT::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
                        const wxPoint& aOffset )
{
    int ux0, uy0, dx, dy;
    int l_trace;
    int mode;
    int radius;
    LAYER_NUM curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
    EDA_COLOR_T color;

    BOARD * brd =  GetBoard( );

    if( brd->IsLayerVisible( GetLayer() ) == false )
        return;

    color = brd->GetLayerColor( GetLayer() );

    if( ( draw_mode & GR_ALLOW_HIGHCONTRAST ) &&  DisplayOpt.ContrastModeDisplay )
    {
        if( !IsOnLayer( curr_layer ) && !IsOnLayer( EDGE_N ) )
            ColorTurnToDarkDarkGray( &color );
    }


    GRSetDrawMode( DC, draw_mode );
    l_trace = m_Width >> 1;  /* half trace width */

    // Line start point or Circle and Arc center
    ux0 = m_Start.x + aOffset.x;
    uy0 = m_Start.y + aOffset.y;

    // Line end point or circle and arc start point
    dx = m_End.x + aOffset.x;
    dy = m_End.y + aOffset.y;

    mode = DisplayOpt.DisplayDrawItems;

    if( m_Flags & FORCE_SKETCH )
        mode = SKETCH;

    if( DC->LogicalToDeviceXRel( l_trace ) <= MIN_DRAW_WIDTH )
        mode = LINE;

    switch( m_Shape )
    {
    case S_CIRCLE:
        radius = KiROUND( Distance( ux0, uy0, dx, dy ) );

        if( mode == LINE )
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, color );
        }
        else if( mode == SKETCH )
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - l_trace, color );
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + l_trace, color );
        }
        else
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color );
        }

        break;

    case S_ARC:
        double StAngle, EndAngle;
        radius   = KiROUND( Distance( ux0, uy0, dx, dy ) );
        StAngle  = ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;

        if( !panel->GetPrintMirrored() )
        {
            if( StAngle > EndAngle )
                EXCHG( StAngle, EndAngle );
        }
        else    // Mirrored mode: arc orientation is reversed
        {
            if( StAngle < EndAngle )
                EXCHG( StAngle, EndAngle );
        }


        if( mode == LINE )
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, color );

        else if( mode == SKETCH )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius - l_trace, color );
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius + l_trace, color );
        }
        else
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius, m_Width, color );
        }
        break;

    case S_CURVE:
        m_BezierPoints = Bezier2Poly(m_Start, m_BezierC1, m_BezierC2, m_End);

        for (unsigned int i=1; i < m_BezierPoints.size(); i++) {
            if( mode == LINE )
                GRLine( panel->GetClipBox(), DC,
                        m_BezierPoints[i].x, m_BezierPoints[i].y,
                        m_BezierPoints[i-1].x, m_BezierPoints[i-1].y, 0,
                        color );
            else if( mode == SKETCH )
            {
                GRCSegm( panel->GetClipBox(), DC,
                         m_BezierPoints[i].x, m_BezierPoints[i].y,
                         m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
                         m_Width, color );
            }
            else
            {
                GRFillCSegm( panel->GetClipBox(), DC,
                             m_BezierPoints[i].x, m_BezierPoints[i].y,
                             m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
                             m_Width, color );
            }
        }

        break;

    default:
        if( mode == LINE )
        {
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, 0, color );
        }
        else if( mode == SKETCH )
        {
            GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
        }
        else
        {
            GRFillCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
        }

        break;
    }
}
/*
 * Update the status bar information.
 */
void PCB_BASE_FRAME::UpdateStatusBar()
{
    PCB_SCREEN* screen = GetScreen();

    if( !screen )
        return;

    int dx;
    int dy;
    double dXpos;
    double dYpos;
    wxString line;
    wxString locformatter;
    DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)GetDisplayOptions();

    EDA_DRAW_FRAME::UpdateStatusBar();

    if( displ_opts->m_DisplayPolarCood )  // display polar coordinates
    {
        double       theta, ro;

        dx = GetCrossHairPosition().x - screen->m_O_Curseur.x;
        dy = GetCrossHairPosition().y - screen->m_O_Curseur.y;

        theta = ArcTangente( -dy, dx ) / 10;

        ro = hypot( dx, dy );
        wxString formatter;
        switch( g_UserUnit )
        {
        case INCHES:
            formatter = wxT( "Ro %.6f  Th %.1f" );
            break;

        case MILLIMETRES:
            formatter = wxT( "Ro %.6f  Th %.1f" );
            break;

        case UNSCALED_UNITS:
            formatter = wxT( "Ro %f  Th %f" );
            break;

        case DEGREES:
            wxASSERT( false );
            break;
        }

        line.Printf( formatter, To_User_Unit( g_UserUnit, ro ), theta );

        SetStatusText( line, 3 );
    }

    // Display absolute coordinates:
    dXpos = To_User_Unit( g_UserUnit, GetCrossHairPosition().x );
    dYpos = To_User_Unit( g_UserUnit, GetCrossHairPosition().y );

    // The following sadly is an if Eeschema/if Pcbnew
    wxString absformatter;

    switch( g_UserUnit )
    {
    case INCHES:
        absformatter = wxT( "X %.6f  Y %.6f" );
        locformatter = wxT( "dx %.6f  dy %.6f  dist %.4f" );
        break;

    case MILLIMETRES:
        absformatter = wxT( "X %.6f  Y %.6f" );
        locformatter = wxT( "dx %.6f  dy %.6f  dist %.3f" );
        break;

    case UNSCALED_UNITS:
        absformatter = wxT( "X %f  Y %f" );
        locformatter = wxT( "dx %f  dy %f  dist %f" );
        break;

    case DEGREES:
        wxASSERT( false );
        break;
    }

    line.Printf( absformatter, dXpos, dYpos );
    SetStatusText( line, 2 );

    if( !displ_opts->m_DisplayPolarCood )  // display relative cartesian coordinates
    {
        // Display relative coordinates:
        dx = GetCrossHairPosition().x - screen->m_O_Curseur.x;
        dy = GetCrossHairPosition().y - screen->m_O_Curseur.y;
        dXpos = To_User_Unit( g_UserUnit, dx );
        dYpos = To_User_Unit( g_UserUnit, dy );

        // We already decided the formatter above
        line.Printf( locformatter, dXpos, dYpos, hypot( dXpos, dYpos ) );
        SetStatusText( line, 3 );
    }
}
bool DRAWSEGMENT::HitTest( const wxPoint& aPosition )
{
    switch( m_Shape )
    {
    case S_CIRCLE:
    case S_ARC:
        {
            wxPoint relPos = aPosition - GetCenter();
            int radius = GetRadius();
            int dist   = KiROUND( EuclideanNorm( relPos ) );

            if( abs( radius - dist ) <= ( m_Width / 2 ) )
            {
                if( m_Shape == S_CIRCLE )
                    return true;

                // For arcs, the test point angle must be >= arc angle start
                // and <= arc angle end
                // However angle values > 360 deg are not easy to handle
                // so we calculate the relative angle between arc start point and teast point
                // this relative arc should be < arc angle if arc angle > 0 (CW arc)
                // and > arc angle if arc angle < 0 (CCW arc)
                double arc_angle_start = GetArcAngleStart();    // Always 0.0 ... 360 deg, in 0.1 deg

                double arc_hittest = ArcTangente( relPos.y, relPos.x );

                // Calculate relative angle between the starting point of the arc, and the test point
                arc_hittest -= arc_angle_start;

                // Normalise arc_hittest between 0 ... 360 deg
                NORMALIZE_ANGLE_POS( arc_hittest );

                // Check angle: inside the arc angle when it is > 0
                // and outside the not drawn arc when it is < 0
                if( GetAngle() >= 0.0 )
                {
                    if( arc_hittest <= GetAngle() )
                        return true;
                }
                else
                {
                    if( arc_hittest >= (3600.0 + GetAngle()) )
                        return true;
                }
            }
        }
        break;

    case S_CURVE:
        for( unsigned int i= 1; i < m_BezierPoints.size(); i++)
        {
            if( TestSegmentHit( aPosition, m_BezierPoints[i-1], m_BezierPoints[i-1], m_Width / 2 ) )
                return true;
        }
        break;

    case S_SEGMENT:
        if( TestSegmentHit( aPosition, m_Start, m_End, m_Width / 2 ) )
            return true;
        break;

    default:
        wxASSERT( 0 );
        break;
    }
    return false;
}
示例#24
0
void DRC::testTexts()
{
    std::vector<wxPoint> textShape;      // a buffer to store the text shape (set of segments)
    std::vector<D_PAD*> padList = m_pcb->GetPads();

    // Test text areas for vias, tracks and pads inside text areas
    for( BOARD_ITEM* item = m_pcb->m_Drawings; item; item = item->Next() )
    {
        // Drc test only items on copper layers
        if( ! IsCopperLayer( item->GetLayer() ) )
            continue;

        // only texts on copper layers are tested
        if( item->Type() !=  PCB_TEXT_T )
            continue;

        textShape.clear();

        // So far the bounding box makes up the text-area
        TEXTE_PCB* text = (TEXTE_PCB*) item;
        text->TransformTextShapeToSegmentList( textShape );

        if( textShape.size() == 0 )     // Should not happen (empty text?)
            continue;

        for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() )
        {
            if( ! track->IsOnLayer( item->GetLayer() ) )
                    continue;

            // Test the distance between each segment and the current track/via
            int min_dist = ( track->GetWidth() + text->GetThickness() ) /2 +
                           track->GetClearance(NULL);

            if( track->Type() == PCB_TRACE_T )
            {
                SEG segref( track->GetStart(), track->GetEnd() );

                // Error condition: Distance between text segment and track segment is
                // smaller than the clearance of the segment
                for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
                {
                    SEG segtest( textShape[jj], textShape[jj+1] );
                    int dist = segref.Distance( segtest );

                    if( dist < min_dist )
                    {
                        addMarkerToPcb( fillMarker( track, text,
                                                    DRCE_TRACK_INSIDE_TEXT,
                                                    m_currentMarker ) );
                        m_currentMarker = nullptr;
                        break;
                    }
                }
            }
            else if( track->Type() == PCB_VIA_T )
            {
                // Error condition: Distance between text segment and via is
                // smaller than the clearance of the via
                for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
                {
                    SEG segtest( textShape[jj], textShape[jj+1] );

                    if( segtest.PointCloserThan( track->GetPosition(), min_dist ) )
                    {
                        addMarkerToPcb( fillMarker( track, text,
                                                    DRCE_VIA_INSIDE_TEXT, m_currentMarker ) );
                        m_currentMarker = nullptr;
                        break;
                    }
                }
            }
        }

        // Test pads
        for( unsigned ii = 0; ii < padList.size(); ii++ )
        {
            D_PAD* pad = padList[ii];

            if( ! pad->IsOnLayer( item->GetLayer() ) )
                    continue;

            wxPoint shape_pos = pad->ShapePos();

            for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
            {
                /* In order to make some calculations more easier or faster,
                 * pads and tracks coordinates will be made relative
                 * to the segment origin
                 */
                wxPoint origin = textShape[jj];  // origin will be the origin of other coordinates
                m_segmEnd = textShape[jj+1] - origin;
                wxPoint delta = m_segmEnd;
                m_segmAngle = 0;

                // for a non horizontal or vertical segment Compute the segment angle
                // in tenths of degrees and its length
                if( delta.x || delta.y )    // delta.x == delta.y == 0 for vias
                {
                    // Compute the segment angle in 0,1 degrees
                    m_segmAngle = ArcTangente( delta.y, delta.x );

                    // Compute the segment length: we build an equivalent rotated segment,
                    // this segment is horizontal, therefore dx = length
                    RotatePoint( &delta, m_segmAngle );    // delta.x = length, delta.y = 0
                }

                m_segmLength = delta.x;
                m_padToTestPos = shape_pos - origin;

                if( !checkClearanceSegmToPad( pad, text->GetThickness(),
                                              pad->GetClearance(NULL) ) )
                {
                    addMarkerToPcb( fillMarker( pad, text,
                                                DRCE_PAD_INSIDE_TEXT, m_currentMarker ) );
                    m_currentMarker = nullptr;
                    break;
                }
            }
        }
    }
}
/**
 * Function TransformRoundedEndsSegmentToPolygon
 * convert a segment with rounded ends to a polygon
 * Convert arcs to multiple straight lines
 * @param aCornerBuffer = a buffer to store the polygon
 * @param aStart = the segment start point coordinate
 * @param aEnd = the segment end point coordinate
 * @param aCircleToSegmentsCount = the number of segments to approximate a circle
 * @param aWidth = the segment width
 * Note: the polygon is inside the arc ends, so if you want to have the polygon
 * outside the circle, you should give aStart and aEnd calculated with a correction factor
 */
void TransformRoundedEndsSegmentToPolygon( std::vector <CPolyPt>& aCornerBuffer,
                                           wxPoint aStart, wxPoint aEnd,
                                           int aCircleToSegmentsCount,
                                           int aWidth )
{
    int     radius = aWidth / 2;
    wxPoint endp   = aEnd - aStart; // end point coordinate for the same segment starting at (0,0)
    wxPoint startp = aStart;
    wxPoint corner;
    int     seg_len;
    CPolyPt polypoint;

    // normalize the position in order to have endp.x >= 0;
    if( endp.x < 0 )
    {
        endp   = aStart - aEnd;
        startp = aEnd;
    }

    int delta_angle = ArcTangente( endp.y, endp.x );    // delta_angle is in 0.1 degrees
    seg_len = (int) sqrt( ( (double) endp.y * endp.y ) + ( (double) endp.x * endp.x ) );

    int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree

    // Compute the outlines of the segment, and creates a polygon
    // add right rounded end:
    for( int ii = 0; ii < 1800; ii += delta )
    {
        corner = wxPoint( 0, radius );
        RotatePoint( &corner, ii );
        corner.x += seg_len;
        RotatePoint( &corner, -delta_angle );
        corner += startp;
        polypoint.x = corner.x;
        polypoint.y = corner.y;
        aCornerBuffer.push_back( polypoint );
    }

    // Finish arc:
    corner = wxPoint( seg_len, -radius );
    RotatePoint( &corner, -delta_angle );
    corner += startp;
    polypoint.x = corner.x;
    polypoint.y = corner.y;
    aCornerBuffer.push_back( polypoint );

    // add left rounded end:
    for( int ii = 0; ii < 1800; ii += delta )
    {
        corner = wxPoint( 0, -radius );
        RotatePoint( &corner, ii );
        RotatePoint( &corner, -delta_angle );
        corner += startp;
        polypoint.x = corner.x;
        polypoint.y = corner.y;
        aCornerBuffer.push_back( polypoint );
    }

    // Finish arc:
    corner = wxPoint( 0, radius );
    RotatePoint( &corner, -delta_angle );
    corner += startp;
    polypoint.x = corner.x;
    polypoint.y = corner.y;
    aCornerBuffer.push_back( polypoint );

    aCornerBuffer.back().end_contour = true;
}