void MODULE::MoveAnchorPosition( const wxPoint& aMoveVector ) { /* Move the reference point of the footprint * the footprints elements (pads, outlines, edges .. ) are moved * but: * - the footprint position is not modified. * - the relative (local) coordinates of these items are modified */ wxPoint footprintPos = GetPosition(); /* Update the relative coordinates: * The coordinates are relative to the anchor point. * Calculate deltaX and deltaY from the anchor. */ wxPoint moveVector = aMoveVector; RotatePoint( &moveVector, -GetOrientation() ); // Update of the reference and value. m_Reference->SetPos0( m_Reference->GetPos0() + moveVector ); m_Reference->SetDrawCoord(); m_Value->SetPos0( m_Value->GetPos0() + moveVector ); m_Value->SetDrawCoord(); // Update the pad local coordinates. for( D_PAD* pad = Pads(); pad; pad = pad->Next() ) { pad->SetPos0( pad->GetPos0() + moveVector ); pad->SetPosition( pad->GetPos0() + footprintPos ); } // Update the draw element coordinates. for( EDA_ITEM* item = GraphicalItems(); item; item = item->Next() ) { switch( item->Type() ) { case PCB_MODULE_EDGE_T: { EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( item ); edge->m_Start0 += moveVector; edge->m_End0 += moveVector; edge->SetDrawCoord(); break; } case PCB_MODULE_TEXT_T: { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item ); text->SetPos0( text->GetPos0() + moveVector ); text->SetDrawCoord(); break; } default: break; } } CalculateBoundingBox(); }
void MODULE::SetOrientation( double newangle ) { double angleChange = newangle - m_Orient; // change in rotation wxPoint pt; NORMALIZE_ANGLE_POS( newangle ); m_Orient = newangle; for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) { pt = pad->GetPos0(); pad->SetOrientation( pad->GetOrientation() + angleChange ); RotatePoint( &pt, m_Orient ); pad->SetPosition( GetPosition() + pt ); } // Update of the reference and value. m_Reference->SetDrawCoord(); m_Value->SetDrawCoord(); // Displace contours and text of the footprint. for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() ) { if( item->Type() == PCB_MODULE_EDGE_T ) { EDGE_MODULE* edge = (EDGE_MODULE*) item; edge->SetDrawCoord(); } else if( item->Type() == PCB_MODULE_TEXT_T ) { TEXTE_MODULE* text = (TEXTE_MODULE*) item; text->SetDrawCoord(); } } CalculateBoundingBox(); }
void PCB_POLYGON::AddToModule( MODULE* aModule ) { if( IsNonCopperLayer( m_KiCadLayer ) ) { EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON ); aModule->GraphicalItemsList().PushBack( dwg ); dwg->SetWidth( 0 ); dwg->SetLayer( m_KiCadLayer ); auto outline = new std::vector<wxPoint>; for( auto point : m_outline ) outline->push_back( wxPoint( point->x, point->y ) ); dwg->SetPolyPoints( *outline ); dwg->SetStart0( *outline->begin() ); dwg->SetEnd0( outline->back() ); dwg->SetDrawCoord(); delete( outline ); } }
MODULE* GPCB_FPL_CACHE::parseMODULE( LINE_READER* aLineReader ) throw( IO_ERROR, PARSE_ERROR ) { #define TEXT_DEFAULT_SIZE ( 40*IU_PER_MILS ) #define OLD_GPCB_UNIT_CONV IU_PER_MILS // Old version unit = 1 mil, so conv_unit is 10 or 0.1 #define NEW_GPCB_UNIT_CONV ( 0.01*IU_PER_MILS ) int paramCnt; double conv_unit = NEW_GPCB_UNIT_CONV; // GPCB unit = 0.01 mils and Pcbnew 0.1 wxPoint textPos; wxString msg; wxArrayString parameters; std::auto_ptr<MODULE> module( new MODULE( NULL ) ); if( aLineReader->ReadLine() == NULL ) THROW_IO_ERROR( "unexpected end of file" ); parameters.Clear(); parseParameters( parameters, aLineReader ); paramCnt = parameters.GetCount(); /* From the Geda PCB documentation, valid Element definitions: * Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags] * Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags) * Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags) * Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags) * Element ("Desc" "Name" TX TY TDir TScale TNFlags) */ if( parameters[0].CmpNoCase( wxT( "Element" ) ) != 0 ) { msg.Printf( _( "unknown token \"%s\"" ), GetChars( parameters[0] ) ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } if( paramCnt < 10 || paramCnt > 14 ) { msg.Printf( _( "Element token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } // Test symbol after "Element": if [ units = 0.01 mils, and if ( units = 1 mil if( parameters[1] == wxT( "(" ) ) conv_unit = OLD_GPCB_UNIT_CONV; if( paramCnt > 10 ) { module->SetDescription( parameters[3] ); module->SetReference( parameters[4] ); } else { module->SetDescription( parameters[2] ); module->SetReference( parameters[3] ); } // Read value if( paramCnt > 10 ) module->SetValue( parameters[5] ); // With gEDA/pcb, value is meaningful after instantiation, only, so it's // often empty in bare footprints. if( module->Value().GetText().IsEmpty() ) module->Value().SetText( wxT( "Val**" ) ); if( paramCnt == 14 ) { textPos = wxPoint( parseInt( parameters[8], conv_unit ), parseInt( parameters[9], conv_unit ) ); } else { textPos = wxPoint( parseInt( parameters[6], conv_unit ), parseInt( parameters[7], conv_unit ) ); } int orientation = parseInt( parameters[paramCnt-4], 1.0 ); module->Reference().SetOrientation( (orientation % 2) ? 900 : 0 ); // Calculate size: default height is 40 mils, width 30 mil. // real size is: default * ibuf[idx+3] / 100 (size in gpcb is given in percent of default size int thsize = parseInt( parameters[paramCnt-3], TEXT_DEFAULT_SIZE ) / 100; thsize = std::max( (int)( 5 * IU_PER_MILS ), thsize ); // Ensure a minimal size = 5 mils int twsize = thsize * 30 / 40; int thickness = thsize / 8; // gEDA/pcb aligns top/left, not pcbnew's default, center/center. // Compensate for this by shifting the insertion point instead of the // aligment, because alignment isn't changeable in the GUI. textPos.x = textPos.x + twsize * module->GetReference().Len() / 2; textPos.y += thsize / 2; // gEDA/pcb draws a bit too low/left, while pcbnew draws a bit too // high/right. Compensate for similar appearance. textPos.x -= thsize / 10; textPos.y += thsize / 2; module->Reference().SetTextPosition( textPos ); module->Reference().SetPos0( textPos ); module->Reference().SetSize( wxSize( twsize, thsize ) ); module->Reference().SetThickness( thickness ); // gEDA/pcb shows only one of value/reference/description at a time. Which // one is selectable by a global menu setting. pcbnew needs reference as // well as value visible, so place the value right below the reference. module->Value().SetOrientation( module->Reference().GetOrientation() ); module->Value().SetSize( module->Reference().GetSize() ); module->Value().SetThickness( module->Reference().GetThickness() ); textPos.y += thsize * 13 / 10; // 130% line height module->Value().SetTextPosition( textPos ); module->Value().SetPos0( textPos ); while( aLineReader->ReadLine() ) { parameters.Clear(); parseParameters( parameters, aLineReader ); if( parameters.IsEmpty() || parameters[0] == wxT( "(" ) ) continue; if( parameters[0] == wxT( ")" ) ) break; paramCnt = parameters.GetCount(); // Test units value for a string line param (more than 3 parameters : ident [ xx ] ) if( paramCnt > 3 ) { if( parameters[1] == wxT( "(" ) ) conv_unit = OLD_GPCB_UNIT_CONV; else conv_unit = NEW_GPCB_UNIT_CONV; } wxLogTrace( traceFootprintLibrary, wxT( "%s parameter count = %d." ), GetChars( parameters[0] ), paramCnt ); // Parse a line with format: ElementLine [X1 Y1 X2 Y2 Thickness] if( parameters[0].CmpNoCase( wxT( "ElementLine" ) ) == 0 ) { if( paramCnt != 8 ) { msg.Printf( wxT( "ElementLine token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } EDGE_MODULE* drawSeg = new EDGE_MODULE( module.get() ); drawSeg->SetLayer( F_SilkS ); drawSeg->SetShape( S_SEGMENT ); drawSeg->SetStart0( wxPoint( parseInt( parameters[2], conv_unit ), parseInt( parameters[3], conv_unit ) ) ); drawSeg->SetEnd0( wxPoint( parseInt( parameters[4], conv_unit ), parseInt( parameters[5], conv_unit ) ) ); drawSeg->SetWidth( parseInt( parameters[6], conv_unit ) ); drawSeg->SetDrawCoord(); module->GraphicalItems().PushBack( drawSeg ); continue; } // Parse an arc with format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness] if( parameters[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 ) { if( paramCnt != 10 ) { msg.Printf( wxT( "ElementArc token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } // Pcbnew does know ellipse so we must have Width = Height EDGE_MODULE* drawSeg = new EDGE_MODULE( module.get() ); drawSeg->SetLayer( F_SilkS ); drawSeg->SetShape( S_ARC ); module->GraphicalItems().PushBack( drawSeg ); // for and arc: ibuf[3] = ibuf[4]. Pcbnew does not know ellipses int radius = ( parseInt( parameters[4], conv_unit ) + parseInt( parameters[5], conv_unit ) ) / 2; wxPoint centre( parseInt( parameters[2], conv_unit ), parseInt( parameters[3], conv_unit ) ); drawSeg->SetStart0( centre ); // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles. double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0; // Pcbnew delta angle direction is the opposite of Geda PCB delta angles. double sweep_angle = parseInt( parameters[7], -10.0 ); // Geda PCB does not support circles. if( sweep_angle == -3600.0 ) drawSeg->SetShape( S_CIRCLE ); // Angle value is clockwise in gpcb and Pcbnew. drawSeg->SetAngle( sweep_angle ); drawSeg->SetEnd0( wxPoint( radius, 0 ) ); // Calculate start point coordinate of arc wxPoint arcStart( drawSeg->GetEnd0() ); RotatePoint( &arcStart, -start_angle ); drawSeg->SetEnd0( centre + arcStart ); drawSeg->SetWidth( parseInt( parameters[8], conv_unit ) ); drawSeg->SetDrawCoord(); continue; } // Parse a Pad with no hole with format: // Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags] // Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags) // Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags) // Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags) if( parameters[0].CmpNoCase( wxT( "Pad" ) ) == 0 ) { if( paramCnt < 10 || paramCnt > 13 ) { msg.Printf( wxT( "Pad token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } D_PAD* pad = new D_PAD( module.get() ); static const LSET pad_front( 3, F_Cu, F_Mask, F_Paste ); static const LSET pad_back( 3, B_Cu, B_Mask, B_Paste ); pad->SetShape( PAD_SHAPE_RECT ); pad->SetAttribute( PAD_ATTRIB_SMD ); pad->SetLayerSet( pad_front ); if( testFlags( parameters[paramCnt-2], 0x0080, wxT( "onsolder" ) ) ) pad->SetLayerSet( pad_back ); // Set the pad name: // Pcbnew pad name is used for electrical connection calculations. // Accordingly it should be mapped to gEDA's pin/pad number, // which is used for the same purpose. // gEDA also features a pin/pad "name", which is an arbitrary string // and set to the pin name of the netlist on instantiation. Many gEDA // bare footprints use identical strings for name and number, so this // can be a bit confusing. pad->SetPadName( parameters[paramCnt-3] ); int x1 = parseInt( parameters[2], conv_unit ); int x2 = parseInt( parameters[4], conv_unit ); int y1 = parseInt( parameters[3], conv_unit ); int y2 = parseInt( parameters[5], conv_unit ); int width = parseInt( parameters[6], conv_unit ); wxPoint delta( x2 - x1, y2 - y1 ); double angle = atan2( (double)delta.y, (double)delta.x ); // Get the pad clearance and the solder mask clearance. if( paramCnt == 13 ) { int clearance = parseInt( parameters[7], conv_unit ); // One of gEDA's oddities is that clearance between pad and polygon // is given as the gap on both sides of the pad together, so for // KiCad it has to halfed. pad->SetLocalClearance( clearance / 2 ); // In GEDA, the mask value is the size of the hole in this // solder mask. In Pcbnew, it is a margin, therefore the distance // between the copper and the mask int maskMargin = parseInt( parameters[8], conv_unit ); maskMargin = ( maskMargin - width ) / 2; pad->SetLocalSolderMaskMargin( maskMargin ); } // Negate angle (due to Y reversed axis) and convert it to internal units angle = - RAD2DECIDEG( angle ); pad->SetOrientation( KiROUND( angle ) ); wxPoint padPos( (x1 + x2) / 2, (y1 + y2) / 2 ); pad->SetSize( wxSize( KiROUND( EuclideanNorm( delta ) ) + width, width ) ); padPos += module->GetPosition(); pad->SetPos0( padPos ); pad->SetPosition( padPos ); if( !testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) ) { if( pad->GetSize().x == pad->GetSize().y ) pad->SetShape( PAD_SHAPE_CIRCLE ); else pad->SetShape( PAD_SHAPE_OVAL ); } module->Add( pad ); continue; } // Parse a Pin with through hole with format: // Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags] // Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags) // Pin (aX aY Thickness Drill "Name" "Number" NFlags) // Pin (aX aY Thickness Drill "Name" NFlags) // Pin (aX aY Thickness "Name" NFlags) if( parameters[0].CmpNoCase( wxT( "Pin" ) ) == 0 ) { if( paramCnt < 8 || paramCnt > 12 ) { msg.Printf( wxT( "Pin token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } D_PAD* pad = new D_PAD( module.get() ); pad->SetShape( PAD_SHAPE_CIRCLE ); static const LSET pad_set = LSET::AllCuMask() | LSET( 3, F_SilkS, F_Mask, B_Mask ); pad->SetLayerSet( pad_set ); if( testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) ) pad->SetShape( PAD_SHAPE_RECT ); // Set the pad name: // Pcbnew pad name is used for electrical connection calculations. // Accordingly it should be mapped to gEDA's pin/pad number, // which is used for the same purpose. pad->SetPadName( parameters[paramCnt-3] ); wxPoint padPos( parseInt( parameters[2], conv_unit ), parseInt( parameters[3], conv_unit ) ); int padSize = parseInt( parameters[4], conv_unit ); pad->SetSize( wxSize( padSize, padSize ) ); int drillSize = 0; // Get the pad clearance, solder mask clearance, and drill size. if( paramCnt == 12 ) { int clearance = parseInt( parameters[5], conv_unit ); // One of gEDA's oddities is that clearance between pad and polygon // is given as the gap on both sides of the pad together, so for // KiCad it has to halfed. pad->SetLocalClearance( clearance / 2 ); // In GEDA, the mask value is the size of the hole in this // solder mask. In Pcbnew, it is a margin, therefore the distance // between the copper and the mask int maskMargin = parseInt( parameters[6], conv_unit ); maskMargin = ( maskMargin - padSize ) / 2; pad->SetLocalSolderMaskMargin( maskMargin ); drillSize = parseInt( parameters[7], conv_unit ); } else { drillSize = parseInt( parameters[5], conv_unit ); } pad->SetDrillSize( wxSize( drillSize, drillSize ) ); padPos += module->GetPosition(); pad->SetPos0( padPos ); pad->SetPosition( padPos ); if( pad->GetShape() == PAD_SHAPE_CIRCLE && pad->GetSize().x != pad->GetSize().y ) pad->SetShape( PAD_SHAPE_OVAL ); module->Add( pad ); continue; } } // Recalculate the bounding box module->CalculateBoundingBox(); return module.release(); }