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.

226 lines
8.1 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 CERN
  5. * @author Maciej Suminski <maciej.suminski@cern.ch>
  6. * Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include "graphics_importer_sch.h"
  26. #include <memory>
  27. #include <tuple>
  28. #include <sch_line.h>
  29. #include <sch_shape.h>
  30. #include <sch_text.h>
  31. GRAPHICS_IMPORTER_SCH::GRAPHICS_IMPORTER_SCH()
  32. {
  33. m_millimeterToIu = schIUScale.mmToIU( 1.0 );
  34. }
  35. VECTOR2I GRAPHICS_IMPORTER_SCH::MapCoordinate( const VECTOR2D& aCoordinate )
  36. {
  37. VECTOR2D coord = aCoordinate;
  38. coord *= GetScale();
  39. coord += GetImportOffsetMM();
  40. coord *= GetMillimeterToIuFactor();
  41. return VECTOR2I( KiROUND( coord.x ), KiROUND( coord.y ) );
  42. }
  43. int GRAPHICS_IMPORTER_SCH::MapLineWidth( double aLineWidth )
  44. {
  45. VECTOR2D factor = ImportScalingFactor();
  46. double scale = ( std::abs( factor.x ) + std::abs( factor.y ) ) * 0.5;
  47. if( aLineWidth <= 0.0 )
  48. return int( GetLineWidthMM() * scale );
  49. // aLineWidth is in mm:
  50. return int( aLineWidth * scale );
  51. }
  52. STROKE_PARAMS GRAPHICS_IMPORTER_SCH::MapStrokeParams( const IMPORTED_STROKE& aStroke )
  53. {
  54. double width = aStroke.GetWidth();
  55. return STROKE_PARAMS( width != -1 ? MapLineWidth( width ) : -1, aStroke.GetPlotStyle(),
  56. aStroke.GetColor() );
  57. }
  58. void GRAPHICS_IMPORTER_SCH::AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
  59. const IMPORTED_STROKE& aStroke )
  60. {
  61. VECTOR2I pt0 = MapCoordinate( aStart );
  62. VECTOR2I pt1 = MapCoordinate( aEnd );
  63. // Skip 0 len lines:
  64. if( pt0 == pt1 )
  65. return;
  66. std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>();
  67. line->SetStroke( MapStrokeParams( aStroke ) );
  68. line->SetStartPoint( pt0 );
  69. line->SetEndPoint( pt1 );
  70. addItem( std::move( line ) );
  71. }
  72. void GRAPHICS_IMPORTER_SCH::AddCircle( const VECTOR2D& aCenter, double aRadius,
  73. const IMPORTED_STROKE& aStroke, bool aFilled,
  74. const COLOR4D& aFillColor )
  75. {
  76. std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
  77. circle->SetFillColor( aFillColor );
  78. circle->SetFilled( aFilled );
  79. circle->SetStroke( MapStrokeParams( aStroke ) );
  80. circle->SetStart( MapCoordinate( aCenter ) );
  81. circle->SetEnd( MapCoordinate( VECTOR2D( aCenter.x + aRadius, aCenter.y ) ) );
  82. addItem( std::move( circle ) );
  83. }
  84. void GRAPHICS_IMPORTER_SCH::AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart,
  85. const EDA_ANGLE& aAngle, const IMPORTED_STROKE& aStroke )
  86. {
  87. std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC );
  88. /**
  89. * We need to perform the rotation/conversion here while still using floating point values
  90. * to avoid rounding errors when operating in integer space in KiCad
  91. */
  92. VECTOR2D end = aStart;
  93. VECTOR2D mid = aStart;
  94. RotatePoint( end, aCenter, -aAngle );
  95. RotatePoint( mid, aCenter, -aAngle / 2.0 );
  96. arc->SetArcGeometry( MapCoordinate( aStart ), MapCoordinate( mid ), MapCoordinate( end ) );
  97. // Ensure the arc can be handled by KiCad. Arcs with a too big radius cannot.
  98. // The criteria used here is radius < MAX_INT / 2.
  99. // this is not perfect, but we do not know the exact final position of the arc, so
  100. // we cannot test the coordinate values, because the arc can be moved before being placed.
  101. VECTOR2D center = CalcArcCenter( arc->GetStart(), arc->GetEnd(), aAngle );
  102. double radius = ( center - arc->GetStart() ).EuclideanNorm();
  103. constexpr double rd_max_value = std::numeric_limits<VECTOR2I::coord_type>::max() / 2.0;
  104. if( radius >= rd_max_value )
  105. {
  106. // Arc cannot be handled: convert it to a segment
  107. AddLine( aStart, end, aStroke );
  108. return;
  109. }
  110. arc->SetStroke( MapStrokeParams( aStroke ) );
  111. addItem( std::move( arc ) );
  112. }
  113. void GRAPHICS_IMPORTER_SCH::AddPolygon( const std::vector<VECTOR2D>& aVertices,
  114. const IMPORTED_STROKE& aStroke, bool aFilled,
  115. const COLOR4D& aFillColor )
  116. {
  117. std::vector<VECTOR2I> convertedPoints;
  118. convertedPoints.reserve( aVertices.size() );
  119. for( const VECTOR2D& precisePoint : aVertices )
  120. convertedPoints.emplace_back( MapCoordinate( precisePoint ) );
  121. if( convertedPoints.empty() )
  122. return;
  123. std::unique_ptr<SCH_SHAPE> polygon = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY );
  124. if( aFilled )
  125. {
  126. polygon->SetFillMode( aFillColor != COLOR4D::UNSPECIFIED ? FILL_T::FILLED_WITH_COLOR
  127. : FILL_T::FILLED_SHAPE );
  128. }
  129. polygon->SetFillColor( aFillColor );
  130. polygon->SetPolyPoints( convertedPoints );
  131. polygon->AddPoint( convertedPoints[0] ); // Need to close last point for libedit
  132. polygon->SetStroke( MapStrokeParams( aStroke ) );
  133. addItem( std::move( polygon ) );
  134. }
  135. void GRAPHICS_IMPORTER_SCH::AddText( const VECTOR2D& aOrigin, const wxString& aText,
  136. double aHeight, double aWidth, double aThickness,
  137. double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
  138. GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor )
  139. {
  140. std::unique_ptr<SCH_TEXT> textItem = std::make_unique<SCH_TEXT>();
  141. textItem->SetTextColor( aColor );
  142. textItem->SetTextThickness( MapLineWidth( aThickness ) );
  143. textItem->SetTextPos( MapCoordinate( aOrigin ) );
  144. textItem->SetTextAngle( EDA_ANGLE( aOrientation, DEGREES_T ) );
  145. textItem->SetTextWidth( aWidth * ImportScalingFactor().x );
  146. textItem->SetTextHeight( aHeight * ImportScalingFactor().y );
  147. textItem->SetVertJustify( aVJustify );
  148. textItem->SetHorizJustify( aHJustify );
  149. textItem->SetText( aText );
  150. addItem( std::move( textItem ) );
  151. }
  152. void GRAPHICS_IMPORTER_SCH::AddSpline( const VECTOR2D& aStart,
  153. const VECTOR2D& aBezierControl1,
  154. const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
  155. const IMPORTED_STROKE& aStroke )
  156. {
  157. std::unique_ptr<SCH_SHAPE> spline = std::make_unique<SCH_SHAPE>( SHAPE_T::BEZIER );
  158. spline->SetStroke( MapStrokeParams( aStroke ) );
  159. spline->SetStart( MapCoordinate( aStart ) );
  160. spline->SetBezierC1( MapCoordinate( aBezierControl1 ) );
  161. spline->SetBezierC2( MapCoordinate( aBezierControl2 ) );
  162. spline->SetEnd( MapCoordinate( aEnd ) );
  163. spline->RebuildBezierToSegmentsPointsList( aStroke.GetWidth() );
  164. // If the spline is degenerated (i.e. a segment) add it as segment or discard it if
  165. // null (i.e. very small) length
  166. if( spline->GetBezierPoints().size() <= 2 )
  167. {
  168. spline->SetShape( SHAPE_T::SEGMENT );
  169. int dist = VECTOR2I( spline->GetStart() - spline->GetEnd() ).EuclideanNorm();
  170. // segment smaller than MIN_SEG_LEN_ACCEPTABLE_NM nanometers are skipped.
  171. #define MIN_SEG_LEN_ACCEPTABLE_NM 20
  172. if( dist < MIN_SEG_LEN_ACCEPTABLE_NM )
  173. return;
  174. }
  175. addItem( std::move( spline ) );
  176. }