You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							669 lines
						
					
					
						
							19 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							669 lines
						
					
					
						
							19 KiB
						
					
					
				| /* | |
|  * This program source code file is part of KiCad, a free EDA CAD application. | |
|  * | |
|  * Copyright (C) 2019 CERN | |
|  * Copyright The KiCad Developers, see AUTHORS.txt for contributors. | |
|  * | |
|  * This program is free software; you can redistribute it and/or | |
|  * modify it under the terms of the GNU General Public License | |
|  * as published by the Free Software Foundation; either version 2 | |
|  * of the License, or (at your option) any later version. | |
|  * | |
|  * This program is distributed in the hope that it will be useful, | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|  * GNU General Public License for more details. | |
|  * | |
|  * You should have received a copy of the GNU General Public License | |
|  * along with this program; if not, you may find one here: | |
|  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html | |
|  * or you may search the http://www.gnu.org website for the version 2 license, | |
|  * or you may write to the Free Software Foundation, Inc., | |
|  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | |
|  */ | |
| 
 | |
| #include <kiface_base.h> | |
| #include <macros.h> | |
| #include <pcb_edit_frame.h> | |
| #include <board.h> | |
| #include <board_design_settings.h> | |
| #include <board_item.h> | |
| #include <footprint.h> | |
| #include <pad.h> | |
| #include <pcb_track.h> | |
| #include <zone.h> | |
| #include <cstdio> | |
| #include <vector> | |
| #include <ki_exception.h> | |
| #include <locale_io.h> | |
| #include <reporter.h> | |
| #include <richio.h> | |
| #include <exporters/board_exporter_base.h> | |
| #include <wx/log.h> | |
|  | |
| static double iu2hyp( double iu ) | |
| { | |
|     return iu / 1e9 / 0.0254; | |
| } | |
| 
 | |
| 
 | |
| class HYPERLYNX_EXPORTER; | |
| 
 | |
| class HYPERLYNX_PAD_STACK | |
| { | |
| public: | |
|     friend class HYPERLYNX_EXPORTER; | |
| 
 | |
|     HYPERLYNX_PAD_STACK( BOARD* aBoard, const PAD* aPad ); | |
|     HYPERLYNX_PAD_STACK( BOARD* aBoard, const PCB_VIA* aVia ); | |
|     ~HYPERLYNX_PAD_STACK(){}; | |
| 
 | |
|     bool IsThrough() const | |
|     { | |
|         return m_type == PAD_ATTRIB::NPTH || m_type == PAD_ATTRIB::PTH; | |
|     } | |
| 
 | |
|     bool operator==( const HYPERLYNX_PAD_STACK& other ) const | |
|     { | |
|         if( m_shape != other.m_shape ) | |
|             return false; | |
| 
 | |
|         if( m_type != other.m_type ) | |
|             return false; | |
| 
 | |
|         if( IsThrough() && other.IsThrough() && m_drill != other.m_drill ) | |
|             return false; | |
| 
 | |
|         if( m_sx != other.m_sx ) | |
|             return false; | |
| 
 | |
|         if( m_sy != other.m_sy ) | |
|             return false; | |
| 
 | |
|         if( m_layers != other.m_layers ) | |
|             return false; | |
| 
 | |
|         if( m_angle != other.m_angle ) | |
|             return false; | |
| 
 | |
|         return true; | |
|     } | |
| 
 | |
|     void SetId( int id ) | |
|     { | |
|         m_id = id; | |
|     } | |
| 
 | |
|     int GetId() const | |
|     { | |
|         return m_id; | |
|     } | |
| 
 | |
|     bool IsEmpty() const | |
|     { | |
|         LSET outLayers = m_layers & LSET::AllCuMask( m_board->GetCopperLayerCount() ); | |
| 
 | |
|         return outLayers.none(); | |
|     } | |
| 
 | |
| private: | |
|     BOARD*      m_board; | |
|     int         m_id; | |
|     int         m_drill; | |
|     PAD_SHAPE   m_shape; | |
|     int         m_sx, m_sy; | |
|     double      m_angle; | |
|     LSET        m_layers; | |
|     PAD_ATTRIB  m_type; | |
| }; | |
| 
 | |
