1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014-2017  Cirilo Bernardo
5  * Copyright (C) 2021 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 
26 #ifndef IDF_OUTLINES_H
27 #define IDF_OUTLINES_H
28 
29 #include <string>
30 #include <list>
31 #include <map>
32 
33 #include <idf_common.h>
34 
35 /*
36  *  NOTES ON OUTLINE TYPES:
37  *
38  *  BOARD_OUTLINE (PANEL_OUTLINE)
39  *      .BOARD_OUTLINE  [OWNER]
40  *      [thickness]
41  *      [outlines]
42  *
43  *  OTHER_OUTLINE
44  *      .OTHER_OUTLINE  [OWNER]
45  *      [outline identifier] [thickness] [board side: Top/Bot]
46  *      [outline]
47  *
48  *  ROUTE_OUTLINE
49  *      .ROUTE_OUTLINE [OWNER]
50  *      [layers]
51  *      [outline]
52  *
53  *  PLACE_OUTLINE
54  *      .PLACE_OUTLINE [OWNER]
55  *      [board side: Top/Bot/Both] [height]
56  *      [outline]
57  *
58  *  ROUTE_KEEPOUT
59  *      .ROUTE_KEEPOUT [OWNER]
60  *      [layers]
61  *      [outline]
62  *
63  *  VIA_KEEPOUT
64  *      .VIA_KEEPOUT [OWNER]
65  *      [outline]
66  *
67  *  PLACE_KEEPOUT
68  *      .PLACE_KEEPOUT [OWNER]
69  *      [board side: Top/Bot/Both] [height]
70  *      [outline]
71  *
72  *  Placement Group
73  *      .PLACE_REGION [OWNER]
74  *      [side: Top/Bot/Both ] [component group name]
75  *      [outline]
76  *
77  *  Component Outline:
78  *      .ELECTRICAL/.MECHANICAL
79  *      [GEOM] [PART] [UNIT] [HEIGHT]
80  *      [outline]
81  *      [PROP] [prop name] [prop value]
82  */
83 
84 class IDF3_BOARD;
85 
86 
87 /**
88  * IDFv3 BOARD OUTLINE data and is the basis of other IDFv3 outline objects.
89  */
90 class BOARD_OUTLINE
91 {
92 public:
93     BOARD_OUTLINE();
94     virtual ~BOARD_OUTLINE();
95 
96     /**
97      * Function SetUnit
98      * sets the native unit of the outline; except for component outlines this must
99      * be the same as the native unit of the parent IDF_BOARD object
100      *
101      * @param aUnit is the native unit (UNIT_MM or UNIT_THOU)
102      */
103     virtual bool SetUnit( IDF3::IDF_UNIT aUnit );
104 
105     /**
106      * Return the native unit type of the outline.
107      *
108      * @return IDF_UNIT is the native unit (UNIT_MM or UNIT_THOU).
109      */
110     virtual IDF3::IDF_UNIT GetUnit( void );
111 
112     /**
113      * Set the thickness or height of the outline (mm).
114      *
115      * @param aThickness is the thickness or height of the outline in mm.
116      */
117     virtual bool SetThickness( double aThickness );
118 
119     /**
120      * @return the thickness or height of an outline (mm).
121      */
122     virtual double GetThickness( void );
123 
124     /**
125      * Free memory and reinitializes all internal data except for the parent pointer.
126      *
127      * @return true if OK, false on ownership violations.
128      */
129     virtual bool Clear( void );
130 
131     /**
132      * @return the type of outline according to the IDFv3 classification.
133      */
134     IDF3::OUTLINE_TYPE GetOutlineType( void );
135 
136     /**
137      * @return the parent IDF_BOARD object.
138      */
139     IDF3_BOARD* GetParent( void );
140 
141 
142     /**
143      * Add the specified outline to this object.
144      *
145      * @param aOutline is a valid IDF outline.
146      * @return true if the outline was added; false if the outline already existed or an
147      *         ownership violation occurs.
148      */
149     bool AddOutline( IDF_OUTLINE* aOutline );
150 
151     /**
152      * Remove the given outline, subject to IDF ownership rules,
153      * if it is owned by this object.
154      *
155      * The outline pointer remains valid and it is the user's responsibility to delete the
156      * object.  The first outline in the list will never be deleted unless it is the sole
157      * remaining outline; this is to ensure that a board outline is not removed while the
158      * cutouts remain.
159      *
160      * @param aOutline is a pointer to the outline to remove from the list.
161      * @return true if the outline was found and removed; false if the outline was not found
162      *         or an ownership violation occurs.
163      */
164     bool DelOutline( IDF_OUTLINE* aOutline );
165 
166     /**
167      * Delete the outline specified by the given index, subject to IDF ownership rules.
168      *
169      * The outline data is destroyed. The first outline in the list will never be deleted
170      * unless it is the sole remaining outline; this is to ensure that a board outline is
171      * not removed while the cutouts remain.
172      *
173      * @param aIndex is an index to the outline to delete
174      * @return true if the outline was found and deleted; false if the outline was not found
175      *         or an ownership violation or indexation error occurs.
176      */
177     bool DelOutline( size_t aIndex );
178 
179     /**
180      *  Return outlines list.
181      *
182      * It is up to the user to respect the IDFv3 specification and avoid changes to this
183      * list which are in violation of the specification.
184      */
185     const std::list< IDF_OUTLINE* >*const GetOutlines( void );
186 
187     /**
188      * @return the number of items in the internal outline list.
189      */
190     size_t OutlinesSize( void );
191 
192     /**
193      * Return a pointer to the outline as specified by aIndex.
194      *
195      * If the index is out of bounds NULL is returned and the error message is set. It is the
196      * responsibility of the user to observe IDF ownership rules.
197      */
198     IDF_OUTLINE* GetOutline( size_t aIndex );
199 
200     /**
201      * @return the ownership status of the outline (ECAD, MCAD, UNOWNED).
202      */
203     IDF3::KEY_OWNER GetOwner( void );
204 
205     /**
206      * Set the ownership status of the outline subject to IDF ownership rules.
207      *
208      * @return true if the ownership was changed and false if a specification violation occurred.
209      */
210     bool SetOwner( IDF3::KEY_OWNER aOwner );
211 
212     /**
213      * @return true if this type of outline only supports a single outline. All outlines except
214      *         for BOARD_OUTLINE are single.
215      */
216     bool IsSingle( void );
217 
218     /**
219      * Clear internal data except for the parent pointer.
220      */
221     void ClearOutlines( void );
222 
223     /**
224      * Add a comment to the outline data.
225      *
226      * This function is not subject to IDF ownership rules.
227      */
228     void AddComment( const std::string& aComment );
229 
230     /**
231      * @return the number of comments in the internal list.
232      */
233     size_t CommentsSize( void );
234 
235     /**
236      * @return the internal list of comments.
237      */
238     std::list< std::string >* GetComments( void );
239 
240     /**
241      * @return indexed comment or NULL if the index is out of bounds.
242      */
243     const std::string* GetComment( size_t aIndex );
244 
245     /**
246      * Deletes a comment based on the given index.
247      *
248      * @return true if a comment was deleted, false if the index is out of bounds.
249      */
250     bool DeleteComment( size_t aIndex );
251 
252     /**
253      * Deletes all comments.
254      */
255     void ClearComments( void );
256 
GetError(void)257     const std::string& GetError( void )
258     {
259         return errormsg;
260     }
261 
262 protected:
263     // Read outline data from a BOARD or LIBRARY file's outline section
264     void readOutlines( std::istream& aBoardFile, IDF3::IDF_VERSION aIdfVersion );
265 
266     // Write comments to a BOARD or LIBRARY file (must not be within a SECTION as per IDFv3 spec)
267     bool writeComments( std::ostream& aBoardFile );
268 
269     // Write the outline owner to a BOARD file
270     bool writeOwner( std::ostream& aBoardFile );
271 
272     // Write the data of a single outline object
273     void writeOutline( std::ostream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex );
274 
275     // Iterate through the outlines and write out all data
276     void writeOutlines( std::ostream& aBoardFile );  // write outline data (no headers)
277 
278     // Clear internal list of outlines
279     void clearOutlines( void );
280 
281     /**
282      * Set the parent IDF_BOARD object.
283      */
284     void setParent( IDF3_BOARD* aParent );
285 
286     // Shadow routines used by friends to bypass ownership checks
287     bool addOutline( IDF_OUTLINE* aOutline );
288     virtual bool setThickness( double aThickness );
289     virtual void clear( void );
290 
291     /**
292      * Read data from a .BOARD_OUTLINE section.
293      *
294      * In case of an unrecoverable error an exception is thrown. On a successful
295      * return the file pointer will be at the line following .END_BOARD_OUTLINE
296      *
297      * @param aBoardFile is an IDFv3 file opened for reading.
298      * @param aHeader is the ".BOARD_OUTLINE" header line as read by FetchIDFLine.
299      */
300     virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
301                            IDF3::IDF_VERSION aIdfVersion );
302 
303     /**
304      * Write the comments and .BOARD_OUTLINE section to an IDFv3 file.
305      * Throws exceptions.
306      *
307      * @param aBoardFile is an IDFv3 file opened for writing.
308      */
309     virtual void writeData( std::ostream& aBoardFile );
310 
311     std::string                 errormsg;
312     std::list< IDF_OUTLINE* >   outlines;
313 
314     // indicates the owner of this outline (MCAD, ECAD, UNOWNED).
315     IDF3::KEY_OWNER             owner;
316     IDF3::OUTLINE_TYPE          outlineType;  // type of IDF outline
317     bool                        single;       // true if only a single outline is accepted
318     std::list< std::string >    comments;     // associated comment list
319     IDF3::IDF_UNIT              unit;         // outline's native unit (MM or THOU)
320     IDF3_BOARD*                 parent;       // BOARD which contains this outline
321     double                      thickness;    // Board/Extrude Thickness or Height (IDF spec)
322 
323 private:
324     friend class IDF3_BOARD;
325 };
326 
327 
328 /**
329  * Miscellaneous extrusions on the board
330  */
331 class OTHER_OUTLINE : public BOARD_OUTLINE
332 {
333 public:
334     OTHER_OUTLINE( IDF3_BOARD* aParent );
335 
336     /**
337      * Function SetOutlineIdentifier
338      * sets the Outline Identifier string of this OTHER_OUTLINE object
339      * as per IDFv3 spec.
340      */
341     virtual bool SetOutlineIdentifier( const std::string& aUniqueID );
342 
343     /**
344      * Function GetOutlineIdentifier
345      * returns the object's Outline Identifier
346      */
347     virtual const std::string& GetOutlineIdentifier( void );
348 
349     /**
350      * Function SetSide
351      * sets the side which this outline is applicable to (TOP, BOTTOM).
352      *
353      * @return bool: true if the side was set, false if the side is invalid
354      * or there is a violation of IDF ownership rules.
355      */
356     virtual bool SetSide( IDF3::IDF_LAYER aSide );
357 
358     /**
359      * Function GetSide
360      * returns the side which this outline is applicable to
361      */
362     virtual IDF3::IDF_LAYER GetSide( void );
363 
364     /**
365      * Function Clear
366      * deletes internal data except for the parent object
367      */
368     virtual bool Clear( void ) override;
369 
370 private:
371     /**
372      * Read an OTHER_OUTLINE data from an IDFv3 file.
373      * If an unrecoverable error occurs an exception is thrown.
374      *
375      * @param aBoardFile is an IDFv3 file open for reading.
376      * @param aHeader is the .OTHER_OUTLINE header as read via FetchIDFLine.
377      */
378     virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
379                            IDF3::IDF_VERSION aIdfVersion ) override;
380 
381     /**
382      * Write the OTHER_OUTLINE data to an open IDFv3 file.
383      *
384      * @param aBoardFile is an IDFv3 file open for writing.
385      * @return true if the data was successfully written, otherwise false.
386      */
387     virtual void writeData( std::ostream& aBoardFile ) override;
388 
389     friend class IDF3_BOARD;
390 
391     std::string uniqueID;   // Outline Identifier (IDF spec)
392     IDF3::IDF_LAYER side;   // Board Side [TOP/BOTTOM ONLY] (IDF spec)
393 };
394 
395 
396 /**
397  * Routing areas on the board.
398  */
399 class ROUTE_OUTLINE : public BOARD_OUTLINE
400 {
401 public:
402     ROUTE_OUTLINE( IDF3_BOARD* aParent );
403 
404     /**
405      * Function SetLayers
406      * sets the layer or group of layers this outline is applicable to.
407      * This function is subject to IDF ownership rules; true is returned
408      * on success, otherwise false is returned and the error message is set.
409      */
410     virtual bool SetLayers( IDF3::IDF_LAYER aLayer );
411 
412     /**
413      * Function GetLayers
414      * returns the layer or group of layers which this outline is applicable to
415      */
416     virtual IDF3::IDF_LAYER GetLayers( void );
417 
418     /**
419      * Function Clear
420      * deletes internal data except for the parent object
421      */
422     virtual bool Clear( void ) override;
423 
424 private:
425     friend class IDF3_BOARD;
426 
427     /**
428      * Read ROUTE_OUTLINE data from an IDFv3 file.
429      * If an unrecoverable error occurs an exception is thrown.
430      *
431      * @param aBoardFile is an open IDFv3 board file.
432      * @param aHeader is the .ROUTE_OUTLINE header as returned by FetchIDFLine.
433      */
434     virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
435                            IDF3::IDF_VERSION aIdfVersion ) override;
436 
437     /**
438      * Write the ROUTE_OUTLINE data to an open IDFv3 file.
439      */
440     virtual void writeData( std::ostream& aBoardFile ) override;
441 
442 protected:
443     IDF3::IDF_LAYER layers; // Routing layers (IDF spec)
444 };
445 
446 
447 /**
448  * Area on the board for placing components.
449  */
450 class PLACE_OUTLINE : public BOARD_OUTLINE
451 {
452 public:
453     PLACE_OUTLINE( IDF3_BOARD* aParent );
454 
455     /**
456      * Function SetSide
457      * sets the side (TOP, BOTTOM, BOTH) which this outline applies to.
458      * This function is subject to IDF ownership rules; true is returned
459      * on success, otherwise false is returned and the error message is set.
460      */
461     virtual bool SetSide( IDF3::IDF_LAYER aSide );
462 
463     /**
464      * Function GetSide
465      * returns the side which this outline is applicable to
466      */
467     virtual IDF3::IDF_LAYER GetSide( void );
468 
469     /**
470      * Function SetMaxHeight
471      * sets the maximum height of a component within this outline.
472      * This function is subject to IDF ownership rules; true is returned
473      * on success, otherwise false is returned and the error message is set.
474      */
475     virtual bool SetMaxHeight( double aHeight );
476 
477     /**
478      * Function GetMaxHeight
479      * returns the maximum allowable height for a component in this region
480      */
481     virtual double GetMaxHeight( void );
482 
483     /**
484      * Function Clear
485      * deletes all internal data
486      */
487     virtual bool Clear( void ) override;
488 
489 private:
490     friend class IDF3_BOARD;
491 
492     /**
493      * Read PLACE_OUTLINE data from an open IDFv3 file.
494      *
495      * If an unrecoverable error occurs an exception is thrown.
496      *
497      * @param aBoardFile is an IDFv3 file opened for reading.
498      * @param aHeader is the .PLACE_OUTLINE header as returned by FetchIDFLine.
499      */
500     virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
501                            IDF3::IDF_VERSION aIdfVersion ) override;
502 
503     /**
504      * Write the PLACE_OUTLINE data to an open IDFv3 file.
505      *
506      * @param aBoardFile is an IDFv3 file opened for writing.
507      * @return true if the data was successfully written, otherwise false.
508      */
509     virtual void writeData( std::ostream& aBoardFile ) override;
510 
511 protected:
512     IDF3::IDF_LAYER side;   // Board Side [TOP/BOTTOM/BOTH ONLY] (IDF spec)
513 };
514 
515 
516 /**
517  * Regions and layers where no electrical routing is permitted.
518  */
519 class ROUTE_KO_OUTLINE : public ROUTE_OUTLINE
520 {
521 public:
522     ROUTE_KO_OUTLINE( IDF3_BOARD* aParent );
523 };
524 
525 
526 /**
527  * Region in which vias are prohibited.
528  *
529  * @note IDFv3 only considers thru-hole vias and makes no statement regarding behavior with
530  *       blind or buried vias.
531  */
532 class VIA_KO_OUTLINE : public OTHER_OUTLINE
533 {
534 public:
535     VIA_KO_OUTLINE( IDF3_BOARD* aParent );
536 };
537 
538 
539 /**
540  * Regions and layers in which no component may be placed or on which a maximum component height
541  * is in effect.
542  */
543 class PLACE_KO_OUTLINE : public PLACE_OUTLINE
544 {
545 public:
546     PLACE_KO_OUTLINE( IDF3_BOARD* aParent );
547 };
548 
549 
550 /**
551  * Regions and layers in which user-specified features or components may be placed.
552  */
553 class GROUP_OUTLINE : public BOARD_OUTLINE
554 {
555 public:
556     GROUP_OUTLINE( IDF3_BOARD* aParent );
557 
558     /**
559      * Set the side which this outline applies to (TOP, BOTTOM, BOTH).
560      *
561      * This function is subject to IDF ownership rules; true is returned
562      * on success, otherwise false is returned and the error message is set.
563      */
564     virtual bool SetSide( IDF3::IDF_LAYER aSide );
565 
566     /**
567      * @return the side which this outline applies to.
568      */
569     virtual IDF3::IDF_LAYER GetSide( void );
570 
571     /**
572      * Set the name of the group, subject to IDF ownership rules.
573      *
574      * This function is subject to IDF ownership rules; true is returned
575      * on success, otherwise false is returned and the error message is set.
576      */
577     virtual bool SetGroupName( std::string aGroupName );
578 
579     /**
580      * Return a reference to the (non-unique) group name.
581      */
582     virtual const std::string& GetGroupName( void );
583 
584     /**
585      * Delete internal data, subject to IDF ownership rules.
586      */
587     virtual bool Clear( void ) override;
588 
589 private:
590     friend class IDF3_BOARD;
591 
592     /**
593      * Read GROUP_OUTLINE data from an open IDFv3 file.
594      *
595      * If an unrecoverable error occurs an exception is thrown.
596      *
597      * @param aBoardFile is an open IDFv3 file.
598      * @param aHeader is the .PLACE_REGION header as returned by FetchIDFLine.
599      */
600     virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
601                            IDF3::IDF_VERSION aIdfVersion ) override;
602 
603     /**
604      * Write the data to a .PLACE_REGION section of an IDFv3 file.
605      *
606      * @param aBoardFile is an IDFv3 file open for writing.
607      * @return true if the data is successfully written, otherwise false.
608      */
609     virtual void writeData( std::ostream& aBoardFile ) override;
610 
611     IDF3::IDF_LAYER side;   // Board Side [TOP/BOTTOM/BOTH ONLY] (IDF spec)
612     std::string groupName;  // non-unique string
613 };
614 
615 
616 /**
617  * A component's outline as stored in an IDF library file.
618  */
619 class IDF3_COMP_OUTLINE : public BOARD_OUTLINE
620 {
621 public:
622     IDF3_COMP_OUTLINE( IDF3_BOARD* aParent );
623 
624     /**
625      * Delete internal outline data.
626      */
627     virtual bool Clear( void ) override;
628 
629     /**
630      * Set the type of component outline (.ELECTRICAL or .MECHANICAL).
631      *
632      * @return true on success, otherwise false and the error message is set.
633      */
634     bool SetComponentClass( IDF3::COMP_TYPE aCompClass );
635 
636     /**
637      * @return2 the class of component represented by this outline.
638      */
639     IDF3::COMP_TYPE GetComponentClass( void );
640 
641     /**
642      * Set the Geometry Name (Package Name, IDFv3 spec) of the component outline.
643      */
644     void SetGeomName( const std::string& aGeomName );
645 
646     /**
647      * @return the Geometry Name (Package Name) of the component outline.
648      */
649     const std::string& GetGeomName( void );
650 
651     /**
652      * Set the Part Name (Part Number, IDFv3 spec) of the component outline.
653      */
654     void SetPartName( const std::string& aPartName );
655 
656     /**
657      * Return the Part Name (Part Number) of the component outline.
658      */
659     const std::string& GetPartName( void );
660 
661     /**
662      * @return the unique identifier for this component outline, this is equal to
663      *         GEOM_NAME + "_" + PART_NAME.
664      */
665     const std::string& GetUID( void );
666 
667     /**
668      * Create a default outline with the given Geometry and Part names.
669      *
670      * This outline is a star with outer radius 5mm and inner radius 2.5mm.
671      */
672     bool CreateDefaultOutline( const std::string &aGeom, const std::string &aPart );
673 
674     // XXX: property manipulators
675 
676 private:
677     friend class IDF3_BOARD;
678     friend class IDF3_COMP_OUTLINE_DATA;
679 
680     void readProperties( std::istream& aLibFile );
681     bool writeProperties( std::ostream& aLibFile );
682 
683     /**
684      * Read a component outline from an open IDFv3 file.
685      *
686      * If an unrecoverable error occurs, an exception is thrown.
687      *
688      * @param aLibFile is an open IDFv3 Library file.
689      * @param aHeader is the .ELECTRICAL or .MECHANICAL header as returned by FetchIDFLine.
690      */
691     virtual void readData( std::istream& aLibFile, const std::string& aHeader,
692                            IDF3::IDF_VERSION aIdfVersion ) override;
693 
694     /**
695      * Write comments and component outline data to an IDFv3 Library file.
696      *
697      * @param aLibFile is an IDFv3 library file open for writing.
698      * @return true if the data was successfully written, otherwise false.
699      */
700     virtual void writeData( std::ostream& aLibFile ) override;
701 
702     /**
703      * Increment the internal reference counter to keep track of the number of
704      * components referring to this outline.
705      *
706      * @return the number of current references to this component outline.
707      */
708     int incrementRef( void );
709 
710     /**
711      * Decrement the internal reference counter to keep track of the number of
712      * components referring to this outline.
713      *
714      * @return the number of remaining references or -1 if there were no references when the
715      *         function was invoked, in which case the error message is also set.
716      */
717     int decrementRef( void );
718 
719     std::string     uid;        // unique ID
720     std::string     geometry;   // geometry name (IDF)
721     std::string     part;       // part name (IDF)
722     IDF3::COMP_TYPE compType;   // component type
723     int             refNum;     // number of components referring to this outline
724 
725     std::map< std::string, std::string >    props;      // properties list
726 };
727 
728 #endif // IDF_OUTLINES_H
729