コード例 #1
0
void TransformOvalClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                                wxPoint aStart, wxPoint aEnd, int aWidth,
                                int aCircleToSegmentsCount, double aCorrectionFactor )
{
    // To build the polygonal shape outside the actual shape, we use a bigger
    // radius to build rounded ends.
    // However, the width of the segment is too big.
    // so, later, we will clamp the polygonal shape with the bounding box
    // of the segment.
    int     radius  = aWidth / 2;

    // Note if we want to compensate the radius reduction of a circle due to
    // the segment approx, aCorrectionFactor must be calculated like this:
    // For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
    // aCorrectionFactor is 1 /cos( PI/s_CircleToSegmentsCount  )

    radius = radius * aCorrectionFactor;    // make segments outside the circles

    // end point is the coordinate relative to aStart
    wxPoint endp    = aEnd - aStart;
    wxPoint startp  = aStart;
    wxPoint corner;
    SHAPE_POLY_SET polyshape;

    polyshape.NewOutline();

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

    // delta_angle is in radian
    double delta_angle = atan2( (double)endp.y, (double)endp.x );
    int seg_len        = KiROUND( EuclideanNorm( endp ) );

    double delta = 3600.0 / aCircleToSegmentsCount;    // rot angle in 0.1 degree

    // Compute the outlines of the segment, and creates a polygon
    // Note: the polygonal shape is built from the equivalent horizontal
    // segment starting ar 0,0, and ending at seg_len,0

    // add right rounded end:
    for( int ii = 0; ii < aCircleToSegmentsCount/2; ii++ )
    {
        corner = wxPoint( 0, radius );
        RotatePoint( &corner, delta*ii );
        corner.x += seg_len;
        polyshape.Append( corner.x, corner.y );
    }

    // Finish arc:
    corner = wxPoint( seg_len, -radius );
    polyshape.Append( corner.x, corner.y );

    // add left rounded end:
    for( int ii = 0; ii < aCircleToSegmentsCount/2; ii++ )
    {
        corner = wxPoint( 0, -radius );
        RotatePoint( &corner, delta*ii );
        polyshape.Append( corner.x, corner.y );
    }

    // Finish arc:
    corner = wxPoint( 0, radius );
    polyshape.Append( corner.x, corner.y );

    // Now, clamp the polygonal shape (too big) with the segment bounding box
    // the polygonal shape bbox equivalent to the segment has a too big height,
    // and the right width
    if( aCorrectionFactor > 1.0 )
    {
        SHAPE_POLY_SET bbox;
        bbox.NewOutline();
        // Build the bbox (a horizontal rectangle).
        int halfwidth = aWidth / 2;     // Use the exact segment width for the bbox height
        corner.x = -radius - 2;         // use a bbox width slightly bigger to avoid
                                        // creating useless corner at segment ends
        corner.y = halfwidth;
        bbox.Append( corner.x, corner.y );
        corner.y = -halfwidth;
        bbox.Append( corner.x, corner.y );
        corner.x = radius + seg_len + 2;
        bbox.Append( corner.x, corner.y );
        corner.y = halfwidth;
        bbox.Append( corner.x, corner.y );

        // Now, clamp the shape
        polyshape.BooleanIntersection( bbox, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
        // Note the final polygon is a simple, convex polygon with no hole
        // due to the shape of initial polygons
    }

    // Rotate and move the polygon to its right location
    polyshape.Rotate( delta_angle, VECTOR2I( 0, 0 ) );
    polyshape.Move( startp );

    aCornerBuffer.Append( polyshape);
}
コード例 #2
0
bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos ) const
{
    // In case the item has a very tiny width defined, allow it to be selected
    const int MIN_HIT_TEST_RADIUS = Millimeter2iu( 0.01 );

    // calculate aRefPos in XY gerber axis:
    wxPoint ref_pos = GetXYPosition( aRefPos );

    SHAPE_POLY_SET poly;

    switch( m_Shape )
    {
    case GBR_POLYGON:
        poly = m_Polygon;
        return poly.Contains( VECTOR2I( ref_pos ), 0 );

    case GBR_SPOT_POLY:
        poly = GetDcodeDescr()->m_Polygon;
        poly.Move( m_Start );
        return poly.Contains( VECTOR2I( ref_pos ), 0 );

    case GBR_SPOT_RECT:
        return GetBoundingBox().Contains( aRefPos );

    case GBR_ARC:
        {
            double radius = GetLineLength( m_Start, m_ArcCentre );
            VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );

            int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS
                                                            : m_Size.x );

            // Are we close enough to the radius?
            bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );

            if( radius_hit )
            {
                // Now check that we are within the arc angle

                VECTOR2D start = VECTOR2D( m_Start ) - VECTOR2D( m_ArcCentre );
                VECTOR2D end = VECTOR2D( m_End ) - VECTOR2D( m_ArcCentre );

                double start_angle = NormalizeAngleRadiansPos( start.Angle() );
                double end_angle = NormalizeAngleRadiansPos( end.Angle() );

                if( m_Start == m_End )
                {
                    start_angle = 0;
                    end_angle = 2 * M_PI;
                }
                else if( end_angle < start_angle )
                {
                    end_angle += 2 * M_PI;
                }

                double test_angle = NormalizeAngleRadiansPos( test_radius.Angle() );

                return ( test_angle > start_angle && test_angle < end_angle );
            }

            return false;
        }

    case GBR_SPOT_MACRO:
        // Aperture macro polygons are already in absolute coordinates
        auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
        for( int i = 0; i < p->OutlineCount(); ++i )
        {
            if( p->Contains( VECTOR2I( aRefPos ), i ) )
                return true;
        }
        return false;
    }

    // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
    int radius = std::min( m_Size.x, m_Size.y ) >> 1;

    if( radius < MIN_HIT_TEST_RADIUS )
        radius = MIN_HIT_TEST_RADIUS;

    if( m_Flashed )
        return HitTestPoints( m_Start, ref_pos, radius );
    else
        return TestSegmentHit( ref_pos, m_Start, m_End, radius );
}
コード例 #3
0
void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                                  const wxPoint& aPosition, const wxSize& aSize,
                                  double aRotation, int aCornerRadius,
                                  double aChamferRatio, int aChamferCorners,
                                  int aCircleToSegmentsCount )
{
    // Build the basic shape in orientation 0.0, position 0,0 for chamfered corners
    // or in actual position/orientation for round rect only
    wxPoint corners[4];
    GetRoundRectCornerCenters( corners, aCornerRadius,
                               aChamferCorners ? wxPoint( 0, 0 ) : aPosition,
                               aSize, aChamferCorners ? 0.0 : aRotation );

    SHAPE_POLY_SET outline;
    outline.NewOutline();

    for( int ii = 0; ii < 4; ++ii )
        outline.Append( corners[ii].x, corners[ii].y );

    outline.Inflate( aCornerRadius, aCircleToSegmentsCount );

    if( aChamferCorners == RECT_NO_CHAMFER )      // no chamfer
    {
        // Add the outline:
        aCornerBuffer.Append( outline );
        return;
    }

    // Now we have the round rect outline, in position 0,0 orientation 0.0.
    // Chamfer the corner(s).
    int chamfer_value = aChamferRatio * std::min( aSize.x, aSize.y );

    SHAPE_POLY_SET chamfered_corner;    // corner shape for the current corner to chamfer

    int corner_id[4] =
    {
        RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT,
        RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT
    };
    // Depending on the corner position, signX[] and signY[] give the sign of chamfer
    // coordinates relative to the corner position
    // The first corner is the top left corner, then top right, bottom left and bottom right
    int signX[4] = {1, -1, 1,-1 };
    int signY[4] = {1, 1, -1,-1 };

    for( int ii = 0; ii < 4; ii++ )
    {
        if( (corner_id[ii] & aChamferCorners) == 0 )
            continue;

        VECTOR2I corner_pos( -signX[ii]*aSize.x/2, -signY[ii]*aSize.y/2 );

        if( aCornerRadius )
        {
            // We recreate a rectangular area covering the full rounded corner (max size = aSize/2)
            // to rebuild the corner before chamfering, to be sure the rounded corner shape does not
            // overlap the chamfered corner shape:
            chamfered_corner.RemoveAllContours();
            chamfered_corner.NewOutline();
            chamfered_corner.Append( 0, 0 );
            chamfered_corner.Append( 0, signY[ii]*aSize.y/2 );
            chamfered_corner.Append( signX[ii]*aSize.x/2, signY[ii]*aSize.y/2 );
            chamfered_corner.Append( signX[ii]*aSize.x/2, 0 );
            chamfered_corner.Move( corner_pos );
            outline.BooleanAdd( chamfered_corner, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
        }

        // Now chamfer this corner
        chamfered_corner.RemoveAllContours();
        chamfered_corner.NewOutline();
        chamfered_corner.Append( 0, 0 );
        chamfered_corner.Append( 0, signY[ii]*chamfer_value );
        chamfered_corner.Append( signX[ii]*chamfer_value, 0 );
        chamfered_corner.Move( corner_pos );
        outline.BooleanSubtract( chamfered_corner, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
    }

    // Rotate and move the outline:
    if( aRotation != 0.0 )
        outline.Rotate( DECIDEG2RAD( -aRotation ), VECTOR2I( 0, 0 ) );

    outline.Move( VECTOR2I( aPosition ) );

    // Add the outline:
    aCornerBuffer.Append( outline );
}