| 
 | |
| class HYPERLYNX_EXPORTER : public BOARD_EXPORTER_BASE | |
| { | |
| public: | |
|     HYPERLYNX_EXPORTER() : m_polyId( 1 ) | |
|     { | |
|     } | |
| 
 | |
|     ~HYPERLYNX_EXPORTER(){}; | |
| 
 | |
|     virtual bool Run() override; | |
| 
 | |
| private: | |
|     HYPERLYNX_PAD_STACK* addPadStack( HYPERLYNX_PAD_STACK stack ) | |
|     { | |
|         for( HYPERLYNX_PAD_STACK* p : m_padStacks ) | |
|         { | |
|             if( *p == stack ) | |
|                 return p; | |
|         } | |
| 
 | |
|         stack.SetId( m_padStacks.size() ); | |
|         m_padStacks.push_back( new HYPERLYNX_PAD_STACK( stack ) ); | |
| 
 | |
|         return m_padStacks.back(); | |
|     } | |
| 
 | |
|     const std::string formatPadShape( const HYPERLYNX_PAD_STACK& aStack ) | |
|     { | |
|         int  shapeId = 0; | |
|         char buf[1024]; | |
| 
 | |
|         switch( aStack.m_shape ) | |
|         { | |
|         case PAD_SHAPE::CIRCLE: | |
|         case PAD_SHAPE::OVAL: | |
|             shapeId = 0; | |
|             break; | |
| 
 | |
|         case PAD_SHAPE::ROUNDRECT: | |
|             shapeId = 2; | |
|             break; | |
| 
 | |
|         case PAD_SHAPE::RECTANGLE: | |
|             shapeId = 1; | |
|             break; | |
| 
 | |
|         default: | |
|             if( m_reporter ) | |
|             { | |
|                 m_reporter->Report( _( "File contains pad shapes that are not supported by the " | |
|                                        "Hyperlynx exporter (supported shapes are oval, rectangle, " | |
|                                        "rounded rectangle, and circle)." ), | |
|                                     RPT_SEVERITY_WARNING ); | |
|                 m_reporter->Report( _( "They have been exported as oval pads." ), | |
|                                     RPT_SEVERITY_INFO ); | |
|             } | |
| 
 | |
|             shapeId = 0; | |
|             break; | |
|         } | |
| 
 | |
|         snprintf( buf, sizeof( buf ), "%d, %.9f, %.9f, %.1f, M", | |
|                   shapeId, | |
|                   iu2hyp( aStack.m_sx ), | |
|                   iu2hyp( aStack.m_sy ), | |
|                   aStack.m_angle ); | |
| 
 | |
|         return buf; | |
|     } | |
| 
 | |
|     bool generateHeaders(); | |
|     bool writeBoardInfo(); | |
|     bool writeStackupInfo(); | |
|     bool writeDevices(); | |
|     bool writePadStacks(); | |
|     bool writeNets(); | |
|     bool writeNetObjects( const std::vector<BOARD_ITEM*>& aObjects ); | |
| 
 | |
| 
 | |
|     void writeSinglePadStack( HYPERLYNX_PAD_STACK& aStack ); | |
| 
 | |
|     const std::vector<BOARD_ITEM*> collectNetObjects( int netcode ); | |
| 
 | |
| private: | |
|     std::vector<HYPERLYNX_PAD_STACK*>           m_padStacks; | |
|     std::map<BOARD_ITEM*, HYPERLYNX_PAD_STACK*> m_padMap; | |
| 
 | |
|     std::shared_ptr<FILE_OUTPUTFORMATTER>       m_out; | |
|     int                                         m_polyId; | |
| }; | |
| 
 | |
