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.

215 lines
6.8 KiB

2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2023 Jon Evans <jon@craftyjon.com>
  5. * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
  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 along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <magic_enum.hpp>
  21. #include <api/api_utils.h>
  22. #include <geometry/shape_poly_set.h>
  23. #include <wx/log.h>
  24. const wxChar* const traceApi = wxT( "KICAD_API" );
  25. namespace kiapi::common
  26. {
  27. KICOMMON_API std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage )
  28. {
  29. static const std::map<std::string, KICAD_T> s_types = {
  30. { "type.googleapis.com/kiapi.board.types.Track", PCB_TRACE_T },
  31. { "type.googleapis.com/kiapi.board.types.Arc", PCB_ARC_T },
  32. { "type.googleapis.com/kiapi.board.types.Via", PCB_VIA_T },
  33. { "type.googleapis.com/kiapi.board.types.BoardText", PCB_TEXT_T },
  34. { "type.googleapis.com/kiapi.board.types.BoardTextBox", PCB_TEXTBOX_T },
  35. { "type.googleapis.com/kiapi.board.types.BoardGraphicShape", PCB_SHAPE_T },
  36. { "type.googleapis.com/kiapi.board.types.Pad", PCB_PAD_T },
  37. { "type.googleapis.com/kiapi.board.types.Zone", PCB_ZONE_T },
  38. { "type.googleapis.com/kiapi.board.types.Dimension", PCB_DIMENSION_T },
  39. { "type.googleapis.com/kiapi.board.types.ReferenceImage", PCB_REFERENCE_IMAGE_T },
  40. { "type.googleapis.com/kiapi.board.types.Group", PCB_GROUP_T },
  41. { "type.googleapis.com/kiapi.board.types.Field", PCB_FIELD_T },
  42. { "type.googleapis.com/kiapi.board.types.FootprintInstance", PCB_FOOTPRINT_T },
  43. };
  44. auto it = s_types.find( aMessage.type_url() );
  45. if( it != s_types.end() )
  46. return it->second;
  47. wxLogTrace( traceApi, wxString::Format( wxS( "Any message type %s is not known" ),
  48. aMessage.type_url() ) );
  49. return std::nullopt;
  50. }
  51. KICOMMON_API LIB_ID LibIdFromProto( const types::LibraryIdentifier& aId )
  52. {
  53. return LIB_ID( aId.library_nickname(), aId.entry_name() );
  54. }
  55. KICOMMON_API types::LibraryIdentifier LibIdToProto( const LIB_ID& aId )
  56. {
  57. types::LibraryIdentifier msg;
  58. msg.set_library_nickname( aId.GetLibNickname() );
  59. msg.set_entry_name( aId.GetLibItemName() );
  60. return msg;
  61. }
  62. KICOMMON_API void PackVector2( types::Vector2& aOutput, const VECTOR2I& aInput )
  63. {
  64. aOutput.set_x_nm( aInput.x );
  65. aOutput.set_y_nm( aInput.y );
  66. }
  67. KICOMMON_API VECTOR2I UnpackVector2( const types::Vector2& aInput )
  68. {
  69. return VECTOR2I( aInput.x_nm(), aInput.y_nm() );
  70. }
  71. KICOMMON_API void PackVector3D( types::Vector3D& aOutput, const VECTOR3D& aInput )
  72. {
  73. aOutput.set_x_nm( aInput.x );
  74. aOutput.set_y_nm( aInput.y );
  75. aOutput.set_z_nm( aInput.z );
  76. }
  77. KICOMMON_API VECTOR3D UnpackVector3D( const types::Vector3D& aInput )
  78. {
  79. return VECTOR3D( aInput.x_nm(), aInput.y_nm(), aInput.z_nm() );
  80. }
  81. KICOMMON_API void PackBox2( types::Box2& aOutput, const BOX2I& aInput )
  82. {
  83. PackVector2( *aOutput.mutable_position(), aInput.GetOrigin() );
  84. PackVector2( *aOutput.mutable_size(), aInput.GetSize() );
  85. }
  86. KICOMMON_API BOX2I UnpackBox2( const types::Box2& aInput )
  87. {
  88. return BOX2I( UnpackVector2( aInput.position() ), UnpackVector2( aInput.size() ) );
  89. }
  90. KICOMMON_API void PackPolyLine( types::PolyLine& aOutput, const SHAPE_LINE_CHAIN& aSlc )
  91. {
  92. for( int vertex = 0; vertex < aSlc.PointCount(); vertex = aSlc.NextShape( vertex ) )
  93. {
  94. if( vertex < 0 )
  95. break;
  96. types::PolyLineNode* node = aOutput.mutable_nodes()->Add();
  97. if( aSlc.IsPtOnArc( vertex ) )
  98. {
  99. const SHAPE_ARC& arc = aSlc.Arc( aSlc.ArcIndex( vertex ) );
  100. node->mutable_arc()->mutable_start()->set_x_nm( arc.GetP0().x );
  101. node->mutable_arc()->mutable_start()->set_y_nm( arc.GetP0().y );
  102. node->mutable_arc()->mutable_mid()->set_x_nm( arc.GetArcMid().x );
  103. node->mutable_arc()->mutable_mid()->set_y_nm( arc.GetArcMid().y );
  104. node->mutable_arc()->mutable_end()->set_x_nm( arc.GetP1().x );
  105. node->mutable_arc()->mutable_end()->set_y_nm( arc.GetP1().y );
  106. }
  107. else
  108. {
  109. node->mutable_point()->set_x_nm( aSlc.CPoint( vertex ).x );
  110. node->mutable_point()->set_y_nm( aSlc.CPoint( vertex ).y );
  111. }
  112. }
  113. aOutput.set_closed( aSlc.IsClosed() );
  114. }
  115. KICOMMON_API SHAPE_LINE_CHAIN UnpackPolyLine( const types::PolyLine& aInput )
  116. {
  117. SHAPE_LINE_CHAIN slc;
  118. for( const types::PolyLineNode& node : aInput.nodes() )
  119. {
  120. if( node.has_point() )
  121. {
  122. slc.Append( VECTOR2I( node.point().x_nm(), node.point().y_nm() ) );
  123. }
  124. else if( node.has_arc() )
  125. {
  126. slc.Append( SHAPE_ARC( VECTOR2I( node.arc().start().x_nm(), node.arc().start().y_nm() ),
  127. VECTOR2I( node.arc().mid().x_nm(), node.arc().mid().y_nm() ),
  128. VECTOR2I( node.arc().end().x_nm(), node.arc().end().y_nm() ),
  129. 0 /* don't care about width here */ ) );
  130. }
  131. }
  132. slc.SetClosed( aInput.closed() );
  133. return slc;
  134. }
  135. KICOMMON_API void PackPolySet( types::PolySet& aOutput, const SHAPE_POLY_SET& aInput )
  136. {
  137. for( int idx = 0; idx < aInput.OutlineCount(); ++idx )
  138. {
  139. const SHAPE_POLY_SET::POLYGON& poly = aInput.Polygon( idx );
  140. if( poly.empty() )
  141. continue;
  142. types::PolygonWithHoles* polyMsg = aOutput.mutable_polygons()->Add();
  143. PackPolyLine( *polyMsg->mutable_outline(), poly.front() );
  144. if( poly.size() > 1 )
  145. {
  146. for( size_t hole = 1; hole < poly.size(); ++hole )
  147. {
  148. types::PolyLine* pl = polyMsg->mutable_holes()->Add();
  149. PackPolyLine( *pl, poly[hole] );
  150. }
  151. }
  152. }
  153. }
  154. KICOMMON_API SHAPE_POLY_SET UnpackPolySet( const types::PolySet& aInput )
  155. {
  156. SHAPE_POLY_SET sps;
  157. for( const types::PolygonWithHoles& polygonWithHoles : aInput.polygons() )
  158. {
  159. SHAPE_POLY_SET::POLYGON polygon;
  160. polygon.emplace_back( UnpackPolyLine( polygonWithHoles.outline() ) );
  161. for( const types::PolyLine& holeMsg : polygonWithHoles.holes() )
  162. polygon.emplace_back( UnpackPolyLine( holeMsg ) );
  163. sps.AddPolygon( polygon );
  164. }
  165. return sps;
  166. }
  167. } // namespace kiapi::common