diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp index 2ec30a323e..1a40487ef9 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp @@ -1014,7 +1014,7 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_SHAPE* aShape ) const || ( aShape->GetShape() == SHAPE_T::RECTANGLE ) || ( aShape->GetShape() == SHAPE_T::CIRCLE ) ) { - m_out->Print( aShape->IsFilled() ? "(fill solid)" : "(fill none)" ); + KICAD_FORMAT::FormatBool( m_out, "fill", aShape->IsFilled() ); } if( aShape->IsLocked() ) diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h index 028eef1813..4de6af764f 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h @@ -170,7 +170,7 @@ class PCB_IO_KICAD_SEXPR; // forward decl //#define SEXPR_BOARD_FILE_VERSION 20241009 // Evolve placement rule areas file format //#define SEXPR_BOARD_FILE_VERSION 20241010 // Graphic shapes can have soldermask layer and margin //#define SEXPR_BOARD_FILE_VERSION 20241030 // Dimension arrow directions, suppress_zeroes normalization -#define SEXPR_BOARD_FILE_VERSION 20241129 // Normalise keep_text_aligned properties +#define SEXPR_BOARD_FILE_VERSION 20241129 // Normalise keep_text_aligned and fill properties #define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag diff --git a/qa/data/pcbnew/graphics_load_save_v20240108.kicad_pcb b/qa/data/pcbnew/graphics_load_save_v20240108.kicad_pcb new file mode 100644 index 0000000000..832c18aad5 --- /dev/null +++ b/qa/data/pcbnew/graphics_load_save_v20240108.kicad_pcb @@ -0,0 +1,155 @@ +(kicad_pcb + (version 20240108) + (generator "pcbnew") + (generator_version "8.0") + (general + (thickness 1.6) + (legacy_teardrops no) + ) + (paper "A4") + (layers + (0 "F.Cu" signal) + (31 "B.Cu" signal) + (32 "B.Adhes" user "B.Adhesive") + (33 "F.Adhes" user "F.Adhesive") + (34 "B.Paste" user) + (35 "F.Paste" user) + (36 "B.SilkS" user "B.Silkscreen") + (37 "F.SilkS" user "F.Silkscreen") + (38 "B.Mask" user) + (39 "F.Mask" user) + (40 "Dwgs.User" user "User.Drawings") + (41 "Cmts.User" user "User.Comments") + (42 "Eco1.User" user "User.Eco1") + (43 "Eco2.User" user "User.Eco2") + (44 "Edge.Cuts" user) + (45 "Margin" user) + (46 "B.CrtYd" user "B.Courtyard") + (47 "F.CrtYd" user "F.Courtyard") + (48 "B.Fab" user) + (49 "F.Fab" user) + (50 "User.1" user) + (51 "User.2" user) + (52 "User.3" user) + (53 "User.4" user) + (54 "User.5" user) + (55 "User.6" user) + (56 "User.7" user) + (57 "User.8" user) + (58 "User.9" user) + ) + (setup + (pad_to_mask_clearance 0) + (allow_soldermask_bridges_in_footprints no) + (pcbplotparams + (layerselection 0x00010fc_ffffffff) + (plot_on_all_layers_selection 0x0000000_00000000) + (disableapertmacros no) + (usegerberextensions no) + (usegerberattributes yes) + (usegerberadvancedattributes yes) + (creategerberjobfile yes) + (dashed_line_dash_ratio 12.000000) + (dashed_line_gap_ratio 3.000000) + (svgprecision 4) + (plotframeref no) + (viasonmask no) + (mode 1) + (useauxorigin no) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (pdf_front_fp_property_popups yes) + (pdf_back_fp_property_popups yes) + (dxfpolygonmode yes) + (dxfimperialunits yes) + (dxfusepcbnewfont yes) + (psnegative no) + (psa4output no) + (plotreference yes) + (plotvalue yes) + (plotfptext yes) + (plotinvisibletext no) + (sketchpadsonfab no) + (subtractmaskfromsilk no) + (outputformat 1) + (mirror no) + (drillshape 1) + (scaleselection 1) + (outputdirectory "") + ) + ) + (net 0 "") + (gr_poly + (pts + (xy 145 85) (xy 160 85) (xy 160 100) (xy 145 100) + ) + (stroke + (width 0.2) + (type solid) + ) + (fill solid) + (layer "F.Cu") + (uuid "65596b4f-7b03-48e9-8be7-5824316ea7fd") + ) + (gr_poly + (pts + (xy 125 85) (xy 135 85) (xy 135 95) (xy 125 95) + ) + (stroke + (width 0.2) + (type solid) + ) + (fill none) + (layer "F.Cu") + (uuid "cf265305-49c9-43d8-bb2a-ad34997b22d6") + ) + (gr_rect + (start 145 65) + (end 160 80) + (stroke + (width 0.2) + (type solid) + ) + (fill solid) + (layer "F.Cu") + (uuid "d0669ae2-442f-427f-af0f-bc3008af779a") + ) + (gr_rect + (start 125 65) + (end 135 75) + (stroke + (width 0.2) + (type default) + ) + (fill none) + (layer "F.Cu") + (uuid "fd1649a3-9a92-4dd3-96b4-88469cb257ba") + ) + (gr_text "Fill" + (at 150 60 0) + (layer "Cmts.User") + (uuid "435629a4-8d9c-4e90-ada3-ce9fb5233170") + (effects + (font + (size 1.5 1.5) + (thickness 0.3) + (bold yes) + ) + (justify bottom) + ) + ) + (gr_text "No fill" + (at 130 60 0) + (layer "Cmts.User") + (uuid "ef55c2a1-fcfc-4a00-81d3-37a24bf772bc") + (effects + (font + (size 1.5 1.5) + (thickness 0.3) + (bold yes) + ) + (justify bottom) + ) + ) +) diff --git a/qa/data/pcbnew/graphics_load_save_v20240108.kicad_pro b/qa/data/pcbnew/graphics_load_save_v20240108.kicad_pro new file mode 100644 index 0000000000..6dc5f77911 --- /dev/null +++ b/qa/data/pcbnew/graphics_load_save_v20240108.kicad_pro @@ -0,0 +1,273 @@ +{ + "board": { + "3dviewports": [], + "design_settings": { + "defaults": { + "apply_defaults_to_fp_fields": false, + "apply_defaults_to_fp_shapes": false, + "apply_defaults_to_fp_text": false, + "board_outline_line_width": 0.05, + "copper_line_width": 0.2, + "copper_text_italic": false, + "copper_text_size_h": 1.5, + "copper_text_size_v": 1.5, + "copper_text_thickness": 0.3, + "copper_text_upright": false, + "courtyard_line_width": 0.05, + "dimension_precision": 4, + "dimension_units": 3, + "dimensions": { + "arrow_length": 1270000, + "extension_offset": 500000, + "keep_text_aligned": true, + "suppress_zeroes": false, + "text_position": 0, + "units_format": 1 + }, + "fab_line_width": 0.1, + "fab_text_italic": false, + "fab_text_size_h": 1.0, + "fab_text_size_v": 1.0, + "fab_text_thickness": 0.15, + "fab_text_upright": false, + "other_line_width": 0.1, + "other_text_italic": false, + "other_text_size_h": 1.0, + "other_text_size_v": 1.0, + "other_text_thickness": 0.15, + "other_text_upright": false, + "pads": { + "drill": 0.762, + "height": 1.524, + "width": 1.524 + }, + "silk_line_width": 0.1, + "silk_text_italic": false, + "silk_text_size_h": 1.0, + "silk_text_size_v": 1.0, + "silk_text_thickness": 0.1, + "silk_text_upright": false, + "zones": { + "min_clearance": 0.5 + } + }, + "diff_pair_dimensions": [], + "drc_exclusions": [], + "meta": { + "version": 2 + }, + "rule_severities": { + "annular_width": "error", + "clearance": "error", + "connection_width": "warning", + "copper_edge_clearance": "error", + "copper_sliver": "warning", + "courtyards_overlap": "error", + "diff_pair_gap_out_of_range": "error", + "diff_pair_uncoupled_length_too_long": "error", + "drill_out_of_range": "error", + "duplicate_footprints": "warning", + "extra_footprint": "warning", + "footprint": "error", + "footprint_symbol_mismatch": "warning", + "footprint_type_mismatch": "ignore", + "hole_clearance": "error", + "hole_near_hole": "error", + "holes_co_located": "warning", + "invalid_outline": "error", + "isolated_copper": "warning", + "item_on_disabled_layer": "error", + "items_not_allowed": "error", + "length_out_of_range": "error", + "lib_footprint_issues": "warning", + "lib_footprint_mismatch": "warning", + "malformed_courtyard": "error", + "microvia_drill_out_of_range": "error", + "missing_courtyard": "ignore", + "missing_footprint": "warning", + "net_conflict": "warning", + "npth_inside_courtyard": "ignore", + "padstack": "warning", + "pth_inside_courtyard": "ignore", + "shorting_items": "error", + "silk_edge_clearance": "warning", + "silk_over_copper": "warning", + "silk_overlap": "warning", + "skew_out_of_range": "error", + "solder_mask_bridge": "error", + "starved_thermal": "error", + "text_height": "warning", + "text_thickness": "warning", + "through_hole_pad_without_hole": "error", + "too_many_vias": "error", + "track_dangling": "warning", + "track_width": "error", + "tracks_crossing": "error", + "unconnected_items": "error", + "unresolved_variable": "error", + "via_dangling": "warning", + "zones_intersect": "error" + }, + "rules": { + "max_error": 0.005, + "min_clearance": 0.0, + "min_connection": 0.0, + "min_copper_edge_clearance": 0.5, + "min_hole_clearance": 0.25, + "min_hole_to_hole": 0.25, + "min_microvia_diameter": 0.2, + "min_microvia_drill": 0.1, + "min_resolved_spokes": 2, + "min_silk_clearance": 0.0, + "min_text_height": 0.8, + "min_text_thickness": 0.08, + "min_through_hole_diameter": 0.3, + "min_track_width": 0.0, + "min_via_annular_width": 0.1, + "min_via_diameter": 0.5, + "solder_mask_to_copper_clearance": 0.0, + "use_height_for_length_calcs": true + }, + "teardrop_options": [ + { + "td_onpadsmd": true, + "td_onroundshapesonly": false, + "td_ontrackend": false, + "td_onviapad": true + } + ], + "teardrop_parameters": [ + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_round_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_rect_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_track_end", + "td_width_to_size_filter_ratio": 0.9 + } + ], + "track_widths": [], + "tuning_pattern_settings": { + "diff_pair_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 1.0 + }, + "diff_pair_skew_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 0.6 + }, + "single_track_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 0.6 + } + }, + "via_dimensions": [], + "zones_allow_external_fillets": false + }, + "ipc2581": { + "dist": "", + "distpn": "", + "internal_id": "", + "mfg": "", + "mpn": "" + }, + "layer_presets": [], + "viewports": [] + }, + "boards": [], + "cvpcb": { + "equivalence_files": [] + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "graphics_load_save_v20240108.kicad_pro", + "version": 1 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.2, + "via_diameter": 0.6, + "via_drill": 0.3, + "wire_width": 6 + } + ], + "meta": { + "version": 3 + }, + "net_colors": null, + "netclass_assignments": null, + "netclass_patterns": [] + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "plot": "", + "pos_files": "", + "specctra_dsn": "", + "step": "", + "svg": "", + "vrml": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "legacy_lib_dir": "", + "legacy_lib_list": [] + }, + "sheets": [], + "text_variables": {} +} diff --git a/qa/tests/pcbnew/CMakeLists.txt b/qa/tests/pcbnew/CMakeLists.txt index ac9d60fca6..478d3a9983 100644 --- a/qa/tests/pcbnew/CMakeLists.txt +++ b/qa/tests/pcbnew/CMakeLists.txt @@ -34,6 +34,7 @@ set( QA_PCBNEW_SRCS test_array_pad_name_provider.cpp test_board_item.cpp test_generator_load_save.cpp + test_graphics_load_save.cpp test_graphics_import_mgr.cpp test_group_load_save.cpp test_footprint_load_save.cpp diff --git a/qa/tests/pcbnew/test_graphics_load_save.cpp b/qa/tests/pcbnew/test_graphics_load_save.cpp new file mode 100644 index 0000000000..a2e34a2060 --- /dev/null +++ b/qa/tests/pcbnew/test_graphics_load_save.cpp @@ -0,0 +1,112 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +struct GRAPHICS_LOAD_TEST_CASE +{ + // Which one to look at in the file? + KIID m_searchUuid; + // Expected values + bool m_expectedFilled; +}; + + +struct GRAPHICS_LOAD_BOARD_TEST_CASE +{ + // The board to load + wxString m_boardFileRelativePath; + + // These tests may well test specific versions of the board file format, + // so don't let it change accidentally! + int m_expectedBoardVersion; + + // List of images to check + std::vector m_generatorCases; +}; + +} // namespace + +BOOST_AUTO_TEST_CASE( GraphicsLoad ) +{ + const std::vector testCases{ + { + // Before 20241129, 'fill' would be solid or none + // in PCB shapes + "graphics_load_save_v20240108", + 20240108, + { + // Filled poly + { + "65596b4f-7b03-48e9-8be7-5824316ea7fd", + true, + }, + // Unfilled poly + { + "cf265305-49c9-43d8-bb2a-ad34997b22d6", + false, + }, + // Filled rect + { + "d0669ae2-442f-427f-af0f-bc3008af779a", + true, + }, + // Unfilled rect + { + "fd1649a3-9a92-4dd3-96b4-88469cb257ba", + false, + }, + }, + }, + }; + + for( const GRAPHICS_LOAD_BOARD_TEST_CASE& testCase : testCases ) + { + const auto doBoardTest = [&]( const BOARD& aBoard ) + { + for( const GRAPHICS_LOAD_TEST_CASE& testCase : testCase.m_generatorCases ) + { + BOOST_TEST_MESSAGE( + "Checking for graphic with UUID: " << testCase.m_searchUuid.AsString() ); + + const auto& graphic = + static_cast( KI_TEST::RequireBoardItemWithTypeAndId( + aBoard, PCB_SHAPE_T, testCase.m_searchUuid ) ); + + BOOST_CHECK_EQUAL( graphic.IsFilled(), testCase.m_expectedFilled ); + } + }; + + KI_TEST::LoadAndTestBoardFile( testCase.m_boardFileRelativePath, true, doBoardTest, + testCase.m_expectedBoardVersion ); + } +} \ No newline at end of file