| 
 | |
| HYPERLYNX_PAD_STACK::HYPERLYNX_PAD_STACK( BOARD* aBoard, const PAD* aPad ) | |
| { | |
|     // TODO(JE) padstacks | |
|     m_board = aBoard; | |
|     m_sx    = aPad->GetSize( PADSTACK::ALL_LAYERS ).x; | |
|     m_sy    = aPad->GetSize( PADSTACK::ALL_LAYERS ).y; | |
|     m_angle = 180.0 - aPad->GetOrientation().AsDegrees(); | |
| 
 | |
|     if( m_angle < 0.0 ) | |
|         m_angle += 360.0; | |
| 
 | |
|     m_layers = aPad->GetLayerSet(); | |
|     m_drill  = aPad->GetDrillSize().x; | |
|     m_shape  = aPad->GetShape( PADSTACK::ALL_LAYERS ); | |
|     m_type   = PAD_ATTRIB::PTH; | |
|     m_id     = 0; | |
| } | |
| 
 | |
| 
 | |
| HYPERLYNX_PAD_STACK::HYPERLYNX_PAD_STACK( BOARD* aBoard, const PCB_VIA* aVia ) | |
| { | |
|     m_board  = aBoard; | |
|     // TODO(JE) padstacks | |
|     m_sx = m_sy = aVia->GetWidth( PADSTACK::ALL_LAYERS ); | |
|     m_angle  = 0; | |
|     m_layers = aVia->GetLayerSet(); | |
|     m_drill  = aVia->GetDrillValue(); | |
|     m_shape  = PAD_SHAPE::CIRCLE; | |
|     m_type   = PAD_ATTRIB::PTH; | |
|     m_id     = 0; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::generateHeaders() | |
| { | |
|     m_out->Print( 0, "{VERSION=2.14}\n" ); | |
|     m_out->Print( 0, "{UNITS=ENGLISH LENGTH}\n\n" ); | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| void HYPERLYNX_EXPORTER::writeSinglePadStack( HYPERLYNX_PAD_STACK& aStack ) | |
| { | |
|     LSET layerMask = LSET::AllCuMask( m_board->GetCopperLayerCount() ); | |
|     LSET outLayers = aStack.m_layers & layerMask; | |
| 
 | |
|     if( outLayers.none() ) | |
|         return; | |
| 
 | |
|     m_out->Print( 0, "{PADSTACK=%d, %.9f\n", aStack.m_id, iu2hyp( aStack.m_drill ) ); | |
| 
 | |
|     if( outLayers == layerMask ) | |
|     { | |
|         m_out->Print( 1, "(\"MDEF\", %s)\n", formatPadShape( aStack ).c_str() ); | |
|     } | |
|     else | |
|     { | |
|         for( PCB_LAYER_ID l : outLayers.Seq() ) | |
|         { | |
|             m_out->Print( 1, "(\"%s\", %s)\n", | |
|                           (const char*) m_board->GetLayerName( l ).c_str(), | |
|                           formatPadShape( aStack ).c_str() ); | |
|         } | |
|     } | |
| 
 | |
|     m_out->Print( 0, "}\n\n" ); | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::writeBoardInfo() | |
| { | |
|     SHAPE_POLY_SET outlines; | |
| 
 | |
|     m_out->Print( 0, "{BOARD \"%s\"\n", (const char*) m_board->GetFileName().c_str() ); | |
| 
 | |
|     if( !m_board->GetBoardPolygonOutlines( outlines ) ) | |
|     { | |
|         wxLogError( _( "Board outline is malformed. Run DRC for a full analysis." ) ); | |
|         return false; | |
|     } | |
| 
 | |
|     for( int o = 0; o < outlines.OutlineCount(); o++ ) | |
|     { | |
|         const SHAPE_LINE_CHAIN& outl = outlines.COutline( o ); | |
| 
 | |
|         for( int i = 0; i < outl.SegmentCount(); i++ ) | |
|         { | |
|             const SEG& s = outl.CSegment( i ); | |
|             m_out->Print( 1, "(PERIMETER_SEGMENT X1=%.9f Y1=%.9f X2=%.9f Y2=%.9f)\n", | |
|                           iu2hyp( s.A.x ), | |
|                           iu2hyp( -s.A.y ), | |
|                           iu2hyp( s.B.x ), | |
|                           iu2hyp( -s.B.y ) ); | |
|         } | |
|     } | |
| 
 | |
|     m_out->Print( 0, "}\n\n" ); | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::writeStackupInfo() | |
| { | |
|     /* Format: | |
|      * {STACKUP | |
|      * (SIGNAL T=thickness [P=plating_thickness] [C=constant] L=layer_name [M=material_name]) [comment] | |
|      * (DIELECTRIC T=thickness [C=constant] [L=layer_name] [M=material_name]) [comment] | |
|      * } | |
|      * name length is <= 20 chars | |
|      */ | |
| 
 | |
|     LSEQ layers = m_board->GetDesignSettings().GetEnabledLayers().CuStack(); | |
| 
 | |
|     // Get the board physical stackup structure | |
|     const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor(); | |
| 
 | |
|     m_out->Print( 0, "{STACKUP\n" ); | |
| 
 | |
|     wxString layer_name;    // The last copper layer name used in stackup | |
|  | |
|     for( BOARD_STACKUP_ITEM* item: stackup.GetList() ) | |
|     { | |
|         if( item->GetType() == BS_ITEM_TYPE_COPPER ) | |
|         { | |
|             layer_name = m_board->GetLayerName( item->GetBrdLayerId() ); | |
|             int plating_thickness = 0; | |
|             double resistivity = 1.724e-8;  // Good for copper | |
|             m_out->Print( 1, "(SIGNAL T=%g P=%g C=%g L=\"%.20s\" M=COPPER)\n", | |
|                           iu2hyp( item->GetThickness( 0 ) ), | |
|                           iu2hyp( plating_thickness ), | |
|                           resistivity, | |
|                           TO_UTF8( layer_name ) ); | |
|         } | |
|         else if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC ) | |
|         { | |
|             if( item->GetSublayersCount() < 2 ) | |
|             { | |
|                 m_out->Print( 1, "(DIELECTRIC T=%g C=%g L=\"DE_%.17s\" M=\"%.20s\")\n", | |
|                               iu2hyp( item->GetThickness( 0 ) ), | |
|                               item->GetEpsilonR( 0 ), | |
|                               TO_UTF8( layer_name ), | |
|                               TO_UTF8( item->GetMaterial( 0 ) ) ); | |
|             } | |
|             else for( int idx = 0; idx < item->GetSublayersCount(); idx++ ) | |
|             { | |
|                 m_out->Print( 1, "(DIELECTRIC T=%g C=%g L=\"DE%d_%.16s\" M=\"%.20s\")\n", | |
|                               iu2hyp( item->GetThickness( idx ) ), | |
|                               item->GetEpsilonR( idx ), | |
|                               idx, | |
|                               TO_UTF8( layer_name ), | |
|                               TO_UTF8( item->GetMaterial( idx ) ) ); | |
|             } | |
|         } | |
|     } | |
| 
 | |
|     m_out->Print( 0, "}\n\n" ); | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::writeDevices() | |
| { | |
|     m_out->Print( 0, "{DEVICES\n" ); | |
| 
 | |
|     for( FOOTPRINT* footprint : m_board->Footprints() ) | |
|     { | |
|         wxString ref = footprint->GetReference(); | |
|         wxString layerName = m_board->GetLayerName( footprint->GetLayer() ); | |
| 
 | |
|         if( ref.IsEmpty() ) | |
|             ref = wxT( "EMPTY" ); | |
| 
 | |
|         m_out->Print( 1, "(? REF=\"%s\" L=\"%s\")\n", | |
|                       (const char*) ref.c_str(), | |
|                       (const char*) layerName.c_str() ); | |
|     } | |
|     m_out->Print( 0, "}\n\n" ); | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::writePadStacks() | |
| { | |
|     for( FOOTPRINT* footprint : m_board->Footprints() ) | |
|     { | |
|         for( PAD* pad : footprint->Pads() ) | |
|         { | |
|             HYPERLYNX_PAD_STACK* ps = addPadStack( HYPERLYNX_PAD_STACK( m_board, pad ) ); | |
|             m_padMap[pad] = ps; | |
|         } | |
|     } | |
| 
 | |
|     for( PCB_TRACK* track : m_board->Tracks() ) | |
|     { | |
|         if( PCB_VIA* via = dyn_cast<PCB_VIA*>( track ) ) | |
|         { | |
|             HYPERLYNX_PAD_STACK* ps = addPadStack( HYPERLYNX_PAD_STACK( m_board, via ) ); | |
|             m_padMap[via] = ps; | |
|         } | |
|     } | |
| 
 | |
|     for( HYPERLYNX_PAD_STACK* pstack : m_padStacks ) | |
|         writeSinglePadStack( *pstack ); | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjects ) | |
| { | |
|     for( BOARD_ITEM* item : aObjects ) | |
|     { | |
|         if( PAD* pad = dyn_cast<PAD*>( item ) ) | |
|         { | |
|             auto pstackIter = m_padMap.find( pad ); | |
| 
 | |
|             if( pstackIter != m_padMap.end() ) | |
|             { | |
|                 wxString ref = pad->GetParentFootprint()->GetReference(); | |
| 
 | |
|                 if( ref.IsEmpty() ) | |
|                     ref = wxT( "EMPTY" ); | |
| 
 | |
|                 wxString padName = pad->GetNumber(); | |
| 
 | |
|                 if( padName.IsEmpty() ) | |
|                     padName = wxT( "1" ); | |
| 
 | |
| 
 | |
|                 m_out->Print( 1, "(PIN X=%.10f Y=%.10f R=\"%s.%s\" P=%d)\n", | |
|                               iu2hyp( pad->GetPosition().x ), | |
|                               iu2hyp( -pad->GetPosition().y ), | |
|                               (const char*) ref.c_str(), | |
|                               (const char*) padName.c_str(), | |
|                               pstackIter->second->GetId() ); | |
|             } | |
|         } | |
|         else if( PCB_VIA* via = dyn_cast<PCB_VIA*>( item ) ) | |
|         { | |
|             auto pstackIter = m_padMap.find( via ); | |
| 
 | |
|             if( pstackIter != m_padMap.end() ) | |
|             { | |
|                 m_out->Print( 1, "(VIA X=%.10f Y=%.10f P=%d)\n", | |
|                               iu2hyp( via->GetPosition().x ), | |
|                               iu2hyp( -via->GetPosition().y ), | |
|                               pstackIter->second->GetId() ); | |
|             } | |
|         } | |
|         else if( PCB_TRACK* track = dyn_cast<PCB_TRACK*>( item ) ) | |
|         { | |
|             const wxString layerName = m_board->GetLayerName( track->GetLayer() ); | |
| 
 | |
|             m_out->Print( 1, "(SEG X1=%.10f Y1=%.10f X2=%.10f Y2=%.10f W=%.10f L=\"%s\")\n", | |
|                           iu2hyp( track->GetStart().x ), | |
|                           iu2hyp( -track->GetStart().y ), | |
|                           iu2hyp( track->GetEnd().x ), | |
|                           iu2hyp( -track->GetEnd().y ), | |
|                           iu2hyp( track->GetWidth() ), | |
|                           (const char*) layerName.c_str() ); | |
|         } | |
|         else if( PCB_ARC* arc = dyn_cast<PCB_ARC*>( item ) ) | |
|         { | |
|             const wxString layerName = m_board->GetLayerName( arc->GetLayer() ); | |
|             VECTOR2I       start = arc->GetStart(); | |
|             VECTOR2I       end = arc->GetEnd(); | |
| 
 | |
|             if( arc->IsCCW() ) | |
|                 std::swap( start, end ); | |
| 
 | |
|             m_out->Print( 1, "(ARC X1=%.10f Y1=%.10f X2=%.10f Y2=%.10f XC=%.10f YC=%.10f R=%.10f W=%.10f L=\"%s\")\n", | |
|                           iu2hyp( start.x ), | |
|                           iu2hyp( -start.y ), | |
|                           iu2hyp( end.x ), | |
|                           iu2hyp( -end.y ), | |
|                           iu2hyp( arc->GetCenter().x ), | |
|                           iu2hyp( -arc->GetCenter().y ), | |
|                           iu2hyp( arc->GetRadius() ), | |
|                           iu2hyp( arc->GetWidth() ), | |
|                           (const char*) layerName.c_str() ); | |
|         } | |
|         else if( ZONE* zone = dyn_cast<ZONE*>( item ) ) | |
|         { | |
|             for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) | |
|             { | |
|                 const wxString layerName   = m_board->GetLayerName( layer ); | |
|                 SHAPE_POLY_SET fill = zone->GetFilledPolysList( layer )->CloneDropTriangulation(); | |
| 
 | |
|                 fill.Simplify(); | |
| 
 | |
|                 for( int i = 0; i < fill.OutlineCount(); i++ ) | |
|                 { | |
|                     const SHAPE_LINE_CHAIN& outl = fill.COutline( i ); | |
|                     const VECTOR2I          p0 = outl.CPoint( 0 ); | |
| 
 | |
|                     m_out->Print( 1, "{POLYGON T=POUR L=\"%s\" ID=%d X=%.10f Y=%.10f\n", | |
|                                   (const char*) layerName.c_str(), | |
|                                   m_polyId, | |
|                                   iu2hyp( p0.x ), | |
|                                   iu2hyp( -p0.y ) ); | |
| 
 | |
|                     for( int v = 0; v < outl.PointCount(); v++ ) | |
|                     { | |
|                         m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", | |
|                                       iu2hyp( outl.CPoint( v ).x ), | |
|                                       iu2hyp( -outl.CPoint( v ).y ) ); | |
|                     } | |
| 
 | |
|                     m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", iu2hyp( p0.x ), iu2hyp( -p0.y ) ); | |
|                     m_out->Print( 1, "}\n" ); | |
| 
 | |
|                     for( int h = 0; h < fill.HoleCount( i ); h++ ) | |
|                     { | |
|                         const SHAPE_LINE_CHAIN& holeShape = fill.CHole( i, h ); | |
|                         const VECTOR2I          ph0       = holeShape.CPoint( 0 ); | |
| 
 | |
|                         m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n", | |
|                                       m_polyId, | |
|                                       iu2hyp( ph0.x ), | |
|                                       iu2hyp( -ph0.y ) ); | |
| 
 | |
|                         for( int v = 0; v < holeShape.PointCount(); v++ ) | |
|                         { | |
|                             m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", | |
|                                           iu2hyp( holeShape.CPoint( v ).x ), | |
|                                           iu2hyp( -holeShape.CPoint( v ).y ) ); | |
|                         } | |
| 
 | |
|                         m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", | |
|                                       iu2hyp( ph0.x ), | |
|                                       iu2hyp( -ph0.y ) ); | |
|                         m_out->Print( 1, "}\n" ); | |
|                     } | |
| 
 | |
|                     m_polyId++; | |
|                 } | |
|             } | |
|         } | |
|     } | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| const std::vector<BOARD_ITEM*> HYPERLYNX_EXPORTER::collectNetObjects( int netcode ) | |
| { | |
|     std::vector<BOARD_ITEM*> rv; | |
| 
 | |
|     auto check = | |
|             [&]( BOARD_CONNECTED_ITEM* item ) -> bool | |
|             { | |
|                 if( ( item->GetLayerSet() & LSET::AllCuMask() ).none() ) | |
|                     return false; | |
| 
 | |
|                 if( item->GetNetCode() == netcode || ( netcode < 0 && item->GetNetCode() <= 0 ) ) | |
|                     return true; | |
| 
 | |
|                 return false; | |
|             }; | |
| 
 | |
|     for( FOOTPRINT* footprint : m_board->Footprints() ) | |
|     { | |
|         for( PAD* pad : footprint->Pads() ) | |
|         { | |
|             if( check( pad ) ) | |
|                 rv.push_back( pad ); | |
|         } | |
|     } | |
| 
 | |
|     for( PCB_TRACK* item : m_board->Tracks() ) | |
|     { | |
|         if( check( item ) ) | |
|             rv.push_back( item ); | |
|     } | |
| 
 | |
|     for( ZONE* zone : m_board->Zones() ) | |
|     { | |
|         if( check( zone ) ) | |
|             rv.push_back( zone ); | |
|     } | |
| 
 | |
|     return rv; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::writeNets() | |
| { | |
|     m_polyId = 1; | |
| 
 | |
|     for( const NETINFO_ITEM* netInfo : m_board->GetNetInfo() ) | |
|     { | |
|         int  netcode = netInfo->GetNetCode(); | |
|         bool isNullNet = netInfo->GetNetCode() <= 0 || netInfo->GetNetname().IsEmpty(); | |
| 
 | |
|         if( isNullNet ) | |
|             continue; | |
| 
 | |
|         const std::vector<BOARD_ITEM*> netObjects = collectNetObjects( netcode ); | |
| 
 | |
|         if( netObjects.size() ) | |
|         { | |
|             m_out->Print( 0, "{NET=\"%s\"\n", (const char*) netInfo->GetNetname().c_str() ); | |
|             writeNetObjects( netObjects ); | |
|             m_out->Print( 0, "}\n\n" ); | |
|         } | |
|     } | |
| 
 | |
|     const std::vector<BOARD_ITEM*> nullNetObjects = collectNetObjects( -1 ); | |
| 
 | |
|     int idx = 0; | |
| 
 | |
|     for( BOARD_ITEM* item : nullNetObjects ) | |
|     { | |
|         m_out->Print( 0, "{NET=\"EmptyNet%d\"\n", idx ); | |
|         writeNetObjects( { item } ); | |
|         m_out->Print( 0, "}\n\n" ); | |
|         idx++; | |
|     } | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| bool HYPERLYNX_EXPORTER::Run() | |
| { | |
|     LOCALE_IO toggle; // toggles on, then off, the C locale. | |
|  | |
|     try | |
|     { | |
|         m_out.reset( new FILE_OUTPUTFORMATTER( m_outputFilePath.GetFullPath() ) ); | |
| 
 | |
|         generateHeaders(); | |
|         writeBoardInfo(); | |
|         writeStackupInfo(); | |
|         writeDevices(); | |
|         writePadStacks(); | |
|         writeNets(); | |
|     } | |
|     catch( IO_ERROR& ) | |
|     { | |
|         return false; | |
|     } | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| bool ExportBoardToHyperlynx( BOARD* aBoard, const wxFileName& aPath ) | |
| { | |
|     HYPERLYNX_EXPORTER exporter; | |
|     exporter.SetBoard( aBoard ); | |
|     exporter.SetOutputFilename( aPath ); | |
|     return exporter.Run(); | |
| }
 |