From 60f7933877474536e5491e7d7cfc2118467eaf82 Mon Sep 17 00:00:00 2001 From: Dominik Wernberger Date: Sat, 15 Jun 2024 16:59:28 +0200 Subject: [PATCH] Add OrCAD Importer --- CMakeLists.txt | 4 + common/CMakeLists.txt | 2 + common/wildcards_and_files_ext.cpp | 4 + eeschema/CMakeLists.txt | 33 +- eeschema/sch_io/orcad/orcad2kicad.cpp | 544 +++++++++++++++++++++++++ eeschema/sch_io/orcad/orcad2kicad.h | 104 +++++ eeschema/sch_io/orcad/sch_io_orcad.cpp | 397 ++++++++++++++++++ eeschema/sch_io/orcad/sch_io_orcad.h | 92 +++++ eeschema/sch_io/sch_io_mgr.cpp | 5 + eeschema/sch_io/sch_io_mgr.h | 1 + include/wildcards_and_files_ext.h | 4 + qa/tests/eeschema/CMakeLists.txt | 1 + qa/tests/spice/CMakeLists.txt | 1 + thirdparty/CMakeLists.txt | 13 +- thirdparty/nanodbc/CMakeLists.txt | 1 + 15 files changed, 1203 insertions(+), 3 deletions(-) create mode 100644 eeschema/sch_io/orcad/orcad2kicad.cpp create mode 100644 eeschema/sch_io/orcad/orcad2kicad.h create mode 100644 eeschema/sch_io/orcad/sch_io_orcad.cpp create mode 100644 eeschema/sch_io/orcad/sch_io_orcad.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e5560f86a4..22a0b638b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,10 @@ endif() project( kicad ) +if( NOT DEFINED OPENORCADPARSER_PATH ) + set(OPENORCADPARSER_PATH "/YOUR/PATH/TO/OpenOrcadParser") +endif() + # Create a default build type for our QA that doesn't include `NDEBUG` set(CMAKE_CXX_FLAGS_QABUILD "-Os -g1 -ggdb1") diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 196902c9cc..6459cb6aa1 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -468,6 +468,8 @@ set( COMMON_IO_SRCS io/cadstar/cadstar_archive_parser.cpp io/cadstar/cadstar_parts_lib_parser.cpp + # OrCAD + # Eagle io/eagle/eagle_parser.cpp diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp index 7b261d6e2b..51394cecb5 100644 --- a/common/wildcards_and_files_ext.cpp +++ b/common/wildcards_and_files_ext.cpp @@ -140,6 +140,10 @@ const std::string FILEEXT::ProjectLocalSettingsFileExtension( "kicad_prl" ); const std::string FILEEXT::LegacySchematicFileExtension( "sch" ); const std::string FILEEXT::CadstarSchematicFileExtension( "csa" ); const std::string FILEEXT::CadstarPartsLibraryFileExtension( "lib" ); +const std::string FILEEXT::OrCadDesignFileExtension( "DSN" ); +const std::string FILEEXT::OrCadDesignBackupFileExtension( "DBK" ); +const std::string FILEEXT::OrCadLibraryFileExtension( "OLB" ); +const std::string FILEEXT::OrCadLibraryBackupFileExtension( "OBK" ); const std::string FILEEXT::KiCadSchematicFileExtension( "kicad_sch" ); const std::string FILEEXT::SpiceFileExtension( "cir" ); const std::string FILEEXT::CadstarNetlistFileExtension( "frp" ); diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 05fab939aa..06a95243bc 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -1,3 +1,5 @@ +include(FetchContent) + # Add all the warnings to the files if( COMPILER_SUPPORTS_WARNINGS ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARN_FLAGS_CXX}") @@ -26,6 +28,24 @@ set_property( SOURCE sim/ngspice.cpp NGSPICE_DLL_FILE="${NGSPICE_DLL_FILE}" ) +set(SPDLOG_FMT_EXTERNAL OFF CACHE BOOL "Use external fmt library" FORCE) +set(SPDLOG_FMT_EXTERNAL_HO OFF CACHE BOOL "Use external fmt library" FORCE) + +FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog + GIT_TAG v1.14.1 +) +FetchContent_MakeAvailable(spdlog) + +FetchContent_Declare( + nameof + GIT_REPOSITORY https://github.com/Neargye/nameof + GIT_TAG v0.10.4 +) +FetchContent_MakeAvailable(nameof) + + include_directories( BEFORE ${INC_BEFORE} ) include_directories( ${CMAKE_SOURCE_DIR}/common @@ -37,6 +57,9 @@ include_directories( ./symbol_editor ./tools ./widgets + ${CMAKE_BINARY_DIR}/_deps/spdlog-src/include + ${CMAKE_BINARY_DIR}/_deps/nameof-src/include + ${OPENORCADPARSER_PATH}/src ) set( EESCHEMA_SCH_IO @@ -74,6 +97,10 @@ set( EESCHEMA_SCH_IO sch_io/cadstar/cadstar_sch_archive_parser.cpp sch_io/cadstar/sch_io_cadstar_archive.cpp + # OrCAD IO plugin + sch_io/orcad/orcad2kicad.cpp + sch_io/orcad/sch_io_orcad.cpp + # LTSpice IO plugin sch_io/ltspice/ltspice_schematic.cpp sch_io/ltspice/sch_io_ltspice.cpp @@ -550,6 +577,8 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE target_link_libraries( eeschema kicommon ${wxWidgets_LIBRARIES} + spdlog::spdlog + ${OPENORCADPARSER_PATH}/build/lib/libOpenOrCadParser.so ) # the main Eeschema program, in DSO form. @@ -567,7 +596,9 @@ target_include_directories( eeschema_kiface_objects target_link_libraries( eeschema_kiface_objects PUBLIC - common ) + common + ${OPENORCADPARSER_PATH}/build/lib/libOpenOrCadParser.so + ) # Since we're not using target_link_libraries, we need to explicitly # declare the dependency diff --git a/eeschema/sch_io/orcad/orcad2kicad.cpp b/eeschema/sch_io/orcad/orcad2kicad.cpp new file mode 100644 index 0000000000..aa5e1410d8 --- /dev/null +++ b/eeschema/sch_io/orcad/orcad2kicad.cpp @@ -0,0 +1,544 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Dominik Wernberger + * Copyright (C) 2024 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 +#include +#include + +#include "orcad2kicad.h" + +#include +#include +#include + + +// OpenOrcadParser Headers +#include "Container.hpp" +#include "GetStreamHelper.hpp" +#include "PinShape.hpp" +#include "Primitives/PrimArc.hpp" +#include "Primitives/PrimBezier.hpp" +#include "Primitives/PrimLine.hpp" +#include "Primitives/PrimPolygon.hpp" +#include "Primitives/PrimPolyline.hpp" +#include "Primitives/PrimRect.hpp" +#include "Streams/StreamPackage.hpp" + + +SCH_SHAPE* convPrimArc2ARC(const PrimArc* aOrcadObj) +{ + // Kicad does not support elliptical arcs, we approximate + // it by straight lines, however arcs are actually not yet + // supported! + + const auto p1 = VECTOR2I( convDimIU( aOrcadObj->x1 ), convDimIU( aOrcadObj->y1 ) ); + const auto p2 = VECTOR2I( convDimIU( aOrcadObj->x2 ), convDimIU( aOrcadObj->y2 ) ); + const auto start = VECTOR2I( convDimIU( aOrcadObj->startX ), convDimIU( aOrcadObj->startY ) ); + const auto end = VECTOR2I( convDimIU( aOrcadObj->endX ), convDimIU( aOrcadObj->endY ) ); + + // if( isCircle( p1, p2 ) ) + // { + // std::unique_ptr kicadObj = std::make_unique( SHAPE_T::ARC, LAYER_DEVICE ); + + // // Circle radius + // double r = std::abs( p1.x - p2.x ) / 2.0; + + // // Point between end and start point + // VECTOR2D m1 = start + (end - start) / 2.0; + + // // Center Point + // VECTOR2D c = VECTOR2D( p1.x + r, p1.y + r ); + + // // Vector from center to m1 + // VECTOR2D m2 = m1 - c; + + // double len_m2 = m2.EuclideanNorm(); + // VECTOR2D mid_d = m2 / len_m2 * r; + + // VECTOR2I mid = VECTOR2I( static_cast( std::round( mid_d.x ) ), static_cast( std::round( mid_d.y ) )); + + // kicadObj->SetArcGeometry( end, mid, start ); + + // ksymbol->AddDrawItem( kicadObj.release() ); + // } + + auto segment = createEllipsoide( p1, p2, start, end ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + + // for( auto& segment : segments ) + { + segment->SetStroke( stroke ); + } + + return segment; +} + + +std::vector convPrimBezier2BEZIER(const PrimBezier* aOrcadObj) +{ + const int segments = static_cast( ( aOrcadObj->points.size() - 1 ) / 3 ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + + std::vector segmentsVec; + + for( int i = 0; i < segments; ++i ) + { + const auto start = VECTOR2I( convDimIU( aOrcadObj->points.at(i + 0).x ), convDimIU( aOrcadObj->points.at(i + 0).y ) ); + const auto c1 = VECTOR2I( convDimIU( aOrcadObj->points.at(i + 1).x ), convDimIU( aOrcadObj->points.at(i + 1).y ) ); + const auto c2 = VECTOR2I( convDimIU( aOrcadObj->points.at(i + 2).x ), convDimIU( aOrcadObj->points.at(i + 2).y ) ); + const auto end = VECTOR2I( convDimIU( aOrcadObj->points.at(i + 3).x ), convDimIU( aOrcadObj->points.at(i + 3).y ) ); + + SCH_SHAPE* kicadObj = new SCH_SHAPE( SHAPE_T::BEZIER, LAYER_DEVICE ); + + kicadObj->SetStroke( stroke ); + + kicadObj->SetStart( start ); + kicadObj->SetBezierC1( c1 ); + kicadObj->SetBezierC2( c2 ); + kicadObj->SetEnd( end ); + + segmentsVec.push_back( kicadObj ); + } + + return segmentsVec; +} + + +SCH_TEXT* convPrimCommentText2SCH_TEXT(const PrimCommentText* aOrcadObj) +{ + int32_t width = aOrcadObj->x2 - aOrcadObj->x1; + int32_t height = aOrcadObj->y2 - aOrcadObj->y1; + + VECTOR2I pos = VECTOR2I( convDimIU( aOrcadObj->locX + width / 2 ), convDimIU( aOrcadObj->locY + height / 2 ) ); + + wxString text = {aOrcadObj->name.c_str(), wxConvUTF8}; + + SCH_TEXT* kicadObj = new SCH_TEXT( pos, text, LAYER_NOTES, SCH_TEXT_T ); + + return kicadObj; +} + + +SCH_SHAPE* convPrimEllipse2POLY(const PrimEllipse* aOrcadObj) +{ + FILL_T fill; + + switch( aOrcadObj->getFillStyle() ) + { + case FillStyle::Solid: + fill = FILL_T::FILLED_SHAPE; + break; + case FillStyle::None: + fill = FILL_T::NO_FILL; + break; + default: // Hatching is not supported in Kicad + fill = FILL_T::NO_FILL; + break; + } + + const auto p1 = VECTOR2I( convDimIU( aOrcadObj->x1 ), convDimIU( aOrcadObj->y1 ) ); + const auto p2 = VECTOR2I( convDimIU( aOrcadObj->x2 ), convDimIU( aOrcadObj->y2 ) ); + + auto kicadObj = createEllipsoide( p1, p2, fill ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + kicadObj->SetStroke( stroke ); + + return kicadObj; +} + + +SCH_SHAPE* convPrimLine2POLY(const PrimLine* aOrcadObj) +{ + SCH_SHAPE* kicadObj = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + kicadObj->SetStroke( stroke ); + + kicadObj->AddPoint( VECTOR2I( convDimIU( aOrcadObj->x1 ), convDimIU( aOrcadObj->y1 ) ) ); + kicadObj->AddPoint( VECTOR2I( convDimIU( aOrcadObj->x2 ), convDimIU( aOrcadObj->y2 ) ) ); + + return kicadObj; +} + + +SCH_SHAPE* convPrimPolygon2POLY(const PrimPolygon* aOrcadObj) +{ + FILL_T fill; + + switch( aOrcadObj->fillStyle ) + { + case FillStyle::Solid: + fill = FILL_T::FILLED_SHAPE; + break; + case FillStyle::None: + fill = FILL_T::NO_FILL; + break; + default: // Hatching is not supported in Kicad + fill = FILL_T::NO_FILL; + break; + } + + SCH_SHAPE* kicadObj = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE, 0, fill ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + kicadObj->SetStroke( stroke ); + + for( const auto& point : aOrcadObj->points ) + { + kicadObj->AddPoint( VECTOR2I( convDimIU( point.x ), convDimIU( point.y ) ) ); + } + + return kicadObj; +} + + +SCH_SHAPE* convPrimPolyline2POLY(const PrimPolyline* aOrcadObj) +{ + SCH_SHAPE* kicadObj = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + kicadObj->SetStroke( stroke ); + + for( const auto& point : aOrcadObj->points ) + { + kicadObj->AddPoint( VECTOR2I( convDimIU( point.x ), convDimIU( point.y ) ) ); + } + + return kicadObj; +} + + +SCH_SHAPE* convPrimRect2RECTANGLE(const PrimRect* aOrcadObj) +{ + SCH_SHAPE* kicadObj = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE ); + + auto stroke = STROKE_PARAMS{}; + stroke.SetLineStyle( LineStyle2LINE_STYLE.at( aOrcadObj->getLineStyle() ) ); + stroke.SetWidth( LineWidth2Width.at( aOrcadObj->getLineWidth() ) ); + // stroke.SetColor( KIGFX::COLOR4D{0.0, 0.0, 0.0, 1.0} ); + kicadObj->SetStroke( stroke ); + + kicadObj->SetPosition( VECTOR2I( 0, 0 ) ); + kicadObj->SetStart( VECTOR2I( convDimIU( aOrcadObj->x1 ), convDimIU( aOrcadObj->y1 ) ) ); + kicadObj->SetEnd( VECTOR2I( convDimIU( aOrcadObj->x2 ), convDimIU( aOrcadObj->y2 ) ) ); + + return kicadObj; +} + + +int32_t convDimIU(int32_t aOrcadIU) +{ + return aOrcadIU * 2540; +} + + +PIN_ORIENTATION getPinOrientation(const StructSymbolPin* aPin) +{ + if( aPin->startX == aPin->hotptX ) + { + if( aPin->startY > aPin->hotptY) + { + return PIN_ORIENTATION::PIN_DOWN; + } + else + { + return PIN_ORIENTATION::PIN_UP; + } + } + + if( aPin->startY == aPin->hotptY ) + { + if( aPin->startX > aPin->hotptX) + { + return PIN_ORIENTATION::PIN_RIGHT; + } + else + { + return PIN_ORIENTATION::PIN_LEFT; + } + } + + // Pin orientation is kind of diagonal, + // return some dummy value. + return PIN_ORIENTATION::PIN_LEFT; +} + + +// aP1, aP2 are the points spanning the bounding rectangle of the ellipsoid +// A circle is a special ellipsoid where the bounding rectangle is square +bool isCircle(const VECTOR2I& aP1, const VECTOR2I& aP2) +{ + int32_t width = std::abs( aP1.x - aP2.x ); + int32_t height = std::abs( aP1.y - aP2.y ); + + if( width == height ) + { + return true; + } + + return false; +} + + +SCH_SHAPE* createEllipsoide(const VECTOR2I& aP1, const VECTOR2I& aP2, FILL_T aFill ) +{ + auto rect = std::make_unique( SHAPE_T::RECTANGLE, LAYER_DEVICE ); + rect->SetPosition( aP1 ); + rect->SetStart( aP1 ); + rect->SetEnd( aP2 ); + + // Draw bounding rectangle + // return rect.release(); + + const double r1 = rect->GetRectangleWidth() / 2.0; //!< Radius 1 + const double r2 = rect->GetRectangleHeight() / 2.0; //!< Radius 2 + + // Ellipsoid midpoint + const VECTOR2D mid = VECTOR2D( aP1.x + r1, aP1.y + r2 ); + + // Number of linear segments we approximate the ellipsoid with + const int numberSegments = 100; + + SCH_SHAPE* s = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE, 0, aFill ); + + for(int i = 0; i < numberSegments; ++i) + { + const double da = 2.0 * std::numbers::pi / (numberSegments - 1); + const double x = mid.x + r1 * std::cos(i * da); + const double y = mid.y + r2 * std::sin(i * da); + const auto p = VECTOR2I( static_cast(std::round(x)), static_cast(std::round(y)) ); + + s->AddPoint( p ); + } + + return s; +} + + +SCH_SHAPE* createEllipsoide(const VECTOR2I& aP1, const VECTOR2I& aP2, const VECTOR2I& aStart, const VECTOR2I& aEnd ) +{ + auto rect = std::make_unique( SHAPE_T::RECTANGLE, LAYER_DEVICE ); + rect->SetPosition( aP1 ); + rect->SetStart( aP1 ); + rect->SetEnd( aP2 ); + + const double r1 = rect->GetRectangleWidth() / 2.0; //!< Radius 1 + const double r2 = rect->GetRectangleHeight() / 2.0; //!< Radius 2 + + // Ellipsoid midpoint + const VECTOR2D mid = VECTOR2D( aP1.x + r1, aP1.y + r2 ); + + const VECTOR2D startVec = aStart - mid; + const VECTOR2D endVec = aEnd - mid; + + const VECTOR2D normX = VECTOR2D( 1.0, 0.0 ); + + const double phi_start = std::acos( (startVec.x * normX.x + startVec.y * normX.y ) / ( startVec.EuclideanNorm() * normX.EuclideanNorm() ) ); + const double phi_end = std::acos( (endVec.x * normX.x + endVec.y * normX.y ) / ( endVec.EuclideanNorm() * normX.EuclideanNorm() ) ); + + double delta_phi = ( endVec.x * startVec.x + endVec.y * startVec.y ) / ( endVec.EuclideanNorm() * startVec.EuclideanNorm() ); + delta_phi = std::acos( delta_phi ); + + // Number of linear segments we approximate the ellipsoid with + const int numberSegments = 100; + + SCH_SHAPE* s = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE ); + + double phi = phi_end; + // double delta_phi = (phi_end - phi_start) - 360; + + for(int i = 0; i < numberSegments; ++i) + { + const double da = delta_phi / (numberSegments - 1); + const double x = mid.x + r1 * std::cos(i * da + phi); + const double y = mid.y + r2 * std::sin(i * da + phi); + const auto p = VECTOR2I( static_cast(std::round(x)), static_cast(std::round(y)) ); + + s->AddPoint( p ); + } + + return s; +} + + +// OrCAD uses trailing backslashes after each character to +// indicate a overbar over that character. +// E.g. OrCAD `R\E\S\E\T\` becomes KiCAD `~{RESET}` +wxString convPinName( const std::string& aOrCadPinName ) +{ + struct CharProp + { + CharProp() : str{}, hasOverbar{false} { } + CharProp(const std::string& aStr, bool aHasOverbar) : str{aStr}, hasOverbar{aHasOverbar} { } + + std::string str; + bool hasOverbar; + }; + + std::deque charProps; + + for( const auto& c : aOrCadPinName ) + { + if( c == '\\' ) + { + if( !charProps.empty() ) + { + charProps.back().hasOverbar = true; + } + } + else + { + charProps.push_back( {std::string{c}, false} ); + } + } + + std::deque strProps; + + // Combine multiple successive short overbars to one large + for( const auto& charProp : charProps ) + { + if( strProps.empty() ) + { + strProps.push_back( charProp ); + continue; + } + + if( (charProp.hasOverbar && strProps.back().hasOverbar) || + (!charProp.hasOverbar && !strProps.back().hasOverbar ) ) + { + strProps.back().str += charProp.str; + } + else + { + strProps.push_back( charProp ); + } + } + + std::string kicadPinName{}; + + for( const auto& strProp : strProps ) + { + if( strProp.hasOverbar ) + { + kicadPinName += std::string{"~{"} + strProp.str + std::string{"}"}; + } + else + { + kicadPinName += strProp.str; + } + } + + return wxString{kicadPinName.c_str(), wxConvUTF8}; +} + + +SCH_PIN* StreamPackage2SCH_PIN( const StreamPackage* aOrcadStream, LIB_SYMBOL* aSymbol, uint32_t aIdx ) +{ + if( !aOrcadStream ) + { + return nullptr; + } + + if( aOrcadStream->libraryParts.empty() ) + { + return nullptr; + } + + StructSymbolPin* pkgPin = nullptr; + + if( aIdx < aOrcadStream->libraryParts.at( 0 )->symbolPins.size() ) + { + pkgPin = aOrcadStream->libraryParts.at( 0 )->symbolPins.at( aIdx ).get(); + } + + if( !pkgPin ) + { + return nullptr; + } + + SCH_PIN* pin = new SCH_PIN( aSymbol ); + + pin->SetName( convPinName( pkgPin->name ) ); + + const GRAPHIC_PINSHAPE shape = OrCad2Kicad_PinShape.at( ToShapeType( pkgPin->pinShape ) ); + pin->SetShape( shape ); + + wxString pinNumber = wxString{"", wxConvUTF8}; + + do + { + if( !aOrcadStream->package ) + { + break; + } + + if( aOrcadStream->package->devices.empty() ) + { + break; + } + + if( !aOrcadStream->package->devices.at( 0 ) ) + { + break; + } + + if( aIdx < aOrcadStream->package->devices.at( 0 )->pinMap.size() ) + { + pinNumber = wxString{aOrcadStream->package->devices.at( 0 )->pinMap.at( aIdx ).c_str(), wxConvUTF8}; + } + } + while( false ); + + pin->SetNumber( pinNumber ); + + const auto pinOrientation = getPinOrientation( pkgPin ); + pin->SetOrientation( pinOrientation ); + pin->SetType( OrCad2Kicad_PinType.at( pkgPin->portType ) ); + pin->SetLength( convDimIU( pkgPin->getPinLength() ) ); + pin->SetPosition( VECTOR2I( convDimIU ( pkgPin->hotptX ), convDimIU( pkgPin->hotptY ) ) ); + + return pin; +} \ No newline at end of file diff --git a/eeschema/sch_io/orcad/orcad2kicad.h b/eeschema/sch_io/orcad/orcad2kicad.h new file mode 100644 index 0000000000..5fe7ac668b --- /dev/null +++ b/eeschema/sch_io/orcad/orcad2kicad.h @@ -0,0 +1,104 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Dominik Wernberger + * Copyright (C) 2024 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 + +#include +#include +#include +#include + +// OpenOrcadParser Headers +#include "Enums/LineStyle.hpp" +#include "Enums/LineWidth.hpp" +#include "PinShape.hpp" +#include "Primitives/PrimArc.hpp" +#include "Primitives/PrimBezier.hpp" +#include "Primitives/PrimCommentText.hpp" +#include "Primitives/PrimEllipse.hpp" +#include "Primitives/PrimLine.hpp" +#include "Primitives/PrimPolygon.hpp" +#include "Primitives/PrimPolyline.hpp" +#include "Primitives/PrimRect.hpp" +#include "Streams/StreamPackage.hpp" +#include "Structures/StructSymbolPin.hpp" + + +SCH_SHAPE* convPrimArc2ARC(const PrimArc* aObj); +std::vector convPrimBezier2BEZIER(const PrimBezier* aOrcadObj); +SCH_TEXT* convPrimCommentText2SCH_TEXT(const PrimCommentText* aOrcadObj); +SCH_SHAPE* convPrimEllipse2POLY(const PrimEllipse* aOrcadObj); +SCH_SHAPE* convPrimLine2POLY(const PrimLine* aOrcadObj); +SCH_SHAPE* convPrimPolyline2POLY(const PrimPolyline* aOrcadObj); +SCH_SHAPE* convPrimPolygon2POLY(const PrimPolygon* aOrcadObj); +SCH_SHAPE* convPrimRect2RECTANGLE(const PrimRect* aOrcadObj); +int32_t convDimIU(int32_t aOrcadIU); +PIN_ORIENTATION getPinOrientation(int32_t aStartX, int32_t aStartY, int32_t aHotptX, int32_t aHotptY); +bool isCircle(const VECTOR2I& aP1, const VECTOR2I& aP2); +SCH_SHAPE* createEllipsoide(const VECTOR2I& aP1, const VECTOR2I& aP2, FILL_T aFill = FILL_T::NO_FILL); +SCH_SHAPE* createEllipsoide(const VECTOR2I& aP1, const VECTOR2I& aP2, const VECTOR2I& aStart, const VECTOR2I& aEnd ); +SCH_PIN* StreamPackage2SCH_PIN( const StreamPackage* aOrcadStream, LIB_SYMBOL* aSymbol, uint32_t aIdx ); + + +const std::map OrCad2Kicad_PinShape = { + {ShapeType::Clock, GRAPHIC_PINSHAPE::CLOCK}, + {ShapeType::Dot, GRAPHIC_PINSHAPE::INVERTED}, + {ShapeType::DotClock, GRAPHIC_PINSHAPE::INVERTED_CLOCK}, + {ShapeType::Line, GRAPHIC_PINSHAPE::LINE}, + {ShapeType::Short, GRAPHIC_PINSHAPE::LINE}, + {ShapeType::ShortClock, GRAPHIC_PINSHAPE::CLOCK}, + {ShapeType::ShortDot, GRAPHIC_PINSHAPE::INVERTED}, + {ShapeType::ShortDotClock, GRAPHIC_PINSHAPE::INVERTED_CLOCK}, + {ShapeType::ZeroLength, GRAPHIC_PINSHAPE::LINE} +}; + + +const std::map OrCad2Kicad_PinType = { + {PortType::Input, ELECTRICAL_PINTYPE::PT_INPUT}, + {PortType::Bidirectional, ELECTRICAL_PINTYPE::PT_BIDI}, + {PortType::Output, ELECTRICAL_PINTYPE::PT_OUTPUT}, + {PortType::OpenCollector, ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR}, + {PortType::Passive, ELECTRICAL_PINTYPE::PT_PASSIVE}, + {PortType::ThreeState, ELECTRICAL_PINTYPE::PT_TRISTATE}, + {PortType::OpenEmitter, ELECTRICAL_PINTYPE::PT_OPENEMITTER}, + {PortType::Power, ELECTRICAL_PINTYPE::PT_UNSPECIFIED} // We can't know whether to use PT_POWER_IN or PT_POWER_OUT +}; + + +const std::map LineWidth2Width = { + {LineWidth::Thin, 3 * 254}, + {LineWidth::Medium, 9 * 254}, + {LineWidth::Wide, 12 * 254}, + {LineWidth::Default, 0} // Defaults to 6 * 254 +}; + + +const std::map LineStyle2LINE_STYLE = { + {LineStyle::Solid, LINE_STYLE::SOLID}, + {LineStyle::Dash, LINE_STYLE::DASH}, + {LineStyle::Dot, LINE_STYLE::DOT}, + {LineStyle::DashDot, LINE_STYLE::DASHDOT}, + {LineStyle::DashDotDot, LINE_STYLE::DASHDOTDOT}, + {LineStyle::Default, LINE_STYLE::DEFAULT} +}; diff --git a/eeschema/sch_io/orcad/sch_io_orcad.cpp b/eeschema/sch_io/orcad/sch_io_orcad.cpp new file mode 100644 index 0000000000..2e14a50382 --- /dev/null +++ b/eeschema/sch_io/orcad/sch_io_orcad.cpp @@ -0,0 +1,397 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Dominik Wernberger + * Copyright (C) 2024 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 +#include +#include + +#include "sch_io_orcad.h" +#include "orcad2kicad.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +// OpenOrcadParser Headers +#include "Container.hpp" +#include "Enums/DirectoryType.hpp" +#include "GetStreamHelper.hpp" +#include "PinShape.hpp" +#include "Primitives/PrimArc.hpp" +#include "Primitives/PrimBezier.hpp" +#include "Primitives/PrimCommentText.hpp" +#include "Primitives/PrimLine.hpp" +#include "Primitives/PrimPolygon.hpp" +#include "Primitives/PrimPolyline.hpp" +#include "Primitives/PrimRect.hpp" +#include "Streams/StreamPackage.hpp" + + +namespace fs = std::filesystem; + + +Database parseDatabase(const wxString& aLibraryPath) +{ + + const fs::path dbPath{std::string{aLibraryPath.mb_str()}}; + Container parser{dbPath, ParserConfig{}}; + + // ContainerContext& ctx = parser.getContext(); + + parser.parseDatabaseFile(); + + Database db = parser.getDb(); + + return db; +} + + +void dummy_create_in_schematic(SCHEMATIC* aSchematic, SCH_SHEET* aRootSheet) +{ + std::unique_ptr ksymbol = std::make_unique( wxEmptyString ); + + LIB_ID libId; + libId.Parse( "foo", true ); + + ksymbol->SetPower(); + ksymbol->SetLibId( libId ); + ksymbol->SetName( "Name" ); + ksymbol->GetReferenceField().SetText( wxS( "#PWR" ) ); + ksymbol->GetReferenceField().SetVisible( false ); + ksymbol->GetValueField().SetText( "Name" ); + ksymbol->GetValueField().SetVisible( true ); + ksymbol->SetDescription( wxString::Format( _( "Power symbol creates a global " + "label with name '%s'" ), + "Name" ) ); + ksymbol->SetKeyWords( wxS( "power-flag" ) ); + ksymbol->SetShowPinNames( false ); + ksymbol->SetShowPinNumbers( false ); + + std::unique_ptr pin = std::make_unique( ksymbol.get() ); + + pin->SetName( "Name" ); + pin->SetNumber( wxS( "1" ) ); + pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); + pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN ); + pin->SetLength( 0 ); + + ksymbol->AddDrawItem( pin.release() ); + + + + LIB_SYMBOL* pwrLibSym = ksymbol.release(); + + + + std::unique_ptr schSym = std::make_unique( + *pwrLibSym, libId, &aSchematic->CurrentSheet(), 0 ); + + VECTOR2D pos( 0, 0 ); + schSym->SetPosition( pos ); + schSym->SetRef( &aSchematic->CurrentSheet(), "asdf" ); + + SCH_SCREEN* screen = aRootSheet->GetScreen(); + screen->Append( schSym.release() ); +} + + +bool SCH_IO_ORCAD::CanReadSchematicFile( const wxString& aFileName ) const +{ + // Not yet supported + return false; +} + + +bool SCH_IO_ORCAD::CanReadLibrary( const wxString& aFileName ) const +{ + return true; +} + + +int SCH_IO_ORCAD::GetModifyHash() const +{ + return 0; +} + + +void SCH_IO_ORCAD::EnumerateSymbolLib( wxArrayString& aSymbolNameList, + const wxString& aLibraryPath, + const STRING_UTF8_MAP* aProperties ) +{ + if( !m_db.has_value() ) + { + m_db = parseDatabase( aLibraryPath ); + } + + const auto dir = getDirectoryStreamFromDb( + m_db.value(), DirectoryType::PackagesDirectory ); + + if( dir ) + { + for( const auto& item : dir->items ) + { + std::cout << "Enumerate package " << item.name << std::endl; + aSymbolNameList.Add( wxString{item.name.c_str(), wxConvUTF8} ); + } + } + + std::cout << "Enumerated " << aSymbolNameList.size() << " packages" << std::endl; +} + + +void SCH_IO_ORCAD::EnumerateSymbolLib( std::vector& aSymbolList, + const wxString& aLibraryPath, + const STRING_UTF8_MAP* aProperties ) +{ + wxArrayString aSymbolNameList{}; + EnumerateSymbolLib( aSymbolNameList, aLibraryPath, aProperties ); + + for(const auto& name : aSymbolNameList ) + { + std::cout << "Loading package " << name << std::endl; + const auto symbol = LoadSymbol( aLibraryPath, name, aProperties ); + aSymbolList.push_back( symbol ); + } + + std::cout << "Loaded " << aSymbolNameList.size() << " packages" << std::endl; +} + + +LIB_SYMBOL* SCH_IO_ORCAD::LoadSymbol( const wxString& aLibraryPath, + const wxString& aAliasName, + const STRING_UTF8_MAP* aProperties ) +{ + std::cout << "Loading " << aAliasName << std::endl; + + if( !m_db.has_value() ) + { + m_db = parseDatabase( aLibraryPath ); + } + + std::shared_ptr package{}; + + for( auto& stream : m_db.value().mStreams ) + { + if( stream->mCtx.mCfbfStreamLocation.matches_pattern({{"Packages"}, {std::string{aAliasName.mb_str()}}}) ) + { + package = std::dynamic_pointer_cast( stream ); + break; + } + } + + LIB_SYMBOL* ksymbol = new LIB_SYMBOL( wxEmptyString ); + + if(package) + { + wxString name{"Dummy", wxConvUTF8}; + wxString refDes{"X", wxConvUTF8}; + wxString pcbFootprint{"", wxConvUTF8}; + + if( package->package ) + { + name = wxString{package->package->name.c_str(), wxConvUTF8}; + refDes = wxString{package->package->refDes.c_str(), wxConvUTF8}; + pcbFootprint = wxString{package->package->pcbFootprint.c_str(), wxConvUTF8}; + } + + for( const auto& libraryPart : package->libraryParts ) + { + if( !libraryPart ) + { + continue; + } + + for( const auto& primitive : libraryPart->primitives ) + { + switch( primitive->getObjectType() ) + { + case Primitive::Arc: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimArc2ARC( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + case Primitive::Bezier: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto segments = convPrimBezier2BEZIER( orcadObj ); + + for( auto& segment : segments ) + { + ksymbol->AddDrawItem( segment ); + } + + break; + } + case Primitive::CommentText: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimCommentText2SCH_TEXT( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + case Primitive::Ellipse: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimEllipse2POLY( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + case Primitive::Line: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimLine2POLY( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + case Primitive::Polygon: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimPolygon2POLY( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + case Primitive::Polyline: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimPolyline2POLY( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + case Primitive::Rect: + { + const auto orcadObj = dynamic_cast( primitive.get() ); + auto kicadObj = convPrimRect2RECTANGLE( orcadObj ); + ksymbol->AddDrawItem( kicadObj ); + break; + } + default: + std::cout << "Unimplemented Primitive detected" << std::endl; + break; + } + } + + for( size_t i = 0U; i < libraryPart->symbolPins.size(); ++i ) + { + auto pin = StreamPackage2SCH_PIN( package.get(), ksymbol, i ); + + if( pin ) + { + ksymbol->AddDrawItem( pin ); + } + } + } + + LIB_ID libId{ wxS( "Library" ), name }; + + ksymbol->SetLibId( libId ); + ksymbol->SetName( name ); + + ksymbol->GetReferenceField().SetText( refDes ); + ksymbol->GetReferenceField().SetVisible( true ); + + ksymbol->GetFootprintField().SetText( pcbFootprint ); + ksymbol->GetFootprintField().SetVisible( false ); + + ksymbol->GetValueField().SetText( wxS( "" ) ); + ksymbol->GetValueField().SetVisible( true ); + + bool pinNameVisible = true; + bool pinNumberVisible = true; + + if( package && !package->libraryParts.empty() ) + { + const auto& generalProperties = package->libraryParts.at(0)->generalProperties; + + pinNameVisible = generalProperties.pinNameVisible; + pinNumberVisible = generalProperties.pinNumberVisible; + } + + ksymbol->SetShowPinNames( pinNameVisible ); + ksymbol->SetShowPinNumbers( pinNumberVisible ); + } + + return ksymbol; +} + + +SCH_SHEET* SCH_IO_ORCAD::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic, + SCH_SHEET* aAppendToMe, + const STRING_UTF8_MAP* aProperties ) +{ + std::cout << "Loading schematic " << std::endl; + + wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr ); + + SCH_SHEET* rootSheet = nullptr; + + if( aAppendToMe ) + { + wxCHECK_MSG( aSchematic->IsValid(), nullptr, + wxS( "Can't append to a schematic with no root!" ) ); + + rootSheet = &aSchematic->Root(); + } + else + { + rootSheet = new SCH_SHEET( aSchematic ); + rootSheet->SetFileName( aFileName ); + aSchematic->SetRoot( rootSheet ); + } + + if( !rootSheet->GetScreen() ) + { + SCH_SCREEN* screen = new SCH_SCREEN( aSchematic ); + + screen->SetFileName( aFileName ); + rootSheet->SetScreen( screen ); + } + + SYMBOL_LIB_TABLE* libTable = PROJECT_SCH::SchSymbolLibTable( &aSchematic->Prj() ); + + wxCHECK_MSG( libTable, nullptr, wxS( "Could not load symbol lib table." ) ); + + // @todo + // LoadSchematic( aSchematic, rootSheet, aFileName ); + dummy_create_in_schematic(aSchematic, rootSheet); + + aSchematic->CurrentSheet().UpdateAllScreenReferences(); + + return rootSheet; +} diff --git a/eeschema/sch_io/orcad/sch_io_orcad.h b/eeschema/sch_io/orcad/sch_io_orcad.h new file mode 100644 index 0000000000..5d830813d9 --- /dev/null +++ b/eeschema/sch_io/orcad/sch_io_orcad.h @@ -0,0 +1,92 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Dominik Wernberger + * Copyright (C) 2024 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 + */ + +#ifndef SCH_IO_ORCAD_H_ +#define SCH_IO_ORCAD_H_ + +#include + +#include +#include +#include +#include +#include + +// OpenOrcadParser headers +#include "Database.hpp" + + +class SCH_SHEET; +class SCH_SCREEN; + + +class SCH_IO_ORCAD : public SCH_IO +{ +public: + SCH_IO_ORCAD() : SCH_IO( wxS( "OrCAD Database" ) ), m_db{} + { + m_reporter = &WXLOG_REPORTER::GetInstance(); + } + + ~SCH_IO_ORCAD() {} + + const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override + { + return IO_BASE::IO_FILE_DESC( _HKI( "OrCAD Design files" ), + { FILEEXT::OrCadDesignFileExtension, FILEEXT::OrCadDesignBackupFileExtension } ); + } + + const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override + { + return IO_BASE::IO_FILE_DESC( _HKI( "OrCAD Library files" ), + { FILEEXT::OrCadLibraryFileExtension, FILEEXT::OrCadLibraryBackupFileExtension } ); + } + + bool CanReadSchematicFile( const wxString& aFileName ) const override; + + bool CanReadLibrary( const wxString& aFileName ) const override; + + int GetModifyHash() const override; + + SCH_SHEET* LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic, + SCH_SHEET* aAppendToMe = nullptr, + const STRING_UTF8_MAP* aProperties = nullptr ) override; + + void EnumerateSymbolLib( wxArrayString& aSymbolNameList, const wxString& aLibraryPath, + const STRING_UTF8_MAP* aProperties = nullptr ) override; + + void EnumerateSymbolLib( std::vector& aSymbolList, const wxString& aLibraryPath, + const STRING_UTF8_MAP* aProperties = nullptr ) override; + + LIB_SYMBOL* LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName, + const STRING_UTF8_MAP* aProperties = nullptr ) override; + + bool IsLibraryWritable( const wxString& aLibraryPath ) override { return false; } + +private: + std::optional m_db; +}; + + +#endif // SCH_IO_ORCAD_H_ diff --git a/eeschema/sch_io/sch_io_mgr.cpp b/eeschema/sch_io/sch_io_mgr.cpp index caef05fbb3..9364b395c5 100644 --- a/eeschema/sch_io/sch_io_mgr.cpp +++ b/eeschema/sch_io/sch_io_mgr.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include // for ExpandEnvVarSubstitutions @@ -74,6 +75,7 @@ SCH_IO* SCH_IO_MGR::FindPlugin( SCH_FILE_T aFileType ) case SCH_EASYEDA: return new SCH_IO_EASYEDA(); case SCH_EASYEDAPRO: return new SCH_IO_EASYEDAPRO(); case SCH_LTSPICE: return new SCH_IO_LTSPICE(); + case SCH_ORCAD: return new SCH_IO_ORCAD(); case SCH_HTTP: return new SCH_IO_HTTP_LIB(); default: return nullptr; } @@ -97,6 +99,7 @@ const wxString SCH_IO_MGR::ShowType( SCH_FILE_T aType ) case SCH_EASYEDA: return wxString( wxT( "EasyEDA (JLCEDA) Std" ) ); case SCH_EASYEDAPRO: return wxString( wxT( "EasyEDA (JLCEDA) Pro" ) ); case SCH_LTSPICE: return wxString( wxT( "LTspice" ) ); + case SCH_ORCAD: return wxString( wxT( "OrCAD" ) ); case SCH_HTTP: return wxString( wxT( "HTTP" ) ); default: return wxString::Format( _( "Unknown SCH_FILE_T value: %d" ), aType ); @@ -128,6 +131,8 @@ SCH_IO_MGR::SCH_FILE_T SCH_IO_MGR::EnumFromStr( const wxString& aType ) return SCH_EASYEDAPRO; else if( aType == wxT( "LTspice" ) ) return SCH_LTSPICE; + else if( aType == wxT( "OrCAD" ) ) + return SCH_ORCAD; else if( aType == wxT( "HTTP" ) ) return SCH_HTTP; diff --git a/eeschema/sch_io/sch_io_mgr.h b/eeschema/sch_io/sch_io_mgr.h index 8e5076ecc9..9471fbf65c 100644 --- a/eeschema/sch_io/sch_io_mgr.h +++ b/eeschema/sch_io/sch_io_mgr.h @@ -68,6 +68,7 @@ public: SCH_EASYEDA, ///< EasyEDA Std schematic file SCH_EASYEDAPRO, ///< EasyEDA Pro archive SCH_LTSPICE, ///< LtSpice Schematic format + SCH_ORCAD, ///< OrCAD file format SCH_HTTP, ///< KiCad HTTP library // Add your schematic type here. diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h index 6686e8a84e..76a2c0ac0f 100644 --- a/include/wildcards_and_files_ext.h +++ b/include/wildcards_and_files_ext.h @@ -133,6 +133,10 @@ public: static const std::string KiCadSchematicFileExtension; static const std::string SpiceFileExtension; static const std::string CadstarNetlistFileExtension; + static const std::string OrCadDesignFileExtension; + static const std::string OrCadDesignBackupFileExtension; + static const std::string OrCadLibraryFileExtension; + static const std::string OrCadLibraryBackupFileExtension; static const std::string OrCadPcb2NetlistFileExtension; static const std::string NetlistFileExtension; static const std::string AllegroNetlistFileExtension; diff --git a/qa/tests/eeschema/CMakeLists.txt b/qa/tests/eeschema/CMakeLists.txt index b0cae74808..e5fbe3759b 100644 --- a/qa/tests/eeschema/CMakeLists.txt +++ b/qa/tests/eeschema/CMakeLists.txt @@ -109,6 +109,7 @@ PRIVATE ${GDI_PLUS_LIBRARIES} Boost::headers Boost::unit_test_framework + ${OPENORCADPARSER_PATH}/build/lib/libOpenOrCadParser.so ) # Eeschema tests, so pretend to be eeschema (for units, etc) diff --git a/qa/tests/spice/CMakeLists.txt b/qa/tests/spice/CMakeLists.txt index 26733ec6fe..c8c73dc5e7 100644 --- a/qa/tests/spice/CMakeLists.txt +++ b/qa/tests/spice/CMakeLists.txt @@ -93,6 +93,7 @@ PRIVATE ${GDI_PLUS_LIBRARIES} Boost::headers Boost::unit_test_framework + ${OPENORCADPARSER_PATH}/build/lib/libOpenOrCadParser.so ) if( KICAD_SPICE_QA AND MSVC ) diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 138f3c9dc8..a7fc3770be 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -21,6 +21,8 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # +include(FetchContent) + # Disable shared library building for all thirdparty libraries set( BUILD_SHARED_LIBS OFF ) @@ -32,6 +34,13 @@ set( BUILD_SHARED_LIBS OFF ) # instead of with cmake_policy will apply the change to the third-party CMakeLists files. set( CMAKE_POLICY_DEFAULT_CMP0077 NEW ) +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt + GIT_TAG 10.2.1 +) +FetchContent_MakeAvailable(fmt) + set( ARGPARSE_INSTALL OFF ) add_subdirectory( argparse ) add_subdirectory( clipper ) @@ -40,8 +49,8 @@ add_subdirectory( compoundfilereader ) add_subdirectory( delaunator ) add_subdirectory( dxflib_qcad ) add_subdirectory( expected ) -set( FMT_INSTALL OFF ) -add_subdirectory( fmt ) +# set( FMT_INSTALL OFF ) +# add_subdirectory( fmt ) add_subdirectory( gzip-hpp ) add_subdirectory( lemon ) add_subdirectory( libcontext ) diff --git a/thirdparty/nanodbc/CMakeLists.txt b/thirdparty/nanodbc/CMakeLists.txt index 4a573199b2..b9be9dd003 100644 --- a/thirdparty/nanodbc/CMakeLists.txt +++ b/thirdparty/nanodbc/CMakeLists.txt @@ -30,6 +30,7 @@ message(STATUS "nanodbc compile: C++${CMAKE_CXX_STANDARD}") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_COMPILER_IS_GNUCXX) include(CheckCXXCompilerFlag) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") string(REGEX REPLACE "[/-]W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") if (NOT (CMAKE_VERSION VERSION_LESS 3.6.0)) # Compiler features for Intel in CMake 3.6+