TRACK* SPECCTRA_DB::makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IO_ERROR )
{
    int layerNdx = findLayerName( aPath->layer_id );

    if( layerNdx == -1 )
    {
        wxString layerName = FROM_UTF8( aPath->layer_id.c_str() );
        THROW_IO_ERROR( wxString::Format( _("Session file uses invalid layer id \"%s\""),
                                          GetChars( layerName ) ) );
    }

    TRACK* track = new TRACK( sessionBoard );

    track->SetStart( mapPt( aPath->points[aPointIndex+0], routeResolution ) );
    track->SetEnd( mapPt( aPath->points[aPointIndex+1], routeResolution ) );
    track->SetLayer( pcbLayer2kicad[layerNdx] );
    track->SetWidth( scale( aPath->aperture_width, routeResolution ) );
    track->SetNetCode( aNetcode );

    return track;
}
void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IO_ERROR )
{
    sessionBoard = aBoard;      // not owned here

    if( !session )
        THROW_IO_ERROR( _("Session file is missing the \"session\" section") );

    /* Dick 16-Jan-2012: session need not have a placement section.
    if( !session->placement )
        THROW_IO_ERROR( _("Session file is missing the \"placement\" section") );
    */

    if( !session->route )
        THROW_IO_ERROR( _("Session file is missing the \"routes\" section") );

    if( !session->route->library )
        THROW_IO_ERROR( _("Session file is missing the \"library_out\" section") );

    // delete all the old tracks and vias
    aBoard->m_Track.DeleteAll();

    aBoard->DeleteMARKERs();

    buildLayerMaps( aBoard );

    if( session->placement )
    {
        // Walk the PLACEMENT object's COMPONENTs list, and for each PLACE within
        // each COMPONENT, reposition and re-orient each component and put on
        // correct side of the board.
        COMPONENTS& components = session->placement->components;
        for( COMPONENTS::iterator comp=components.begin();  comp!=components.end();  ++comp )
        {
            PLACES& places = comp->places;
            for( unsigned i=0; i<places.size();  ++i )
            {
                PLACE* place = &places[i];  // '&' even though places[] holds a pointer!

                wxString reference = FROM_UTF8( place->component_id.c_str() );
                MODULE* module = aBoard->FindModuleByReference( reference );
                if( !module )
                {
                    THROW_IO_ERROR( wxString::Format( _("Session file has 'reference' to non-existent component \"%s\""),
                                                      GetChars( reference ) ) );
                }

                if( !place->hasVertex )
                    continue;

                UNIT_RES* resolution = place->GetUnits();
                wxASSERT( resolution );

                wxPoint newPos = mapPt( place->vertex, resolution );
                module->SetPosition( newPos );

                if( place->side == T_front )
                {
                    // convert from degrees to tenths of degrees used in KiCad.
                    int orientation = KiROUND( place->rotation * 10.0 );

                    if( module->GetLayer() != F_Cu )
                    {
                        // module is on copper layer (back)
                        module->Flip( module->GetPosition() );
                    }

                    module->SetOrientation( orientation );
                }
                else if( place->side == T_back )
                {
                    int orientation = KiROUND( (place->rotation + 180.0) * 10.0 );

                    if( module->GetLayer() != B_Cu )
                    {
                        // module is on component layer (front)
                        module->Flip( module->GetPosition() );
                    }

                    module->SetOrientation( orientation );
                }
                else
                {
                    // as I write this, the PARSER *is* catching this, so we should never see below:
                    wxFAIL_MSG( wxT("DSN::PARSER did not catch an illegal side := 'back|front'") );
                }
            }
        }
    }

    routeResolution = session->route->GetUnits();

    // Walk the NET_OUTs and create tracks and vias anew.
    NET_OUTS& net_outs = session->route->net_outs;
    for( NET_OUTS::iterator net = net_outs.begin(); net!=net_outs.end(); ++net )
    {
        int         netCode = 0;

        // page 143 of spec says wire's net_id is optional
        if( net->net_id.size() )
        {
            wxString netName = FROM_UTF8( net->net_id.c_str() );
            NETINFO_ITEM* netinfo = aBoard->FindNet( netName );

            if( netinfo )
                netCode = netinfo->GetNet();
            else  // else netCode remains 0
            {
                // int breakhere = 1;
            }
        }

        WIRES& wires = net->wires;
        for( unsigned i = 0; i<wires.size(); ++i )
        {
            WIRE*   wire  = &wires[i];
            DSN_T   shape = wire->shape->Type();

            if( shape != T_path )
            {
                /*  shape == T_polygon is expected from freerouter if you have
                    a zone on a non "power" type layer, i.e. a T_signal layer
                    and the design does a round trip back in as session here.
                    We kept our own zones in the BOARD, so ignore this so called
                    'wire'.

                wxString netId = FROM_UTF8( wire->net_id.c_str() );
                THROW_IO_ERROR( wxString::Format( _("Unsupported wire shape: \"%s\" for net: \"%s\""),
                                                    DLEX::GetTokenString(shape).GetData(),
                                                    netId.GetData()
                    ) );
                */
            }
            else
            {
                PATH*   path = (PATH*) wire->shape;
                for( unsigned pt=0;  pt<path->points.size()-1;  ++pt )
                {
                    /* a debugging aid, may come in handy
                    if( path->points[pt].x == 547800
                    &&  path->points[pt].y == -380250 )
                    {
                        int breakhere = 1;
                    }
                    */

                    TRACK* track = makeTRACK( path, pt, netCode );
                    aBoard->Add( track );
                }
            }
        }

        WIRE_VIAS& wire_vias = net->wire_vias;
        LIBRARY& library = *session->route->library;
        for( unsigned i=0;  i<wire_vias.size();  ++i )
        {
            int         netCode = 0;

            // page 144 of spec says wire_via's net_id is optional
            if( net->net_id.size() )
            {
                wxString netName = FROM_UTF8( net->net_id.c_str() );

                NETINFO_ITEM* net = aBoard->FindNet( netName );
                if( net )
                    netCode = net->GetNet();

                // else netCode remains 0
            }

            WIRE_VIA* wire_via = &wire_vias[i];

            // example: (via Via_15:8_mil 149000 -71000 )

            PADSTACK* padstack = library.FindPADSTACK( wire_via->GetPadstackId() );
            if( !padstack )
            {
                // Dick  Feb 29, 2008:
                // Freerouter has a bug where it will not round trip all vias.
                // Vias which have a (use_via) element will be round tripped.
                // Vias which do not, don't come back in in the session library,
                // even though they may be actually used in the pre-routed,
                // protected wire_vias. So until that is fixed, create the
                // padstack from its name as a work around.


                // Could use a STRING_FORMATTER here and convert the entire
                // wire_via to text and put that text into the exception.
                wxString psid( FROM_UTF8( wire_via->GetPadstackId().c_str() ) );

                THROW_IO_ERROR( wxString::Format( _("A wire_via references a missing padstack \"%s\""),
                                                  GetChars( psid ) ) );
            }

            NETCLASSPTR netclass = aBoard->GetDesignSettings().m_NetClasses.GetDefault();

            int via_drill_default = netclass->GetViaDrill();

            for( unsigned v=0;  v<wire_via->vertexes.size();  ++v )
            {
                ::VIA* via = makeVIA( padstack, wire_via->vertexes[v], netCode, via_drill_default );
                aBoard->Add( via );
            }
        }
    }
}
::VIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint,
            int aNetCode, int aViaDrillDefault )
    throw( IO_ERROR )
{
    ::VIA*  via = 0;
    SHAPE*  shape;

    int     shapeCount = aPadstack->Length();
    int     drill_diam_iu = -1;
    int     copperLayerCount = sessionBoard->GetCopperLayerCount();


    // The drill diameter is encoded in the padstack name if Pcbnew did the DSN export.
    // It is after the colon and before the last '_'
    int     drillStartNdx = aPadstack->padstack_id.find( ':' );

    if( drillStartNdx != -1 )
    {
        ++drillStartNdx;    // skip over the ':'

        int drillEndNdx = aPadstack->padstack_id.rfind( '_' );
        if( drillEndNdx != -1 )
        {
            std::string diam_txt( aPadstack->padstack_id,
                            drillStartNdx, drillEndNdx-drillStartNdx );

            double drill_um = strtod( diam_txt.c_str(), 0 );

            drill_diam_iu = int( drill_um * (IU_PER_MM / 1000.0) );

            if( drill_diam_iu == aViaDrillDefault )
                drill_diam_iu = UNDEFINED_DRILL_DIAMETER;
        }
    }

    if( shapeCount == 0 )
    {
        THROW_IO_ERROR( _( "Session via padstack has no shapes" ) );
    }
    else if( shapeCount == 1 )
    {
        shape = (SHAPE*) (*aPadstack)[0];
        DSN_T type = shape->shape->Type();
        if( type != T_circle )
            THROW_IO_ERROR( wxString::Format( _( "Unsupported via shape: %s"),
                                              GetChars( GetTokenString( type ) ) ) );

        CIRCLE* circle = (CIRCLE*) shape->shape;
        int viaDiam = scale( circle->diameter, routeResolution );

        via = new ::VIA( sessionBoard );
        via->SetPosition( mapPt( aPoint, routeResolution ) );
        via->SetDrill( drill_diam_iu );
        via->SetViaType( VIA_THROUGH );
        via->SetWidth( viaDiam );
        via->SetLayerPair( F_Cu, B_Cu );
    }
    else if( shapeCount == copperLayerCount )
    {
        shape = (SHAPE*) (*aPadstack)[0];
        DSN_T type = shape->shape->Type();
        if( type != T_circle )
            THROW_IO_ERROR( wxString::Format( _( "Unsupported via shape: %s"),
                                              GetChars( GetTokenString( type ) ) ) );

        CIRCLE* circle = (CIRCLE*) shape->shape;
        int viaDiam = scale( circle->diameter, routeResolution );

        via = new ::VIA( sessionBoard );
        via->SetPosition( mapPt( aPoint, routeResolution ) );
        via->SetDrill( drill_diam_iu );
        via->SetViaType( VIA_THROUGH );
        via->SetWidth( viaDiam );
        via->SetLayerPair( F_Cu, B_Cu );
    }
    else    // VIA_MICROVIA or VIA_BLIND_BURIED
    {
        int topLayerNdx = -1;           // session layer detectors
        int botLayerNdx = INT_MAX;

        int viaDiam = -1;

        for( int i=0; i<shapeCount;  ++i )
        {
            shape = (SHAPE*) (*aPadstack)[i];
            DSN_T type = shape->shape->Type();
            if( type != T_circle )
                THROW_IO_ERROR( wxString::Format( _( "Unsupported via shape: %s"),
                                                  GetChars( GetTokenString( type ) ) ) );

            CIRCLE* circle = (CIRCLE*) shape->shape;

            int layerNdx = findLayerName( circle->layer_id );
            if( layerNdx == -1 )
            {
                wxString layerName = FROM_UTF8( circle->layer_id.c_str() );
                THROW_IO_ERROR( wxString::Format( _("Session file uses invalid layer id \"%s\""),
                                                  GetChars( layerName ) ) );
            }

            if( layerNdx > topLayerNdx )
                topLayerNdx = layerNdx;

            if( layerNdx < botLayerNdx )
                botLayerNdx = layerNdx;

            if( viaDiam == -1 )
                viaDiam = scale( circle->diameter, routeResolution );
        }

        via = new ::VIA( sessionBoard );
        via->SetPosition( mapPt( aPoint, routeResolution ) );
        via->SetDrill( drill_diam_iu );

        if( (topLayerNdx==0 && botLayerNdx==1)
         || (topLayerNdx==copperLayerCount-2 && botLayerNdx==copperLayerCount-1))
            via->SetViaType( VIA_MICROVIA );
        else
            via->SetViaType( VIA_BLIND_BURIED );

        via->SetWidth( viaDiam );

        LAYER_ID topLayer = pcbLayer2kicad[topLayerNdx];
        LAYER_ID botLayer = pcbLayer2kicad[botLayerNdx];

        via->SetLayerPair( topLayer, botLayer );
    }

    if( via )
        via->SetNetCode( aNetCode );

    return via;
}
Ejemplo n.º 4
0
void AM_PRIMITIVE::DrawBasicShape( const GERBER_DRAW_ITEM* aParent,
                                   SHAPE_POLY_SET& aShapeBuffer,
                                   wxPoint aShapePos )
{
    #define TO_POLY_SHAPE { aShapeBuffer.NewOutline(); \
                            for( unsigned jj = 0; jj < polybuffer.size(); jj++ )\
                                aShapeBuffer.Append( polybuffer[jj].x, polybuffer[jj].y );\
                            aShapeBuffer.Append( polybuffer[0].x, polybuffer[0].y );}

    // Draw the primitive shape for flashed items.
    static std::vector<wxPoint> polybuffer;     // create a static buffer to avoid a lot of memory reallocation
    polybuffer.clear();

    wxPoint curPos = aShapePos;
    D_CODE* tool   = aParent->GetDcodeDescr();
    double rotation;

    switch( primitive_id )
    {
    case AMP_CIRCLE:        // Circle, given diameter and position
    {
        /* 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
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation (if any):
        if( params.size() >= 5 )
        {
            rotation = params[4].GetValue( tool ) * 10.0;

            if( rotation != 0)
            {
                for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                    RotatePoint( &polybuffer[ii], -rotation );
            }
        }


        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;
    }
    break;

    case AMP_LINE2:
    case AMP_LINE20:        // Line with rectangle ends. (Width, start and end pos + rotation)
    {
        /* Vector Line, Primitive Code 20.
         * A vector line is a rectangle defined by its line width, start and end points.
         * The line ends are rectangular.
        */
        /* Generated by an aperture macro declaration like:
         * "2,1,0.3,0,0, 0.5, 1.0,-135*"
         * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[6].GetValue( tool ) * 10.0;

        if( rotation != 0)
        {
            for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;
    }
    break;

    case AMP_LINE_CENTER:
    {
        /* Center Line, Primitive Code 21
         * A center line primitive is a rectangle defined by its width, height, and center point
         */
        /* Generated by an aperture macro declaration like:
         * "21,1,0.3,0.03,0,0,-135*"
         * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[5].GetValue( tool ) * 10.0;

        if( rotation != 0 )
        {
            for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;
    }
    break;

    case AMP_LINE_LOWER_LEFT:
    {
        /* Generated by an aperture macro declaration like:
         * "22,1,0.3,0.03,0,0,-135*"
         * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[5].GetValue( tool ) * 10.0;
        if( rotation != 0)
        {
            for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;
    }
    break;

    case AMP_THERMAL:
    {
        /* Generated by an aperture macro declaration like:
         * "7, 0,0,1.0,0.3,0.01,-13*"
         * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
         * type is not stored in parameters list, so the first parameter is center.x
         *
         * The thermal primitive is a ring (annulus) interrupted by four gaps. Exposure is always on.
         */
        std::vector<wxPoint> subshape_poly;
        curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
        ConvertShapeToPolygon( aParent, subshape_poly );

        // shape rotation:
        rotation = params[5].GetValue( tool ) * 10.0;

        // Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly.
        // We must draw 4 sub-shapes rotated by 90 deg
        for( int ii = 0; ii < 4; ii++ )
        {
            polybuffer = subshape_poly;
            double sub_rotation = rotation + 900 * ii;

            for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
                RotatePoint( &polybuffer[jj], -sub_rotation );

            // Move to current position:
            for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
            {
                polybuffer[jj] += curPos;
                polybuffer[jj] = aParent->GetABPosition( polybuffer[jj] );
            }

            TO_POLY_SHAPE;
        }
    }
    break;

    case AMP_MOIRE:
    {
        /* Moir�, Primitive Code 6
         * The moir� primitive is a cross hair centered on concentric rings (annuli).
         * Exposure is always on.
         */
        curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
                         m_GerbMetric );

        /* Generated by an aperture macro declaration like:
         * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
         * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation
         * type is not stored in parameters list, so the first parameter is pos.x
         */
        int outerDiam    = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
        int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
        int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
        int numCircles = KiROUND( params[5].GetValue( tool ) );

        // Draw circles:
        wxPoint center = aParent->GetABPosition( curPos );
        // adjust outerDiam by this on each nested circle
        int diamAdjust = (gap + penThickness) * 2;

        for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
        {
            if( outerDiam <= 0 )
                break;

            // Note: outerDiam is the outer diameter of the ring.
            // the ring graphic diameter is (outerDiam - penThickness)
            if( outerDiam <= penThickness )
            {   // No room to draw a ring (no room for the hole):
                // draw a circle instead (with no hole), with the right diameter
                TransformCircleToPolygon( aShapeBuffer, center,
                                          outerDiam / 2, seg_per_circle );
            }
            else
                TransformRingToPolygon( aShapeBuffer, center,
                                        (outerDiam - penThickness) / 2,
                                        seg_per_circle, penThickness );
        }

        // Draw the cross:
        ConvertShapeToPolygon( aParent, polybuffer );

        rotation = params[8].GetValue( tool ) * 10.0;
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            // shape rotation:
            RotatePoint( &polybuffer[ii], -rotation );
            // Move to current position:
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;
    }
        break;

    case AMP_OUTLINE:
    {
        /* Outline, Primitive Code 4
         * An outline primitive is an area enclosed by an n-point polygon defined by its start point and n
         * subsequent points. The outline must be closed, i.e. the last point must be equal to the start
         * point. There must be at least one subsequent point (to close the outline).
         * The outline of the primitive is actually the contour (see 2.6) that consists of linear segments
         * only, so it must conform to all the requirements described for contours.
         * Warning: Make no mistake: n is the number of subsequent points, being the number of
         * vertices of the outline or one less than the number of coordinate pairs.
        */
        /* Generated by an aperture macro declaration like:
         * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25"
         * type(4), exposure, corners count, corner1.x, corner.1y, ..., corner1.x, corner.1y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        // params[0] is the exposure and params[1] is the corners count after the first corner
        int numCorners = (int) params[1].GetValue( tool );
        // the shape rotation is the last param of list, after corners
        int last_prm = params.size() - 1;
        rotation  = params[last_prm].GetValue( tool ) * 10.0;
        wxPoint pos;

        // Read points.
        // Note: numCorners is the polygon corner count, following the first corner
        // * the polygon is always closed,
        // * therefore the last XY coordinate is the same as the first
        int prm_idx = 2;    //  params[2] is the first X coordinate
        for( int i = 0; i <= numCorners; ++i )
        {
            pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
            prm_idx++;
            pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
            prm_idx++;
            polybuffer.push_back(pos);

            // Guard: ensure prm_idx < last_prm
            // I saw malformed gerber files with numCorners = number
            // of coordinates instead of number of coordinates following the first point
            if( prm_idx >= last_prm )
                break;
        }
        // rotate polygon and move it to the actual position
        // shape rotation:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            RotatePoint( &polybuffer[ii], -rotation );
       }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;
    }
        break;

    case AMP_POLYGON:
        /* Polygon, Primitive Code 5
         * A polygon primitive is a regular polygon defined by the number of vertices n, the center point
         * and the diameter of the circumscribed circle
        */
        /* Generated by an aperture macro declaration like:
         * "5,1,0.6,0,0,0.5,25"
         * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
        // Creates the shape:
        ConvertShapeToPolygon( aParent, polybuffer );

        // rotate polygon and move it to the actual position
        rotation  = params[5].GetValue( tool ) * 10.0;
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            RotatePoint( &polybuffer[ii], -rotation );
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        TO_POLY_SHAPE;

        break;

    case AMP_EOF:
        // not yet supported, waiting for you.
        break;

    case AMP_UNKNOWN:
    default:
        DBG( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) );
        break;
    }
}
Ejemplo n.º 5
0
/** GetShapeDim
 * Calculate a value that can be used to evaluate the size of text
 * when displaying the D-Code of an item
 * due to the complexity of the shape of some primitives
 * one cannot calculate the "size" of a shape (only abounding box)
 * but here, the "dimension" of the shape is the diameter of the primitive
 * or for lines the width of the line
 * @param aParent = the parent GERBER_DRAW_ITEM which is actually drawn
 * @return a dimension, or -1 if no dim to calculate
  */
int AM_PRIMITIVE::GetShapeDim( const GERBER_DRAW_ITEM* aParent )
{
    int dim = -1;
    D_CODE* tool = aParent->GetDcodeDescr();

    switch( primitive_id )
    {
    case AMP_CIRCLE:
        // params = exposure, diameter, pos.x, pos.y
        dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );     // Diameter
        break;

    case AMP_LINE2:
    case AMP_LINE20:        // Line with rectangle ends. (Width, start and end pos + rotation)
        dim  = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );   // linne width
    break;

    case AMP_LINE_CENTER:
    {
        wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
        dim = std::min(size.x, size.y);
    }
    break;

    case AMP_LINE_LOWER_LEFT:
    {
        wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
        dim = std::min(size.x, size.y);
    }
    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
        dim   = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2;  // Outer diam
    }
    break;

    case AMP_MOIRE:     // A cross hair with n concentric circles.
        dim = scaletoIU( params[7].GetValue( tool ), m_GerbMetric );    // = cross hair len
        break;

    case AMP_OUTLINE:   // a free polygon :
    // dim = min side of the bounding box (this is a poor criteria, but what is a good criteria b?)
    {
        // exposure, corners count, corner1.x, corner.1y, ..., rotation
        // note: corners count is the count of corners following corner1
        int numPoints = (int) params[1].GetValue( tool );
        // Read points. numPoints does not include the starting point, so add 1.
        // and calculate the bounding box;
        wxSize pos_min, pos_max, pos;
        int prm_idx = 2;    //  params[2] is the first X coordinate
        int last_prm = params.size() - 1;

        for( int i = 0; i<= numPoints; ++i )
        {
            pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
            prm_idx++;
            pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
            prm_idx++;
            if( i == 0 )
                pos_min = pos_max = pos;
            else
            {
                // upper right corner:
                if( pos_min.x > pos.x )
                    pos_min.x = pos.x;
                if( pos_min.y > pos.y )
                    pos_min.y = pos.y;
                // lower left corner:
                if( pos_max.x < pos.x )
                    pos_max.x = pos.x;
                if( pos_max.y < pos.y )
                    pos_max.y = pos.y;
            }

            // Guard: ensure prm_idx < last_prm (last prm is orientation)
            // I saw malformed gerber files with numCorners = number
            // of coordinates instead of number of coordinates following the first point
            if( prm_idx >= last_prm )
                break;
        }
        // calculate dim
        wxSize size;
        size.x = pos_max.x - pos_min.x;
        size.y = pos_max.y - pos_min.y;
        dim = std::min( size.x, size.y );
    }
        break;

    case AMP_POLYGON:   // Regular polygon
        dim = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;      // Radius
        break;

    case AMP_COMMENT:
    case AMP_UNKNOWN:
    case AMP_EOF:
        break;
    }
    return dim;
}
Ejemplo n.º 6
0
/**
 * 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;
    }
}
/**
 * Function DrawBasicShape
 * Draw the primitive shape for flashed items.
 */
