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.

1117 lines
40 KiB

* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
2 years ago
2 years ago
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU 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, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file PS_plotter.cpp
  26. * @brief KiCad: specialized plotter for PS files format
  27. */
  28. #include <convert_basic_shapes_to_polygon.h>
  29. #include <macros.h>
  30. #include <math/util.h> // for KiROUND
  31. #include <string_utils.h>
  32. #include <trigo.h>
  33. #include <plotters/plotters_pslike.h>
  34. /* Forward declaration of the font width metrics
  35. (yes extern! this is the way to forward declare variables */
  36. extern const double hv_widths[256];
  37. extern const double hvb_widths[256];
  38. extern const double hvo_widths[256];
  39. extern const double hvbo_widths[256];
  40. const double PSLIKE_PLOTTER::postscriptTextAscent = 0.718;
  41. // return a id used to select a ps macro (see StartPlot() ) from a FILL_TYPE
  42. // fill mode, for arc, rect, circle and poly draw primitives
  43. static int getFillId( FILL_T aFill )
  44. {
  45. if( aFill == FILL_T::NO_FILL )
  46. return 0;
  47. if( aFill == FILL_T::FILLED_SHAPE )
  48. return 1;
  49. return 2;
  50. }
  51. void PSLIKE_PLOTTER::SetColor( const COLOR4D& color )
  52. {
  53. if( m_colorMode )
  54. {
  55. if( m_negativeMode )
  56. emitSetRGBColor( 1 - color.r, 1 - color.g, 1 - color.b, color.a );
  57. else
  58. emitSetRGBColor( color.r, color.g, color.b, color.a );
  59. }
  60. else
  61. {
  62. /* B/W Mode - Use BLACK or WHITE for all items
  63. * note the 2 colors are used in B&W mode, mainly by Pcbnew to draw
  64. * holes in white on pads in black
  65. */
  66. double k = 1; // White
  67. if( color != COLOR4D::WHITE )
  68. k = 0;
  69. if( m_negativeMode )
  70. emitSetRGBColor( 1 - k, 1 - k, 1 - k, 1.0 );
  71. else
  72. emitSetRGBColor( k, k, k, 1.0 );
  73. }
  74. }
  75. void PSLIKE_PLOTTER::FlashPadOval( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
  76. const EDA_ANGLE& aPadOrient, OUTLINE_MODE aTraceMode,
  77. void* aData )
  78. {
  79. wxASSERT( m_outputFile );
  80. VECTOR2I size( aSize );
  81. EDA_ANGLE orient( aPadOrient );
  82. // The pad is reduced to an oval by dy > dx
  83. if( size.x > size.y )
  84. {
  85. std::swap( size.x, size.y );
  86. orient += ANGLE_90;
  87. }
  88. int delta = size.y - size.x;
  89. VECTOR2I a( 0, -delta / 2 );
  90. VECTOR2I b( 0, delta / 2 );
  91. RotatePoint( a, orient );
  92. RotatePoint( b, orient );
  93. if( aTraceMode == FILLED )
  94. ThickSegment( a + aPadPos, b + aPadPos, size.x, aTraceMode, nullptr );
  95. else
  96. sketchOval( aPadPos, size, orient, USE_DEFAULT_LINE_WIDTH );
  97. }
  98. void PSLIKE_PLOTTER::FlashPadCircle( const VECTOR2I& aPadPos, int aDiameter,
  99. OUTLINE_MODE aTraceMode, void* aData )
  100. {
  101. if( aTraceMode == FILLED )
  102. {
  103. Circle( aPadPos, aDiameter, FILL_T::FILLED_SHAPE, 0 );
  104. }
  105. else // Plot a ring:
  106. {
  107. SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
  108. Circle( aPadPos, aDiameter, FILL_T::NO_FILL, GetCurrentLineWidth() );
  109. }
  110. SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
  111. }
  112. void PSLIKE_PLOTTER::FlashPadRect( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
  113. const EDA_ANGLE& aPadOrient, OUTLINE_MODE aTraceMode,
  114. void* aData )
  115. {
  116. std::vector<VECTOR2I> cornerList;
  117. VECTOR2I size( aSize );
  118. cornerList.reserve( 4 );
  119. if( aTraceMode == FILLED )
  120. SetCurrentLineWidth( 0 );
  121. else
  122. SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
  123. int dx = size.x / 2;
  124. int dy = size.y / 2;
  125. VECTOR2I corner;
  126. corner.x = aPadPos.x - dx;
  127. corner.y = aPadPos.y + dy;
  128. cornerList.push_back( corner );
  129. corner.x = aPadPos.x - dx;
  130. corner.y = aPadPos.y - dy;
  131. cornerList.push_back( corner );
  132. corner.x = aPadPos.x + dx;
  133. corner.y = aPadPos.y - dy;
  134. cornerList.push_back( corner );
  135. corner.x = aPadPos.x + dx;
  136. corner.y = aPadPos.y + dy,
  137. cornerList.push_back( corner );
  138. for( unsigned ii = 0; ii < cornerList.size(); ii++ )
  139. RotatePoint( cornerList[ii], aPadPos, aPadOrient );
  140. cornerList.push_back( cornerList[0] );
  141. PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL,
  142. GetCurrentLineWidth() );
  143. }
  144. void PSLIKE_PLOTTER::FlashPadRoundRect( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
  145. int aCornerRadius, const EDA_ANGLE& aOrient,
  146. OUTLINE_MODE aTraceMode, void* aData )
  147. {
  148. if( aTraceMode == FILLED )
  149. SetCurrentLineWidth( 0 );
  150. else
  151. SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
  152. SHAPE_POLY_SET outline;
  153. TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient, aCornerRadius, 0.0, 0,
  154. 0, GetPlotterArcHighDef(), ERROR_INSIDE );
  155. std::vector<VECTOR2I> cornerList;
  156. // TransformRoundRectToPolygon creates only one convex polygon
  157. SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
  158. cornerList.reserve( poly.PointCount() );
  159. for( int ii = 0; ii < poly.PointCount(); ++ii )
  160. cornerList.emplace_back( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
  161. // Close polygon
  162. cornerList.push_back( cornerList[0] );
  163. PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL,
  164. GetCurrentLineWidth() );
  165. }
  166. void PSLIKE_PLOTTER::FlashPadCustom( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
  167. const EDA_ANGLE& aOrient, SHAPE_POLY_SET* aPolygons,
  168. OUTLINE_MODE aTraceMode, void* aData )
  169. {
  170. if( aTraceMode == FILLED )
  171. SetCurrentLineWidth( 0 );
  172. else
  173. SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
  174. std::vector<VECTOR2I> cornerList;
  175. for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
  176. {
  177. SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
  178. cornerList.clear();
  179. for( int ii = 0; ii < poly.PointCount(); ++ii )
  180. cornerList.emplace_back( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
  181. // Close polygon
  182. cornerList.push_back( cornerList[0] );
  183. PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL,
  184. GetCurrentLineWidth() );
  185. }
  186. }
  187. void PSLIKE_PLOTTER::FlashPadTrapez( const VECTOR2I& aPadPos, const VECTOR2I* aCorners,
  188. const EDA_ANGLE& aPadOrient, OUTLINE_MODE aTraceMode,
  189. void* aData )
  190. {
  191. static std::vector<VECTOR2I> cornerList;
  192. cornerList.clear();
  193. for( int ii = 0; ii < 4; ii++ )
  194. cornerList.push_back( aCorners[ii] );
  195. if( aTraceMode == FILLED )
  196. {
  197. SetCurrentLineWidth( 0 );
  198. }
  199. else
  200. {
  201. SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
  202. }
  203. for( int ii = 0; ii < 4; ii++ )
  204. {
  205. RotatePoint( cornerList[ii], aPadOrient );
  206. cornerList[ii] += aPadPos;
  207. }
  208. cornerList.push_back( cornerList[0] );
  209. PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL,
  210. GetCurrentLineWidth() );
  211. }
  212. void PSLIKE_PLOTTER::FlashRegularPolygon( const VECTOR2I& aShapePos, int aRadius, int aCornerCount,
  213. const EDA_ANGLE& aOrient, OUTLINE_MODE aTraceMode,
  214. void* aData )
  215. {
  216. // Do nothing
  217. wxASSERT( 0 );
  218. }
  219. std::string PSLIKE_PLOTTER::encodeStringForPlotter( const wxString& aUnicode )
  220. {
  221. // Write on a std::string a string escaped for postscript/PDF
  222. std::string converted;
  223. converted += '(';
  224. for( unsigned i = 0; i < aUnicode.Len(); i++ )
  225. {
  226. // Laziness made me use stdio buffering yet another time...
  227. wchar_t ch = aUnicode[i];
  228. if( ch < 256 )
  229. {
  230. switch (ch)
  231. {
  232. // The ~ shouldn't reach the outside
  233. case '~':
  234. break;
  235. // These characters must be escaped
  236. case '(':
  237. case ')':
  238. case '\\':
  239. converted += '\\';
  240. KI_FALLTHROUGH;
  241. default:
  242. converted += ch;
  243. break;
  244. }
  245. }
  246. }
  247. converted += ')';
  248. return converted;
  249. }
  250. int PSLIKE_PLOTTER::returnPostscriptTextWidth( const wxString& aText, int aXSize,
  251. bool aItalic, bool aBold )
  252. {
  253. const double *width_table = aBold ? ( aItalic ? hvbo_widths : hvb_widths )
  254. : ( aItalic ? hvo_widths : hv_widths );
  255. double tally = 0;
  256. for( wchar_t asciiCode : aText)
  257. {
  258. // Skip the negation marks and untabled points.
  259. if( asciiCode != '~' && asciiCode < 256 )
  260. tally += width_table[asciiCode];
  261. }
  262. // Widths are proportional to height, but height is enlarged by a scaling factor.
  263. return KiROUND( aXSize * tally / postscriptTextAscent );
  264. }
  265. void PS_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
  266. double aScale, bool aMirror )
  267. {
  268. wxASSERT( !m_outputFile );
  269. m_plotMirror = aMirror;
  270. m_plotOffset = aOffset;
  271. m_plotScale = aScale;
  272. m_IUsPerDecimil = aIusPerDecimil;
  273. m_iuPerDeviceUnit = 1.0 / aIusPerDecimil;
  274. /* Compute the paper size in IUs */
  275. m_paperSize = m_pageInfo.GetSizeMils();
  276. m_paperSize.x *= 10.0 * aIusPerDecimil;
  277. m_paperSize.y *= 10.0 * aIusPerDecimil;
  278. }
  279. void PSLIKE_PLOTTER::computeTextParameters( const VECTOR2I& aPos,
  280. const wxString& aText,
  281. const EDA_ANGLE& aOrient,
  282. const VECTOR2I& aSize,
  283. bool aMirror,
  284. enum GR_TEXT_H_ALIGN_T aH_justify,
  285. enum GR_TEXT_V_ALIGN_T aV_justify,
  286. int aWidth,
  287. bool aItalic,
  288. bool aBold,
  289. double *wideningFactor,
  290. double *ctm_a,
  291. double *ctm_b,
  292. double *ctm_c,
  293. double *ctm_d,
  294. double *ctm_e,
  295. double *ctm_f,
  296. double *heightFactor )
  297. {
  298. // Compute the starting position (compensated for alignment)
  299. VECTOR2I start_pos = aPos;
  300. // This is an approximation of the text bounds (in IUs)
  301. int tw = returnPostscriptTextWidth( aText, aSize.x, aItalic, aWidth );
  302. int th = aSize.y;
  303. int dx = 0, dy = 0;
  304. switch( aH_justify )
  305. {
  306. case GR_TEXT_H_ALIGN_CENTER: dx = -tw / 2; break;
  307. case GR_TEXT_H_ALIGN_RIGHT: dx = -tw; break;
  308. case GR_TEXT_H_ALIGN_LEFT: dx = 0; break;
  309. case GR_TEXT_H_ALIGN_INDETERMINATE:
  310. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  311. break;
  312. }
  313. switch( aV_justify )
  314. {
  315. case GR_TEXT_V_ALIGN_CENTER: dy = th / 2; break;
  316. case GR_TEXT_V_ALIGN_TOP: dy = th; break;
  317. case GR_TEXT_V_ALIGN_BOTTOM: dy = 0; break;
  318. case GR_TEXT_V_ALIGN_INDETERMINATE:
  319. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  320. break;
  321. }
  322. RotatePoint( &dx, &dy, aOrient );
  323. RotatePoint( &tw, &th, aOrient );
  324. start_pos.x += dx;
  325. start_pos.y += dy;
  326. VECTOR2D pos_dev = userToDeviceCoordinates( start_pos );
  327. VECTOR2D sz_dev = userToDeviceSize( aSize );
  328. // Now returns the final values... the widening factor
  329. *wideningFactor = sz_dev.x / sz_dev.y;
  330. // Mirrored texts must be plotted as mirrored!
  331. if( m_plotMirror ^ aMirror )
  332. *wideningFactor = -*wideningFactor;
  333. // The CTM transformation matrix
  334. double alpha = m_plotMirror ? aOrient.Invert().AsRadians() : aOrient.AsRadians();
  335. double sinalpha = sin( alpha );
  336. double cosalpha = cos( alpha );
  337. *ctm_a = cosalpha;
  338. *ctm_b = sinalpha;
  339. *ctm_c = -sinalpha;
  340. *ctm_d = cosalpha;
  341. *ctm_e = pos_dev.x;
  342. *ctm_f = pos_dev.y;
  343. // This is because the letters are less than 1 unit high
  344. *heightFactor = sz_dev.y / postscriptTextAscent;
  345. }
  346. void PS_PLOTTER::SetCurrentLineWidth( int aWidth, void* aData )
  347. {
  348. wxASSERT( m_outputFile );
  349. if( aWidth == DO_NOT_SET_LINE_WIDTH )
  350. return;
  351. else if( aWidth == USE_DEFAULT_LINE_WIDTH )
  352. aWidth = m_renderSettings->GetDefaultPenWidth();
  353. else if( aWidth == 0 )
  354. aWidth = 1;
  355. wxASSERT_MSG( aWidth > 0, "Plotter called to set negative pen width" );
  356. if( aWidth != GetCurrentLineWidth() )
  357. fprintf( m_outputFile, "%g setlinewidth\n", userToDeviceSize( aWidth ) );
  358. m_currentPenWidth = aWidth;
  359. }
  360. void PS_PLOTTER::emitSetRGBColor( double r, double g, double b, double a )
  361. {
  362. wxASSERT( m_outputFile );
  363. // Postscript treats all colors as opaque, so the best we can do with alpha is generate
  364. // an appropriate blended color assuming white paper. (It's possible that a halftone would
  365. // work better on *some* drivers, but most drivers are known to still treat halftones as
  366. // opaque and remove any colors underneath them.)
  367. if( a < 1.0 )
  368. {
  369. r = ( r * a ) + ( 1 - a );
  370. g = ( g * a ) + ( 1 - a );
  371. b = ( b * a ) + ( 1 - a );
  372. }
  373. // XXX why %.3g ? shouldn't %g suffice? who cares...
  374. fprintf( m_outputFile, "%.3g %.3g %.3g setrgbcolor\n", r, g, b );
  375. }
  376. void PS_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
  377. {
  378. switch( aLineStyle )
  379. {
  380. case LINE_STYLE::DASH:
  381. fprintf( m_outputFile, "[%d %d] 0 setdash\n",
  382. (int) GetDashMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ) );
  383. break;
  384. case LINE_STYLE::DOT:
  385. fprintf( m_outputFile, "[%d %d] 0 setdash\n",
  386. (int) GetDotMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ) );
  387. break;
  388. case LINE_STYLE::DASHDOT:
  389. fprintf( m_outputFile, "[%d %d %d %d] 0 setdash\n",
  390. (int) GetDashMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ),
  391. (int) GetDotMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ) );
  392. break;
  393. case LINE_STYLE::DASHDOTDOT:
  394. fprintf( m_outputFile, "[%d %d %d %d %d %d] 0 setdash\n",
  395. (int) GetDashMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ),
  396. (int) GetDotMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ),
  397. (int) GetDotMarkLenIU( aLineWidth ), (int) GetDashGapLenIU( aLineWidth ) );
  398. break;
  399. default:
  400. fputs( "solidline\n", m_outputFile );
  401. }
  402. }
  403. void PS_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
  404. {
  405. if( fill == FILL_T::NO_FILL && width <= 0 )
  406. return;
  407. VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
  408. VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
  409. SetCurrentLineWidth( width );
  410. fprintf( m_outputFile, "%g %g %g %g rect%d\n", p1_dev.x, p1_dev.y,
  411. p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y, getFillId( fill ) );
  412. }
  413. void PS_PLOTTER::Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width )
  414. {
  415. if( fill == FILL_T::NO_FILL && width <= 0 )
  416. return;
  417. wxASSERT( m_outputFile );
  418. VECTOR2D pos_dev = userToDeviceCoordinates( pos );
  419. double radius = userToDeviceSize( diametre / 2.0 );
  420. SetCurrentLineWidth( width );
  421. fprintf( m_outputFile, "%g %g %g cir%d\n", pos_dev.x, pos_dev.y, radius, getFillId( fill ) );
  422. }
  423. VECTOR2D mapCoords( const VECTOR2D& aSource )
  424. {
  425. return VECTOR2D( aSource.x, aSource.y );
  426. }
  427. void PS_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
  428. const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth )
  429. {
  430. wxASSERT( m_outputFile );
  431. VECTOR2D center_device = userToDeviceCoordinates( aCenter );
  432. double radius_device = userToDeviceSize( aRadius );
  433. EDA_ANGLE endA = aStartAngle + aAngle;
  434. VECTOR2D start( aRadius * aStartAngle.Cos(), aRadius * aStartAngle.Sin() );
  435. VECTOR2D end( aRadius * endA.Cos(), aRadius * endA.Sin() );
  436. start += aCenter;
  437. end += aCenter;
  438. VECTOR2D start_device = userToDeviceCoordinates( start );
  439. VECTOR2D end_device = userToDeviceCoordinates( end );
  440. EDA_ANGLE startAngle( mapCoords( start_device - center_device ) );
  441. EDA_ANGLE endAngle( mapCoords( end_device - center_device ) );
  442. // userToDeviceCoordinates gets our start/ends out of order
  443. if( !m_plotMirror ^ ( aAngle < ANGLE_0 ) )
  444. std::swap( startAngle, endAngle );
  445. SetCurrentLineWidth( aWidth );
  446. fprintf( m_outputFile, "%g %g %g %g %g arc%d\n", center_device.x, center_device.y,
  447. radius_device, startAngle.AsDegrees(), endAngle.AsDegrees(), getFillId( aFill ) );
  448. }
  449. void PS_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill, int aWidth,
  450. void* aData )
  451. {
  452. if( aFill == FILL_T::NO_FILL && aWidth <= 0 )
  453. return;
  454. if( aCornerList.size() <= 1 )
  455. return;
  456. SetCurrentLineWidth( aWidth );
  457. VECTOR2D pos = userToDeviceCoordinates( aCornerList[0] );
  458. fprintf( m_outputFile, "newpath\n%g %g moveto\n", pos.x, pos.y );
  459. for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
  460. {
  461. pos = userToDeviceCoordinates( aCornerList[ii] );
  462. fprintf( m_outputFile, "%g %g lineto\n", pos.x, pos.y );
  463. }
  464. // Close/(fill) the path
  465. fprintf( m_outputFile, "poly%d\n", getFillId( aFill ) );
  466. }
  467. void PS_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
  468. {
  469. VECTOR2I pix_size; // size of the bitmap in pixels
  470. pix_size.x = aImage.GetWidth();
  471. pix_size.y = aImage.GetHeight();
  472. VECTOR2D drawsize( aScaleFactor * pix_size.x,
  473. aScaleFactor * pix_size.y ); // requested size of image
  474. // calculate the bottom left corner position of bitmap
  475. VECTOR2I start = aPos;
  476. start.x -= drawsize.x / 2; // left
  477. start.y += drawsize.y / 2; // bottom (Y axis reversed)
  478. // calculate the top right corner position of bitmap
  479. VECTOR2I end;
  480. end.x = start.x + drawsize.x;
  481. end.y = start.y - drawsize.y;
  482. fprintf( m_outputFile, "/origstate save def\n" );
  483. fprintf( m_outputFile, "/pix %d string def\n", pix_size.x );
  484. // Locate lower-left corner of image
  485. VECTOR2D start_dev = userToDeviceCoordinates( start );
  486. fprintf( m_outputFile, "%g %g translate\n", start_dev.x, start_dev.y );
  487. // Map image size to device
  488. VECTOR2D end_dev = userToDeviceCoordinates( end );
  489. fprintf( m_outputFile, "%g %g scale\n",
  490. std::abs( end_dev.x - start_dev.x ),
  491. std::abs( end_dev.y - start_dev.y ) );
  492. // Dimensions of source image (in pixels
  493. fprintf( m_outputFile, "%d %d 8", pix_size.x, pix_size.y );
  494. // Map unit square to source
  495. fprintf( m_outputFile, " [%d 0 0 %d 0 %d]\n", pix_size.x, -pix_size.y , pix_size.y);
  496. // include image data in ps file
  497. fprintf( m_outputFile, "{currentfile pix readhexstring pop}\n" );
  498. if( m_colorMode )
  499. fputs( "false 3 colorimage\n", m_outputFile );
  500. else
  501. fputs( "image\n", m_outputFile );
  502. // Single data source, 3 colors, Output RGB data (hexadecimal)
  503. // (or the same downscaled to gray)
  504. int jj = 0;
  505. for( int yy = 0; yy < pix_size.y; yy ++ )
  506. {
  507. for( int xx = 0; xx < pix_size.x; xx++, jj++ )
  508. {
  509. if( jj >= 16 )
  510. {
  511. jj = 0;
  512. fprintf( m_outputFile, "\n");
  513. }
  514. int red, green, blue;
  515. red = aImage.GetRed( xx, yy) & 0xFF;
  516. green = aImage.GetGreen( xx, yy) & 0xFF;
  517. blue = aImage.GetBlue( xx, yy) & 0xFF;
  518. // PS doesn't support alpha, so premultiply against white background
  519. if( aImage.HasAlpha() )
  520. {
  521. unsigned char alpha = aImage.GetAlpha( xx, yy ) & 0xFF;
  522. if( alpha < 0xFF )
  523. {
  524. float a = 1.0 - ( (float) alpha / 255.0 );
  525. red = ( int )( red + ( a * 0xFF ) ) & 0xFF;
  526. green = ( int )( green + ( a * 0xFF ) ) & 0xFF;
  527. blue = ( int )( blue + ( a * 0xFF ) ) & 0xFF;
  528. }
  529. }
  530. if( aImage.HasMask() )
  531. {
  532. if( red == aImage.GetMaskRed() && green == aImage.GetMaskGreen()
  533. && blue == aImage.GetMaskBlue() )
  534. {
  535. red = 0xFF;
  536. green = 0xFF;
  537. blue = 0xFF;
  538. }
  539. }
  540. if( m_colorMode )
  541. {
  542. fprintf( m_outputFile, "%2.2X%2.2X%2.2X", red, green, blue );
  543. }
  544. else
  545. {
  546. // Greyscale conversion (CIE 1931)
  547. unsigned char grey = KiROUND( red * 0.2126 + green * 0.7152 + blue * 0.0722 );
  548. fprintf( m_outputFile, "%2.2X", grey );
  549. }
  550. }
  551. }
  552. fprintf( m_outputFile, "\n");
  553. fprintf( m_outputFile, "origstate restore\n" );
  554. }
  555. void PS_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
  556. {
  557. wxASSERT( m_outputFile );
  558. if( plume == 'Z' )
  559. {
  560. if( m_penState != 'Z' )
  561. {
  562. fputs( "stroke\n", m_outputFile );
  563. m_penState = 'Z';
  564. m_penLastpos.x = -1;
  565. m_penLastpos.y = -1;
  566. }
  567. return;
  568. }
  569. if( m_penState == 'Z' )
  570. {
  571. fputs( "newpath\n", m_outputFile );
  572. }
  573. if( m_penState != plume || pos != m_penLastpos )
  574. {
  575. VECTOR2D pos_dev = userToDeviceCoordinates( pos );
  576. fprintf( m_outputFile, "%g %g %sto\n",
  577. pos_dev.x, pos_dev.y,
  578. ( plume=='D' ) ? "line" : "move" );
  579. }
  580. m_penState = plume;
  581. m_penLastpos = pos;
  582. }
  583. bool PS_PLOTTER::StartPlot( const wxString& aPageNumber )
  584. {
  585. wxASSERT( m_outputFile );
  586. static const char* PSMacro[] =
  587. {
  588. "%%BeginProlog\n",
  589. "/line { newpath moveto lineto stroke } bind def\n",
  590. "/cir0 { newpath 0 360 arc stroke } bind def\n",
  591. "/cir1 { newpath 0 360 arc gsave fill grestore stroke } bind def\n",
  592. "/cir2 { newpath 0 360 arc gsave fill grestore stroke } bind def\n",
  593. "/arc0 { newpath arc stroke } bind def\n",
  594. "/arc1 { newpath 4 index 4 index moveto arc closepath gsave fill\n",
  595. " grestore stroke } bind def\n",
  596. "/arc2 { newpath 4 index 4 index moveto arc closepath gsave fill\n",
  597. " grestore stroke } bind def\n",
  598. "/poly0 { stroke } bind def\n",
  599. "/poly1 { closepath gsave fill grestore stroke } bind def\n",
  600. "/poly2 { closepath gsave fill grestore stroke } bind def\n",
  601. "/rect0 { rectstroke } bind def\n",
  602. "/rect1 { rectfill } bind def\n",
  603. "/rect2 { rectfill } bind def\n",
  604. "/linemode0 { 0 setlinecap 0 setlinejoin 0 setlinewidth } bind def\n",
  605. "/linemode1 { 1 setlinecap 1 setlinejoin } bind def\n",
  606. "/dashedline { [200] 100 setdash } bind def\n",
  607. "/solidline { [] 0 setdash } bind def\n",
  608. // This is for 'hidden' text (search anchors for PDF)
  609. "/phantomshow { moveto\n",
  610. " /KicadFont findfont 0.000001 scalefont setfont\n",
  611. " show } bind def\n",
  612. // This is for regular postscript text
  613. "/textshow { gsave\n",
  614. " findfont exch scalefont setfont concat 1 scale 0 0 moveto show\n",
  615. " } bind def\n",
  616. // Utility for getting Latin1 encoded fonts
  617. "/reencodefont {\n",
  618. " findfont dup length dict begin\n",
  619. " { 1 index /FID ne\n",
  620. " { def }\n",
  621. " { pop pop } ifelse\n",
  622. " } forall\n",
  623. " /Encoding ISOLatin1Encoding def\n",
  624. " currentdict\n",
  625. " end } bind def\n"
  626. // Remap AdobeStandard fonts to Latin1
  627. "/KicadFont /Helvetica reencodefont definefont pop\n",
  628. "/KicadFont-Bold /Helvetica-Bold reencodefont definefont pop\n",
  629. "/KicadFont-Oblique /Helvetica-Oblique reencodefont definefont pop\n",
  630. "/KicadFont-BoldOblique /Helvetica-BoldOblique reencodefont definefont pop\n",
  631. "%%EndProlog\n",
  632. nullptr
  633. };
  634. time_t time1970 = time( nullptr );
  635. fputs( "%!PS-Adobe-3.0\n", m_outputFile ); // Print header
  636. fprintf( m_outputFile, "%%%%Creator: %s\n", TO_UTF8( m_creator ) );
  637. /* A "newline" character ("\n") is not included in the following string,
  638. because it is provided by the ctime() function. */
  639. fprintf( m_outputFile, "%%%%CreationDate: %s", ctime( &time1970 ) );
  640. fprintf( m_outputFile, "%%%%Title: %s\n", encodeStringForPlotter( m_title ).c_str() );
  641. fprintf( m_outputFile, "%%%%Pages: 1\n" );
  642. fprintf( m_outputFile, "%%%%PageOrder: Ascend\n" );
  643. // Print boundary box in 1/72 pixels per inch, box is in mils
  644. const double BIGPTsPERMIL = 0.072;
  645. /* The coordinates of the lower left corner of the boundary
  646. box need to be "rounded down", but the coordinates of its
  647. upper right corner need to be "rounded up" instead. */
  648. VECTOR2I psPaperSize = m_pageInfo.GetSizeMils();
  649. if( !m_pageInfo.IsPortrait() )
  650. {
  651. psPaperSize.x = m_pageInfo.GetHeightMils();
  652. psPaperSize.y = m_pageInfo.GetWidthMils();
  653. }
  654. fprintf( m_outputFile, "%%%%BoundingBox: 0 0 %d %d\n",
  655. (int) ceil( psPaperSize.x * BIGPTsPERMIL ),
  656. (int) ceil( psPaperSize.y * BIGPTsPERMIL ) );
  657. // Specify the size of the sheet and the name associated with that size.
  658. // (If the "User size" option has been selected for the sheet size,
  659. // identify the sheet size as "Custom" (rather than as "User"), but
  660. // otherwise use the name assigned by KiCad for each sheet size.)
  661. //
  662. // (The Document Structuring Convention also supports sheet weight,
  663. // sheet color, and sheet type properties being specified within a
  664. // %%DocumentMedia comment, but they are not being specified here;
  665. // a zero and two null strings are subsequently provided instead.)
  666. //
  667. // (NOTE: m_Size.y is *supposed* to be listed before m_Size.x;
  668. // the order in which they are specified is not wrong!)
  669. // Also note pageSize is given in mils, not in internal units and must be
  670. // converted to internal units.
  671. if( m_pageInfo.IsCustom() )
  672. {
  673. fprintf( m_outputFile, "%%%%DocumentMedia: Custom %d %d 0 () ()\n",
  674. KiROUND( psPaperSize.x * BIGPTsPERMIL ),
  675. KiROUND( psPaperSize.y * BIGPTsPERMIL ) );
  676. }
  677. else // a standard paper size
  678. {
  679. fprintf( m_outputFile, "%%%%DocumentMedia: %s %d %d 0 () ()\n",
  680. TO_UTF8( m_pageInfo.GetType() ),
  681. KiROUND( psPaperSize.x * BIGPTsPERMIL ),
  682. KiROUND( psPaperSize.y * BIGPTsPERMIL ) );
  683. }
  684. if( m_pageInfo.IsPortrait() )
  685. fprintf( m_outputFile, "%%%%Orientation: Portrait\n" );
  686. else
  687. fprintf( m_outputFile, "%%%%Orientation: Landscape\n" );
  688. fprintf( m_outputFile, "%%%%EndComments\n" );
  689. // Now specify various other details.
  690. for( int ii = 0; PSMacro[ii] != nullptr; ii++ )
  691. {
  692. fputs( PSMacro[ii], m_outputFile );
  693. }
  694. // The following strings are output here (rather than within PSMacro[])
  695. // to highlight that it has been provided to ensure that the contents of
  696. // the postscript file comply with the Document Structuring Convention.
  697. std::string page_num = encodeStringForPlotter( aPageNumber );
  698. fprintf( m_outputFile, "%%Page: %s 1\n", page_num.c_str() );
  699. fputs( "%%BeginPageSetup\n"
  700. "gsave\n"
  701. "0.0072 0.0072 scale\n" // Configure postscript for decimils coordinates
  702. "linemode1\n", m_outputFile );
  703. // Rototranslate the coordinate to achieve the landscape layout
  704. if( !m_pageInfo.IsPortrait() )
  705. fprintf( m_outputFile, "%d 0 translate 90 rotate\n", 10 * psPaperSize.x );
  706. // Apply the user fine scale adjustments
  707. if( plotScaleAdjX != 1.0 || plotScaleAdjY != 1.0 )
  708. fprintf( m_outputFile, "%g %g scale\n", plotScaleAdjX, plotScaleAdjY );
  709. // Set default line width
  710. fprintf( m_outputFile, "%g setlinewidth\n",
  711. userToDeviceSize( m_renderSettings->GetDefaultPenWidth() ) );
  712. fputs( "%%EndPageSetup\n", m_outputFile );
  713. return true;
  714. }
  715. bool PS_PLOTTER::EndPlot()
  716. {
  717. wxASSERT( m_outputFile );
  718. fputs( "showpage\n"
  719. "grestore\n"
  720. "%%EOF\n", m_outputFile );
  721. fclose( m_outputFile );
  722. m_outputFile = nullptr;
  723. return true;
  724. }
  725. void PS_PLOTTER::Text( const VECTOR2I& aPos,
  726. const COLOR4D& aColor,
  727. const wxString& aText,
  728. const EDA_ANGLE& aOrient,
  729. const VECTOR2I& aSize,
  730. enum GR_TEXT_H_ALIGN_T aH_justify,
  731. enum GR_TEXT_V_ALIGN_T aV_justify,
  732. int aWidth,
  733. bool aItalic,
  734. bool aBold,
  735. bool aMultilineAllowed,
  736. KIFONT::FONT* aFont,
  737. const KIFONT::METRICS& aFontMetrics,
  738. void* aData )
  739. {
  740. SetCurrentLineWidth( aWidth );
  741. SetColor( aColor );
  742. // Draw the hidden postscript text (if requested)
  743. if( m_textMode == PLOT_TEXT_MODE::PHANTOM )
  744. {
  745. std::string ps_test = encodeStringForPlotter( aText );
  746. VECTOR2D pos_dev = userToDeviceCoordinates( aPos );
  747. fprintf( m_outputFile, "%s %g %g phantomshow\n", ps_test.c_str(), pos_dev.x, pos_dev.y );
  748. }
  749. PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, aWidth, aItalic,
  750. aBold, aMultilineAllowed, aFont, aFontMetrics, aData );
  751. }
  752. void PS_PLOTTER::PlotText( const VECTOR2I& aPos,
  753. const COLOR4D& aColor,
  754. const wxString& aText,
  755. const TEXT_ATTRIBUTES& aAttributes,
  756. KIFONT::FONT* aFont,
  757. const KIFONT::METRICS& aFontMetrics,
  758. void* aData )
  759. {
  760. SetCurrentLineWidth( aAttributes.m_StrokeWidth );
  761. SetColor( aColor );
  762. // Draw the hidden postscript text (if requested)
  763. if( m_textMode == PLOT_TEXT_MODE::PHANTOM )
  764. {
  765. std::string ps_test = encodeStringForPlotter( aText );
  766. VECTOR2D pos_dev = userToDeviceCoordinates( aPos );
  767. fprintf( m_outputFile, "%s %g %g phantomshow\n", ps_test.c_str(), pos_dev.x, pos_dev.y );
  768. }
  769. PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aFontMetrics, aData );
  770. }
  771. /**
  772. * Character widths for Helvetica
  773. */
  774. const double hv_widths[256] = {
  775. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  776. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  777. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  778. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  779. 0.278, 0.278, 0.355, 0.556, 0.556, 0.889, 0.667, 0.191,
  780. 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278,
  781. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556,
  782. 0.556, 0.556, 0.278, 0.278, 0.584, 0.584, 0.584, 0.556,
  783. 1.015, 0.667, 0.667, 0.722, 0.722, 0.667, 0.611, 0.778,
  784. 0.722, 0.278, 0.500, 0.667, 0.556, 0.833, 0.722, 0.778,
  785. 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944,
  786. 0.667, 0.667, 0.611, 0.278, 0.278, 0.278, 0.469, 0.556,
  787. 0.333, 0.556, 0.556, 0.500, 0.556, 0.556, 0.278, 0.556,
  788. 0.556, 0.222, 0.222, 0.500, 0.222, 0.833, 0.556, 0.556,
  789. 0.556, 0.556, 0.333, 0.500, 0.278, 0.556, 0.500, 0.722,
  790. 0.500, 0.500, 0.500, 0.334, 0.260, 0.334, 0.584, 0.278,
  791. 0.278, 0.278, 0.222, 0.556, 0.333, 1.000, 0.556, 0.556,
  792. 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278,
  793. 0.278, 0.222, 0.222, 0.333, 0.333, 0.350, 0.556, 1.000,
  794. 0.333, 1.000, 0.500, 0.333, 0.944, 0.278, 0.278, 0.667,
  795. 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.260, 0.556,
  796. 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333,
  797. 0.400, 0.584, 0.333, 0.333, 0.333, 0.556, 0.537, 0.278,
  798. 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611,
  799. 0.667, 0.667, 0.667, 0.667, 0.667, 0.667, 1.000, 0.722,
  800. 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278,
  801. 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584,
  802. 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611,
  803. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.500,
  804. 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278,
  805. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.584,
  806. 0.611, 0.556, 0.556, 0.556, 0.556, 0.500, 0.556, 0.500
  807. };
  808. /**
  809. * Character widths for Helvetica-Bold
  810. */
  811. const double hvb_widths[256] = {
  812. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  813. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  814. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  815. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  816. 0.278, 0.333, 0.474, 0.556, 0.556, 0.889, 0.722, 0.238,
  817. 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278,
  818. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556,
  819. 0.556, 0.556, 0.333, 0.333, 0.584, 0.584, 0.584, 0.611,
  820. 0.975, 0.722, 0.722, 0.722, 0.722, 0.667, 0.611, 0.778,
  821. 0.722, 0.278, 0.556, 0.722, 0.611, 0.833, 0.722, 0.778,
  822. 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944,
  823. 0.667, 0.667, 0.611, 0.333, 0.278, 0.333, 0.584, 0.556,
  824. 0.333, 0.556, 0.611, 0.556, 0.611, 0.556, 0.333, 0.611,
  825. 0.611, 0.278, 0.278, 0.556, 0.278, 0.889, 0.611, 0.611,
  826. 0.611, 0.611, 0.389, 0.556, 0.333, 0.611, 0.556, 0.778,
  827. 0.556, 0.556, 0.500, 0.389, 0.280, 0.389, 0.584, 0.278,
  828. 0.278, 0.278, 0.278, 0.556, 0.500, 1.000, 0.556, 0.556,
  829. 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278,
  830. 0.278, 0.278, 0.278, 0.500, 0.500, 0.350, 0.556, 1.000,
  831. 0.333, 1.000, 0.556, 0.333, 0.944, 0.278, 0.278, 0.667,
  832. 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.280, 0.556,
  833. 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333,
  834. 0.400, 0.584, 0.333, 0.333, 0.333, 0.611, 0.556, 0.278,
  835. 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611,
  836. 0.722, 0.722, 0.722, 0.722, 0.722, 0.722, 1.000, 0.722,
  837. 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278,
  838. 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584,
  839. 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611,
  840. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.556,
  841. 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278,
  842. 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.584,
  843. 0.611, 0.611, 0.611, 0.611, 0.611, 0.556, 0.611, 0.556
  844. };
  845. /**
  846. * Character widths for Helvetica-Oblique
  847. */
  848. const double hvo_widths[256] = {
  849. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  850. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  851. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  852. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  853. 0.278, 0.278, 0.355, 0.556, 0.556, 0.889, 0.667, 0.191,
  854. 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278,
  855. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556,
  856. 0.556, 0.556, 0.278, 0.278, 0.584, 0.584, 0.584, 0.556,
  857. 1.015, 0.667, 0.667, 0.722, 0.722, 0.667, 0.611, 0.778,
  858. 0.722, 0.278, 0.500, 0.667, 0.556, 0.833, 0.722, 0.778,
  859. 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944,
  860. 0.667, 0.667, 0.611, 0.278, 0.278, 0.278, 0.469, 0.556,
  861. 0.333, 0.556, 0.556, 0.500, 0.556, 0.556, 0.278, 0.556,
  862. 0.556, 0.222, 0.222, 0.500, 0.222, 0.833, 0.556, 0.556,
  863. 0.556, 0.556, 0.333, 0.500, 0.278, 0.556, 0.500, 0.722,
  864. 0.500, 0.500, 0.500, 0.334, 0.260, 0.334, 0.584, 0.278,
  865. 0.278, 0.278, 0.222, 0.556, 0.333, 1.000, 0.556, 0.556,
  866. 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278,
  867. 0.278, 0.222, 0.222, 0.333, 0.333, 0.350, 0.556, 1.000,
  868. 0.333, 1.000, 0.500, 0.333, 0.944, 0.278, 0.278, 0.667,
  869. 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.260, 0.556,
  870. 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333,
  871. 0.400, 0.584, 0.333, 0.333, 0.333, 0.556, 0.537, 0.278,
  872. 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611,
  873. 0.667, 0.667, 0.667, 0.667, 0.667, 0.667, 1.000, 0.722,
  874. 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278,
  875. 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584,
  876. 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611,
  877. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.500,
  878. 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278,
  879. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.584,
  880. 0.611, 0.556, 0.556, 0.556, 0.556, 0.500, 0.556, 0.500
  881. };
  882. /**
  883. * Character widths for Helvetica-BoldOblique
  884. */
  885. const double hvbo_widths[256] = {
  886. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  887. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  888. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  889. 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278,
  890. 0.278, 0.333, 0.474, 0.556, 0.556, 0.889, 0.722, 0.238,
  891. 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278,
  892. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556,
  893. 0.556, 0.556, 0.333, 0.333, 0.584, 0.584, 0.584, 0.611,
  894. 0.975, 0.722, 0.722, 0.722, 0.722, 0.667, 0.611, 0.778,
  895. 0.722, 0.278, 0.556, 0.722, 0.611, 0.833, 0.722, 0.778,
  896. 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944,
  897. 0.667, 0.667, 0.611, 0.333, 0.278, 0.333, 0.584, 0.556,
  898. 0.333, 0.556, 0.611, 0.556, 0.611, 0.556, 0.333, 0.611,
  899. 0.611, 0.278, 0.278, 0.556, 0.278, 0.889, 0.611, 0.611,
  900. 0.611, 0.611, 0.389, 0.556, 0.333, 0.611, 0.556, 0.778,
  901. 0.556, 0.556, 0.500, 0.389, 0.280, 0.389, 0.584, 0.278,
  902. 0.278, 0.278, 0.278, 0.556, 0.500, 1.000, 0.556, 0.556,
  903. 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278,
  904. 0.278, 0.278, 0.278, 0.500, 0.500, 0.350, 0.556, 1.000,
  905. 0.333, 1.000, 0.556, 0.333, 0.944, 0.278, 0.278, 0.667,
  906. 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.280, 0.556,
  907. 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333,
  908. 0.400, 0.584, 0.333, 0.333, 0.333, 0.611, 0.556, 0.278,
  909. 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611,
  910. 0.722, 0.722, 0.722, 0.722, 0.722, 0.722, 1.000, 0.722,
  911. 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278,
  912. 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584,
  913. 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611,
  914. 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.556,
  915. 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278,
  916. 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.584,
  917. 0.611, 0.611, 0.611, 0.611, 0.611, 0.556, 0.611, 0.556
  918. };