KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_component.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 * Author: SYSUEric <[email protected]>.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <wx/regex.h>
22#include <wx/log.h>
23
24#include <algorithm>
25#include <cmath>
26#include <mutex>
27
28#include <3d_cache/3d_cache.h>
29#include <3d_math.h>
30#include <base_units.h>
31#include <board.h>
33#include <footprint.h>
35#include <pad.h>
36#include <pcb_field.h>
38#include <project_pcb.h>
41
42#include "odb_component.h"
43#include "odb_util.h"
44#include "hash_eda.h"
45#include "pcb_io_odbpp.h"
46#include <trace_helpers.h>
47
48double ODB::ModelHeightAboveBoard( const S3DMODEL& aModel, const FP_3DMODEL& aPlacement )
49{
50 glm::mat4 transform = CalcModelMatrix( SFVEC3F( aPlacement.m_Offset.x, aPlacement.m_Offset.y,
51 aPlacement.m_Offset.z ),
52 SFVEC3F( aPlacement.m_Rotation.x, aPlacement.m_Rotation.y,
53 aPlacement.m_Rotation.z ),
54 SFVEC3F( aPlacement.m_Scale.x, aPlacement.m_Scale.y,
55 aPlacement.m_Scale.z ) );
56 double height = 0.0;
57
58 for( unsigned int meshIndex = 0; meshIndex < aModel.m_MeshesSize; ++meshIndex )
59 {
60 const SMESH& mesh = aModel.m_Meshes[meshIndex];
61
62 for( unsigned int vertexIndex = 0; vertexIndex < mesh.m_VertexSize; ++vertexIndex )
63 {
64 const SFVEC3F& vertex = mesh.m_Positions[vertexIndex];
65 double z = ( transform * glm::vec4( vertex.x, vertex.y, vertex.z, 1.0f ) ).z;
66
67 if( std::isfinite( z ) )
68 height = std::max( height, z );
69 }
70 }
71
72 return height;
73}
74
75
76bool ODB::HasShownModel( const FOOTPRINT* aFp )
77{
78 return std::any_of( aFp->Models().begin(), aFp->Models().end(),
79 []( const FP_3DMODEL& model )
80 {
81 return model.m_Show && !model.m_Filename.IsEmpty();
82 } );
83}
84
85
86namespace
87{
88double componentModelHeight( const FOOTPRINT* aFp )
89{
90 if( !ODB::HasShownModel( aFp ) )
91 return 0.0;
92
93 const BOARD* board = aFp->GetBoard();
94
95 if( !board || !board->GetProject() )
96 return 0.0;
97
98 static std::mutex cacheMutex;
99 std::lock_guard<std::mutex> lock( cacheMutex );
100 PROJECT* project = board->GetProject();
102 wxString basePath;
103
105 {
106 std::optional<LIBRARY_TABLE_ROW*> row = adapter->GetRow( aFp->GetFPID().GetLibNickname() );
107
108 if( row )
109 basePath = LIBRARY_MANAGER::GetFullURI( *row, true );
110 }
111
112 double height = 0.0;
113
114 for( const FP_3DMODEL& placement : aFp->Models() )
115 {
116 if( !placement.m_Show || placement.m_Filename.IsEmpty() )
117 continue;
118
119 std::vector<const EMBEDDED_FILES*> embeddedFiles = { aFp->GetEmbeddedFiles(),
120 board->GetEmbeddedFiles() };
121 S3DMODEL* model = cache->GetModel( placement.m_Filename, basePath, std::move( embeddedFiles ) );
122
123 if( model )
124 height = std::max( height, ODB::ModelHeightAboveBoard( *model, placement ) );
125 }
126
127 return height;
128}
129}
130
131
133 const EDA_DATA::PACKAGE& aPkg )
134{
135 auto& comp = m_compList.emplace_back( m_compList.size(), aPkg.m_index );
136
137 comp.m_center = ODB::AddXY( m_plugin->GetFormat(), aFp->GetPosition() );
138 EDA_ANGLE angle = aFp->GetOrientation();
139
140 if( angle != ANGLE_0 )
141 {
142 // odb Rotation is expressed in degrees and is always clockwise.
143 // while kicad EDA_ANGLE is anticlockwise.
144 angle = ANGLE_360 - angle;
145 comp.m_rot = ODB::Double2String( m_plugin->GetFormat(), angle.Normalize().AsDegrees() );
146 }
147
148 if( aFp->IsFlipped() )
149 {
150 comp.m_mirror = wxT( "M" );
151 }
152
153 wxString originalRef = aFp->GetReference();
154 comp.m_comp_name = ODB::GenLegalComponentName( originalRef );
155
156 const ODB_FORMAT& format = m_plugin->GetFormat();
158 comp.m_part_name = format.m_mpnField.IsEmpty() ? wxString() : row.Field( format.m_mpnField );
159
160 if( comp.m_part_name.IsEmpty() )
161 comp.m_part_name = wxString::Format( "%s_%s", aFp->GetFPID().GetFullLibraryName(),
162 aFp->GetFPID().GetLibItemName().wx_str() );
163
164 // ODB++ cannot handle spaces in these fields
165 ODB::RemoveWhitespace( comp.m_part_name );
166 comp.m_part_name = ODB::GenLegalComponentName( comp.m_part_name );
167
168 double heightMm = componentModelHeight( aFp );
169
170 if( heightMm <= 0.0 )
171 {
172 wxString value = row.Field( wxS( "Height" ) );
173
174 if( !value.IsEmpty() )
175 {
177 heightMm = pcbIUScale.IUTomm( heightIU );
178 }
179 }
180
181 if( std::isfinite( heightMm ) && heightMm > 0.0 )
182 {
183 double outputHeight = format.m_unitsStr == "INCH" ? heightMm / 25.4 : heightMm;
184 AddSystemAttribute( comp, ODB_ATTR::COMP_HEIGHT{ outputHeight } );
185 }
186
187 if( comp.m_comp_name.IsEmpty() )
188 {
189 // The spec requires a component name; some ODB++ parsers can't handle it being empty
190 comp.m_comp_name = wxString::Format( "UNNAMED%zu", m_compList.size() );
191 }
192
193 // Warn if non-ASCII characters were converted
194 if( comp.m_comp_name != originalRef )
195 {
196 if( m_plugin )
197 {
198 m_plugin->Report( wxString::Format( _( "Component '%s' has non-ASCII characters in its "
199 "designator; converted to '%s' for ODB++ export." ),
200 originalRef,
201 comp.m_comp_name ),
203 }
204 }
205
206 wxString base_comp_name = comp.m_comp_name;
207
208 if( !m_usedCompNames.insert( comp.m_comp_name ).second )
209 {
210 size_t suffix = 1;
211 wxString candidate;
212
213 do
214 {
215 candidate = wxString::Format( "%s_%zu", base_comp_name, suffix++ );
216 } while( !m_usedCompNames.insert( candidate ).second );
217
218 if( m_plugin )
219 {
220 m_plugin->Report( wxString::Format( _( "Component '%s' has an ambiguous designator after "
221 "conversion; renamed to '%s' for ODB++ export." ),
222 originalRef,
223 candidate ),
225 }
226
227 comp.m_comp_name = candidate;
228 }
229
230 for( PCB_FIELD* field : aFp->GetFields() )
231 {
232 if( field->GetId() == FIELD_T::REFERENCE )
233 continue;
234
235 wxString key = field->GetName();
237
238 // A PRP record is one line
239 wxString value = row.Field( field->GetName() );
240 value.Replace( wxS( "\r" ), wxEmptyString );
241 value.Replace( wxS( "\n" ), wxS( " " ) );
242
243 comp.m_prp[key] = wxString::Format( "'%s'", value );
244 }
245
246 if( row.m_dnp )
247 {
248 AddSystemAttribute( comp, ODB_ATTR::NO_POP{ true } );
249 }
250
251 if( const BOARD* board = aFp->GetBoard(); board && !board->GetVariantNames().empty()
252 && m_plugin->GetFormat().m_variantNames.m_listsFit )
253 {
254 std::vector<wxString> included;
255
256 for( const wxString& variant : board->GetVariantNames() )
257 {
258 if( !aFp->GetDNPForVariant( variant ) )
259 included.push_back( variant );
260 }
261
262 AddSystemAttribute( comp, ODB_ATTR::COMP_VARIANT_LIST{
263 m_plugin->GetFormat().m_variantNames.Join( included ).ToStdString() } );
264 }
265
266 if( row.m_pressFit )
267 {
269 }
270 else if( row.m_mount == FAB_MOUNT::SMT )
271 {
273 }
274 else if( row.m_mount == FAB_MOUNT::THT )
275 {
277 }
278 else
279 {
281 }
282
283 return comp;
284}
285
286
287void COMPONENTS_MANAGER::Write( std::ostream& ost ) const
288{
289 ost << "UNITS=" << m_plugin->GetFormat().m_unitsStr << std::endl;
290
291 WriteAttributes( ost );
292
293 for( const auto& comp : m_compList )
294 {
295 comp.Write( ost );
296 }
297}
298
299
300void ODB_COMPONENT::Write( std::ostream& ost ) const
301{
302 ost << "# CMP " << m_index << std::endl;
303 ost << "CMP " << m_pkg_ref << " " << m_center.first << " " << m_center.second << " " << m_rot << " " << m_mirror
304 << " " << m_comp_name.utf8_string() << " " << m_part_name.utf8_string();
305
306 WriteAttributes( ost );
307
308 ost << std::endl;
309
310 for( const auto& [key, value] : m_prp )
311 {
312 ost << "PRP " << key.utf8_string() << " " << value.utf8_string() << std::endl;
313 }
314
315 for( const auto& toep : m_toeprints )
316 {
317 toep.Write( ost );
318 }
319
320 ost << "#" << std::endl;
321}
322
323
324void ODB_COMPONENT::TOEPRINT::Write( std::ostream& ost ) const
325{
326 ost << "TOP " << m_pin_num << " " << m_center.first << " " << m_center.second << " " << m_rot << " " << m_mirror
327 << " " << m_net_num << " " << m_subnet_num << " " << m_toeprint_name.utf8_string() << std::endl;
328}
glm::mat4 CalcModelMatrix(const SFVEC3F &aOffset, const SFVEC3F &aRotation, const SFVEC3F &aScale)
Build the model-to-footprint transform used by rendering and picking.
Definition 3d_math.cpp:34
Defines math related functions.
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
define an internal structure to be used by the 3D renders
void WriteAttributes(std::ostream &ost, const std::string &prefix="") const
void AddSystemAttribute(Tr &r, Ta v)
void WriteAttributes(std::ostream &ost) const
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:410
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3846
const std::vector< wxString > & GetVariantNames() const
Definition board.h:532
PROJECT * GetProject() const
Definition board.h:775
PCB_IO_ODBPP * m_plugin
Plugin the export runs under, used for formatting and designator reports.
std::list< ODB_COMPONENT > m_compList
ODB_COMPONENT & AddComponent(const FOOTPRINT *aFp, const EDA_DATA::PACKAGE &aPkg)
void Write(std::ostream &ost) const
std::set< wxString > m_usedCompNames
const size_t m_index
An interface to the global shared library manager that is schematic-specific and linked to one projec...
EDA_ANGLE GetOrientation() const
Definition footprint.h:439
bool IsFlipped() const
Definition footprint.h:662
const LIB_ID & GetFPID() const
Definition footprint.h:474
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:425
const wxString & GetReference() const
Definition footprint.h:909
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition footprint.h:1397
VECTOR2I GetPosition() const override
Definition footprint.h:436
VECTOR3D m_Offset
3D model offset (mm)
Definition footprint.h:184
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition footprint.h:183
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition footprint.h:182
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
const wxString GetFullLibraryName() const
Definition lib_id.cpp:262
wxString m_mirror
const size_t m_index
! CMP index number on board to be used in SNT(TOP), 0~n-1
std::list< TOEPRINT > m_toeprints
std::pair< wxString, wxString > m_center
size_t m_pkg_ref
! package ref number from PKG in eda/data file, 0~n-1
wxString m_part_name
! Part identification is a single string of ASCII characters without spaces
void Write(std::ostream &ost) const
wxString m_comp_name
! Unique reference designator (component name)
std::map< wxString, wxString > m_prp
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:63
Cache for storing the 3D shapes.
Definition 3d_cache.h:53
S3DMODEL * GetModel(const wxString &aModelFileName, const wxString &aBasePath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition 3d_cache.cpp:588
wxString wx_str() const
Definition utf8.cpp:41
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:454
FAB_COMPONENT_ROW MakeFabComponentRow(const FOOTPRINT &aFootprint, const wxString &aVariant)
Hashing functions for EDA_ITEMs.
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
wxString GenLegalComponentName(const wxString &aStr)
Definition odb_util.cpp:185
std::pair< wxString, wxString > AddXY(const ODB_FORMAT &aFormat, const VECTOR2I &aVec)
Definition odb_util.cpp:412
void RemoveWhitespace(wxString &aStr)
Definition odb_util.cpp:374
double ModelHeightAboveBoard(const S3DMODEL &aModel, const FP_3DMODEL &aPlacement)
bool HasShownModel(const FOOTPRINT *aFp)
wxString Double2String(const ODB_FORMAT &aFormat, double aVal)
Definition odb_util.cpp:382
@ RPT_SEVERITY_WARNING
Footprint facts resolved for one assembly variant.
wxString Field(const wxString &aName) const
Variant-resolved shown text, empty when the field is missing.
size_t m_subnet_num
! Number of subnet (SNT record TOP) in the referenced net
std::pair< wxString, wxString > m_center
! Board location of the pin.
void Write(std::ostream &ost) const
size_t m_net_num
! Number of NET record in the eda/data file.
wxString m_mirror
! equal to CMP m_mirror.
const size_t m_pin_num
! index of PIN record in the eda/data file, 0~n-1.
wxString m_toeprint_name
! Name of the pad in PIN record
std::string m_unitsStr
Definition odb_util.h:73
wxString m_mpnField
Definition odb_util.h:76
wxString m_variantName
Definition odb_util.h:74
Store the a model based on meshes and materials.
Definition c3dmodel.h:111
unsigned int m_MeshesSize
Number of meshes in the array.
Definition c3dmodel.h:112
SMESH * m_Meshes
The meshes list of this model.
Definition c3dmodel.h:113
Per-vertex normal/color/texcoors structure.
Definition c3dmodel.h:77
unsigned int m_VertexSize
Number of vertex in the arrays.
Definition c3dmodel.h:78
SFVEC3F * m_Positions
Vertex position array.
Definition c3dmodel.h:79
@ REFERENCE
Field Reference of part, i.e. "IC21".
KIBIS_MODEL * model
KIBIS_COMPONENT * comp
wxLogTrace helper definitions.
glm::vec3 SFVEC3F
Definition xv3d_types.h:40