altium: initial code to import STEP models
For now, they are extracted into the same directory as the project file. Furthermore, there seems to be a problem with rotation / positioning of some models.
This commit is contained in:
parent
76a100984a
commit
41a6791928
|
@ -81,8 +81,10 @@ BOARD* ALTIUM_CIRCUIT_MAKER_PLUGIN::Load(
|
|||
{ ALTIUM_PCB_DIR::BOARDREGIONS, "E3A544335C30403A991912052C936F\\Data" },
|
||||
{ ALTIUM_PCB_DIR::CLASSES6, "4F71DD45B09143988210841EA1C28D\\Data" },
|
||||
{ ALTIUM_PCB_DIR::COMPONENTS6, "F9D060ACC7DD4A85BC73CB785BAC81\\Data" },
|
||||
{ ALTIUM_PCB_DIR::COMPONENTBODIES6, "44D9487C98CE4F0EB46AB6E9CDAF40\\Data" }, // or: A0DB41FBCB0D49CE8C32A271AA7EF5 ?
|
||||
{ ALTIUM_PCB_DIR::DIMENSIONS6, "068B9422DBB241258BA2DE9A6BA1A6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::FILLS6, "6FFE038462A940E9B422EFC8F5D85E\\Data" },
|
||||
{ ALTIUM_PCB_DIR::MODELS, "0DB009C021D946C88F1B3A32DAE94B\\Data" },
|
||||
{ ALTIUM_PCB_DIR::NETS6, "35D7CF51BB9B4875B3A138B32D80DC\\Data" },
|
||||
{ ALTIUM_PCB_DIR::PADS6, "4F501041A9BC4A06BDBDAB67D3820E\\Data" },
|
||||
{ ALTIUM_PCB_DIR::POLYGONS6, "A1931C8B0B084A61AA45146575FDD3\\Data" },
|
||||
|
|
|
@ -81,8 +81,10 @@ BOARD* ALTIUM_CIRCUIT_STUDIO_PLUGIN::Load(
|
|||
{ ALTIUM_PCB_DIR::BOARDREGIONS, "8957CF30F167408D9D263D23FE7C89\\Data" },
|
||||
{ ALTIUM_PCB_DIR::CLASSES6, "847EFBF87A5149B1AA326A52AD6357\\Data" },
|
||||
{ ALTIUM_PCB_DIR::COMPONENTS6, "465416896A15486999A39C643935D2\\Data" },
|
||||
{ ALTIUM_PCB_DIR::COMPONENTBODIES6, "1849D9B5512D452A93EABF4E40B122\\Data" }, // or B6AD30D75241498BA2536EBF001752 ?
|
||||
{ ALTIUM_PCB_DIR::DIMENSIONS6, "16C81DBC13C447FF8B42A426677F3C\\Data" },
|
||||
{ ALTIUM_PCB_DIR::FILLS6, "4E83BDC3253747F08E9006D7F57020\\Data" },
|
||||
{ ALTIUM_PCB_DIR::MODELS, "C0F7599ECC6A4D648DF5BB557679AF\\Data" },
|
||||
{ ALTIUM_PCB_DIR::NETS6, "D95A0DA2FE9047779A5194C127F30B\\Data" },
|
||||
{ ALTIUM_PCB_DIR::PADS6, "47D69BC5107A4B8DB8DAA23E39C238\\Data" },
|
||||
{ ALTIUM_PCB_DIR::POLYGONS6, "D7038392280E4E229B9D9B5426B295\\Data" },
|
||||
|
|
|
@ -81,8 +81,10 @@ BOARD* ALTIUM_DESIGNER_PLUGIN::Load(
|
|||
{ ALTIUM_PCB_DIR::BOARDREGIONS, "BoardRegions\\Data" },
|
||||
{ ALTIUM_PCB_DIR::CLASSES6, "Classes6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::COMPONENTS6, "Components6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::COMPONENTBODIES6, "ComponentBodies6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::DIMENSIONS6, "Dimensions6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::FILLS6, "Fills6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::MODELS, "Models\\Data" },
|
||||
{ ALTIUM_PCB_DIR::NETS6, "Nets6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::PADS6, "Pads6\\Data" },
|
||||
{ ALTIUM_PCB_DIR::POLYGONS6, "Polygons6\\Data" },
|
||||
|
|
|
@ -34,6 +34,7 @@ types:
|
|||
record_id::text6: text
|
||||
record_id::fill6: fill
|
||||
record_id::region6: region
|
||||
record_id::componentbody6: componentbody
|
||||
|
||||
arc:
|
||||
seq:
|
||||
|
@ -570,6 +571,26 @@ types:
|
|||
# repeat-expr: vertices_num+1
|
||||
# type: xyf2
|
||||
|
||||
componentbody:
|
||||
seq:
|
||||
- id: sub1_len
|
||||
type: u4
|
||||
- id: data
|
||||
type: componentbody_sub1
|
||||
size: sub1_len
|
||||
|
||||
componentbody_sub1:
|
||||
seq:
|
||||
- size: 7
|
||||
- id: component
|
||||
type: u2
|
||||
- size: 9
|
||||
- id: propterties_len
|
||||
type: u4
|
||||
- id: properties
|
||||
size: propterties_len
|
||||
type: str
|
||||
|
||||
xy:
|
||||
seq:
|
||||
- id: x
|
||||
|
@ -609,6 +630,7 @@ enums:
|
|||
0x05: text6
|
||||
0x06: fill6
|
||||
0x0b: region6
|
||||
0x0c: componentbody6
|
||||
|
||||
boolean:
|
||||
0: false
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include <ki_exception.h>
|
||||
#include <math/util.h>
|
||||
#include <wx/translation.h>
|
||||
|
||||
#include "altium_parser.h"
|
||||
#include "altium_parser_pcb.h"
|
||||
|
@ -378,6 +377,28 @@ ADIMENSION6::ADIMENSION6( ALTIUM_PARSER& aReader )
|
|||
}
|
||||
}
|
||||
|
||||
AMODEL::AMODEL( ALTIUM_PARSER& aReader )
|
||||
{
|
||||
std::map<wxString, wxString> properties = aReader.ReadProperties();
|
||||
if( properties.empty() )
|
||||
{
|
||||
THROW_IO_ERROR( "Classes6 stream has no properties!" );
|
||||
}
|
||||
|
||||
name = ALTIUM_PARSER::PropertiesReadString( properties, "NAME", "" );
|
||||
id = ALTIUM_PARSER::PropertiesReadString( properties, "ID", "" );
|
||||
isEmbedded = ALTIUM_PARSER::PropertiesReadBool( properties, "EMBED", false );
|
||||
|
||||
rotation.x = ALTIUM_PARSER::PropertiesReadDouble( properties, "ROTX", 0. );
|
||||
rotation.y = ALTIUM_PARSER::PropertiesReadDouble( properties, "ROTY", 0. );
|
||||
rotation.z = ALTIUM_PARSER::PropertiesReadDouble( properties, "ROTZ", 0. );
|
||||
|
||||
if( aReader.HasParsingError() )
|
||||
{
|
||||
THROW_IO_ERROR( "Classes6 stream was not parsed correctly" );
|
||||
}
|
||||
}
|
||||
|
||||
ANET6::ANET6( ALTIUM_PARSER& aReader )
|
||||
{
|
||||
std::map<wxString, wxString> properties = aReader.ReadProperties();
|
||||
|
@ -569,6 +590,48 @@ AARC6::AARC6( ALTIUM_PARSER& aReader )
|
|||
}
|
||||
}
|
||||
|
||||
ACOMPONENTBODY6::ACOMPONENTBODY6( ALTIUM_PARSER& aReader )
|
||||
{
|
||||
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
|
||||
if( recordtype != ALTIUM_RECORD::MODEL )
|
||||
{
|
||||
THROW_IO_ERROR( "ComponentsBodies6 stream has invalid recordtype" );
|
||||
}
|
||||
|
||||
aReader.ReadAndSetSubrecordLength();
|
||||
|
||||
aReader.Skip( 7 );
|
||||
component = aReader.Read<uint16_t>();
|
||||
aReader.Skip( 9 );
|
||||
|
||||
std::map<wxString, wxString> properties = aReader.ReadProperties();
|
||||
if( properties.empty() )
|
||||
{
|
||||
THROW_IO_ERROR( "ComponentsBodies6 stream has no properties" );
|
||||
}
|
||||
|
||||
modelName = ALTIUM_PARSER::PropertiesReadString( properties, "MODEL.NAME", "" );
|
||||
modelId = ALTIUM_PARSER::PropertiesReadString( properties, "MODELID", "" );
|
||||
modelIsEmbedded = ALTIUM_PARSER::PropertiesReadBool( properties, "MODEL.EMBED", false );
|
||||
|
||||
modelPosition.x = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "MODEL.2D.X", "0mil" );
|
||||
modelPosition.y = -ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "MODEL.2D.Y", "0mil" );
|
||||
modelPosition.z = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "MODEL.3D.DZ", "0mil" );
|
||||
|
||||
modelRotation.x = ALTIUM_PARSER::PropertiesReadDouble( properties, "MODEL.3D.ROTX", 0. );
|
||||
modelRotation.y = ALTIUM_PARSER::PropertiesReadDouble( properties, "MODEL.3D.ROTY", 0. );
|
||||
modelRotation.z = ALTIUM_PARSER::PropertiesReadDouble( properties, "MODEL.3D.ROTZ", 0. );
|
||||
|
||||
rotation = ALTIUM_PARSER::PropertiesReadDouble( properties, "MODEL.2D.ROTATION", 0. );
|
||||
|
||||
aReader.SkipSubrecord();
|
||||
|
||||
if( aReader.HasParsingError() )
|
||||
{
|
||||
THROW_IO_ERROR( "Components6 stream was not parsed correctly" );
|
||||
}
|
||||
}
|
||||
|
||||
APAD6::APAD6( ALTIUM_PARSER& aReader )
|
||||
{
|
||||
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <class_module.h>
|
||||
#include <wx/gdicmn.h>
|
||||
|
||||
// tthis constant specifies an unconnected net
|
||||
|
@ -395,6 +396,17 @@ struct ADIMENSION6
|
|||
explicit ADIMENSION6( ALTIUM_PARSER& aReader );
|
||||
};
|
||||
|
||||
struct AMODEL
|
||||
{
|
||||
wxString name;
|
||||
wxString id;
|
||||
bool isEmbedded;
|
||||
|
||||
MODULE_3D_SETTINGS::VECTOR3D rotation;
|
||||
|
||||
explicit AMODEL( ALTIUM_PARSER& aReader );
|
||||
};
|
||||
|
||||
struct ANET6
|
||||
{
|
||||
wxString name;
|
||||
|
@ -486,6 +498,21 @@ struct AARC6
|
|||
explicit AARC6( ALTIUM_PARSER& aReader );
|
||||
};
|
||||
|
||||
struct ACOMPONENTBODY6
|
||||
{
|
||||
uint16_t component;
|
||||
|
||||
wxString modelName;
|
||||
wxString modelId;
|
||||
bool modelIsEmbedded;
|
||||
|
||||
MODULE_3D_SETTINGS::VECTOR3D modelPosition;
|
||||
MODULE_3D_SETTINGS::VECTOR3D modelRotation;
|
||||
double rotation;
|
||||
|
||||
explicit ACOMPONENTBODY6( ALTIUM_PARSER& aReader );
|
||||
};
|
||||
|
||||
struct APAD6_SIZE_AND_SHAPE
|
||||
{
|
||||
ALTIUM_PAD_HOLE_SHAPE holeshape;
|
||||
|
|
|
@ -38,8 +38,13 @@
|
|||
|
||||
#include <compoundfilereader.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <project.h>
|
||||
#include <trigo.h>
|
||||
#include <utf.h>
|
||||
#include <wx/docview.h>
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/zstream.h>
|
||||
|
||||
|
||||
void ParseAltiumPcb( BOARD* aBoard, const wxString& aFileName,
|
||||
|
@ -350,6 +355,16 @@ void ALTIUM_PCB::Parse( const CFB::CompoundFileReader& aReader,
|
|||
[this]( auto aReader, auto fileHeader ) {
|
||||
this->ParseComponents6Data( aReader, fileHeader );
|
||||
} },
|
||||
{ true, ALTIUM_PCB_DIR::MODELS,
|
||||
[this, aFileMapping]( auto aReader, auto fileHeader ) {
|
||||
wxString dir( aFileMapping.at( ALTIUM_PCB_DIR::MODELS ) );
|
||||
dir.RemoveLast( 4 ); // Remove "Data" from the path
|
||||
this->ParseModelsData( aReader, fileHeader, dir );
|
||||
} },
|
||||
{ true, ALTIUM_PCB_DIR::COMPONENTBODIES6,
|
||||
[this]( auto aReader, auto fileHeader ) {
|
||||
this->ParseComponentsBodies6Data( aReader, fileHeader );
|
||||
} },
|
||||
{ true, ALTIUM_PCB_DIR::NETS6,
|
||||
[this]( auto aReader, auto fileHeader ) {
|
||||
this->ParseNets6Data( aReader, fileHeader );
|
||||
|
@ -449,6 +464,9 @@ void ALTIUM_PCB::Parse( const CFB::CompoundFileReader& aReader,
|
|||
{
|
||||
module->CalculateBoundingBox();
|
||||
}
|
||||
|
||||
// Otherwise we cannot save the imported board
|
||||
m_board->SetModified();
|
||||
}
|
||||
|
||||
int ALTIUM_PCB::GetNetCode( uint16_t aId ) const
|
||||
|
@ -783,6 +801,66 @@ void ALTIUM_PCB::ParseComponents6Data(
|
|||
}
|
||||
|
||||
|
||||
void ALTIUM_PCB::ParseComponentsBodies6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry )
|
||||
{
|
||||
ALTIUM_PARSER reader( aReader, aEntry );
|
||||
|
||||
while( reader.GetRemainingBytes() >= 4 /* TODO: use Header section of file */ )
|
||||
{
|
||||
ACOMPONENTBODY6 elem( reader ); // TODO: implement
|
||||
|
||||
if( elem.component == ALTIUM_COMPONENT_NONE )
|
||||
{
|
||||
continue; // TODO: we do not support components for the board yet
|
||||
}
|
||||
|
||||
if( m_components.size() <= elem.component )
|
||||
{
|
||||
THROW_IO_ERROR( wxString::Format(
|
||||
"ComponentsBodies6 stream tries to access component id %d of %d existing components",
|
||||
elem.component, m_components.size() ) );
|
||||
}
|
||||
|
||||
if( !elem.modelIsEmbedded )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto modelTuple = m_models.find( elem.modelId );
|
||||
if( modelTuple == m_models.end() )
|
||||
{
|
||||
THROW_IO_ERROR( wxString::Format(
|
||||
"ComponentsBodies6 stream tries to access model id %s which does not exist",
|
||||
elem.modelId ) );
|
||||
}
|
||||
|
||||
MODULE* module = m_components.at( elem.component );
|
||||
const wxPoint& modulePosition = module->GetPosition();
|
||||
|
||||
MODULE_3D_SETTINGS modelSettings;
|
||||
|
||||
modelSettings.m_Filename = modelTuple->second;
|
||||
|
||||
modelSettings.m_Offset.x = Iu2Millimeter( (int) elem.modelPosition.x - modulePosition.x );
|
||||
modelSettings.m_Offset.y = -Iu2Millimeter( (int) elem.modelPosition.y - modulePosition.y );
|
||||
modelSettings.m_Offset.z = Iu2Millimeter( (int) elem.modelPosition.z );
|
||||
|
||||
modelSettings.m_Rotation.x = NormalizeAngleDegrees( elem.modelRotation.x, -180, 180 );
|
||||
modelSettings.m_Rotation.y = NormalizeAngleDegrees( elem.modelRotation.y + 180, -180, 180 );
|
||||
modelSettings.m_Rotation.z = NormalizeAngleDegrees(
|
||||
elem.modelRotation.z + module->GetOrientationDegrees() + 180, -180, 180 );
|
||||
|
||||
module->Models().push_back( modelSettings );
|
||||
}
|
||||
|
||||
if( reader.GetRemainingBytes() != 0 )
|
||||
{
|
||||
THROW_IO_ERROR( "ComponentsBodies6 stream is not fully parsed" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ALTIUM_PCB::HelperParseDimensions6Linear( const ADIMENSION6& aElem )
|
||||
{
|
||||
if( aElem.referencePoint.size() != 2 )
|
||||
|
@ -1035,6 +1113,50 @@ void ALTIUM_PCB::ParseDimensions6Data(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ALTIUM_PCB::ParseModelsData( const CFB::CompoundFileReader& aReader,
|
||||
const CFB::COMPOUND_FILE_ENTRY* aEntry, const wxString aRootDir )
|
||||
{
|
||||
ALTIUM_PARSER reader( aReader, aEntry );
|
||||
|
||||
wxString altiumModelsPath = wxPathOnly( m_board->GetFileName() );
|
||||
wxSetEnv( PROJECT_VAR_NAME,
|
||||
altiumModelsPath ); // TODO: set KIPRJMOD always after import (not only when loading project)?
|
||||
|
||||
int idx = 0;
|
||||
while( reader.GetRemainingBytes() >= 4 /* TODO: use Header section of file */ )
|
||||
{
|
||||
AMODEL elem( reader );
|
||||
|
||||
wxString stepPath = aRootDir + std::to_string( idx++ );
|
||||
|
||||
const CFB::COMPOUND_FILE_ENTRY* stepEntry = FindStream( aReader, stepPath.c_str() );
|
||||
|
||||
size_t stepSize = static_cast<size_t>( stepEntry->size );
|
||||
std::unique_ptr<char[]> stepContent( new char[stepSize] );
|
||||
|
||||
// read file into buffer
|
||||
aReader.ReadFile( stepEntry, 0, stepContent.get(), stepSize );
|
||||
|
||||
wxFileName storagePath( altiumModelsPath, elem.name );
|
||||
|
||||
wxMemoryInputStream stepStream( stepContent.get(), stepSize );
|
||||
wxZlibInputStream zlibInputStream( stepStream );
|
||||
|
||||
wxFileOutputStream outputStream( storagePath.GetFullPath() );
|
||||
outputStream.Write( zlibInputStream );
|
||||
outputStream.Close();
|
||||
|
||||
m_models.insert( { elem.id, "${KIPRJMOD}/" + elem.name } ); // KIPRJMOD
|
||||
}
|
||||
|
||||
if( reader.GetRemainingBytes() != 0 )
|
||||
{
|
||||
THROW_IO_ERROR( "Models stream is not fully parsed" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ALTIUM_PCB::ParseNets6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry )
|
||||
{
|
||||
|
|
|
@ -138,6 +138,8 @@ private:
|
|||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParseDimensions6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParseModelsData( const CFB::CompoundFileReader& aReader,
|
||||
const CFB::COMPOUND_FILE_ENTRY* aEntry, const wxString aRootDir );
|
||||
void ParseNets6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParsePolygons6Data(
|
||||
|
@ -148,6 +150,8 @@ private:
|
|||
// Binary Format
|
||||
void ParseArcs6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParseComponentsBodies6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParsePads6Data(
|
||||
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParseVias6Data(
|
||||
|
@ -181,6 +185,7 @@ private:
|
|||
BOARD* m_board;
|
||||
std::vector<MODULE*> m_components;
|
||||
std::vector<ZONE_CONTAINER*> m_polygons;
|
||||
std::map<wxString, wxString> m_models;
|
||||
size_t m_num_nets;
|
||||
std::map<ALTIUM_LAYER, PCB_LAYER_ID> m_layermap; // used to correctly map copper layers
|
||||
std::map<ALTIUM_RULE_KIND, std::vector<ARULE6>> m_rules;
|
||||
|
|
Loading…
Reference in New Issue