KiCad PCB EDA Suite
Loading...
Searching...
No Matches
orcad_converter_sheet.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * Based on the dsn2kicad reference implementation and on OrCAD file format
7 * documentation from the OpenOrCadParser project (MIT licensed).
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28
31
32#include <algorithm>
33#include <array>
34#include <cctype>
35#include <cmath>
36#include <functional>
37#include <limits>
38#include <map>
39#include <memory>
40#include <set>
41#include <string>
42#include <utility>
43#include <vector>
44
45#include <wx/buffer.h>
46#include <wx/filename.h>
47#include <wx/log.h>
48#include <wx/translation.h>
49
50#include <base_units.h>
51#include <ki_exception.h>
52#include <layer_ids.h>
53#include <lib_symbol.h>
54#include <math/util.h>
55#include <page_info.h>
56#include <progress_reporter.h>
57#include <project.h>
58#include <reference_image.h>
59#include <reporter.h>
60#include <schematic.h>
61#include <sch_bitmap.h>
62#include <sch_bus_entry.h>
63#include <sch_junction.h>
64#include <sch_label.h>
65#include <sch_line.h>
66#include <sch_no_connect.h>
67#include <sch_screen.h>
68#include <sch_shape.h>
69#include <sch_sheet.h>
70#include <sch_sheet_path.h>
71#include <sch_sheet_pin.h>
72#include <sch_text.h>
73#include <string_utils.h>
74#include <stroke_params.h>
75#include <template_fieldnames.h>
76#include <title_block.h>
77
79
80
81namespace
82{
83
85constexpr double DBU_TO_MM = 0.254;
86
87
88
89std::string trimmed( const std::string& aText )
90{
91 size_t begin = aText.find_first_not_of( " \t\r\n\f\v" );
92
93 if( begin == std::string::npos )
94 return std::string();
95
96 size_t end = aText.find_last_not_of( " \t\r\n\f\v" );
97
98 return aText.substr( begin, end - begin + 1 );
99}
100
101
102void pollProgress( PROGRESS_REPORTER* aReporter, const std::string& aPageName )
103{
104 if( !aReporter )
105 return;
106
107 aReporter->Report( wxString::Format( _( "Converting page '%s'..." ),
108 FromOrcadString( aPageName ) ) );
109
110 if( !aReporter->KeepRefreshing() )
111 THROW_IO_ERROR( _( "Open canceled by user." ) );
112}
113
114
115SCH_SHAPE* makeSheetPoly( const std::vector<VECTOR2I>& aPoints, const ORCAD_PRIMITIVE& aPrimitive,
116 const KIGFX::COLOR4D& aColor, bool aCanFill = false )
117{
119
120 for( const VECTOR2I& pt : aPoints )
121 poly->AddPoint( pt );
122
124 OrcadLineStyle( aPrimitive.lineStyle ), aColor ) );
125
126 // Page graphics have no symbol body color, so solid fill uses the foreground color.
127 if( aCanFill && aPrimitive.fillStyle == 0 )
129 else
130 poly->SetFillMode( aCanFill ? OrcadFillType( aPrimitive.fillStyle, aPrimitive.hatchStyle )
131 : FILL_T::NO_FILL );
132
133 return poly;
134}
135
136
137VECTOR2I dbuPointToIu( double aX, double aY )
138{
139 return VECTOR2I( KiROUND( aX * ORCAD_IU_PER_DBU ), KiROUND( aY * ORCAD_IU_PER_DBU ) );
140}
141
142} // namespace
143
144
145KIGFX::COLOR4D OrcadColor( int aColorIndex )
146{
147 static constexpr uint8_t palette[][3] = {
148 { 0, 0, 0 }, { 255, 255, 128 }, { 128, 255, 128 }, { 0, 255, 128 }, { 128, 255, 255 }, { 0, 128, 255 },
149 { 255, 128, 192 }, { 255, 128, 255 }, { 255, 0, 0 }, { 255, 255, 0 }, { 128, 255, 0 }, { 0, 255, 64 },
150 { 0, 255, 255 }, { 0, 128, 192 }, { 128, 128, 192 }, { 255, 0, 255 }, { 128, 64, 64 }, { 255, 128, 64 },
151 { 0, 255, 0 }, { 0, 128, 128 }, { 0, 64, 128 }, { 128, 128, 255 }, { 128, 0, 64 }, { 255, 0, 128 },
152 { 128, 0, 0 }, { 255, 128, 0 }, { 0, 128, 0 }, { 0, 128, 64 }, { 0, 0, 255 }, { 0, 0, 160 },
153 { 128, 0, 128 }, { 128, 0, 255 }, { 64, 0, 0 }, { 128, 64, 0 }, { 0, 64, 0 }, { 0, 64, 64 },
154 { 0, 0, 128 }, { 0, 0, 64 }, { 64, 0, 64 }, { 64, 0, 128 }, { 0, 0, 0 }, { 128, 128, 0 },
155 { 128, 128, 64 }, { 128, 128, 128 }, { 64, 128, 128 }, { 192, 192, 192 }, { 64, 0, 64 }, { 255, 255, 255 }
156 };
157
158 if( aColorIndex < 1 || aColorIndex >= static_cast<int>( std::size( palette ) ) )
160
161 return KIGFX::COLOR4D( palette[aColorIndex][0] / 255.0, palette[aColorIndex][1] / 255.0,
162 palette[aColorIndex][2] / 255.0, 1.0 );
163}
164
165
167 PROGRESS_REPORTER* aProgressReporter ) :
168 m_design( aDesign ),
169 m_schematic( aSchematic ),
170 m_reporter( aReporter ),
171 m_progressReporter( aProgressReporter ),
172 m_rootSheet( nullptr ),
173 m_powerCount( 0 ),
175{
176}
177
178
180
181
182void ORCAD_CONVERTER::warn( const wxString& aMsg )
183{
184 if( m_reporter )
185 m_reporter->Report( aMsg, RPT_SEVERITY_WARNING );
186}
187
188
189void ORCAD_CONVERTER::note( const wxString& aMsg )
190{
191 if( m_reporter )
192 m_reporter->Report( aMsg, RPT_SEVERITY_INFO );
193}
194
195
197int OrcadPageOrder( wxString& aName )
198{
199 size_t digitStart = 0;
200 wxString upper = aName.Upper();
201
202 for( const wxString& prefix : { wxS( "PAGE" ), wxS( "SCH" ), wxS( "PAG" ) } )
203 {
204 if( upper.StartsWith( prefix )
205 && ( aName.length() == prefix.length() || wxIsdigit( aName[prefix.length()] )
206 || wxIsspace( aName[prefix.length()] ) || aName[prefix.length()] == '_' ) )
207 {
208 digitStart = prefix.length();
209
210 while( digitStart < aName.length()
211 && ( wxIsspace( aName[digitStart] ) || aName[digitStart] == '_' ) )
212 {
213 digitStart++;
214 }
215
216 break;
217 }
218 }
219
220 size_t digitEnd = digitStart;
221
222 while( digitEnd < aName.length() && wxIsdigit( aName[digitEnd] ) )
223 digitEnd++;
224
225 long order = 0;
226
227 if( digitEnd == digitStart
228 || !aName.Mid( digitStart, digitEnd - digitStart ).ToLong( &order ) )
229 {
230 return -1;
231 }
232
233 size_t separator = digitEnd;
234
235 while( separator < aName.length() && wxIsspace( aName[separator] ) )
236 separator++;
237
238 if( separator == aName.length()
239 || ( aName[separator] != '-' && aName[separator] != '.' && aName[separator] != ':' ) )
240 return -1;
241
242 if( aName[separator] == '-' )
243 {
244 wxString rest = aName.Mid( separator + 1 );
245 rest.Trim( false );
246 aName = rest;
247 }
248
249 return static_cast<int>( order );
250}
251
252
254{
255 m_rootSheet = aRootSheet;
256
258
259 SCH_SCREEN* rootScreen = aRootSheet->GetScreen();
260
261 SCH_SHEET_PATH rootPath;
262 rootPath.push_back( aRootSheet );
263 rootPath.SetPageNumber( wxS( "1" ) );
264
265 std::function<bool( const ORCAD_RAW_PAGE&, const ORCAD_OCC_SCOPE& )> canBuildHierarchy =
266 [&]( const ORCAD_RAW_PAGE& aPage, const ORCAD_OCC_SCOPE& aScope )
267 {
268 if( aPage.blocks.size() != aScope.blocks.size() )
269 return false;
270
271 std::set<uint32_t> matchedBlocks;
272
273 for( const ORCAD_OCC_BLOCK& occurrence : aScope.blocks )
274 {
275 auto drawn = std::find_if( aPage.blocks.begin(), aPage.blocks.end(),
276 [&]( const ORCAD_DRAWN_INSTANCE& aBlock )
277 {
278 return aBlock.dbId == occurrence.targetDbId;
279 } );
280
281 std::string key = occurrence.childFolder;
282 std::transform( key.begin(), key.end(), key.begin(),
283 []( unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
284
285 auto pages = m_design.childFolderPages.find( key );
286
287 if( !matchedBlocks.insert( occurrence.targetDbId ).second
288 || drawn == aPage.blocks.end() || pages == m_design.childFolderPages.end()
289 || pages->second.size() != 1 || !canBuildHierarchy( pages->second.front(), occurrence.scope ) )
290 {
291 return false;
292 }
293 }
294
295 return true;
296 };
297
298 bool nativeHierarchy = m_design.pages.size() == 1 && !m_design.occurrenceRoot.blocks.empty()
299 && canBuildHierarchy( m_design.pages.front(), m_design.occurrenceRoot );
300
301 if( nativeHierarchy )
302 {
303 ORCAD_RAW_PAGE& rootPage = m_design.pages.front();
304
305 pollProgress( m_progressReporter, rootPage.name );
306 m_currentOccRefs = &m_design.occurrenceRoot.partRefs;
307 applyPageSettings( rootPage, rootScreen );
308 convertPage( rootPage, rootScreen, rootPath );
309
310 int pageIndex = 1;
311
312 std::function<void( ORCAD_RAW_PAGE&, const ORCAD_OCC_SCOPE&, SCH_SHEET*,
313 const SCH_SHEET_PATH& )> placeChildren =
314 [&]( ORCAD_RAW_PAGE& aParentPage, const ORCAD_OCC_SCOPE& aScope,
315 SCH_SHEET* aParentSheet, const SCH_SHEET_PATH& aParentPath )
316 {
317 std::vector<const ORCAD_OCC_BLOCK*> occurrences;
318
319 for( const ORCAD_OCC_BLOCK& occurrence : aScope.blocks )
320 occurrences.push_back( &occurrence );
321
322 std::stable_sort( occurrences.begin(), occurrences.end(),
323 []( const ORCAD_OCC_BLOCK* a, const ORCAD_OCC_BLOCK* b )
324 {
325 wxString aName = FromOrcadString( a->childFolder );
326 wxString bName = FromOrcadString( b->childFolder );
327 int aOrder = OrcadPageOrder( aName );
328 int bOrder = OrcadPageOrder( bName );
329 int aKey = aOrder >= 0 ? aOrder : std::numeric_limits<int>::max();
330 int bKey = bOrder >= 0 ? bOrder : std::numeric_limits<int>::max();
331 return aKey < bKey;
332 } );
333
334 for( const ORCAD_OCC_BLOCK* occurrencePtr : occurrences )
335 {
336 const ORCAD_OCC_BLOCK& occurrence = *occurrencePtr;
337 auto drawn = std::find_if( aParentPage.blocks.begin(), aParentPage.blocks.end(),
338 [&]( const ORCAD_DRAWN_INSTANCE& aBlock )
339 {
340 return aBlock.dbId == occurrence.targetDbId;
341 } );
342
343 std::string key = occurrence.childFolder;
344 std::transform( key.begin(), key.end(), key.begin(),
345 []( unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
346
347 ORCAD_RAW_PAGE& childPage = m_design.childFolderPages.at( key ).front();
348 SCH_SCREEN* childScreen = new SCH_SCREEN( m_schematic );
349 SCH_SHEET* childSheet = new SCH_SHEET( aParentSheet,
350 OrcadDbuToIu( drawn->x1, drawn->y1 ),
351 OrcadDbuToIu( drawn->w, drawn->h ) );
352 wxString sheetName = FromOrcadString( drawn->reference );
353
354 if( sheetName.IsEmpty() )
355 sheetName = FromOrcadString( childPage.name );
356
357 wxString base = sheetName;
358
359 for( int suffix = 2; !m_usedSheetNames.insert( sheetName.Lower() ).second; ++suffix )
360 sheetName = wxString::Format( wxS( "%s (%d)" ), base, suffix );
361
362 wxString fileName = MakePageFileName( ++pageIndex, childPage.name );
363 childSheet->GetField( FIELD_T::SHEET_NAME )->SetText( sheetName );
364 childSheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( fileName );
365 childSheet->SetScreen( childScreen );
366 childScreen->SetFileName( m_schematic->Project().GetProjectPath() + fileName );
367
368 for( const ORCAD_BLOCK_PIN& sourcePin : drawn->pins )
369 {
370 VECTOR2I position = OrcadDbuToIu( sourcePin.x, sourcePin.y );
371 SCH_SHEET_PIN* pin = new SCH_SHEET_PIN( childSheet, position,
372 FromOrcadString( sourcePin.name ) );
373 std::array<std::pair<int, SHEET_SIDE>, 4> sides = {
374 std::pair{ std::abs( sourcePin.x - drawn->x1 ), SHEET_SIDE::LEFT },
375 std::pair{ std::abs( sourcePin.x - drawn->x1 - drawn->w ), SHEET_SIDE::RIGHT },
376 std::pair{ std::abs( sourcePin.y - drawn->y1 ), SHEET_SIDE::TOP },
377 std::pair{ std::abs( sourcePin.y - drawn->y1 - drawn->h ), SHEET_SIDE::BOTTOM }
378 };
379
380 pin->SetSide( std::min_element( sides.begin(), sides.end(),
381 []( const auto& a, const auto& b )
382 {
383 return a.first < b.first;
384 } )->second );
385
386 switch( sourcePin.portType )
387 {
388 case ORCAD_PORT_TYPE::INPUT: pin->SetShape( LABEL_FLAG_SHAPE::L_INPUT ); break;
392 default: pin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED ); break;
393 }
394
395 childSheet->AddPin( pin );
396 }
397
398 aParentSheet->GetScreen()->Append( childSheet );
399
400 SCH_SHEET_PATH childPath = aParentPath;
401 childPath.push_back( childSheet );
402 childPath.SetPageNumber( wxString::Format( wxS( "%d" ), pageIndex ) );
403
404 pollProgress( m_progressReporter, childPage.name );
405 m_currentOccRefs = &occurrence.scope.partRefs;
406 applyPageSettings( childPage, childScreen );
407 convertPage( childPage, childScreen, childPath );
408 placeChildren( childPage, occurrence.scope, childSheet, childPath );
409 }
410 };
411
412 placeChildren( rootPage, m_design.occurrenceRoot, aRootSheet, rootPath );
413 m_currentOccRefs = nullptr;
414 return aRootSheet;
415 }
416
417 // Page list = root pages + each block occurrence's child pages, tagged w/ scope refs.
418 // Child schematic reused N times yields N jobs, each w/ own designators.
419 struct PAGE_JOB
420 {
421 ORCAD_RAW_PAGE* page;
422 const std::map<uint32_t, std::string>* refs;
423 };
424
425 std::vector<PAGE_JOB> jobs;
426
427 for( ORCAD_RAW_PAGE& page : m_design.pages )
428 jobs.push_back( { &page, &m_design.occurrenceRoot.partRefs } );
429
430 std::function<void( const ORCAD_OCC_SCOPE& )> expand =
431 [&]( const ORCAD_OCC_SCOPE& aScope )
432 {
433 for( const ORCAD_OCC_BLOCK& block : aScope.blocks )
434 {
435 std::string key = block.childFolder;
436 std::transform( key.begin(), key.end(), key.begin(),
437 []( unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
438
439 auto it = m_design.childFolderPages.find( key );
440
441 if( it != m_design.childFolderPages.end() )
442 {
443 for( ORCAD_RAW_PAGE& childPage : it->second )
444 jobs.push_back( { &childPage, &block.scope.partRefs } );
445 }
446
447 expand( block.scope );
448 }
449 };
450
451 expand( m_design.occurrenceRoot );
452
453 if( jobs.size() == 1 )
454 {
455 PAGE_JOB& job = jobs[0];
456
457 pollProgress( m_progressReporter, job.page->name );
458 m_currentOccRefs = job.refs;
459 applyPageSettings( *job.page, rootScreen );
460 convertPage( *job.page, rootScreen, rootPath );
461 m_currentOccRefs = nullptr;
462 }
463 else
464 {
465 // Each page = flat top-level sheet (no stitching root); order root pages by
466 // leading "N - " prefix, also stripped for title.
467 struct SHEET_JOB
468 {
469 PAGE_JOB job;
470 wxString name;
471 int order;
472 };
473
474 std::vector<SHEET_JOB> sheetJobs;
475
476 for( size_t i = 0; i < jobs.size(); ++i )
477 {
478 wxString name = FromOrcadString( jobs[i].page->name );
479 int order = i < m_design.pages.size() ? OrcadPageOrder( name ) : -1;
480
481 if( name.IsEmpty() )
482 name = wxString::Format( wxS( "PAGE%zu" ), i + 1 );
483
484 sheetJobs.push_back( { jobs[i], name, order } );
485 }
486
487 std::stable_sort( sheetJobs.begin(), sheetJobs.end(),
488 []( const SHEET_JOB& a, const SHEET_JOB& b )
489 {
490 int ka = a.order >= 0 ? a.order : std::numeric_limits<int>::max();
491 int kb = b.order >= 0 ? b.order : std::numeric_limits<int>::max();
492 return ka < kb;
493 } );
494
495 std::vector<SCH_SHEET*> topSheets;
496
497 for( size_t i = 0; i < sheetJobs.size(); ++i )
498 {
499 SHEET_JOB& sj = sheetJobs[i];
500
501 pollProgress( m_progressReporter, sj.job.page->name );
502
503 SCH_SHEET* sheet;
504 SCH_SCREEN* screen;
505
506 if( i == 0 )
507 {
508 // Reuse sheet the loader created for first page
509 sheet = aRootSheet;
510 screen = rootScreen;
511 }
512 else
513 {
514 screen = new SCH_SCREEN( m_schematic );
515 sheet = new SCH_SHEET( m_schematic );
516 sheet->SetScreen( screen );
517 const_cast<KIID&>( sheet->m_Uuid ) = screen->GetUuid();
518 }
519
520 wxString base = sj.name;
521
522 for( int suffix = 2; !m_usedSheetNames.insert( sj.name.Lower() ).second; ++suffix )
523 sj.name = wxString::Format( wxS( "%s (%d)" ), base, suffix );
524
525 wxString fileName = MakePageFileName( static_cast<int>( i + 1 ), sj.job.page->name );
526
527 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( sj.name );
528 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( fileName );
529 screen->SetFileName( m_schematic->Project().GetProjectPath() + fileName );
530
531 SCH_SHEET_PATH pagePath;
532 pagePath.push_back( sheet );
533 pagePath.SetPageNumber( wxString::Format( wxS( "%zu" ), i + 1 ) );
534
535 m_currentOccRefs = sj.job.refs;
536 applyPageSettings( *sj.job.page, screen );
537 convertPage( *sj.job.page, screen, pagePath );
538 m_currentOccRefs = nullptr;
539
540 topSheets.push_back( sheet );
541 }
542
543 m_schematic->SetTopLevelSheets( topSheets );
544 }
545
546 return aRootSheet;
547}
548
549
551 const SCH_SHEET_PATH& aSheetPath )
552{
553 applyTitleBlock( aPage, aScreen );
554 buildNetLookup( aPage );
555
556 placeJunctions( aPage, aScreen );
557 placeNoConnects( aPage, aScreen );
558 placeBusEntries( aPage, aScreen );
559 placeWires( aPage, aScreen );
560 placeOffpageConnectors( aPage, aScreen );
561 placePorts( aPage, aScreen, aSheetPath.size() > 1 );
562 placeGraphics( aPage, aScreen );
563
564 for( const ORCAD_PLACED_INSTANCE& instance : aPage.instances )
565 placeInstance( aPage, instance, aScreen, aSheetPath );
566
567 for( const ORCAD_GRAPHIC_INST& global : aPage.globals )
568 placePowerSymbol( aPage, global, powerNet( aPage, global ), aScreen, aSheetPath );
569}
570
571
572wxString ORCAD_CONVERTER::MakePageFileName( int aPageIndex, const std::string& aPageName )
573{
574 wxString fileName = wxString::Format( wxS( "P%02d_" ), aPageIndex )
575 + SanitizeFileName( aPageName ) + wxS( ".kicad_sch" );
576
577 ReplaceIllegalFileNameChars( fileName, '_' );
578
579 return fileName;
580}
581
582
583wxString ORCAD_CONVERTER::SanitizeFileName( const std::string& aName )
584{
585 const wxString illegal( wxS( "<>:\"/\\|?*" ) );
586 wxString in = FromOrcadString( aName );
587 wxString out;
588
589 for( wxUniChar c : in )
590 {
591 if( c.GetValue() < 0x20 || illegal.Find( c ) != wxNOT_FOUND )
592 out += '_';
593 else
594 out += c;
595 }
596
597 while( !out.IsEmpty() && ( out.Last() == ' ' || out.Last() == '.' ) )
598 out.RemoveLast();
599
600 while( !out.IsEmpty() && ( out.GetChar( 0 ) == ' ' || out.GetChar( 0 ) == '.' ) )
601 out.Remove( 0, 1 );
602
603 if( out.IsEmpty() )
604 out = wxS( "unnamed" );
605
606 return out;
607}
608
609
611{
612 BOX2I extent = pageExtentDbu( aPage );
613
614 // Shift content clear of frame, round up to 10-DBU grid to keep points on grid.
615 int dx = std::max( 0, MARGIN_L_DBU - extent.GetLeft() );
616 int dy = std::max( 0, MARGIN_T_DBU - extent.GetTop() );
617
618 dx = ( dx + 9 ) / 10 * 10;
619 dy = ( dy + 9 ) / 10 * 10;
620
621 int maxX = extent.GetRight();
622 int maxY = extent.GetBottom();
623
624 if( dx || dy )
625 {
626 offsetPage( aPage, dx, dy );
627 maxX += dx;
628 maxY += dy;
629 }
630
631 // Nominal paper from stored page size; mils, or micrometres when metric.
632 double k = aPage.isMetric ? 0.001 : 0.0254;
633 double nominalWmm = aPage.width * k;
634 double nominalHmm = aPage.height * k;
635
636 // Needed paper = shifted content extent plus right/bottom margins.
637 double neededWmm = ( maxX + MARGIN_R_DBU ) * DBU_TO_MM;
638 double neededHmm = ( maxY + MARGIN_B_DBU ) * DBU_TO_MM;
639
640 int paperWmm = static_cast<int>( std::ceil( std::max( nominalWmm, neededWmm ) ) );
641 int paperHmm = static_cast<int>( std::ceil( std::max( nominalHmm, neededHmm ) ) );
642
643 PAGE_INFO pageInfo;
644 PAGE_INFO::SetCustomWidthMils( paperWmm * 1000.0 / 25.4 );
645 PAGE_INFO::SetCustomHeightMils( paperHmm * 1000.0 / 25.4 );
646 pageInfo.SetType( PAGE_SIZE_TYPE::User );
647
648 aScreen->SetPageSettings( pageInfo );
649}
650
651
653{
654 bool any = false;
655 int minX = 0;
656 int minY = 0;
657 int maxX = 0;
658 int maxY = 0;
659
660 auto add = [&]( int aX, int aY )
661 {
662 if( !any )
663 {
664 minX = maxX = aX;
665 minY = maxY = aY;
666 any = true;
667 }
668 else
669 {
670 minX = std::min( minX, aX );
671 minY = std::min( minY, aY );
672 maxX = std::max( maxX, aX );
673 maxY = std::max( maxY, aY );
674 }
675 };
676
677 for( const ORCAD_WIRE& wire : aPage.wires )
678 {
679 add( wire.x1, wire.y1 );
680 add( wire.x2, wire.y2 );
681 }
682
683 for( const ORCAD_PLACED_INSTANCE& instance : aPage.instances )
684 {
685 add( instance.bbox.x1, instance.bbox.y1 );
686 add( instance.bbox.x2, instance.bbox.y2 );
687
688 for( const ORCAD_PIN_INST& pin : instance.pins )
689 add( pin.x, pin.y );
690 }
691
692 for( const std::vector<ORCAD_GRAPHIC_INST>* list :
693 { &aPage.globals, &aPage.offpage, &aPage.ports, &aPage.ercObjects } )
694 {
695 for( const ORCAD_GRAPHIC_INST& inst : *list )
696 {
697 add( inst.x, inst.y );
698 add( inst.bbox.x1, inst.bbox.y1 );
699 add( inst.bbox.x2, inst.bbox.y2 );
700 }
701 }
702
703 // Free graphics outer bbox = anchor-relative junk; only nested primitives carry real coords.
704 for( const ORCAD_GRAPHIC_INST& gfx : aPage.graphics )
705 {
706 if( !gfx.nested )
707 continue;
708
709 for( const ORCAD_PRIMITIVE& prim : gfx.nested->primitives )
710 {
711 if( !prim.points.empty() )
712 {
713 for( const ORCAD_POINT& pt : prim.points )
714 add( pt.x, pt.y );
715 }
716 else
717 {
718 add( prim.x1, prim.y1 );
719 add( prim.x2, prim.y2 );
720 }
721 }
722 }
723
724 for( const ORCAD_BUS_ENTRY& entry : aPage.busEntries )
725 {
726 add( entry.x1, entry.y1 );
727 add( entry.x2, entry.y2 );
728 }
729
730 for( const ORCAD_DRAWN_INSTANCE& block : aPage.blocks )
731 {
732 add( block.x1, block.y1 );
733 add( block.x1 + block.w, block.y1 + block.h );
734
735 for( const ORCAD_BLOCK_PIN& pin : block.pins )
736 add( pin.x, pin.y );
737 }
738
739 if( !any )
740 return BOX2I( VECTOR2I( 0, 0 ), VECTOR2I( 3800, 2700 ) );
741
742 return BOX2I( VECTOR2I( minX, minY ), VECTOR2I( maxX - minX, maxY - minY ) );
743}
744
745
746void ORCAD_CONVERTER::offsetPage( ORCAD_RAW_PAGE& aPage, int aDx, int aDy )
747{
748 for( ORCAD_WIRE& wire : aPage.wires )
749 {
750 wire.x1 += aDx;
751 wire.y1 += aDy;
752 wire.x2 += aDx;
753 wire.y2 += aDy;
754
755 for( ORCAD_ALIAS& alias : wire.aliases )
756 {
757 alias.x += aDx;
758 alias.y += aDy;
759 }
760 }
761
762 for( ORCAD_PLACED_INSTANCE& instance : aPage.instances )
763 {
764 instance.x += aDx;
765 instance.y += aDy;
766 instance.bbox.x1 += aDx;
767 instance.bbox.y1 += aDy;
768 instance.bbox.x2 += aDx;
769 instance.bbox.y2 += aDy;
770
771 for( ORCAD_PIN_INST& pin : instance.pins )
772 {
773 pin.x += aDx;
774 pin.y += aDy;
775 }
776 }
777
778 auto shiftGraphic = [&]( ORCAD_GRAPHIC_INST& aInst )
779 {
780 aInst.x += aDx;
781 aInst.y += aDy;
782 aInst.bbox.x1 += aDx;
783 aInst.bbox.y1 += aDy;
784 aInst.bbox.x2 += aDx;
785 aInst.bbox.y2 += aDy;
786
787 if( !aInst.nested )
788 return;
789
790 for( ORCAD_PRIMITIVE& prim : aInst.nested->primitives )
791 {
792 prim.x1 += aDx;
793 prim.y1 += aDy;
794 prim.x2 += aDx;
795 prim.y2 += aDy;
796
797 for( ORCAD_POINT& pt : prim.points )
798 {
799 pt.x += aDx;
800 pt.y += aDy;
801 }
802
803 if( prim.start )
804 {
805 prim.start->x += aDx;
806 prim.start->y += aDy;
807 }
808
809 if( prim.end )
810 {
811 prim.end->x += aDx;
812 prim.end->y += aDy;
813 }
814 }
815 };
816
817 for( std::vector<ORCAD_GRAPHIC_INST>* list : { &aPage.globals, &aPage.offpage, &aPage.ports,
818 &aPage.ercObjects, &aPage.graphics } )
819 {
820 for( ORCAD_GRAPHIC_INST& inst : *list )
821 shiftGraphic( inst );
822 }
823
824 for( ORCAD_BUS_ENTRY& entry : aPage.busEntries )
825 {
826 entry.x1 += aDx;
827 entry.y1 += aDy;
828 entry.x2 += aDx;
829 entry.y2 += aDy;
830 }
831
832 for( ORCAD_DRAWN_INSTANCE& block : aPage.blocks )
833 {
834 block.x1 += aDx;
835 block.y1 += aDy;
836
837 for( ORCAD_BLOCK_PIN& pin : block.pins )
838 {
839 pin.x += aDx;
840 pin.y += aDy;
841 }
842 }
843}
844
845
847{
848 for( const ORCAD_GRAPHIC_INST& tbInst : aPage.titleBlocks )
849 {
850 auto symbolIt = m_design.symbols.find( tbInst.name );
851
852 if( symbolIt != m_design.symbols.end() )
853 {
854 placeDefinitionVectors( symbolIt->second, tbInst.bbox.x1, tbInst.bbox.y1,
855 OrcadOrientOf( tbInst.rotation, tbInst.mirror ), aScreen );
856 placeDefinitionImages( symbolIt->second, tbInst.bbox.x1, tbInst.bbox.y1,
857 OrcadOrientOf( tbInst.rotation, tbInst.mirror ), aScreen );
858 }
859
860 if( tbInst.props.empty() )
861 continue;
862
863 auto get = [&]( const char* aKey ) -> wxString
864 {
865 auto it = tbInst.props.find( aKey );
866
867 return it != tbInst.props.end() ? FromOrcadString( it->second ) : wxString();
868 };
869
870 TITLE_BLOCK titleBlock;
871
872 titleBlock.SetTitle( get( "Title" ) );
873
874 wxString date = get( "Page Modify Date" );
875
876 if( date.IsEmpty() )
877 date = get( "Doc Date" );
878
879 titleBlock.SetDate( date );
880 titleBlock.SetRevision( get( "RevCode" ) );
881 titleBlock.SetCompany( get( "OrgName" ) );
882 titleBlock.SetComment( 0, get( "Doc" ) );
883 titleBlock.SetComment( 1, get( "OrgAddr1" ) );
884 titleBlock.SetComment( 2, get( "OrgAddr2" ) );
885
886 aScreen->SetTitleBlock( titleBlock );
887 return;
888 }
889}
890
891
892void ORCAD_CONVERTER::placeDefinitionVectors( const ORCAD_SYMBOL_DEF& aDefinition, int aBaseX, int aBaseY, int aOrient,
893 SCH_SCREEN* aScreen )
894{
895 ORCAD_BBOX bbox = aDefinition.bbox.value_or( ORCAD_BBOX() );
896 int width = bbox.x2 - bbox.x1;
897 int height = bbox.y2 - bbox.y1;
898
899 auto transform = [&]( int aX, int aY )
900 {
901 return OrcadTransformPoint( aOrient, width, height, aBaseX, aBaseY, aX, aY );
902 };
903
904 ORCAD_GRAPHIC_INST graphic;
905 graphic.rotation = aOrient & 3;
906 graphic.color = aDefinition.color;
907 graphic.nested = std::make_unique<ORCAD_SYMBOL_DEF>();
908
909 std::function<void( const std::vector<ORCAD_PRIMITIVE>&, int, int )> appendVectors =
910 [&]( const std::vector<ORCAD_PRIMITIVE>& aPrimitives, int aOffsetX, int aOffsetY )
911 {
912 for( const ORCAD_PRIMITIVE& source : aPrimitives )
913 {
914 if( source.kind == ORCAD_PRIM_KIND::GROUP )
915 {
916 appendVectors( source.children, aOffsetX + source.x1, aOffsetY + source.y1 );
917 continue;
918 }
919
920 if( source.kind == ORCAD_PRIM_KIND::IMAGE )
921 continue;
922
923 ORCAD_PRIMITIVE primitive = source;
924
925 auto transformBox = [&]
926 {
927 std::array<VECTOR2I, 4> corners = { transform( aOffsetX + source.x1, aOffsetY + source.y1 ),
928 transform( aOffsetX + source.x2, aOffsetY + source.y1 ),
929 transform( aOffsetX + source.x2, aOffsetY + source.y2 ),
930 transform( aOffsetX + source.x1, aOffsetY + source.y2 ) };
931
932 primitive.x1 = primitive.x2 = corners[0].x;
933 primitive.y1 = primitive.y2 = corners[0].y;
934
935 for( const VECTOR2I& corner : corners )
936 {
937 primitive.x1 = std::min( primitive.x1, corner.x );
938 primitive.y1 = std::min( primitive.y1, corner.y );
939 primitive.x2 = std::max( primitive.x2, corner.x );
940 primitive.y2 = std::max( primitive.y2, corner.y );
941 }
942 };
943
944 if( source.kind == ORCAD_PRIM_KIND::LINE )
945 {
946 VECTOR2I p1 = transform( aOffsetX + source.x1, aOffsetY + source.y1 );
947 VECTOR2I p2 = transform( aOffsetX + source.x2, aOffsetY + source.y2 );
948 primitive.x1 = p1.x;
949 primitive.y1 = p1.y;
950 primitive.x2 = p2.x;
951 primitive.y2 = p2.y;
952 }
953 else
954 {
955 transformBox();
956 }
957
958 for( ORCAD_POINT& point : primitive.points )
959 {
960 VECTOR2I transformed = transform( aOffsetX + point.x, aOffsetY + point.y );
961 point.x = transformed.x;
962 point.y = transformed.y;
963 }
964
965 if( primitive.start )
966 {
967 VECTOR2I transformed = transform( aOffsetX + primitive.start->x, aOffsetY + primitive.start->y );
968 primitive.start = ORCAD_POINT{ transformed.x, transformed.y };
969 }
970
971 if( primitive.end )
972 {
973 VECTOR2I transformed = transform( aOffsetX + primitive.end->x, aOffsetY + primitive.end->y );
974 primitive.end = ORCAD_POINT{ transformed.x, transformed.y };
975 }
976
977 graphic.nested->primitives.push_back( std::move( primitive ) );
978 }
979 };
980
981 appendVectors( aDefinition.primitives, 0, 0 );
982
983 ORCAD_RAW_PAGE page;
984 page.graphics.push_back( std::move( graphic ) );
985 placeGraphics( page, aScreen );
986}
987
988
989void ORCAD_CONVERTER::placeDefinitionImages( const ORCAD_SYMBOL_DEF& aDefinition, int aBaseX, int aBaseY, int aOrient,
990 SCH_SCREEN* aScreen )
991{
992 ORCAD_BBOX bbox = aDefinition.bbox.value_or( ORCAD_BBOX() );
993 int width = bbox.x2 - bbox.x1;
994 int height = bbox.y2 - bbox.y1;
995
996 std::function<void( const std::vector<ORCAD_PRIMITIVE>&, int, int )> placeImages =
997 [&]( const std::vector<ORCAD_PRIMITIVE>& aPrimitives, int aOffsetX, int aOffsetY )
998 {
999 for( const ORCAD_PRIMITIVE& primitive : aPrimitives )
1000 {
1001 if( primitive.kind == ORCAD_PRIM_KIND::GROUP )
1002 {
1003 placeImages( primitive.children, aOffsetX + primitive.x1, aOffsetY + primitive.y1 );
1004 continue;
1005 }
1006
1007 if( primitive.kind != ORCAD_PRIM_KIND::IMAGE )
1008 continue;
1009
1010 VECTOR2I center = OrcadTransformPoint( aOrient, width, height, aBaseX, aBaseY,
1011 aOffsetX + ( primitive.x1 + primitive.x2 ) / 2,
1012 aOffsetY + ( primitive.y1 + primitive.y2 ) / 2 );
1013 int imageWidth = std::abs( primitive.x2 - primitive.x1 );
1014 int imageHeight = std::abs( primitive.y2 - primitive.y1 );
1015 ORCAD_PRIMITIVE image = primitive;
1016 image.x1 = center.x - imageWidth / 2;
1017 image.y1 = center.y - imageHeight / 2;
1018 image.x2 = image.x1 + imageWidth;
1019 image.y2 = image.y1 + imageHeight;
1020 placeBitmap( image, aScreen, aOrient );
1021 }
1022 };
1023
1024 placeImages( aDefinition.primitives, 0, 0 );
1025}
1026
1027
1029{
1030 m_wireEndpoints.clear();
1031
1032 for( const ORCAD_WIRE& wire : aPage.wires )
1033 {
1034 m_wireEndpoints[{ wire.x1, wire.y1 }].push_back( &wire );
1035 m_wireEndpoints[{ wire.x2, wire.y2 }].push_back( &wire );
1036 }
1037}
1038
1039
1040std::string ORCAD_CONVERTER::netAt( const ORCAD_RAW_PAGE& aPage, int aX, int aY ) const
1041{
1042 auto endIt = m_wireEndpoints.find( { aX, aY } );
1043
1044 const std::vector<const ORCAD_WIRE*>* endWires =
1045 endIt != m_wireEndpoints.end() ? &endIt->second : nullptr;
1046
1047 if( endWires )
1048 {
1049 for( const ORCAD_WIRE* wire : *endWires )
1050 {
1051 auto netIt = aPage.netmap.find( wire->id );
1052
1053 if( netIt != aPage.netmap.end() )
1054 return netIt->second;
1055 }
1056 }
1057
1058 // Also try wires passing through point.
1059 for( const ORCAD_WIRE& wire : aPage.wires )
1060 {
1061 if( onSegment( aX, aY, wire ) )
1062 {
1063 auto netIt = aPage.netmap.find( wire.id );
1064
1065 if( netIt != aPage.netmap.end() )
1066 return netIt->second;
1067 }
1068 }
1069
1070 if( endWires )
1071 {
1072 for( const ORCAD_WIRE* wire : *endWires )
1073 {
1074 for( const ORCAD_ALIAS& alias : wire->aliases )
1075 return alias.name;
1076 }
1077 }
1078
1079 return std::string();
1080}
1081
1082
1084 const ORCAD_GRAPHIC_INST& aInst ) const
1085{
1086 // Capture's Name property is the effective net name, including renamed stock power symbols.
1087 auto nameIt = aInst.props.find( "Name" );
1088
1089 if( nameIt != aInst.props.end() && !trimmed( nameIt->second ).empty() )
1090 return trimmed( nameIt->second );
1091
1092 if( !trimmed( aInst.logicalName ).empty() )
1093 return trimmed( aInst.logicalName );
1094
1095 VECTOR2I pin = graphicPinPos( aInst );
1096 std::string net = netAt( aPage, pin.x, pin.y );
1097
1098 if( net.empty() )
1099 {
1100 // No wire touches the pin (direct pin-to-pin placement): the record's resolved
1101 // logical name is the net; the symbol shape name (e.g. a "VCC_BAR" graphic
1102 // shared by differently-named rails) is only a last resort.
1103 net = aInst.logicalName.empty() ? aInst.name : aInst.logicalName;
1104 }
1105
1106 return trimmed( net );
1107}
1108
1109
1111{
1112 auto symIt = m_design.symbols.find( aInst.name );
1113
1114 if( symIt == m_design.symbols.end() || symIt->second.pins.empty() )
1115 return VECTOR2I( aInst.x, aInst.y );
1116
1117 const ORCAD_SYMBOL_DEF& sym = symIt->second;
1118
1119 int baseX = std::min( aInst.bbox.x1, aInst.bbox.x2 );
1120 int baseY = std::min( aInst.bbox.y1, aInst.bbox.y2 );
1121
1122 ORCAD_BBOX symBox = sym.bbox.value_or( ORCAD_BBOX() );
1123
1124 int width = symBox.x2 - symBox.x1;
1125 int height = symBox.y2 - symBox.y1;
1126 int orient = OrcadOrientOf( aInst.rotation, aInst.mirror );
1127
1128 const ORCAD_SYMBOL_PIN& pin = sym.pins[0];
1129
1130 return OrcadTransformPoint( orient, width, height, baseX, baseY, pin.hotptX, pin.hotptY );
1131}
1132
1133
1134std::vector<ORCAD_CONVERTER::OFFPAGE_NET>
1136{
1137 std::vector<OFFPAGE_NET> out;
1138
1139 for( size_t i = 0; i < aPage.offpage.size(); ++i )
1140 {
1141 const ORCAD_GRAPHIC_INST& conn = aPage.offpage[i];
1142 VECTOR2I pin = graphicPinPos( conn );
1143
1144 OFFPAGE_NET entry;
1145 entry.index = static_cast<int>( i );
1146
1147 // Connector name = cross-page net identity; prefer over local wire net which
1148 // OrCAD may name differently (CAM0_IO1 on net GPIO19). Global label still binds wire.
1149 entry.net = trimmed( conn.logicalName );
1150
1151 if( entry.net.empty() )
1152 entry.net = trimmed( netAt( aPage, pin.x, pin.y ) );
1153
1154 entry.x = pin.x;
1155 entry.y = pin.y;
1156
1157 out.push_back( entry );
1158 }
1159
1160 return out;
1161}
1162
1163
1164std::vector<VECTOR2I> ORCAD_CONVERTER::computeJunctions( const ORCAD_RAW_PAGE& aPage ) const
1165{
1166 std::set<std::pair<int, int>> pinPts;
1167
1168 for( const ORCAD_PLACED_INSTANCE& instance : aPage.instances )
1169 {
1170 for( const ORCAD_PIN_INST& pin : instance.pins )
1171 pinPts.insert( { pin.x, pin.y } );
1172 }
1173
1174 for( const ORCAD_DRAWN_INSTANCE& block : aPage.blocks )
1175 {
1176 for( const ORCAD_BLOCK_PIN& pin : block.pins )
1177 pinPts.insert( { pin.x, pin.y } );
1178 }
1179
1180 std::map<std::pair<int, int>, int> ends;
1181
1182 for( const ORCAD_WIRE& wire : aPage.wires )
1183 {
1184 ends[{ wire.x1, wire.y1 }]++;
1185 ends[{ wire.x2, wire.y2 }]++;
1186 }
1187
1188 std::set<std::pair<int, int>> candidates = pinPts;
1189
1190 for( const std::pair<const std::pair<int, int>, int>& end : ends )
1191 candidates.insert( end.first );
1192
1193 std::vector<VECTOR2I> out;
1194
1195 for( const std::pair<int, int>& pt : candidates )
1196 {
1197 auto endIt = ends.find( pt );
1198 int endCount = endIt != ends.end() ? endIt->second : 0;
1199 int through = 0;
1200
1201 for( const ORCAD_WIRE& wire : aPage.wires )
1202 {
1203 if( onSegment( pt.first, pt.second, wire ) )
1204 through++;
1205 }
1206
1207 int pinCount = pinPts.count( pt ) ? 1 : 0;
1208 int score = endCount + 2 * through + pinCount;
1209
1210 // Junction needed when 3+ contributions meet and at least one terminates there.
1211 if( score >= 3 && endCount + pinCount >= 1 && endCount + through >= 2 )
1212 out.emplace_back( pt.first, pt.second );
1213 }
1214
1215 return out;
1216}
1217
1218
1220{
1221 for( const VECTOR2I& pt : computeJunctions( aPage ) )
1222 aScreen->Append( new SCH_JUNCTION( OrcadDbuToIu( pt.x, pt.y ) ) );
1223}
1224
1225
1227{
1228 for( const ORCAD_WIRE& wire : aPage.wires )
1229 {
1230 SCH_LINE* line = new SCH_LINE( OrcadDbuToIu( wire.x1, wire.y1 ),
1231 wire.isBus ? LAYER_BUS : LAYER_WIRE );
1232 line->SetEndPoint( OrcadDbuToIu( wire.x2, wire.y2 ) );
1233
1234 line->SetLineWidth( OrcadLineWidthIu( wire.lineWidth ) );
1235 line->SetLineStyle( OrcadLineStyle( wire.lineStyle ) );
1236
1237 line->SetLineColor( OrcadColor( wire.color ) );
1238
1239 aScreen->Append( line );
1240
1241 for( const ORCAD_ALIAS& alias : wire.aliases )
1242 {
1243 wxString text = FromOrcadString( trimmed( alias.name ) );
1244
1245 if( text.IsEmpty() )
1246 continue;
1247
1248 // Alias stores free display position; snap anchor onto wire so label binds
1249 // electrically.
1250 VECTOR2I anchor = snapToWire( alias.x, alias.y, wire );
1251
1252 SCH_LABEL* label = new SCH_LABEL( OrcadDbuToIu( anchor.x, anchor.y ), text );
1253
1254 // Quadrants 2/3 fold to 0/90 so text reads upright.
1255 int quadrant = alias.rotation & 3;
1256
1257 label->SetSpinStyle( ( quadrant == 1 || quadrant == 3 ) ? SPIN_STYLE::UP
1259
1260 int size = textSizeIU( alias.fontIdx );
1261 label->SetTextSize( VECTOR2I( size, size ) );
1262 applyFont( label, alias.fontIdx );
1263 label->SetTextColor( OrcadColor( alias.color ) );
1264
1265 aScreen->Append( label );
1266 }
1267 }
1268}
1269
1270
1272{
1273 for( const ORCAD_BUS_ENTRY& busEntry : aPage.busEntries )
1274 {
1275 SCH_BUS_WIRE_ENTRY* entry = new SCH_BUS_WIRE_ENTRY( OrcadDbuToIu( busEntry.x1,
1276 busEntry.y1 ) );
1277 entry->SetSize( VECTOR2I( ( busEntry.x2 - busEntry.x1 ) * ORCAD_IU_PER_DBU,
1278 ( busEntry.y2 - busEntry.y1 ) * ORCAD_IU_PER_DBU ) );
1279 entry->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::DEFAULT, OrcadColor( busEntry.color ) ) );
1280 aScreen->Append( entry );
1281 }
1282}
1283
1284
1286{
1287 for( const ORCAD_GRAPHIC_INST& erc : aPage.ercObjects )
1288 aScreen->Append( new SCH_NO_CONNECT( OrcadDbuToIu( erc.x, erc.y ) ) );
1289}
1290
1291
1293{
1294 for( const OFFPAGE_NET& offpage : offpageNets( aPage ) )
1295 {
1296 if( offpage.net.empty() )
1297 {
1298 note( wxString::Format( _( "Page '%s': the off-page connector at (%d, %d) is "
1299 "unconnected in the source design; skipped." ),
1300 FromOrcadString( aPage.name ), offpage.x, offpage.y ) );
1301 continue;
1302 }
1303
1304 SCH_GLOBALLABEL* label = new SCH_GLOBALLABEL( OrcadDbuToIu( offpage.x, offpage.y ),
1305 FromOrcadString( offpage.net ) );
1307 label->SetTextColor( OrcadColor( aPage.offpage[offpage.index].color ) );
1308
1309 // Point label away from attached wire; vertical wire gives up/down, horizontal left/right.
1311 auto endIt = m_wireEndpoints.find( { offpage.x, offpage.y } );
1312
1313 if( endIt != m_wireEndpoints.end() && !endIt->second.empty() )
1314 {
1315 const ORCAD_WIRE* wire = endIt->second.front();
1316 int64_t dx = (int64_t) wire->x1 + wire->x2 - 2LL * offpage.x;
1317 int64_t dy = (int64_t) wire->y1 + wire->y2 - 2LL * offpage.y;
1318
1319 if( std::abs( dx ) >= std::abs( dy ) )
1320 spin = dx > 0 ? SPIN_STYLE::LEFT : SPIN_STYLE::RIGHT;
1321 else
1322 spin = dy > 0 ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM;
1323 }
1324
1325 label->SetSpinStyle( spin );
1326
1327 if( SCH_FIELD* refs = label->GetField( FIELD_T::INTERSHEET_REFS ) )
1328 refs->SetVisible( false );
1329
1330 aScreen->Append( label );
1331 }
1332}
1333
1334
1336 bool aHierarchical )
1337{
1338 for( const ORCAD_GRAPHIC_INST& port : aPage.ports )
1339 {
1340 std::string net = trimmed( port.logicalName.empty() ? port.name : port.logicalName );
1341
1342 if( net.empty() )
1343 continue;
1344
1345 VECTOR2I pos = graphicPinPos( port );
1346
1347 // Symbol name encodes arrow direction, e.g. "PORTLEFT-L".
1348 wxString symbolName = FromOrcadString( port.name ).Upper();
1350
1351 if( symbolName.Contains( wxS( "LEFT" ) ) )
1353 else if( symbolName.Contains( wxS( "RIGHT" ) ) )
1355
1356 SCH_LABEL_BASE* label;
1357
1358 if( aHierarchical )
1359 label = new SCH_HIERLABEL( OrcadDbuToIu( pos.x, pos.y ), FromOrcadString( net ) );
1360 else
1361 label = new SCH_GLOBALLABEL( OrcadDbuToIu( pos.x, pos.y ), FromOrcadString( net ) );
1362
1363 label->SetShape( shape );
1365 label->SetTextColor( OrcadColor( port.color ) );
1366
1367 if( SCH_GLOBALLABEL* global = dynamic_cast<SCH_GLOBALLABEL*>( label ) )
1368 {
1369 if( SCH_FIELD* refs = global->GetField( FIELD_T::INTERSHEET_REFS ) )
1370 refs->SetVisible( false );
1371 }
1372
1373 aScreen->Append( label );
1374 }
1375}
1376
1377
1379{
1380 for( const ORCAD_GRAPHIC_INST& gfx : aPage.graphics )
1381 {
1382 if( !gfx.nested )
1383 continue;
1384
1385 KIGFX::COLOR4D graphicColor = OrcadColor( gfx.color );
1386 std::function<void( const ORCAD_PRIMITIVE&, int, int )> placePrimitive =
1387 [&]( const ORCAD_PRIMITIVE& aSource, int aOffsetX, int aOffsetY )
1388 {
1389 if( aSource.kind == ORCAD_PRIM_KIND::GROUP )
1390 {
1391 for( const ORCAD_PRIMITIVE& child : aSource.children )
1392 placePrimitive( child, aOffsetX + aSource.x1, aOffsetY + aSource.y1 );
1393
1394 return;
1395 }
1396
1397 ORCAD_PRIMITIVE prim = aSource;
1398 prim.x1 += aOffsetX;
1399 prim.y1 += aOffsetY;
1400 prim.x2 += aOffsetX;
1401 prim.y2 += aOffsetY;
1402
1403 for( ORCAD_POINT& point : prim.points )
1404 {
1405 point.x += aOffsetX;
1406 point.y += aOffsetY;
1407 }
1408
1409 if( prim.start )
1410 {
1411 prim.start->x += aOffsetX;
1412 prim.start->y += aOffsetY;
1413 }
1414
1415 if( prim.end )
1416 {
1417 prim.end->x += aOffsetX;
1418 prim.end->y += aOffsetY;
1419 }
1420
1421 switch( prim.kind )
1422 {
1423 case ORCAD_PRIM_KIND::GROUP: break;
1424
1425 case ORCAD_PRIM_KIND::IMAGE: placeBitmap( prim, aScreen ); break;
1426
1428 {
1429 wxString content = FromOrcadString( prim.text );
1430
1431 if( content.IsEmpty() )
1432 break;
1433
1434 SCH_TEXT* text = new SCH_TEXT( OrcadDbuToIu( prim.x1, prim.y1 ), content );
1435
1436 // Comment text anchors at top-left of bbox.
1437 text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
1438 text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
1439 text->SetMultilineAllowed( true );
1440
1441 int size = textSizeIU( prim.fontIdx );
1442 text->SetTextSize( VECTOR2I( size, size ) );
1443 applyFont( text, prim.fontIdx );
1444 text->SetTextColor( graphicColor );
1445
1446 // Quadrants 2/3 fold to horizontal so text reads upright.
1447 if( ( gfx.rotation & 3 ) == 1 )
1448 text->SetTextAngle( ANGLE_VERTICAL );
1449
1450 aScreen->Append( text );
1451 break;
1452 }
1453
1455 aScreen->Append( makeSheetPoly( { OrcadDbuToIu( prim.x1, prim.y1 ), OrcadDbuToIu( prim.x2, prim.y2 ) },
1456 prim, graphicColor ) );
1457 break;
1458
1460 aScreen->Append( makeSheetPoly( { OrcadDbuToIu( prim.x1, prim.y1 ), OrcadDbuToIu( prim.x2, prim.y1 ),
1461 OrcadDbuToIu( prim.x2, prim.y2 ), OrcadDbuToIu( prim.x1, prim.y2 ),
1462 OrcadDbuToIu( prim.x1, prim.y1 ) },
1463 prim, graphicColor, true ) );
1464 break;
1465
1468 {
1469 if( prim.points.size() < 2 )
1470 break;
1471
1472 std::vector<VECTOR2I> pts;
1473
1474 for( const ORCAD_POINT& pt : prim.points )
1475 pts.push_back( OrcadDbuToIu( pt.x, pt.y ) );
1476
1477 if( prim.kind == ORCAD_PRIM_KIND::POLYGON )
1478 pts.push_back( pts.front() );
1479
1480 aScreen->Append( makeSheetPoly( pts, prim, graphicColor, prim.kind == ORCAD_PRIM_KIND::POLYGON ) );
1481 break;
1482 }
1483
1485 {
1486 if( prim.points.size() < 4 || ( prim.points.size() - 1 ) % 3 != 0 )
1487 {
1488 if( prim.points.size() >= 2 )
1489 {
1490 std::vector<VECTOR2I> pts;
1491
1492 for( const ORCAD_POINT& pt : prim.points )
1493 pts.push_back( OrcadDbuToIu( pt.x, pt.y ) );
1494
1495 aScreen->Append( makeSheetPoly( pts, prim, graphicColor ) );
1496 }
1497
1498 break;
1499 }
1500
1501 for( size_t i = 0; i + 3 < prim.points.size(); i += 3 )
1502 {
1504 shape->SetPosition( OrcadDbuToIu( prim.points[i].x, prim.points[i].y ) );
1505 shape->SetBezierC1( OrcadDbuToIu( prim.points[i + 1].x, prim.points[i + 1].y ) );
1506 shape->SetBezierC2( OrcadDbuToIu( prim.points[i + 2].x, prim.points[i + 2].y ) );
1507 shape->SetEnd( OrcadDbuToIu( prim.points[i + 3].x, prim.points[i + 3].y ) );
1508
1510 OrcadLineStyle( prim.lineStyle ), graphicColor ) );
1511 shape->SetFillMode( FILL_T::NO_FILL );
1512 aScreen->Append( shape );
1513 }
1514
1515 break;
1516 }
1517
1520 {
1521 double cx = ( prim.x1 + prim.x2 ) / 2.0;
1522 double cy = ( prim.y1 + prim.y2 ) / 2.0;
1523 double rx = std::abs( prim.x2 - prim.x1 ) / 2.0;
1524 double ry = std::abs( prim.y2 - prim.y1 ) / 2.0;
1525
1526 if( rx == 0.0 )
1527 rx = 0.01;
1528
1529 if( ry == 0.0 )
1530 ry = 0.01;
1531
1532 double a0 = 0.0;
1533 double a1 = 2.0 * M_PI;
1534
1535 if( prim.kind == ORCAD_PRIM_KIND::ARC && prim.start && prim.end )
1536 {
1537 a0 = std::atan2( ( prim.start->y - cy ) / ry, ( prim.start->x - cx ) / rx );
1538 a1 = std::atan2( ( prim.end->y - cy ) / ry, ( prim.end->x - cx ) / rx );
1539
1540 // Arcs run CCW in screen (Y-down) coords.
1541 if( a1 >= a0 )
1542 a1 -= 2.0 * M_PI;
1543 }
1544
1545 int steps = std::max( 8, static_cast<int>( std::abs( a1 - a0 )
1546 / ( M_PI / 16.0 ) ) );
1547
1548 std::vector<VECTOR2I> pts;
1549
1550 for( int k = 0; k <= steps; ++k )
1551 {
1552 double a = a0 + ( a1 - a0 ) * k / steps;
1553 pts.push_back( dbuPointToIu( cx + rx * std::cos( a ),
1554 cy + ry * std::sin( a ) ) );
1555 }
1556
1557 aScreen->Append( makeSheetPoly( pts, prim, graphicColor, prim.kind == ORCAD_PRIM_KIND::ELLIPSE ) );
1558 break;
1559 }
1560 }
1561 };
1562
1563 for( const ORCAD_PRIMITIVE& sourcePrimitive : gfx.nested->primitives )
1564 placePrimitive( sourcePrimitive, 0, 0 );
1565 }
1566}
1567
1568
1569void ORCAD_CONVERTER::placeBitmap( const ORCAD_PRIMITIVE& aPrim, SCH_SCREEN* aScreen, int aOrient )
1570{
1571 int widthDbu = std::abs( aPrim.x2 - aPrim.x1 );
1572 int heightDbu = std::abs( aPrim.y2 - aPrim.y1 );
1573
1574 if( widthDbu < 2 || heightDbu < 2 || aPrim.data.empty() )
1575 return;
1576
1577 wxMemoryBuffer bmpData;
1578
1579 VECTOR2I center = dbuPointToIu( ( aPrim.x1 + aPrim.x2 ) / 2.0, ( aPrim.y1 + aPrim.y2 ) / 2.0 );
1580
1581 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>( center );
1582 REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
1583
1584 bool readOk = false;
1585
1586 if( MakeBmpFromDib( aPrim.data, bmpData ) )
1587 {
1588 wxLogNull noLog;
1589 readOk = refImage.ReadImageFile( bmpData );
1590 }
1591 else
1592 {
1594
1595 if( preview.type == ORCAD_OLE_PREVIEW_TYPE::BMP )
1596 {
1597 bmpData.AppendData( preview.data.data(), preview.data.size() );
1598 wxLogNull noLog;
1599 readOk = refImage.ReadImageFile( bmpData );
1600 }
1601 else if( preview.type == ORCAD_OLE_PREVIEW_TYPE::DIB && MakeBmpFromDib( preview.data, bmpData ) )
1602 {
1603 wxLogNull noLog;
1604 readOk = refImage.ReadImageFile( bmpData );
1605 }
1606 else if( preview.type == ORCAD_OLE_PREVIEW_TYPE::WMF )
1607 {
1608 wxImage image;
1609 int maxWidth = std::clamp( widthDbu * 2, 1, 4096 );
1610 int maxHeight = std::clamp( heightDbu * 2, 1, 4096 );
1611
1612 if( OrcadRenderWmf( preview.data, maxWidth, maxHeight, image ) )
1613 readOk = refImage.SetImage( image );
1614 }
1615 }
1616
1617 if( !readOk )
1618 {
1619 warn( _( "An embedded picture could not be decoded and was skipped." ) );
1620 return;
1621 }
1622
1623 VECTOR2I nativeSize = refImage.GetSize();
1624
1625 if( nativeSize.x > 0 && nativeSize.y > 0 )
1626 {
1627 double scaleX = static_cast<double>( widthDbu * ORCAD_IU_PER_DBU ) / nativeSize.x;
1628 double scaleY = static_cast<double>( heightDbu * ORCAD_IU_PER_DBU ) / nativeSize.y;
1629
1630 refImage.SetImageScale( std::min( scaleX, scaleY ) );
1631 }
1632
1633 const ORCAD_ORIENT_ENTRY& orientation = ORCAD_ORIENT_TABLE[aOrient & 7];
1634
1635 if( orientation.mirror == 'x' )
1636 bitmap->MirrorVertically( center.y );
1637 else if( orientation.mirror == 'y' )
1638 bitmap->MirrorHorizontally( center.x );
1639
1640 for( int angle = 0; angle < orientation.angle; angle += 90 )
1641 bitmap->Rotate( center, true );
1642
1643 aScreen->Append( bitmap.release() );
1644}
1645
1646
1647bool ORCAD_CONVERTER::MakeBmpFromDib( const std::vector<uint8_t>& aDib, wxMemoryBuffer& aOut )
1648{
1649 // DIB = BITMAPINFOHEADER + optional palette + pixels; prepend 14-byte BITMAPFILEHEADER
1650 // with palette-aware pixel offset for loadable .BMP.
1651 if( aDib.size() < 40 )
1652 return false;
1653
1654 auto readU16 = [&aDib]( size_t aOffset ) -> uint32_t
1655 {
1656 return static_cast<uint32_t>( aDib[aOffset] )
1657 | ( static_cast<uint32_t>( aDib[aOffset + 1] ) << 8 );
1658 };
1659
1660 auto readU32 = [&aDib]( size_t aOffset ) -> uint32_t
1661 {
1662 return static_cast<uint32_t>( aDib[aOffset] )
1663 | ( static_cast<uint32_t>( aDib[aOffset + 1] ) << 8 )
1664 | ( static_cast<uint32_t>( aDib[aOffset + 2] ) << 16 )
1665 | ( static_cast<uint32_t>( aDib[aOffset + 3] ) << 24 );
1666 };
1667
1668 uint32_t biSize = readU32( 0 );
1669
1670 // Header size outside BITMAPINFOHEADER..BITMAPV5HEADER = not DIB (rejects OLE embeds).
1671 if( biSize < 40 || biSize > 200 )
1672 return false;
1673
1674 uint32_t bitCount = readU16( 14 );
1675 uint32_t compression = readU32( 16 );
1676 uint32_t clrUsed = readU32( 32 );
1677 uint32_t paletteEntries = clrUsed ? clrUsed : ( bitCount <= 8 ? ( 1u << bitCount ) : 0 );
1678 uint32_t pixelOffset = 14 + biSize + paletteEntries * 4;
1679
1680 if( compression == 3 ) // BI_BITFIELDS, three DWORD channel masks follow header
1681 pixelOffset += 12;
1682
1683 uint32_t fileSize = 14 + static_cast<uint32_t>( aDib.size() );
1684
1685 uint8_t header[14];
1686 header[0] = 'B';
1687 header[1] = 'M';
1688 header[2] = static_cast<uint8_t>( fileSize );
1689 header[3] = static_cast<uint8_t>( fileSize >> 8 );
1690 header[4] = static_cast<uint8_t>( fileSize >> 16 );
1691 header[5] = static_cast<uint8_t>( fileSize >> 24 );
1692 header[6] = 0;
1693 header[7] = 0;
1694 header[8] = 0;
1695 header[9] = 0;
1696 header[10] = static_cast<uint8_t>( pixelOffset );
1697 header[11] = static_cast<uint8_t>( pixelOffset >> 8 );
1698 header[12] = static_cast<uint8_t>( pixelOffset >> 16 );
1699 header[13] = static_cast<uint8_t>( pixelOffset >> 24 );
1700
1701 aOut.AppendData( header, sizeof( header ) );
1702 aOut.AppendData( aDib.data(), aDib.size() );
1703
1704 return true;
1705}
1706
1707
1708VECTOR2I ORCAD_CONVERTER::snapToWire( int aX, int aY, const ORCAD_WIRE& aWire )
1709{
1710 if( aWire.x1 == aWire.x2 ) // vertical
1711 {
1712 return VECTOR2I( aWire.x1, std::clamp( aY, std::min( aWire.y1, aWire.y2 ),
1713 std::max( aWire.y1, aWire.y2 ) ) );
1714 }
1715
1716 if( aWire.y1 == aWire.y2 ) // horizontal
1717 {
1718 return VECTOR2I( std::clamp( aX, std::min( aWire.x1, aWire.x2 ),
1719 std::max( aWire.x1, aWire.x2 ) ),
1720 aWire.y1 );
1721 }
1722
1723 // diagonal, project onto segment
1724 double dx = aWire.x2 - aWire.x1;
1725 double dy = aWire.y2 - aWire.y1;
1726 double t = ( ( aX - aWire.x1 ) * dx + ( aY - aWire.y1 ) * dy ) / ( dx * dx + dy * dy );
1727
1728 t = std::clamp( t, 0.0, 1.0 );
1729
1730 return VECTOR2I( KiROUND( aWire.x1 + t * dx ), KiROUND( aWire.y1 + t * dy ) );
1731}
1732
1733
1734bool ORCAD_CONVERTER::onSegment( int aX, int aY, const ORCAD_WIRE& aWire )
1735{
1736 if( ( aX == aWire.x1 && aY == aWire.y1 ) || ( aX == aWire.x2 && aY == aWire.y2 ) )
1737 return false;
1738
1739 if( aWire.x1 == aWire.x2 && aWire.x1 == aX )
1740 return std::min( aWire.y1, aWire.y2 ) < aY && aY < std::max( aWire.y1, aWire.y2 );
1741
1742 if( aWire.y1 == aWire.y2 && aWire.y1 == aY )
1743 return std::min( aWire.x1, aWire.x2 ) < aX && aX < std::max( aWire.x1, aWire.x2 );
1744
1745 return false;
1746}
const char * name
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr coord_type GetTop() const
Definition box2.h:225
constexpr coord_type GetBottom() const
Definition box2.h:218
const KIID m_Uuid
Definition eda_item.h:531
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:244
virtual void SetBezierC2(const VECTOR2I &aPt)
Definition eda_shape.h:282
virtual void SetBezierC1(const VECTOR2I &aPt)
Definition eda_shape.h:279
void SetFillMode(FILL_T aFill)
void SetTextColor(const COLOR4D &aColor)
Definition eda_text.h:290
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:532
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:398
Definition kiid.h:44
void placePowerSymbol(ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst, const std::string &aNet, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath)
Place one power symbol: transform base = placed bbox min corner (fall back to the anchor when the bbo...
void placeJunctions(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Append computed junctions as SCH_JUNCTION items.
std::vector< VECTOR2I > computeJunctions(const ORCAD_RAW_PAGE &aPage) const
Junction points (DBU) from wire geometry + shared net ids.
void prepareSymbols()
Pre-pass over all pages: synthesize placeholder definitions for symbols absent from the cache (one no...
std::vector< OFFPAGE_NET > offpageNets(const ORCAD_RAW_PAGE &aPage) const
Resolve every off-page connector on the page to (index, net, pin position).
std::string netAt(const ORCAD_RAW_PAGE &aPage, int aX, int aY) const
Net name at a point: first a wire with an endpoint here whose id is in the page net table; then any w...
static constexpr int MARGIN_B_DBU
PROGRESS_REPORTER * m_progressReporter
SCH_SHEET * Convert(SCH_SHEET *aRootSheet)
Populate the schematic.
void buildNetLookup(const ORCAD_RAW_PAGE &aPage)
Rebuild m_wireEndpoints for a page (both endpoints of every wire).
void convertPage(ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath)
Convert one page onto a screen: applyTitleBlock(), buildNetLookup(), then junctions,...
static constexpr int MARGIN_R_DBU
const std::map< uint32_t, std::string > * m_currentOccRefs
Occurrence reference designators of the scope currently being converted; set per page so a child sche...
VECTOR2I graphicPinPos(const ORCAD_GRAPHIC_INST &aInst) const
Absolute connection point (DBU) of a GraphicInst-derived instance (power symbol / off-page connector ...
void applyPageSettings(ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Fit the page and set the screen's PAGE_INFO.
ORCAD_CONVERTER(ORCAD_DESIGN &aDesign, SCHEMATIC *aSchematic, REPORTER *aReporter, PROGRESS_REPORTER *aProgressReporter=nullptr)
static bool onSegment(int aX, int aY, const ORCAD_WIRE &aWire)
True when the point lies strictly INSIDE (not at an endpoint of) an H/V wire.
void placeBitmap(const ORCAD_PRIMITIVE &aPrim, SCH_SCREEN *aScreen, int aOrient=0)
One image primitive -> SCH_BITMAP centered on the primitive's page extent, scaled from its native pix...
~ORCAD_CONVERTER()
Out-of-line: LIB_ENTRY holds LIB_SYMBOL by unique_ptr. [orcad_converter_sheet.cpp].
SCH_SHEET * m_rootSheet
static wxString MakePageFileName(int aPageIndex, const std::string &aPageName)
"P%02d_<pagename>.kicad_sch" (1-based index), sanitized: control characters and the characters <>:"/|...
static BOX2I pageExtentDbu(const ORCAD_RAW_PAGE &aPage)
Bounding box (DBU) of everything drawable on the page: wire ends, instance placed bboxes + T0x10 pin ...
void note(const wxString &aMsg)
Fact about the source design (not a conversion problem): RPT_SEVERITY_INFO.
void placeInstance(ORCAD_RAW_PAGE &aPage, const ORCAD_PLACED_INSTANCE &aInst, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath)
Place one part instance on a screen: SCH_SYMBOL from the built LIB_SYMBOL (flattened-copy constructor...
ORCAD_DESIGN & m_design
int m_fontBaselineDbu
dominant text height; 0 = none
std::set< wxString > m_usedSheetNames
Lower-cased sheet names already emitted, to keep sibling sheet names unique.
int textSizeIU(int aFontIdx) const
Text size in IU for a font reference: 1.27 mm when the height is unknown; with a baseline,...
void placeWires(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Wires/buses as SCH_LINE on LAYER_WIRE / LAYER_BUS, plus a local SCH_LABEL per wire alias: anchor snap...
void applyFont(EDA_TEXT *aText, int aFontIdx) const
int m_powerCount
"#PWR%04d" counter
void applyTitleBlock(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Fill the screen TITLE_BLOCK from the first page title block carrying properties: Title,...
void placeDefinitionImages(const ORCAD_SYMBOL_DEF &aDefinition, int aBaseX, int aBaseY, int aOrient, SCH_SCREEN *aScreen)
static void offsetPage(ORCAD_RAW_PAGE &aPage, int aDx, int aDy)
Shift every drawable coordinate on the page by (aDx, aDy) DBU: wires and their aliases,...
void placeOffpageConnectors(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
SCH_GLOBALLABEL per resolved off-page connector, at the connection point; an unconnected connector (e...
static constexpr int MARGIN_T_DBU
SCHEMATIC * m_schematic
void placeGraphics(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Free page graphics from the nested primitives of each Graphic*Inst (the outer record itself is not dr...
void warn(const wxString &aMsg)
Conversion problem: REPORTER at RPT_SEVERITY_WARNING.
void placeDefinitionVectors(const ORCAD_SYMBOL_DEF &aDefinition, int aBaseX, int aBaseY, int aOrient, SCH_SCREEN *aScreen)
REPORTER * m_reporter
void placeNoConnects(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
SCH_NO_CONNECT per ERC object, at the object's anchor.
void placePorts(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen, bool aHierarchical)
SCH_HIERLABEL per port on a hierarchical child page, otherwise SCH_GLOBALLABEL.
static VECTOR2I snapToWire(int aX, int aY, const ORCAD_WIRE &aWire)
Closest point (DBU) on a wire segment to (aX, aY); exact for H/V wires.
static constexpr int MARGIN_L_DBU
Page content margins, DBU.
std::string powerNet(const ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst) const
Net stamped by a power-symbol instance: the net of the wire its pin touches (authoritative — ports ca...
std::map< std::pair< int, int >, std::vector< const ORCAD_WIRE * > > m_wireEndpoints
Per-page wire lookup: endpoint -> wires ending there. Rebuilt by buildNetLookup().
void placeBusEntries(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
SCH_BUS_WIRE_ENTRY per bus entry (position x1,y1; size x2-x1, y2-y1).
static wxString SanitizeFileName(const std::string &aName)
Filesystem-safe name: control characters and <>:"/|?
static bool MakeBmpFromDib(const std::vector< uint8_t > &aDib, wxMemoryBuffer &aOut)
Synthesize a .BMP in front of a raw DIB (BITMAPINFOHEADER + optional palette + pixels): pixel data of...
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
bool SetType(PAGE_SIZE_TYPE aPageSize, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
static void SetCustomWidthMils(double aWidthInMils)
Set the width of Custom page in mils for any custom page constructed or made via SetType() after maki...
static void SetCustomHeightMils(double aHeightInMils)
Set the height of Custom page in mils for any custom page constructed or made via SetType() after mak...
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
bool SetImage(const wxImage &aImage)
Set the image from an existing wxImage.
VECTOR2I GetSize() const
void SetImageScale(double aScale)
Set the image "zoom" value.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:72
Holds all the data relating to one schematic.
Definition schematic.h:90
void SetSize(const VECTOR2I &aSize)
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Class for a wire to bus entry.
void SetText(const wxString &aText) override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this label.
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:179
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:38
void SetLineColor(const COLOR4D &aColor)
Definition sch_line.cpp:319
void SetLineWidth(const int aSize)
Definition sch_line.cpp:385
void SetLineStyle(const LINE_STYLE aStyle)
Definition sch_line.cpp:356
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:145
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition sch_screen.h:164
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition sch_screen.h:138
const KIID & GetUuid() const
Definition sch_screen.h:529
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:85
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:98
void AddPoint(const VECTOR2I &aPosition)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Simple container to manage line stroke parameters.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:37
void SetRevision(const wxString &aRevision)
Definition title_block.h:77
void SetComment(int aIdx, const wxString &aComment)
Definition title_block.h:97
void SetTitle(const wxString &aTitle)
Definition title_block.h:54
void SetCompany(const wxString &aCompany)
Definition title_block.h:87
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition title_block.h:67
A type-safe container of any type.
Definition ki_any.h:92
#define _(s)
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
@ NO_FILL
Definition eda_shape.h:60
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:61
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
@ LAYER_WIRE
Definition layer_ids.h:458
@ LAYER_NOTES
Definition layer_ids.h:473
@ LAYER_BUS
Definition layer_ids.h:459
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
ORCAD_CONVERTER turns a parsed ORCAD_DESIGN into KiCad schematic objects.
constexpr ORCAD_ORIENT_ENTRY ORCAD_ORIENT_TABLE[8]
Orientation table, indexed by the 3-bit orientation code.
VECTOR2I OrcadDbuToIu(int aX, int aY)
FILL_T OrcadFillType(int aFillStyle, int aHatchStyle)
VECTOR2I OrcadTransformPoint(int aOrient, int aWidth, int aHeight, int aBaseX, int aBaseY, int aPx, int aPy)
Absolute canvas position (DBU) of symbol-space point (aPx, aPy) for an instance with transform base (...
int OrcadLineWidthIu(int aWidth)
int OrcadPageOrder(wxString &aName)
Return a numeric page prefix (or -1); strip only the "N - title" convention.
KIGFX::COLOR4D OrcadColor(int aColorIndex)
int OrcadOrientOf(int aRotation, bool aMirror)
Compose the 3-bit orientation code from the rotation bits and mirror bit.
constexpr int ORCAD_IU_PER_DBU
Schematic internal units per OrCAD DBU: 10 mil * 254 IU/mil.
LINE_STYLE OrcadLineStyle(int aStyle)
int OrcadPageOrder(wxString &aName)
Return a numeric page prefix (or -1); strip only the "N - title" convention.
KIGFX::COLOR4D OrcadColor(int aColorIndex)
ORCAD_OLE_PREVIEW OrcadExtractOlePreview(const std::vector< uint8_t > &aPayload)
Definition orcad_ole.cpp:78
bool OrcadRenderWmf(const std::vector< uint8_t > &aWmf, int aMaxWidth, int aMaxHeight, wxImage &aImage)
wxString FromOrcadString(const std::string &aText)
Decode raw stream bytes (Windows-1252) into a wxString for UI/UX use.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_INFO
LABEL_FLAG_SHAPE
Definition sch_label.h:97
@ L_BIDI
Definition sch_label.h:100
@ L_TRISTATE
Definition sch_label.h:101
@ L_UNSPECIFIED
Definition sch_label.h:102
@ L_OUTPUT
Definition sch_label.h:99
@ L_INPUT
Definition sch_label.h:98
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
bool ReplaceIllegalFileNameChars(std::string &aName, int aReplaceChar)
Checks aName for illegal file name characters.
Net alias attached to a wire (becomes a local label).
std::string name
int rotation
0..3 quarter turns
Axis-aligned box in OrCAD DBU; corner order as stored (not normalized).
One interface pin of a hierarchical block, at its absolute page position.
ORCAD_PORT_TYPE portType
std::string name
Bus entry (structure type 29).
int y1
int color
int x2
int y2
int x1
One resolved off-page connector: index into page.offpage, net, pin position.
Everything parsed from one .DSN, as handed to ORCAD_CONVERTER.
Structure type 12: a hierarchical block instance placed on a page.
int x1
block rectangle top-left, page DBU
std::vector< ORCAD_BLOCK_PIN > pins
Shared body of Port / Global / OffPageConnector / TitleBlock / ERCObject and the Graphic*Inst shapes ...
std::unique_ptr< ORCAD_SYMBOL_DEF > nested
SthInPages0 body, else nullptr.
std::map< std::string, std::string > props
int rotation
0..3 quarter turns
std::string name
cache symbol name
std::string logicalName
ports: resolved net/port name
A hierarchical block occurrence: one placement of a child schematic folder on a parent page.
uint32_t targetDbId
type-12 drawn-instance dbId on the parent page
ORCAD_OCC_SCOPE scope
the child's occurrences under this path
std::string childFolder
child schematic folder name
One node of the design occurrence tree parsed from the root Hierarchy stream.
std::map< uint32_t, std::string > partRefs
type-13 dbId -> occurrence refdes
std::vector< uint8_t > data
Definition orcad_ole.h:31
ORCAD_OLE_PREVIEW_TYPE type
Definition orcad_ole.h:30
One entry of the 8-orientation placement table.
char mirror
0 = none, 'x' or 'y' = KiCad mirror axis
int angle
KiCad placement angle in degrees (0/90/180/270, CCW)
T0x10: one pin of a placed instance, carrying the pin's absolute page position (the connection point ...
A placed part instance on a page (structure type 13).
ORCAD_BBOX bbox
placed box, page DBU
std::vector< ORCAD_PIN_INST > pins
successfully parsed T0x10 records
Integer point in OrCAD DBU.
One graphic primitive of a symbol body or nested page graphic.
int fillStyle
0 solid, 1 none, 2 hatch pattern
std::string text
kind == TEXT
std::vector< ORCAD_PRIMITIVE > children
kind == GROUP, translated by (x1, y1)
std::vector< ORCAD_POINT > points
polygon/polyline/bezier vertices
ORCAD_PRIM_KIND kind
std::vector< uint8_t > data
kind == IMAGE: raw embedded payload
int lineStyle
0 solid, 1 dash, 2 dot, 3 dash-dot, 4 dash-dot-dot, 5 default
std::optional< ORCAD_POINT > start
arc start point
std::optional< ORCAD_POINT > end
arc end point
int lineWidth
Capture width enum: 0 thin, 1 medium, 2 wide, 3 default.
One parsed 'Views/<folder>/Pages/<page>' stream, raw structure lists in stream order.
std::vector< ORCAD_GRAPHIC_INST > ports
std::string name
std::vector< ORCAD_GRAPHIC_INST > globals
placed power symbols
std::map< uint32_t, std::string > netmap
net db id -> net name
std::vector< ORCAD_WIRE > wires
uint32_t width
mils, or um when isMetric
std::vector< ORCAD_DRAWN_INSTANCE > blocks
hierarchical blocks (detection only)
std::vector< ORCAD_PLACED_INSTANCE > instances
std::vector< ORCAD_GRAPHIC_INST > graphics
free comment text/shapes/images
std::vector< ORCAD_GRAPHIC_INST > offpage
off-page connectors
std::vector< ORCAD_GRAPHIC_INST > titleBlocks
std::vector< ORCAD_BUS_ENTRY > busEntries
std::vector< ORCAD_GRAPHIC_INST > ercObjects
no-connect markers
A symbol definition from the design Cache (LibraryPart / GlobalSymbol / PortSymbol / OffPageSymbol / ...
std::vector< ORCAD_SYMBOL_PIN > pins
std::vector< ORCAD_PRIMITIVE > primitives
std::optional< ORCAD_BBOX > bbox
symbol-space body box
One pin of a symbol definition (structure types 26/27).
One wire or bus segment.
uint32_t id
bool isBus
true for structure type 21
std::vector< ORCAD_ALIAS > aliases
@ INTERSHEET_REFS
Global label cross-reference page numbers.
KIBIS_PIN * pin
std::vector< std::string > header
VECTOR2I center
VECTOR2I end
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_TOP
#define M_PI
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683