void AM_PRIMITIVE::DrawBasicShape( GERBER_DRAW_ITEM* aParent,
                                   EDA_RECT* aClipBox,
                                   wxDC* aDC,
                                   EDA_COLOR_T aColor, EDA_COLOR_T aAltColor,
                                   wxPoint aShapePos,
                                   bool aFilledShape )
{
    static std::vector<wxPoint> polybuffer;     // create a static buffer to avoid a lot of memory reallocation
    polybuffer.clear();

    wxPoint curPos = aShapePos;
    D_CODE* tool   = aParent->GetDcodeDescr();
    double rotation;
    if( mapExposure( aParent ) == false )
    {
        EXCHG(aColor, aAltColor);
    }

    switch( primitive_id )
    {
    case AMP_CIRCLE:        // Circle, given diameter and position
    {
        /* Generated by an aperture macro declaration like:
         * "1,1,0.3,0.5, 1.0*"
         * type (1), exposure, diameter, pos.x, pos.y
         * type is not stored in parameters list, so the first parameter is exposure
         */
        curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
        curPos = aParent->GetABPosition( curPos );
        int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2;
        if( !aFilledShape )
            GRCircle( aClipBox, aDC, curPos, radius, 0, aColor );
        else
            GRFilledCircle( aClipBox, aDC, curPos, radius, aColor );
    }
    break;

    case AMP_LINE2:
    case AMP_LINE20:        // Line with rectangle ends. (Width, start and end pos + rotation)
    {
        /* Generated by an aperture macro declaration like:
         * "2,1,0.3,0,0, 0.5, 1.0,-135*"
         * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[6].GetValue( tool ) * 10.0;
        if( rotation != 0)
        {
            for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        GRClosedPoly( aClipBox, aDC,
                      polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
    }
    break;

    case AMP_LINE_CENTER:
    {
        /* Generated by an aperture macro declaration like:
         * "21,1,0.3,0.03,0,0,-135*"
         * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[5].GetValue( tool ) * 10.0;
        if( rotation != 0 )
        {
            for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        GRClosedPoly( aClipBox, aDC,
                      polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
    }
    break;

    case AMP_LINE_LOWER_LEFT:
    {
        /* Generated by an aperture macro declaration like:
         * "22,1,0.3,0.03,0,0,-135*"
         * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[5].GetValue( tool ) * 10.0;
        if( rotation != 0)
        {
            for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
                RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        GRClosedPoly( aClipBox, aDC,
                      polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
    }
    break;

    case AMP_THERMAL:
    {
        /* Generated by an aperture macro declaration like:
         * "7, 0,0,1.0,0.3,0.01,-13*"
         * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
         * type is not stored in parameters list, so the first parameter is center.x
         */
        curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
        ConvertShapeToPolygon( aParent, polybuffer );

        // shape rotation:
        rotation = params[5].GetValue( tool ) * 10.0;

        // Because a thermal shape has 4 identical sub-shapes, only one is created in polybuffer.
        // We must draw 4 sub-shapes rotated by 90 deg
        std::vector<wxPoint> subshape_poly;
        for( int ii = 0; ii < 4; ii++ )
        {
            subshape_poly = polybuffer;
            double sub_rotation = rotation + 900 * ii;
            for( unsigned jj = 0; jj < subshape_poly.size(); jj++ )
                RotatePoint( &subshape_poly[jj], -sub_rotation );

            // Move to current position:
            for( unsigned jj = 0; jj < subshape_poly.size(); jj++ )
            {
                subshape_poly[jj] += curPos;
                subshape_poly[jj] = aParent->GetABPosition( subshape_poly[jj] );
            }

            GRClosedPoly( aClipBox, aDC,
                          subshape_poly.size(), &subshape_poly[0], true, aAltColor,
                          aAltColor );
        }
    }
    break;

    case AMP_MOIRE:     // A cross hair with n concentric circles
    {
        curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
                         m_GerbMetric );

        /* Generated by an aperture macro declaration like:
         * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
         * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation
         * type is not stored in parameters list, so the first parameter is pos.x
         */
        int outerDiam    = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
        int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
        int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
        int numCircles = KiROUND( params[5].GetValue( tool ) );

        // Draw circles:
        wxPoint center = aParent->GetABPosition( curPos );
        // adjust outerDiam by this on each nested circle
        int diamAdjust = (gap + penThickness); //*2;     //Should we use * 2 ?
        for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
        {
            if( outerDiam <= 0 )
                break;
            if( !aFilledShape )
            {
                // draw the border of the pen's path using two circles, each as narrow as possible
                GRCircle( aClipBox, aDC, center, outerDiam / 2, 0, aColor );
                GRCircle( aClipBox, aDC, center, outerDiam / 2 - penThickness, 0, aColor );
            }
            else    // Filled mode
            {
                GRCircle( aClipBox, aDC, center,
                          (outerDiam - penThickness) / 2, penThickness, aColor );
            }
        }

        // Draw the cross:
        ConvertShapeToPolygon( aParent, polybuffer );

        rotation = params[8].GetValue( tool ) * 10.0;
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            // shape rotation:
            RotatePoint( &polybuffer[ii], -rotation );
            // Move to current position:
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        GRClosedPoly( aClipBox, aDC,
                      polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
    }
    break;

    case AMP_OUTLINE:
    {
        /* Generated by an aperture macro declaration like:
         * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25"
         * type(4), exposure, corners count, corner1.x, corner.1y, ..., rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        int numPoints = (int) params[1].GetValue( tool );
        rotation  = params[numPoints * 2 + 4].GetValue( tool ) * 10.0;
        wxPoint pos;
        // Read points. numPoints does not include the starting point, so add 1.
        for( int i = 0; i<numPoints + 1; ++i )
        {
            int jj = i * 2 + 2;
            pos.x = scaletoIU( params[jj].GetValue( tool ), m_GerbMetric );
            pos.y = scaletoIU( params[jj + 1].GetValue( tool ), m_GerbMetric );
            polybuffer.push_back(pos);
        }
        // rotate polygon and move it to the actual position
        // shape rotation:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            RotatePoint( &polybuffer[ii], -rotation );
        }

        // Move to current position:
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }

        GRClosedPoly( aClipBox, aDC,
                      polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
    }
    break;

    case AMP_POLYGON:   // Is a regular polygon
        /* Generated by an aperture macro declaration like:
         * "5,1,0.6,0,0,0.5,25"
         * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
         * type is not stored in parameters list, so the first parameter is exposure
         */
        curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
        // Creates the shape:
        ConvertShapeToPolygon( aParent, polybuffer );

        // rotate polygon and move it to the actual position
        rotation  = params[5].GetValue( tool ) * 10.0;
        for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
        {
            RotatePoint( &polybuffer[ii], -rotation );
            polybuffer[ii] += curPos;
            polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
        }
        GRClosedPoly( aClipBox, aDC,
                      polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
        break;

    case AMP_EOF:
        // not yet supported, waiting for you.
        break;

    case AMP_UNKNOWN:
    default:
        DBG( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) );
        break;
    }
}
/*------------------------------------------------------------------------------
| DrawingArea::mouseMoved                                                      |
|                                                                              |
| Handle button 1 down mouse move events.  This allows data points to be       |
| moved while the object is drawn with a rubber band effect.                   |
------------------------------------------------------------------------------*/
Boolean DrawingArea::mouseMoved( IMouseEvent& event )
{
  IPoint point(event.mousePosition());
  if ( hasPointerCaptured() )
  {
    IRectangle windowRect(this->rect());
    windowRect.moveTo(IPoint(0,0));
    if (!windowRect.contains(point))
    {
      if ((short)point.x() < (short)windowRect.left())
        point.setX(windowRect.left());
      else if ((short)point.x() > (short)windowRect.right())
        point.setX(windowRect.right());
      else if ((short)point.y() < (short)windowRect.bottom())
        point.setY(windowRect.bottom());
      else if ((short)point.y() > (short)windowRect.top())
        point.setY(windowRect.top());

      IPoint mapPt( IWindow::mapPoint( point,
                                       this->handle(),
                                       IWindow::desktopWindow()->handle()));

      IWindow::movePointerTo( mapPt );
    }
  }

  // If we're not moving an object
  if (!moveGraphic)
  {
    if (( drawState() == drawing ) || ( drawState() == waitingForInput ))
    {
      switch (currentObj)
      {
        case move:
        break;
        case eraser:
        break;
        case stylecan:
        break;
        case line:
          ((IGLine*)iGraphic)->drawOn( gc );
          ((IGLine*)iGraphic)->setEndingPoint( point );
          ((IGLine*)iGraphic)->drawOn( gc );
        break;
        case freehand:
          ((IGPolygon*)iGraphic)->addPoint( point );
          ((IGPolyline*)iGraphic)->IGPolyline::drawOn( gc );
        break;
        case rectangle:
        {
          IRectangle rc(((IGRectangle*)iGraphic)->enclosingRect());
          iGraphic->drawOn( gc );
          rc.sizeTo( rc.size() + point - previousPt );
          ((IGRectangle*)iGraphic)->setEnclosingRect( rc );
          iGraphic->drawOn( gc );
          previousPt = point;
        }
        break;
        case ellipse:
        {
          iGraphic->drawOn( gc );
          IRectangle rc(((IGEllipse*)iGraphic)->enclosingRect());
          rc.sizeTo( rc.size() + point - previousPt );
          ((IGEllipse*)iGraphic)->setEnclosingRect( rc );
          iGraphic->drawOn( gc );
          previousPt = point;
        }
        break;
        case polyline:
        case polygon:
          ((IGPolyline*)iGraphic)->IGPolyline::drawOn( gc );
          ((IGPolyline*)iGraphic)->setPoint(
                           ((IGPolyline*)iGraphic)->numberOfPoints()-1, point );
          ((IGPolyline*)iGraphic)->IGPolyline::drawOn( gc );
        break;
        case arc:
          if (drawState() != waitingForInput)
          {
            if ( pointCount == 2 )
            {
              IGLine tempLine( ((IG3PointArc*)iGraphic)->startingPoint(), previousPt );
              tempLine.drawOn( gc );
              tempLine.setEndingPoint( point );
              tempLine.drawOn( gc );
              previousPt = point;
            } else if ( pointCount == 3 ) {
              iGraphic->drawOn( gc );
              ((IG3PointArc*)iGraphic)->setEndingPoint( point );
              iGraphic->drawOn( gc );
            }
          } /* endif */
        break;
        case pie:
        case chord:
          if (drawState() != waitingForInput)
          {
            if ( pointCount == 2 )
            {
              IGLine tempLine( ((IGPie*)iGraphic)->enclosingRect().center(), previousPt );
              tempLine.drawOn( gc );
              tempLine.setEndingPoint( point );
              tempLine.drawOn( gc );
              previousPt = point;
            } else if ( pointCount == 3 ) {
              iGraphic->drawOn( gc );
              double sweep(angleFromPoints( ((IGPie*)iGraphic)->enclosingRect().center(), point ));
              if ( sweep < ((IGPie*)iGraphic)->startAngle() )
                ((IGPie*)iGraphic)->setSweepAngle( 360.0 -
                                    ( ((IGPie*)iGraphic)->startAngle() - sweep ));
              else
                ((IGPie*)iGraphic)->setSweepAngle( sweep -
                                                ((IGPie*)iGraphic)->startAngle());
              iGraphic->drawOn( gc );
            }
          } /* endif */
        break;
      } /* endswitch */
    }
  }
  else  // We are moving a graphic
  {
    moveRect.drawOn( gc );
    moveRect.translateBy( point - previousPt );
    moveRect.drawOn( gc );
    previousPt = point;
  }
  return false;
}