Compare commits

...

141 Commits

Author SHA1 Message Date
Wayne Stambaugh 59f308850e Tag release version 7.0.9. 2023-11-05 08:16:47 -05:00
jean-pierre charras e775a7581a pcb_calculator, MICROSTRIP::calcSynthesize(): fix incorrect init of a variable
It was initialized before other calculations, thus using a bad value.
From master branch
2023-11-01 17:31:16 +01:00
Wayne Stambaugh ec99e10b31 Tag stable version 7.0.9 release candidate 2. 2023-10-31 16:27:24 -04:00
Seth Hillbrand 240d7921ba Allow multiple strong drivers with same name
Multiple labels with the same name are allowed (and expected) so ensure
that we use a structure that allows duplicate names

(cherry picked from commit de0736863b)
2023-10-31 11:53:56 -07:00
Seth Hillbrand 9ac006b114 Don't use KiROUND when we should trunc
When calculating the viewport extents, we only need the maximum size
that can be represented.  Anything larger should be truncated.  We do
this in many other places (wx_view_controls, ruler_item,
ds_proxy_view_item, etc) and this brings pcb_selection_tool into
alignment with this, avoiding an unneeded warning message

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15529

(cherry picked from commit 6d957e9d65)
2023-10-30 09:43:45 -07:00
Seth Hillbrand c3fef1cae2 Update translations 2023-10-30 09:43:40 -07:00
Wellington Terumi Uemura ca1c99a0d1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8023 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pt_BR/
2023-10-30 17:42:13 +01:00
Mert Gülsoy 06ae7a20df Translated using Weblate (Turkish)
Currently translated at 61.4% (4929 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/tr/
2023-10-30 17:42:13 +01:00
Wellington Terumi Uemura f536ecdc00 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8023 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pt_BR/
2023-10-30 17:42:13 +01:00
ZbeeGin a4bdd38367 Translated using Weblate (Polish)
Currently translated at 100.0% (8023 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pl/
2023-10-30 17:42:13 +01:00
Arend-Jan van Hilten 6fb6d3e444 Translated using Weblate (Dutch)
Currently translated at 83.9% (6736 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/nl/
2023-10-30 17:42:13 +01:00
Toni Laiho a3952c37bf Translated using Weblate (Finnish)
Currently translated at 99.7% (8006 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/fi/
2023-10-30 17:42:13 +01:00
dsa-t c24ee72fe3 Translated using Weblate (Russian)
Currently translated at 99.9% (8022 of 8023 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/ru/
2023-10-30 17:42:13 +01:00
Wayne Stambaugh f988b807c4 Don't show integer overflow errors in release builds.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15529

(cherry picked from commit bfd3e71a88)
2023-10-30 10:09:35 -04:00
Alex Shvartzkop cb1a596b10 kicad manager: make extension change warning for Rename case-insensitive. 2023-10-29 22:01:50 +03:00
jean-pierre charras c41cd75b62 kicad manager: fix broken Rename file command.
From master branch.
2023-10-29 18:38:32 +01:00
Ian McInerney 0df48f3002 PCM: Fix use of variable after it was moved into the cache
(cherry picked from commit c52fb23d4f)
2023-10-29 13:40:08 +00:00
Jeff Young 2d58184080 We don't want to do collision testing against virtual vias.
(Which means they had better not have a hole.)

(cherry picked from commit f1efae1e05)
2023-10-25 18:51:14 +01:00
Jeff Young 1ef6e69d83 Don't run DRC checks against reference images.
fixes https://gitlab.com/kicad/code/kicad/-/issues/15932
2023-10-25 18:51:14 +01:00
jean-pierre charras dbd4af16c6 Gerber place files: do not quote strings (fields, pad name, pad function ...)
Double quotes have no special meaning, so adding them modify the texts
Fixes #15944
https://gitlab.com/kicad/code/kicad/-/issues/15944
2023-10-25 09:13:59 +02:00
Alex Shvartzkop 2263535d3a Add Python API compatibility for GetEffectiveTextShape. 2023-10-25 00:03:28 +03:00
Seth Hillbrand 3ce4a5bf7f Fix missing random sim command 2023-10-24 13:57:44 -07:00
Alex Shvartzkop f62c3431ff Semi-fix schematic text properties dialog on wx 3.2.3.
Based on https://gitlab.com/kicad/code/kicad/-/commit/d9b5257b9e90c53d1cba39499c76ea917344128f
2023-10-24 23:30:31 +03:00
Seth Hillbrand a652084922 Update translations 2023-10-24 12:11:15 -07:00
김랑기 ed30599db8 Translated using Weblate (Korean)
Currently translated at 99.6% (7993 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/ko/
2023-10-24 21:09:50 +02:00
ZbeeGin d8752970e9 Translated using Weblate (Polish)
Currently translated at 100.0% (8022 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pl/
2023-10-24 21:09:50 +02:00
rtyuionoop 57a4c93cf5 Translated using Weblate (Vietnamese)
Currently translated at 14.8% (1189 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/vi/
2023-10-24 21:09:50 +02:00
Tokita, Hiroshi a116f5783d Translated using Weblate (Japanese)
Currently translated at 99.9% (8021 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/ja/
2023-10-24 21:09:50 +02:00
Jan Straka 2730098c42 Translated using Weblate (Czech)
Currently translated at 91.7% (7364 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/cs/
2023-10-24 21:09:49 +02:00
Luc 836d17359f Translated using Weblate (German)
Currently translated at 100.0% (8022 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/de/
2023-10-24 21:09:49 +02:00
Marine Biologist a4406bb137 Translated using Weblate (Turkish)
Currently translated at 61.4% (4928 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/tr/
2023-10-24 21:09:49 +02:00
Wellington Terumi Uemura bbb67b415a Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8022 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pt_BR/
2023-10-24 21:09:49 +02:00
dsa-t 0842360dbb Translated using Weblate (Russian)
Currently translated at 100.0% (8022 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/ru/
2023-10-24 21:09:49 +02:00
Tokita, Hiroshi e58b23a54b Translated using Weblate (Japanese)
Currently translated at 99.9% (8021 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/ja/
2023-10-24 21:09:49 +02:00
ZbeeGin 72342bd8a5 Translated using Weblate (Polish)
Currently translated at 100.0% (8022 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pl/
2023-10-24 21:09:49 +02:00
Wellington Terumi Uemura fa77fc3310 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8022 of 8022 strings)

Translation: KiCad EDA/v7
Translate-URL: https://hosted.weblate.org/projects/kicad/v7/pt_BR/
2023-10-24 21:09:49 +02:00
Alex Shvartzkop 53fe2a7203 Set UNPACK_ALIGNMENT properly for RGB bitmaps.
(cherry picked from commit 00904e8e23)
2023-10-24 06:59:53 +03:00
Alex Shvartzkop 480dfafb4f Fix variable shadowing.
(cherry picked from commit 0e4553b1fa)
2023-10-24 04:26:02 +03:00
Alex Shvartzkop f5e13c5ceb Fix up ccc29e9776 for masked images.
(cherry picked from commit 977912dcd5)
2023-10-24 04:00:30 +03:00
Alex Shvartzkop eadc902f84 Don't draw PCB bitmaps on layers not visible in high-contrast mode.
(cherry picked from commit e6cf5e5e01)
2023-10-24 03:42:54 +03:00
Alex Shvartzkop b461a3b64d OpenGL: Improve logic when bitmap cache memory is exhausted.
Don't remove the front entry, as it will likely be needed for the next bitmap.
Instead, implement neuristics based on access times.

(cherry picked from commit 71d0c7f6af)
2023-10-24 03:42:45 +03:00
Alex Shvartzkop 75c758e5f4 Improve bitmap caching performance.
(cherry picked from commit ccc29e9776)
2023-10-24 03:42:24 +03:00
Jeff Young 05912b0381 Check vias before holes as we assume any hole is non-pushable.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15840

(cherry picked from commit fb84f4592b)
2023-10-23 23:53:55 +01:00
Seth Hillbrand fb387a2c09 Don't leave deleted items in group
We filter out ref/value text in copies so we need to remove them from
the copied group (if any) as well

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15930
2023-10-23 13:34:15 -07:00
Seth Hillbrand 1380feef72 Compare bus local names
When running ERC, we want to check if bus members exist in the bus and
this should be done using m_local_name (i.e. the name it take from the
parent bus) not the resolved name as this will change depending on
connections
2023-10-23 12:54:31 -07:00
Seth Hillbrand 6c91a3022e Fix stdlib assertion
The assertion checks if an element has been added to vector.  Since we
are merely manipulating the allocated data, the number of elements does
not change and the assertion check fails.  Using the pointer to the
allocated data is a cleaner/clearer way of accomplishing this
2023-10-23 12:54:31 -07:00
Alex Shvartzkop e55989120e NanoSVG: parse 'class' attribute before 'style'.
(cherry picked from commit 64a64f5216)
2023-10-23 21:30:16 +03:00
Alex Shvartzkop 14f12ccf51 Add ngspice lib paths for when running from build dir.
(cherry picked from commit 71fb1afe4c)
2023-10-23 21:29:11 +03:00
jean-pierre charras 82a1b02b4a Plotters (especially DXF) add more precision when plotting arcs (and others)
- in DXF coordinates were using 6 digits for coordinate mantissa:
this is not enough for coord in inches. Now use 16 digits
- Arc( VECTOR2I& aCentre, EDA_ANGLE& aStartAngle, EDA_ANGLE& aEndAngle, ...)
was using integers for coord.
This creates significant errors for start point and end points of the arc.
Now the center is given in double, and its position is calculated from angle end points
(and radius) to do not generate a position error for these end points
(previously the error could be 20 ... 50 nm)
From master branch
Fixes #15056 https://gitlab.com/kicad/code/kicad/-/issues/15056
2023-10-23 17:59:31 +02:00
Jeff Young e99a2fbc56 Score initializing is done by LIB_TREE_NODE::ResetScore().
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15875

(cherry picked from commit bc0fe74f72)
2023-10-23 13:28:14 +01:00
Alex Shvartzkop d3d23d18fb Fix footprints being difficult to select in high-contrast modes.
(regression)

(cherry picked from commit 97901c9ac5)
2023-10-23 06:10:23 +03:00
Alex Shvartzkop cbf1b2af47 HPGL plotting: fix random lines connecting to circles.
(cherry picked from commit 45791ff8d6)
2023-10-22 13:56:21 +03:00
Alex Shvartzkop 4f5fca4e67 HPGL plotting: write rects as polygons to prevent always filling.
(cherry picked from commit d9c123b1ec)
2023-10-22 13:55:54 +03:00
Alex Shvartzkop e0158a8ed7 DXF plotting: write zero-sized rects and circles as points.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15862

(cherry picked from commit 3e82e59c24)
2023-10-22 13:55:54 +03:00
Alex Shvartzkop 40e7ba67d1 PDF plotting: fix zero-sized or too thick rectangles.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15862

(cherry picked from commit 843bd4f79c)
2023-10-22 13:22:42 +03:00
Wayne Stambaugh e664605c90 Fix false positive DRC footprint parity test.
This fix removed the Euclidean normalization test and replaced it with an
arc center X and Y coordinate differential check.  The error epsilon was
increased to 200nm due to the arc center position calculation code using
the near 100nm position.

https://gitlab.com/kicad/code/kicad/-/issues/15917
2023-10-21 12:37:17 -04:00
Jeff Young 5a51a6b179 Make offset-zone check multi-layer aware.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15916

(cherry picked from commit b97d8ddef4)
2023-10-21 15:09:37 +01:00
Jeff Young eb7929ccb6 Fix layer handling for create similar zone.
(cherry picked from commit f18ce8c6de)
2023-10-20 22:22:27 +01:00
Jeff Young e85eec2e6b Don't leave deleted items in a group.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15797

(cherry picked from commit 14d5a404b2)
2023-10-19 17:52:00 +01:00
Alex Shvartzkop 121394c0c0 vcpkg: Lock glm at 0.9.9.8#2
Version 2023-06-08 changed the default order of quaternion
values from xyzw to wxyz, which we don't support.

Fixes animations in the 3D viewer.

(cherry picked from commit a52ee04fc7)
2023-10-16 14:55:57 +03:00
jean-pierre charras 5ad74d58f8 pcb_calculator/transline/stripline: add missing conv from log to db.
From master branch
Fixes #15873
https://gitlab.com/kicad/code/kicad/-/issues/15873
2023-10-16 10:35:22 +02:00
Ian McInerney afe2516d57 Fix casing for gerber wildcards
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15877

(Cherry-picked from 55caa9c1e8)
2023-10-15 19:54:05 +01:00
Jeff Young ccf6e78cd5 It is legal to have nullptr zones in the m_CopperZoneRTreeCache.
(Though we might want to re-think this strategy....)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15853
2023-10-14 22:35:06 +01:00
Jeff Young fef91fc8b9 Fix merge breakage. 2023-10-14 15:33:00 +01:00
Jeff Young 4156587abe Don't assume an error location for PAD::GetEffectivePolygon().
While ERROR_INSIDE was good for plotting, 3D generation, etc., it's
not good for generating router hulls.

Also reverts part of the change to always use polygons for PNS::SOLIDs.  A single shape in a SHAPE_COMPOUND will be faster (and
more accurate).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14898

(cherry picked from commit 62d959ed0e)
2023-10-14 15:33:00 +01:00
Jon Evans 629eccaf09 PNS: Allow for approximation error in hull clearance
Also revert to using exact hulls for non-compound shapes

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14898

(cherry picked from commit 96f9f2c658)
2023-10-14 15:33:00 +01:00
Jeff Young f89803eb64 Don't turn an empty string into a '0'.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15871

(cherry picked from commit 0b06a1376b)
2023-10-14 15:33:00 +01:00
Jeff Young da12746a3a Clear selection before deleting board layers.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15866

(cherry picked from commit 8d3047d6eb)
2023-10-14 15:33:00 +01:00
Jeff Young b023019b0d Include solder mask in STEP export stackup height.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15632

(cherry picked from commit b4986030da)
2023-10-14 15:33:00 +01:00
Jeff Young 1fdaa1083e Honour custom layer names for Layer_Top and Layer_Bottom.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15835

(cherry picked from commit da5f5536c8)
2023-10-14 15:33:00 +01:00
Jeff Young 2f8e846b9e Adjust colours in appropriate direction depending on background.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15841

(cherry picked from commit 3f0067cbaa)
2023-10-14 15:33:00 +01:00
Alex Shvartzkop e42db52d14 Fix a crash when using length tuning tools.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15874

(cherry picked from commit 61bdee027b)
2023-10-14 16:54:16 +03:00
Alex Shvartzkop d4ec455ce0 Fix loading thru-hole pads when drill token is missing.
(cherry picked from commit f7ed9cc5c7)
2023-10-14 15:52:57 +03:00
Alex Shvartzkop 0547c7ba91 Fix loading legacy (until 2009) schematic files.
(cherry picked from commit b87496b834)
2023-10-14 15:45:20 +03:00
Alex Shvartzkop 8f4b809599 Fix the insufficient privileges message in symbol remap dialog.
(cherry picked from commit 7b94ecdc01)
2023-10-14 15:44:52 +03:00
jean-pierre charras 8432fb4fea Pcbnew: when adding layers, do not change via layers.
Via layers are not defined by a LSET, and the code that used the new LSET
broke the Via start and/or end layers (for blind/buried vias)
From master branch
Fixes #15856
https://gitlab.com/kicad/code/kicad/-/issues/15856
2023-10-14 08:56:19 +02:00
Marek Roszko 84df2c86ae Fix ambiguous cast 2023-10-13 19:26:16 -04:00
Mark Roszko 49ced23ba8 Reduce the boost dependencies in vcpkg 2023-10-13 17:03:57 +00:00
jean-pierre charras 00bf2ca36f Pcbnew: rename ZONE* m_SolderMask to m_SolderMaskBridges
(It is a container to build bridges on solder mask layers by DRC, not real zone)
Disable also this special zone selection by adding it in
PCB_SELECTION_TOOL::itemPassesFilter
Do not display the outlines of this very special zone used by DRC
to show layer mask bridges created by DRC to show these bridges.
From Master branch
Fixes #15847
https://gitlab.com/kicad/code/kicad/-/issues/15847
2023-10-13 17:15:37 +02:00
Marek Roszko b92861c7e3 Bump the wxpython in vcpkg to fix build 2023-10-13 07:51:27 -04:00
Mark Roszko a189102628 Move vcpkg forwards for curl and wx 2023-10-12 23:22:28 +00:00
jean-pierre charras 58a6eb653b protect protect RC_ITEM::SetItems() against null pointer.
Fixes #15865
https://gitlab.com/kicad/code/kicad/-/issues/15865
2023-10-12 14:56:56 +02:00
Alex Shvartzkop 9159f5a004 Restore fill polygons on proper layers when flipping zones.
(cherry picked from commit 0ea85ec9f5)
2023-10-12 02:45:05 +03:00
jean-pierre charras f1c570d793 OPENGL_GAL: ensure 0 sized rect with thickness is shown (already shown by Cairo)
From master branch
Fixes #15850
https://gitlab.com/kicad/code/kicad/-/issues/15850
2023-10-11 20:08:15 +02:00
Marek Roszko 832af39f34 Unbind ACTION_MENU events in destructor
(cherry picked from commit d801037c93)
2023-10-11 00:17:03 +00:00
Seth Hillbrand 9260f58803 Fix memory leak in connection graph
When generating virtual connections to represent bus aliases, we need to
store the pointers for future deletion otherwise we will leak the memory
2023-10-06 09:14:07 -07:00
Seth Hillbrand 1a5c515e45 Improve pin-pin iteration in ERC checks
Rather than generating expensive classes to store in a set to check for
duplicate checks, we avoid double-checking elements in the vector.  For
large schematics this results in a substantial speed increase
2023-10-06 09:14:07 -07:00
jean-pierre charras 87c8688f70 genDrillMapFile: reduce the pen width used to plot oval shapes (better look)
From master branch
2023-10-06 09:33:57 +02:00
Alex Shvartzkop d13179f9e4 EAGLE PCB: fix a regression causing polygons not being imported.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15829

(cherry picked from commit bf29b25190)
2023-10-06 01:16:43 +03:00
Seth Hillbrand 75de21314c Protect against subgraph loops
Optimize the subgraph processing to avoid repeated loops when multiple
items belong to the same subgraph.
2023-10-05 08:39:56 -07:00
Jeff Young 239f8e0905 Pull fixes back from master.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15813
2023-10-04 19:25:28 +01:00
Jeff Young f4ac624bb3 Make sure sorts are deterministic. 2023-10-04 18:52:39 +01:00
Jeff Young 2be0b98135 Make sure sort is deterministic.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15336

(cherry picked from commit 0d51729537)
2023-10-04 18:51:59 +01:00
Jeff Young 36c5719535 Fix logic screw-up in earlier commit.
(cherry picked from commit f2c0f4c87f)
2023-10-04 18:51:37 +01:00
Jeff Young 1f870bf76c Handle justification when hit-testing fields.
This steals the algo used in SCH_PAINTER to get the right coords
for the text.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15722

(cherry picked from commit 6fbbf981f0)
2023-10-04 18:51:33 +01:00
Jeff Young d5cc334e20 Clear render caches before plotting.
Also fixes a bug where text variables in LIB_TEXT weren't getting
expanded when plotting.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15765

(cherry picked from commit 003acbd686)
2023-10-04 18:49:56 +01:00
Jeff Young fd98188ee4 Use netclass values when reaching netclass entry.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15774

(cherry picked from commit 904bdc3c66)
2023-10-04 18:49:03 +01:00
Jeff Young c3446f9c2d Handle flipped state when checkging item against viewport.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15768

(cherry picked from commit 3c1478367f)
2023-10-04 18:48:42 +01:00
Marek Roszko e6e29b6c4c Unbind events in DIALOG_PCM destructor
Maybe fixes KICAD-KR


(cherry picked from commit b00871ad77)
2023-10-02 00:20:46 +00:00
Marek Roszko 6096b5c4d8 Unbind event handlers in the DIALOG_SHIM destructor to prevent late event crashes
Fixes KICAD-1XF


(cherry picked from commit 3a567a3ae1)
2023-10-01 21:55:36 +00:00
jean-pierre charras 838eadd47f Eeschema: fix a crash when loading a schematic if a symbol in a sheet has
a lib_name containing {slash} instead of /
(related to commits #2f51d22b and b2bf28f5)
From master branch.
Fixes #15791
https://gitlab.com/kicad/code/kicad/-/issues/15791
2023-10-01 10:08:33 +02:00
jean-pierre charras afb43531e8 Eeschema: fix a crash when loading a schematic if a symbol in a sheet has
a lib_id containing {slash} instead of /
(related to commit #2f51d22b)
Fixes #15791
https://gitlab.com/kicad/code/kicad/-/issues/15791
2023-09-30 18:25:18 +02:00
Jon Evans 3533e8b119 DbLib: support columns with numeric data
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15662

(cherry picked from commit 6f9af10912)
2023-09-30 10:27:34 -04:00
Jeff Young 0e6ad13db8 Fix missing part of cherry-pick. 2023-09-30 14:12:54 +01:00
Jeff Young 0d725fcc2c Fix errors in calculating tuning length.
Fix mismatched parameter passing in TOPOLOGY::followTrivialPath()
and TOPOLOGY::AssembleTrivialPath().
Fix logic error in PNS::JOINT::IsLineCorner().
Handle VVIAs in PNS::JOINT::IsNonFanoutVia().

Fixes https://gitlab.com/kicad/code/kicad/-/issues/10614

(cherry picked from commit be532e96d6)
2023-09-30 13:37:00 +01:00
Jeff Young 7e747085d3 Handle read-only libraries when saving symbol from canvas.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15519

(cherry picked from commit 1fd3f4e375)
2023-09-30 13:36:13 +01:00
Jeff Young f1376396c2 Use original event position if it's available.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15623

(cherry picked from commit e962615407)
2023-09-30 13:35:48 +01:00
Jeff Young 4eb9281f4d Tidy up shutdown of APPEARANCE_CONTROLS.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15024

(cherry picked from commit c2c71facb1)
2023-09-30 13:35:22 +01:00
Jeff Young c895816cb0 Fix arg parsing in ExecuteFile.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15326

(cherry picked from commit 0f94b467ba)
2023-09-30 13:34:26 +01:00
Jeff Young 9f814c0f6a Repair standalone application 3D plugin path resolution.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15322

(cherry picked from commit 04214983cf)
2023-09-30 13:34:09 +01:00
Jeff Young e14aef9bd5 Correct path of pcb drawing sheet file on saveAs.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15551

(cherry picked from commit 722a90213c)
2023-09-30 13:31:16 +01:00
Jeff Young 2b106a2b34 Handle flipped horiz/vert justifications in FIELDS_GRID_TABLE.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15677

(cherry picked from commit 6f62565093)
2023-09-30 13:27:28 +01:00
Jeff Young f6494d2980 Implement printing and plotting for directive-specific label shapes.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15650

(cherry picked from commit 394ab8ccb1)
2023-09-30 13:26:59 +01:00
Jeff Young 78a6c1a909 Smarten the UpdateAllItemsConditionally() tests in SetActiveLayer().
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15329

(cherry picked from commit 5842e9c57e)
2023-09-30 13:26:18 +01:00
Jeff Young c858643100 Collect comment lines into following spice unit.
This can't distinguish a header block comment in front of a file
with multiple spice units, and so will include that into the first
unit only.

Also fixes the pin assignments reference textbox to use a
fixed-width font as many .subckt's contain ASCII graphics for
pin definitions (not that it helps any with the test case from
the given bug).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15660

(cherry picked from commit ede542f911)
2023-09-30 13:25:44 +01:00
Jeff Young 17b0bdc9fe Check value-follows-name case in symbol Save As.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15647

(cherry picked from commit 849a4656c8)
2023-09-30 13:24:32 +01:00
Jeff Young 2e0cdebb0c Do full high-contrast update of vias & pads if netnames are shown.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15657

(cherry picked from commit c7f69503c0)
2023-09-30 13:22:17 +01:00
Jeff Young a5f8955d78 Don't import Altium objects to disabled layers.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15586

(cherry picked from commit 962f79334f)
2023-09-30 13:21:16 +01:00
Jeff Young 0eca698a39 Update symbol editor's title bar when renaming the canvas symbol.
(cherry picked from commit 7d1dbb77c3)
2023-09-30 13:19:40 +01:00
Jeff Young 16f259da81 Only update value on rename if it previously matched the symbol name.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15621

(cherry picked from commit ee724f6a2b)
2023-09-30 13:18:53 +01:00
Jeff Young c3ee477a1b Apply DC voltage source exception to current sources.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/15626

(cherry picked from commit 4a59f0de43)
2023-09-30 13:18:17 +01:00
Jeff Young 33da35db04 Fix typo in arguments list to EvalRules().
Also fixes a bug where we weren't clearing the previous tabs from
the notebook.

(cherry picked from commit 31e30a5f56)
2023-09-30 13:16:39 +01:00
John Beard 533be1ec70 Port EDA_SHAPE arc tests to FP_SHAPE
These tests apply only to v7, since FP_SHAPE is removed
in master. But this checks that arcs in footprints get the
same winding treatment as EDA_SHAPE arcs (using the 0-suffix
functions).
2023-09-30 12:11:50 +00:00
John Beard b64573f5d4 Add regression test for arc winding
While the bug has been fixes, the winding handling in the
SetArcGeometry() function isn't tested. This adds a regression
test on EDA_SHAPE, which is where the logic now lives.

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/15694
Cherry-Pick: fb12db5f2c
2023-09-30 12:11:50 +00:00
John Beard 1d6caa9a35 Fix winding of FP_SHAPE arcs
Implement "0" versions of some arc calculations and fix some
initialisation bugs in the handling of FP_SHAPE arcs. Also
set m_endsSwapped.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/15694
2023-09-30 12:11:50 +00:00
Mark Roszko c74b0943f3 StartPlot can fail and leave a broken file handle
Related #15782
2023-09-29 23:54:49 +00:00
Marek Roszko bb579294a0 Don't search when board is null (during board changes)
(cherry picked from commit 98685b37ff)
2023-09-29 23:53:02 +00:00
Josue Huaroto ad9f5f4dd7 Extend boundary size of PCB_VIEW
(cherry picked from commit 156288bfcf)
2023-09-29 12:12:03 -07:00
Josue Huaroto bf2e34f32e Change variable substitution for paths in Windows.
(cherry picked from commit 74695b0995)
2023-09-29 12:10:07 -07:00
Seth Hillbrand bd57957df7 Revise method of selecting footprints in contrast
When working in high contrast mode, we want to be able to select a
footprint with only elements in, e.g. silk and fab layers.

The previous design for footprint IsOnLayer had one behavior of every
other element and a different behavior for footprints.  This leads to
multiple bugs as new features use the overloaded IsOnLayer expecting it
to report if the element exists on a layer or not.

For footprints, we need a different routine to determine whether or not
to select the footprint when clicking on it.  IsOnLayer will report if
the footprint has any elements on a specific layer but we don't want to
use the bbox for a hittest because large footprints with through hole
pads will exist on every layer and have an enormous bbox.  Instead, we
filter footprints based on the hittest of each element.  This behaves in
a more logical fashion, allowing you to select a footprint by clicking
on a visible element of that footprint.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15284

(cherry picked from commit f3d65b5156)
2023-09-29 12:09:11 -07:00
Seth Hillbrand 093db600ff Fix cherry-pick issue with file locking 2023-09-29 11:15:59 -07:00
Seth Hillbrand 131013f291 Fix Portuguese(Brasil) translation naming
On case-sensitive systems, the country code needs to be capitalized for
the language to be correctly identified between two dialects.  Since
`br` was not capitalized, we fell back on european portuguese for Linux
and MacOS

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15592

(cherry picked from commit 2be87e4527)
2023-09-29 11:10:37 -07:00
Josue Huaroto 909d199379 Save flip board status in custom preset
(cherry picked from commit 2d54bc42cb)
2023-09-29 11:07:49 -07:00
Seth Hillbrand 5f16f4ab99 Focus back to the main window after dialog
Mouse actions would focus the window but we explicitly set it here to
allow keyboard shortcuts

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15603

(cherry picked from commit b2ef620ea6)
2023-09-29 11:06:44 -07:00
Seth Hillbrand fff95fa4e6 Disable non-KiCad import for project-mode
Adds warning if project schematic contains data

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15570

(cherry picked from commit b837aa823c)
2023-09-29 11:05:49 -07:00
Seth Hillbrand a38327a39c Ensure that layer names are unique when importing
Altium allows duplicate layer names but KiCad prefers to have unique
names for each layer.  This enforces a unique name for each layer when
importing

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15583

(cherry picked from commit c772d116b2)
2023-09-29 11:03:21 -07:00
Seth Hillbrand 686048dcce Be smarter about releasing lockfiles
If KiCad crashes or exits without deleting the lockfile, don't show the
warning message unless we are not the one who locked it or there are
other KiCad instances running locally.

This should catch 99% of the cases where the message is shown
incorrectly.  There may be some corner cases where the lock file is
created on a network drive using two different machines with the same
name and same user but these cases should be (famous last words)
sufficiently rare as to not be observed in practice

(cherry picked from commit 7fe83993cf)
2023-09-29 11:02:42 -07:00
Seth Hillbrand 330c0f86de Set pinmap after updating pins
When duplicating and existing symbol, we must set the pins before
setting the lib symbol as the lib symbol will generate a pin map that
will be broken by the shift to new pins

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15728

(cherry picked from commit 12ebb2bbfa)
2023-09-29 17:59:24 +00:00
Seth Hillbrand 83317f1b80 Don't destroy the pin cache in symbols
SCH_PIN pointers are used through KiCad and removing them without a
global refresh risks crashes.  A safer approach is to simply reuse the
SCH_PIN structures, updating the data to the revised library

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15715

(cherry picked from commit bdb7b99fc8)
2023-09-29 17:59:24 +00:00
Wayne Stambaugh a416eb2cf6 Fix schematic editor crash when updating symbols.
Some how symbol names that still have escaped '/' character get mixed with
symbol names that have '/' characters now that it is no longer an invalid
LIB_ID character.  This was causing derived symbols to loose the link to
the parent symbol.  This fix replaces any instances of "{slash}" with "/"
to convert symbol names to the proper escaping.

Thanks to JP for the inspiration for the fix.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15715

Manually cherry picked from commit 2f51d22b3a.
2023-09-29 12:53:33 -04:00
Wayne Stambaugh 2959c94bd3 Begin version 7.0.9 development. 2023-09-29 12:26:05 -04:00
190 changed files with 40125 additions and 38122 deletions
@@ -792,7 +792,7 @@ void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BAS
}
// For other shapes, add outlines as thick segments in polygon buffer
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
for( int j = 0; j < path.PointCount(); j++ )
+1 -1
View File
@@ -51,7 +51,7 @@ void BOARD_ADAPTER::buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& a
}
// For other shapes, add outlines as thick segments in polygon buffer
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ++ii )
+14 -16
View File
@@ -483,23 +483,21 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
// Sort from back to front
std::sort( materialsSorted.begin(), materialsSorted.end(),
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
std::pair<const MODEL_3D::MATERIAL*, float>& b ) {
// If A is inside B, then A is rendered first
if( b.first->m_bbox.Inside( a.first->m_bbox ) )
{
return true;
}
else
{
if( a.first->m_bbox.Inside( b.first->m_bbox ) )
{
return false;
}
}
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
std::pair<const MODEL_3D::MATERIAL*, float>& b )
{
bool aInsideB = a.first->m_bbox.Inside( b.first->m_bbox );
bool bInsideA = b.first->m_bbox.Inside( a.first->m_bbox );
return a.second > b.second;
} );
// If A is inside B, then A is rendered first
if( aInsideB != bInsideA )
return bInsideA;
if( a.second != b.second )
return a.second > b.second;
return a.first > b.first; // compare pointers as a last resort
} );
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
{
@@ -1388,10 +1388,14 @@ void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatr
// Sort from back to front
std::sort( transparentModelList.begin(), transparentModelList.end(),
[&]( std::pair<const MODELTORENDER *, float>& a,
std::pair<const MODELTORENDER *, float>& b ) {
return a.second > b.second;
} );
[&]( std::pair<const MODELTORENDER *, float>& a,
std::pair<const MODELTORENDER *, float>& b )
{
if( a.second != b.second )
return a.second > b.second;
return a.first > b.first; // use pointers as a last resort
} );
// Start rendering calls
glPushMatrix();
@@ -1911,9 +1911,19 @@ void RENDER_3D_RAYTRACE::initializeBlockPositions()
const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
std::sort( m_blockPositions.begin(), m_blockPositions.end(),
[&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
[&]( const SFVEC2UI& a, const SFVEC2UI& b )
{
// Sort order: inside out.
return distance( a, center ) < distance( b, center );
float distanceA = distance( a, center );
float distanceB = distance( b, center );
if( distanceA != distanceB )
return distanceA < distanceB;
if( a[0] != b[0] )
return a[0] < b[0];
return a[1] < b[1];
} );
// Create m_shader buffer
+1 -1
View File
@@ -37,7 +37,7 @@
# KiCad.
#
# Note: This version string should follow the semantic versioning system
set( KICAD_SEMANTIC_VERSION "7.0.8" )
set( KICAD_SEMANTIC_VERSION "7.0.9" )
# Default the version to the semantic version.
# This is overridden by the git repository tag though (if using git)
+1 -1
View File
@@ -155,7 +155,7 @@ long KIDIALOG::getStyle( KD_TYPE aType )
}
bool OverrideLock( wxWindow* aParent, const wxString& aMessage )
bool AskOverrideLock( wxWindow* aParent, const wxString& aMessage )
{
#ifdef __APPLE__
// wxMessageDialog gets the button spacing wrong on Mac so we have to use wxRichMessageDialog.
+33 -2
View File
@@ -435,7 +435,22 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
for( short i = 0; i < results.columns(); ++i )
{
std::string column = toUTF8( results.column_name( i ) );
aResult[ column ] = toUTF8( results.get<nanodbc::string>( i, NANODBC_TEXT( "" ) ) );
switch( results.column_datatype( i ) )
{
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
{
aResult[column] = fmt::format( "{:G}", results.get<double>( i ) );
break;
}
default:
aResult[column] = toUTF8( results.get<nanodbc::string>( i, NANODBC_TEXT( "" ) ) );
}
}
}
catch( nanodbc::database_error& e )
@@ -534,7 +549,23 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
for( short j = 0; j < results.columns(); ++j )
{
std::string column = toUTF8( results.column_name( j ) );
result[column] = toUTF8( results.get<nanodbc::string>( j, NANODBC_TEXT( "" ) ) );
switch( results.column_datatype( j ) )
{
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
{
result[column] = fmt::format( "{:G}", results.get<double>( j ) );
break;
}
default:
result[column] = toUTF8( results.get<nanodbc::string>( j,
NANODBC_TEXT( "" ) ) );
}
}
aResults.emplace_back( std::move( result ) );
+36 -1
View File
@@ -133,12 +133,41 @@ DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& titl
Pgm().App().SetTopWindow( (EDA_BASE_FRAME*) kiwayHolder );
#endif
Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_SHIM::OnPaint ) );
Bind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
}
DIALOG_SHIM::~DIALOG_SHIM()
{
Unbind( wxEVT_CLOSE_WINDOW, &DIALOG_SHIM::OnCloseWindow, this );
Unbind( wxEVT_BUTTON, &DIALOG_SHIM::OnButton, this );
Unbind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
std::function<void( wxWindowList& )> disconnectFocusHandlers = [&]( wxWindowList& children )
{
for( wxWindow* child : children )
{
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
{
textCtrl->Disconnect( wxEVT_SET_FOCUS,
wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ), nullptr,
this );
}
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
{
scintilla->Disconnect( wxEVT_SET_FOCUS,
wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ), nullptr,
this );
}
else
{
disconnectFocusHandlers( child->GetChildren() );
}
}
};
disconnectFocusHandlers( GetChildren() );
// if the dialog is quasi-modal, this will end its event loop
if( IsQuasiModal() )
EndQuasiModal( wxID_CANCEL );
@@ -282,6 +311,9 @@ bool DIALOG_SHIM::Show( bool show )
ret = wxDialog::Show( show );
}
if( m_parent )
m_parent->SetFocus();
return ret;
}
@@ -483,6 +515,9 @@ int DIALOG_SHIM::ShowQuasiModal()
m_qmodal_showing = false;
if( parent )
parent->SetFocus();
return GetReturnCode();
}
+9 -3
View File
@@ -106,14 +106,22 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
buildDrawList( aView, m_properties, &drawList );
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
// Draw the title block normally even if the view is flipped
bool flipped = gal->IsFlippedX();
if( flipped )
{
int pageWidth = m_pageInfo->GetWidthMils() * m_mils2IUscalefactor;
gal->Save();
gal->Translate( VECTOR2D( m_pageInfo->GetWidthMils() * m_mils2IUscalefactor, 0 ) );
gal->Translate( VECTOR2D( pageWidth, 0 ) );
gal->Scale( VECTOR2D( -1.0, 1.0 ) );
int right = pageWidth - viewport.GetLeft();
int left = right - viewport.GetWidth();
viewport.SetOrigin( left, viewport.GetTop() );
}
DS_PAINTER ws_painter( gal );
@@ -126,8 +134,6 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
ws_settings->SetDefaultFont( settings->GetDefaultFont() );
// Draw all the components that make the drawing sheet
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
for( DS_DRAW_ITEM_BASE* item = drawList.GetFirst(); item; item = drawList.GetNext() )
{
if( viewport.Intersects( item->GetApproxBBox() ) )
+9
View File
@@ -230,6 +230,15 @@ bool EDA_DRAW_FRAME::LockFile( const wxString& aFileName )
m_file_checker = std::make_unique<LOCKFILE>( aFileName );
if( !m_file_checker->Valid() && m_file_checker->IsLockedByMe() )
{
// If we cannot acquire the lock but we appear to be the one who
// locked it, check to see if there is another KiCad instance running.
// If there is not, then we can override the lock. This could happen if
// KiCad crashed or was interrupted
if( !Pgm().SingleInstance()->IsAnotherRunning() )
m_file_checker->OverrideLock();
}
// If the file is valid, return true. This could mean that the file is
// locked or it could mean that the file is read-only
return m_file_checker->Valid();
+10 -6
View File
@@ -881,7 +881,8 @@ void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl
std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangulate,
bool aUseTextRotation ) const
const BOX2I& aBBox,
const EDA_ANGLE& aAngle ) const
{
std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
@@ -893,17 +894,20 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangula
std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
if( aUseTextRotation )
if( aBBox.GetWidth() )
{
drawPos = aBBox.GetCenter();
attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER;
attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
attrs.m_Angle = aAngle;
}
else
{
attrs.m_Angle = GetDrawRotation();
if( font->IsOutline() )
cache = GetRenderCache( font, shownText, VECTOR2I() );
}
else
{
attrs.m_Angle = ANGLE_0;
}
if( aTriangulate )
{
-5
View File
@@ -253,11 +253,6 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName, const wxStri
// first attempt to use the name as specified:
wxString tname = aFileName;
#ifdef _WIN32
// translate from KiCad's internal UNIX-like path to MSWin paths
tname.Replace( wxT( "/" ), wxT( "\\" ) );
#endif
// Note: variable expansion must preferably be performed via a threadsafe wrapper for the
// getenv() system call. If we allow the wxFileName::Normalize() routine to perform expansion
// then we will have a race condition since wxWidgets does not assure a threadsafe wrapper
+111 -42
View File
@@ -94,9 +94,10 @@ public:
private:
struct CACHED_BITMAP
{
GLuint id;
int w, h;
size_t size;
GLuint id;
int w, h;
size_t size;
long long int accessTime;
};
GLuint cacheBitmap( const BITMAP_BASE* aBitmap );
@@ -105,9 +106,9 @@ private:
const size_t m_cacheMaxSize = 256 * 1024 * 1024;
std::map<const KIID, CACHED_BITMAP> m_bitmaps;
std::list<KIID> m_cacheLru;
size_t m_cacheSize;
std::list<GLuint> m_freedTextureIds;
std::list<KIID> m_cacheLru;
size_t m_cacheSize;
std::list<GLuint> m_freedTextureIds;
};
}; // namespace KIGFX
@@ -130,6 +131,7 @@ GLuint GL_BITMAP_CACHE::RequestBitmap( const BITMAP_BASE* aBitmap )
// A bitmap is found in cache bitmap. Ensure the associated texture is still valid.
if( glIsTexture( it->second.id ) )
{
it->second.accessTime = wxGetUTCTimeMillis().GetValue();
return it->second.id;
}
else
@@ -182,56 +184,115 @@ GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
m_freedTextureIds.pop_front();
}
bmp.size = bmp.w * bmp.h * 4;
auto buf = std::make_unique<uint8_t[]>( bmp.size );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
for( int y = 0; y < bmp.h; y++ )
if( imgData.HasAlpha() || imgData.HasMask() )
{
for( int x = 0; x < bmp.w; x++ )
bmp.size = bmp.w * bmp.h * 4;
auto buf = std::make_unique<uint8_t[]>( bmp.size );
uint8_t* dstP = buf.get();
uint8_t* srcP = imgData.GetData();
long long pxCount = static_cast<long long>( bmp.w ) * bmp.h;
if( imgData.HasAlpha() )
{
uint8_t* p = buf.get() + ( bmp.w * y + x ) * 4;
uint8_t* srcAlpha = imgData.GetAlpha();
p[0] = imgData.GetRed( x, y );
p[1] = imgData.GetGreen( x, y );
p[2] = imgData.GetBlue( x, y );
for( long long px = 0; px < pxCount; px++ )
{
memcpy( dstP, srcP, 3 );
dstP[3] = *srcAlpha;
if( imgData.HasAlpha() )
p[3] = imgData.GetAlpha( x, y );
else if( imgData.HasMask() && p[0] == imgData.GetMaskRed()
&& p[1] == imgData.GetMaskGreen() && p[2] == imgData.GetMaskBlue() )
p[3] = wxALPHA_TRANSPARENT;
else
p[3] = wxALPHA_OPAQUE;
srcAlpha += 1;
srcP += 3;
dstP += 4;
}
}
}
else if( imgData.HasMask() )
{
uint8_t maskRed = imgData.GetMaskRed();
uint8_t maskGreen = imgData.GetMaskGreen();
uint8_t maskBlue = imgData.GetMaskBlue();
glBindTexture( GL_TEXTURE_2D, textureID );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
buf.get() );
for( long long px = 0; px < pxCount; px++ )
{
memcpy( dstP, srcP, 3 );
if( srcP[0] == maskRed && srcP[1] == maskGreen && srcP[2] == maskBlue )
dstP[3] = wxALPHA_TRANSPARENT;
else
dstP[3] = wxALPHA_OPAQUE;
srcP += 3;
dstP += 4;
}
}
glBindTexture( GL_TEXTURE_2D, textureID );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
buf.get() );
}
else
{
bmp.size = bmp.w * bmp.h * 3;
uint8_t* srcP = imgData.GetData();
glBindTexture( GL_TEXTURE_2D, textureID );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, bmp.w, bmp.h, 0, GL_RGB, GL_UNSIGNED_BYTE, srcP );
}
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
long long currentTime = wxGetUTCTimeMillis().GetValue();
bmp.id = textureID;
bmp.accessTime = currentTime;
#ifndef DISABLE_BITMAP_CACHE
m_cacheLru.emplace_back( aBitmap->GetImageID() );
m_cacheSize += bmp.size;
m_bitmaps.emplace( aBitmap->GetImageID(), std::move( bmp ) );
if( m_cacheLru.size() > m_cacheMaxElements
|| m_cacheSize > m_cacheMaxSize )
if( m_cacheLru.size() + 1 > m_cacheMaxElements || m_cacheSize + bmp.size > m_cacheMaxSize )
{
KIID last = m_cacheLru.front();
CACHED_BITMAP& cachedBitmap = m_bitmaps[last];
KIID toRemove( 0 );
auto toRemoveLru = m_cacheLru.end();
// Remove entries accessed > 1s ago first
for( const auto& [kiid, cachedBmp] : m_bitmaps )
{
const int cacheTimeoutMillis = 1000L;
if( currentTime - cachedBmp.accessTime > cacheTimeoutMillis )
{
toRemove = kiid;
toRemoveLru = std::find( m_cacheLru.begin(), m_cacheLru.end(), toRemove );
break;
}
}
// Otherwise, remove the latest entry (it's less likely to be needed soon)
if( toRemove == niluuid )
{
toRemoveLru = m_cacheLru.end();
toRemoveLru--;
toRemove = *toRemoveLru;
}
CACHED_BITMAP& cachedBitmap = m_bitmaps[toRemove];
m_cacheSize -= cachedBitmap.size;
glDeleteTextures( 1, &cachedBitmap.id );
m_freedTextureIds.emplace_back( cachedBitmap.id );
m_bitmaps.erase( last );
m_cacheLru.pop_front();
m_bitmaps.erase( toRemove );
m_cacheLru.erase( toRemoveLru );
}
m_cacheLru.emplace_back( aBitmap->GetImageID() );
m_cacheSize += bmp.size;
m_bitmaps.emplace( aBitmap->GetImageID(), std::move( bmp ) );
#endif
return textureID;
@@ -1111,13 +1172,21 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b,
m_strokeColor.a );
std::deque<VECTOR2D> pointList;
pointList.push_back( aStartPoint );
pointList.push_back( diagonalPointA );
pointList.push_back( aEndPoint );
pointList.push_back( diagonalPointB );
pointList.push_back( aStartPoint );
DrawPolyline( pointList );
// DrawLine (and DrawPolyline )
// has problem with 0 length lines so enforce minimum
if( aStartPoint == aEndPoint )
DrawLine( aStartPoint + VECTOR2D( 1.0, 0.0 ), aEndPoint );
else
{
std::deque<VECTOR2D> pointList;
pointList.push_back( aStartPoint );
pointList.push_back( diagonalPointA );
pointList.push_back( aEndPoint );
pointList.push_back( diagonalPointB );
pointList.push_back( aStartPoint );
DrawPolyline( pointList );
}
}
}
+72 -12
View File
@@ -38,6 +38,7 @@
#include <gestfich.h>
#include <string_utils.h>
#include <launch_ext.h>
#include "wx/tokenzr.h"
void QuoteString( wxString& string )
{
@@ -114,22 +115,78 @@ wxString FindKicadFile( const wxString& shortname )
int ExecuteFile( const wxString& aEditorName, const wxString& aFileName, wxProcess *aCallback )
{
wxString fullEditorName;
wxString param;
wxString fullEditorName;
std::vector<wxString> params;
#ifdef __UNIX__
int space = aEditorName.Find( ' ' );
wxString param;
bool inSingleQuotes = false;
bool inDoubleQuotes = false;
if( space > 0 && !aEditorName.Contains( "\"" ) && !aEditorName.Contains( "\'" ) )
auto pushParam =
[&]()
{
if( !param.IsEmpty() )
{
params.push_back( param );
param.clear();
}
};
for( wxUniChar ch : aEditorName )
{
fullEditorName = FindKicadFile( aEditorName.Mid( 0, space ) );
param = aEditorName.Mid( space + 1 );
if( inSingleQuotes )
{
if( ch == '\'' )
{
pushParam();
inSingleQuotes = false;
continue;
}
else
{
param += ch;
}
}
else if( inDoubleQuotes )
{
if( ch == '"' )
{
pushParam();
inDoubleQuotes = false;
}
else
{
param += ch;
}
}
else if( ch == '\'' )
{
pushParam();
inSingleQuotes = true;
}
else if( ch == '"' )
{
pushParam();
inDoubleQuotes = true;
}
else if( ch == ' ' )
{
pushParam();
}
else
{
param += ch;
}
}
else
pushParam();
fullEditorName = FindKicadFile( params[0] );
params.erase( params.begin() );
#else
fullEditorName = FindKicadFile( aEditorName );
#endif
{
fullEditorName = FindKicadFile( aEditorName );
}
if( wxFileExists( fullEditorName ) )
{
@@ -138,8 +195,11 @@ int ExecuteFile( const wxString& aEditorName, const wxString& aFileName, wxProce
args[i++] = fullEditorName.wc_str();
if( !param.IsEmpty() )
args[i++] = param.wc_str();
if( !params.empty() )
{
for( const wxString& p : params )
args[i++] = p.wc_str();
}
if( !aFileName.IsEmpty() )
args[i++] = aFileName.wc_str();
-2
View File
@@ -322,8 +322,6 @@ LIB_TREE_NODE_LIB_ID& LIB_TREE_NODE_LIB::AddItem( LIB_TREE_ITEM* aItem )
void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
{
m_Score = 0;
// We need to score leaf nodes, which are usually (but not always) children.
if( m_Children.size() )
+18
View File
@@ -288,6 +288,24 @@ wxString PATHS::GetStockPlugins3DPath()
fn.AppendDir( wxT( "plugins" ) );
#elif defined( __WXMAC__ )
fn.Assign( wxStandardPaths::Get().GetPluginsDir(), wxEmptyString );
// This must be mapped to main bundle for everything but kicad.app
const wxArrayString dirs = fn.GetDirs();
// Check if we are the main kicad binary. in this case, the path will be
// /path/to/bundlename.app/Contents/PlugIns
// If we are an aux binary, the path will be something like
// /path/to/bundlename.app/Contents/Applications/<standalone>.app/Contents/PlugIns
if( dirs.GetCount() >= 6 &&
dirs[dirs.GetCount() - 4] == wxT( "Applications" ) &&
dirs[dirs.GetCount() - 6].Lower().EndsWith( wxT( "app" ) ) )
{
fn.RemoveLastDir();
fn.RemoveLastDir();
fn.RemoveLastDir();
fn.RemoveLastDir();
fn.AppendDir( wxT( "PlugIns" ) );
}
#else
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
{
+4
View File
@@ -161,6 +161,8 @@ void PGM_BASE::Destroy()
// unlike a normal destructor, this is designed to be called more than once safely:
delete m_locale;
m_locale = nullptr;
m_pgm_checker.reset();
}
@@ -443,6 +445,8 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
return false;
}
#endif
m_pgm_checker = std::make_unique<wxSingleInstanceChecker>();
m_pgm_checker->Create( pgm_name, wxStandardPaths::Get().GetTempDir() );
// Init KiCad environment
// the environment variable KICAD (if exists) gives the kicad path:
+83 -32
View File
@@ -30,6 +30,7 @@
#include <string_utils.h>
#include <convert_basic_shapes_to_polygon.h>
#include <trigo.h>
#include <fmt/core.h>
/**
* Oblique angle for DXF native text
@@ -146,6 +147,26 @@ void DXF_PLOTTER::SetUnits( DXF_UNITS aUnit )
}
// convert aValue to a string, and remove trailing zeros
// In DXF files coordinates need a high precision: at least 9 digits when given
// in inches and 7 digits when in mm.
// So we use 16 digits and remove trailing 0 (if any)
static std::string formatCoord( double aValue )
{
std::string buf;
buf = fmt::format( "{:.16f}", aValue );
// remove trailing zeros
while( !buf.empty() && buf[buf.size() - 1] == '0' )
{
buf.pop_back();
}
return buf;
}
void DXF_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
double aScale, bool aMirror )
{
@@ -417,11 +438,24 @@ void DXF_PLOTTER::SetColor( const COLOR4D& color )
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
{
wxASSERT( m_outputFile );
MoveTo( p1 );
LineTo( VECTOR2I( p1.x, p2.y ) );
LineTo( VECTOR2I( p2.x, p2.y ) );
LineTo( VECTOR2I( p2.x, p1.y ) );
FinishTo( VECTOR2I( p1.x, p1.y ) );
if( p1 != p2 )
{
MoveTo( p1 );
LineTo( VECTOR2I( p1.x, p2.y ) );
LineTo( VECTOR2I( p2.x, p2.y ) );
LineTo( VECTOR2I( p2.x, p1.y ) );
FinishTo( VECTOR2I( p1.x, p1.y ) );
}
else
{
// Draw as a point
wxString cname = getDXFColorName( m_currentColor );
VECTOR2D point_dev = userToDeviceCoordinates( p1 );
fprintf( m_outputFile, "0\nPOINT\n8\n%s\n10\n%g\n20\n%g\n", TO_UTF8( cname ), point_dev.x,
point_dev.y );
}
}
@@ -431,31 +465,43 @@ void DXF_PLOTTER::Circle( const VECTOR2I& centre, int diameter, FILL_T fill, int
double radius = userToDeviceSize( diameter / 2 );
VECTOR2D centre_dev = userToDeviceCoordinates( centre );
wxString cname = getDXFColorName( m_currentColor );
if( radius > 0 )
{
wxString cname = getDXFColorName( m_currentColor );
if( fill == FILL_T::NO_FILL )
{
fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%s\n20\n%s\n40\n%s\n",
TO_UTF8( cname ),
centre_dev.x, centre_dev.y, radius );
formatCoord( centre_dev.x ).c_str(),
formatCoord( centre_dev.y ).c_str(),
formatCoord( radius ).c_str() );
}
else if( fill == FILL_T::FILLED_SHAPE )
{
double r = radius*0.5;
double r = radius * 0.5;
fprintf( m_outputFile, "0\nPOLYLINE\n" );
fprintf( m_outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ) );
fprintf( m_outputFile, "40\n%g\n41\n%g\n", radius, radius);
fprintf( m_outputFile, "40\n%s\n41\n%s\n",
formatCoord( radius ).c_str(),
formatCoord( radius ).c_str() );
fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
centre_dev.x-r, centre_dev.y );
fprintf( m_outputFile, "10\n%s\n 20\n%s\n42\n1.0\n",
formatCoord( centre_dev.x-r ).c_str(),
formatCoord( centre_dev.y ).c_str() );
fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
centre_dev.x+r, centre_dev.y );
fprintf( m_outputFile, "10\n%s\n 20\n%s\n42\n1.0\n",
formatCoord( centre_dev.x+r ).c_str(),
formatCoord( centre_dev.y ).c_str() );
fprintf( m_outputFile, "0\nSEQEND\n");
}
}
else
{
// Draw as a point
fprintf( m_outputFile, "0\nPOINT\n8\n%s\n10\n%g\n20\n%g\n", TO_UTF8( cname ), centre_dev.x,
centre_dev.y );
}
}
@@ -578,9 +624,12 @@ void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
// DXF LINE
wxString cname = getDXFColorName( m_currentColor );
const char* lname = getDXFLineType( static_cast<PLOT_DASH_TYPE>( m_currentLineType ) );
fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%s\n20\n%s\n11\n%s\n21\n%s\n",
TO_UTF8( cname ), lname,
pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
formatCoord( pen_lastpos_dev.x ).c_str(),
formatCoord( pen_lastpos_dev.y ).c_str(),
formatCoord( pos_dev.x ).c_str(),
formatCoord( pos_dev.y ).c_str() );
}
m_penLastpos = pos;
@@ -626,8 +675,8 @@ void DXF_PLOTTER::ThickSegment( const VECTOR2I& aStart, const VECTOR2I& aEnd, in
}
void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
void DXF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
{
wxASSERT( m_outputFile );
@@ -648,9 +697,11 @@ void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
// Emit a DXF ARC entity
wxString cname = getDXFColorName( m_currentColor );
fprintf( m_outputFile,
"0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
"0\nARC\n8\n%s\n10\n%s\n20\n%s\n40\n%s\n50\n%.8f\n51\n%.8f\n",
TO_UTF8( cname ),
centre_device.x, centre_device.y, radius_device,
formatCoord( centre_device.x ).c_str(),
formatCoord( centre_device.y ).c_str(),
formatCoord( radius_device ).c_str(),
startAngle.AsDegrees(), endAngle.AsDegrees() );
}
@@ -936,21 +987,21 @@ void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor
" 8\n"
"%s\n" // Layer name
" 10\n"
"%g\n" // First point X
"%s\n" // First point X
" 11\n"
"%g\n" // Second point X
"%s\n" // Second point X
" 20\n"
"%g\n" // First point Y
"%s\n" // First point Y
" 21\n"
"%g\n" // Second point Y
"%s\n" // Second point Y
" 40\n"
"%g\n" // Text height
"%s\n" // Text height
" 41\n"
"%g\n" // Width factor
"%s\n" // Width factor
" 50\n"
"%g\n" // Rotation
"%.8f\n" // Rotation
" 51\n"
"%g\n" // Oblique angle
"%.8f\n" // Oblique angle
" 71\n"
"%d\n" // Mirror flags
" 72\n"
@@ -960,9 +1011,9 @@ void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor
aAttributes.m_Bold ?
(aAttributes.m_Italic ? "KICADBI" : "KICADB")
: (aAttributes.m_Italic ? "KICADI" : "KICAD"), TO_UTF8( cname ),
origin_dev.x, origin_dev.x,
origin_dev.y, origin_dev.y,
size_dev.y, fabs( size_dev.x / size_dev.y ),
formatCoord( origin_dev.x ).c_str(), formatCoord( origin_dev.x ).c_str(),
formatCoord( origin_dev.y ).c_str(), formatCoord( origin_dev.y ).c_str(),
formatCoord( size_dev.y ).c_str(), formatCoord( fabs( size_dev.x / size_dev.y ) ).c_str(),
aAttributes.m_Angle.AsDegrees(),
aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
+4 -4
View File
@@ -826,8 +826,8 @@ void GERBER_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFil
void GERBER_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
void GERBER_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
{
SetCurrentLineWidth( aWidth );
@@ -1149,8 +1149,8 @@ void GERBER_PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, i
}
}
void GERBER_PLOTTER::ThickArc( const VECTOR2I& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
void GERBER_PLOTTER::ThickArc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
OUTLINE_MODE aTraceMode, void* aData )
{
GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
+10 -18
View File
@@ -394,22 +394,16 @@ void HPGL_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T aFill, i
VECTOR2D p1_device = userToDeviceCoordinates( p1 );
VECTOR2D p2_device = userToDeviceCoordinates( p2 );
MoveTo( p1 );
// EA command seems to always fill the rectangle, so plot as a polygon instead
std::vector<VECTOR2I> cornerList;
if( aFill == FILL_T::FILLED_SHAPE )
{
startOrAppendItem( p1_device, wxString::Format( "RA %.0f,%.0f;",
p2_device.x,
p2_device.y ) );
}
cornerList.emplace_back( p1.x, p1.y );
cornerList.emplace_back( p2.x, p1.y );
cornerList.emplace_back( p2.x, p2.y );
cornerList.emplace_back( p1.x, p2.y );
cornerList.emplace_back( p1.x, p1.y );
startOrAppendItem( p1_device, wxString::Format( "EA %.0f,%.0f;",
p2_device.x,
p2_device.y ) );
m_current_item->loc_end = m_current_item->loc_start;
m_current_item->bbox.Merge( p2_device );
PenFinish();
PlotPoly( cornerList, aFill, aWidth, nullptr );
}
@@ -435,7 +429,6 @@ void HPGL_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill,
chord_angle.AsDegrees(),
hpgl_end_polygon_cmd ) );
m_current_item->lift_before = true;
m_current_item->pen_returns = true;
m_current_item->bbox.Merge( BOX2D( center_dev - radius,
VECTOR2D( 2 * radius, 2 * radius ) ) );
PenFinish();
@@ -448,7 +441,6 @@ void HPGL_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill,
radius,
chord_angle.AsDegrees() ) );
m_current_item->lift_before = true;
m_current_item->pen_returns = true;
m_current_item->bbox.Merge( BOX2D( center_dev - radius,
VECTOR2D( 2 * radius, 2 * radius ) ) );
PenFinish();
@@ -567,8 +559,8 @@ void HPGL_PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end,
}
void HPGL_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
{
if( aRadius <= 0 )
return;
+36 -5
View File
@@ -217,12 +217,43 @@ void PDF_PLOTTER::SetDash( int aLineWidth, PLOT_DASH_TYPE aLineStyle )
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
{
wxASSERT( m_workFile );
SetCurrentLineWidth( width );
VECTOR2I size = p2 - p1;
if( size.x == 0 && size.y == 0 )
{
// Can't draw zero-sized rectangles
SetCurrentLineWidth( width );
MoveTo( VECTOR2I( p1.x, p1.y ) );
FinishTo( VECTOR2I( p1.x, p1.y ) );
return;
}
if( std::min( std::abs( size.x ), std::abs( size.y ) ) < width )
{
// Too thick stroked rectangles are buggy, draw as polygon
std::vector<VECTOR2I> cornerList;
cornerList.emplace_back( p1.x, p1.y );
cornerList.emplace_back( p2.x, p1.y );
cornerList.emplace_back( p2.x, p2.y );
cornerList.emplace_back( p1.x, p2.y );
cornerList.emplace_back( p1.x, p1.y );
PlotPoly( cornerList, fill, width, nullptr );
return;
}
VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
SetCurrentLineWidth( width );
fprintf( m_workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y,
p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y, fill == FILL_T::NO_FILL ? 'S' : 'B' );
fprintf( m_workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y, p2_dev.x - p1_dev.x,
p2_dev.y - p1_dev.y, fill == FILL_T::NO_FILL ? 'S' : 'B' );
}
@@ -336,8 +367,8 @@ void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VE
}
void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
void PDF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
{
wxASSERT( m_workFile );
+1 -1
View File
@@ -113,7 +113,7 @@ void PSLIKE_PLOTTER::FlashPadOval( const VECTOR2I& aPadPos, const VECTOR2I& aSiz
if( aTraceMode == FILLED )
ThickSegment( a + aPadPos, b + aPadPos, size.x, aTraceMode, nullptr );
else
sketchOval( aPadPos, size, orient, -1 );
sketchOval( aPadPos, size, orient, USE_DEFAULT_LINE_WIDTH );
}
+2 -2
View File
@@ -443,8 +443,8 @@ void SVG_PLOTTER::Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int wi
}
void SVG_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
void SVG_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
{
/* Draws an arc of a circle, centered on (xc,yc), with starting point (x1, y1) and ending
* at (x2, y2). The current pen is used for the outline and the current brush for filling
+27 -9
View File
@@ -145,13 +145,31 @@ double PLOTTER::GetDashGapLenIU( int aLineWidth ) const
return userToDeviceSize( m_renderSettings->GetGapLength( aLineWidth ) );
}
#include <wx/log.h>
void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
FILL_T aFill, int aWidth, int aMaxError )
{
EDA_ANGLE startAngle( aStart - aCenter );
EDA_ANGLE endAngle( aEnd - aCenter );
int radius = ( aStart - aCenter ).EuclideanNorm();
// Recalculate aCenter using double to be sure we will use a exact value, from aStart and aEnd
// it must be on the line passing by the middle of segment {aStart, aEnd}
// To simplify calculations, use aStart as origin in intermediate calculations
VECTOR2D center = aCenter - aStart;
VECTOR2D end = aEnd - aStart;
EDA_ANGLE segAngle( end );
// Rotate end and center, to make segment {aStart, aEnd} horizontal
RotatePoint( end, segAngle );
RotatePoint( center, segAngle );
// center.x must be at end.x/2 coordinate
center.x = end.x / 2;
// Now calculate the right center position
RotatePoint( center, -segAngle );
center += aStart;
EDA_ANGLE startAngle( VECTOR2D( aStart ) - center );
EDA_ANGLE endAngle( VECTOR2D( aEnd ) - center );
double radius = ( VECTOR2D( aStart ) - center ).EuclideanNorm();
if( startAngle > endAngle )
{
@@ -168,12 +186,12 @@ void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR
startAngle = -startAngle;
endAngle = -endAngle;
Arc( aCenter, startAngle, endAngle, radius, aFill, aWidth );
Arc( center, startAngle, endAngle, radius, aFill, aWidth );
}
void PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
void PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
{
EDA_ANGLE startAngle( aStartAngle );
EDA_ANGLE endAngle( aEndAngle );
@@ -570,8 +588,8 @@ void PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int widt
}
void PLOTTER::ThickArc( const VECTOR2I& centre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
void PLOTTER::ThickArc( const VECTOR2D& centre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
OUTLINE_MODE aTraceMode, void* aData )
{
if( aTraceMode == FILLED )
+33
View File
@@ -569,9 +569,42 @@ bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
bool PROJECT_FILE::SaveAs( const wxString& aDirectory, const wxString& aFile )
{
wxFileName oldFilename( GetFilename() );
wxString oldProjectName = oldFilename.GetName();
wxString oldProjectPath = oldFilename.GetPath();
Set( "meta.filename", aFile + "." + ProjectFileExtension );
SetFilename( aFile );
auto updatePath =
[&]( wxString& aPath )
{
if( aPath.StartsWith( oldProjectName + wxS( "." ) ) )
aPath.Replace( oldProjectName, aFile, false );
else if( aPath.StartsWith( oldProjectPath + wxS( "/" ) ) )
aPath.Replace( oldProjectPath, aDirectory, false );
};
updatePath( m_BoardDrawingSheetFile );
for( int ii = LAST_PATH_FIRST; ii < (int) LAST_PATH_SIZE; ++ii )
updatePath( m_PcbLastPath[ ii ] );
auto updatePathByPtr =
[&]( const std::string& aPtr )
{
if( std::optional<wxString> path = Get<wxString>( aPtr ) )
{
updatePath( path.value() );
Set( aPtr, path.value() );
}
};
updatePathByPtr( "schematic.page_layout_descr_file" );
updatePathByPtr( "schematic.plot_directory" );
updatePathByPtr( "schematic.ngspice.workbook_filename" );
updatePathByPtr( "pcbnew.page_layout_descr_file" );
// While performing Save As, we have already checked that we can write to the directory
// so don't carry the previous flag
SetReadOnly( false );
+2 -1
View File
@@ -63,7 +63,8 @@ void RC_ITEM::SetItems( const EDA_ITEM* aItem, const EDA_ITEM* bItem,
{
m_ids.clear();
m_ids.push_back( aItem->m_Uuid );
if( aItem )
m_ids.push_back( aItem->m_Uuid );
if( bItem )
m_ids.push_back( bItem->m_Uuid );
+10 -28
View File
@@ -48,35 +48,17 @@
static int vprint( std::string* result, const char* format, va_list ap )
{
char msg[512];
// This function can call vsnprintf twice.
// But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
// va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
// see: www.cplusplus.com/reference/cstdio/vsnprintf
// we make a copy of va_list ap for the second call, if happens
va_list tmp;
va_copy( tmp, ap );
size_t len = vsnprintf( nullptr, 0, format, tmp );
va_end( tmp );
size_t len = vsnprintf( msg, sizeof(msg), format, ap );
// Resize the output to hold the required data
size_t size = result->size();
result->resize( size + len );
if( len < sizeof(msg) ) // the output fit into msg
{
result->append( msg, msg + len );
}
else
{
// output was too big, so now incur the expense of allocating
// a buf for holding suffient characters.
std::vector<char> buf;
buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
len = vsnprintf( &buf[0], len+1, format, tmp );
result->append( &buf[0], &buf[0] + len );
}
va_end( tmp ); // Release the temporary va_list, initialised from ap
// Now do the actual printing
len = vsnprintf( result->data() + size, len + 1, format, ap );
return len;
}
@@ -443,18 +425,18 @@ int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
// we make a copy of va_list ap for the second call, if happens
va_list tmp;
va_copy( tmp, ap );
int ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, ap );
int ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, ap );
if( ret >= (int) m_buffer.size() )
{
m_buffer.resize( ret + 1000 );
ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, tmp );
ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, tmp );
}
va_end( tmp ); // Release the temporary va_list, initialised from ap
if( ret > 0 )
write( &m_buffer[0], ret );
write( m_buffer.data(), ret );
return ret;
}
+14
View File
@@ -80,6 +80,20 @@ principle should be easily implemented by adapting the current STL containers.
%ignore to_json;
%ignore from_json;
%rename(GetEffectiveTextShapeNative) EDA_TEXT::GetEffectiveTextShape;
%extend EDA_TEXT
{
%pythoncode
%{
# KiCad 7.0 API Compatibility
def GetEffectiveTextShape(self, aTriangulate=True, aUseTextRotation=True):
return self.GetEffectiveTextShapeNative(aTriangulate)
%}
}
// headers/imports that must be included in the _wrapper.cpp at top
%{
+4
View File
@@ -59,6 +59,10 @@ ACTION_MENU::ACTION_MENU( bool isContextMenu, TOOL_INTERACTIVE* aTool ) :
ACTION_MENU::~ACTION_MENU()
{
Disconnect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ),
nullptr, this );
Disconnect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
// Set parent to NULL to prevent submenus from unregistering from a nonexistent object
for( ACTION_MENU* menu : m_submenus )
menu->SetParent( nullptr );
+14 -13
View File
@@ -127,16 +127,9 @@ bool CONNECTION_SUBGRAPH::ResolveDrivers( bool aCheckMultipleDrivers )
return a_name < b_name;
};
auto strong_cmp = [this]( SCH_ITEM* a, SCH_ITEM* b ) -> bool
{
const wxString& a_name = GetNameForDriver( a );
const wxString& b_name = GetNameForDriver( b );
return a_name < b_name;
};
PRIORITY highest_priority = PRIORITY::INVALID;
std::set<SCH_ITEM*, decltype( candidate_cmp )> candidates( candidate_cmp );
std::set<SCH_ITEM*, decltype( strong_cmp )> strong_drivers( strong_cmp );
std::set<SCH_ITEM*> strong_drivers;
m_driver = nullptr;
@@ -239,7 +232,11 @@ void CONNECTION_SUBGRAPH::getAllConnectedItems( std::set<std::pair<SCH_SHEET_PAT
sg = sg->m_absorbed_by;
}
aSubgraphs.insert( sg );
// If we are unable to insert the subgraph into the set, then we have already
// visited it and don't need to add it again.
if( aSubgraphs.insert( sg ).second == false )
return;
aSubgraphs.insert( sg->m_absorbed_subgraphs.begin(), sg->m_absorbed_subgraphs.end() );
for( SCH_ITEM* item : sg->m_items )
@@ -1345,11 +1342,15 @@ void CONNECTION_GRAPH::generateBusAliasMembers()
wxString name = conn->FullLocalName();
CONNECTION_SUBGRAPH* new_sg = new CONNECTION_SUBGRAPH( this );
// This connection cannot form a part of the item because the item is not, itself
// connected to this subgraph. It exists as part of a virtual item that may be connected
// to other items but is not in the schematic.
SCH_CONNECTION* new_conn = new SCH_CONNECTION( item, subgraph->m_sheet );
new_conn->SetGraph( this );
new_conn->SetName( name );
new_conn->SetType( CONNECTION_TYPE::NET );
subgraph->StoreImplicitConnection( new_conn );
int code = assignNewNetCode( *new_conn );
wxLogTrace( ConnTrace, wxS( "SG(%ld), Adding full local name (%s) with sg (%d) on subsheet %s" ), subgraph->m_code,
@@ -3125,7 +3126,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
bus_name = bus_wire->Connection( &sheet )->Name();
std::set<wxString> test_names;
test_names.insert( bus_entry->Connection( &sheet )->Name() );
test_names.insert( bus_entry->Connection( &sheet )->FullLocalName() );
wxString baseName = sheet.PathHumanReadable();
@@ -3138,11 +3139,11 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
{
for( const auto& sub_member : member->Members() )
{
if( test_names.count( sub_member->Name() ) )
if( test_names.count( sub_member->FullLocalName() ) )
conflict = false;
}
}
else if( test_names.count( member->Name() ) )
else if( test_names.count( member->FullLocalName() ) )
{
conflict = false;
}
+16 -1
View File
@@ -89,7 +89,11 @@ public:
m_hier_parent( nullptr )
{}
~CONNECTION_SUBGRAPH() = default;
~CONNECTION_SUBGRAPH()
{
for( SCH_CONNECTION* connection : m_bus_element_connections )
delete connection;
}
/**
* Determines which potential driver should drive the subgraph.
@@ -162,6 +166,13 @@ public:
void RemoveItem( SCH_ITEM* aItem );
// Use this to keep a connection pointer that is not owned by any item
// This will be destroyed with the subgraph
void StoreImplicitConnection( SCH_CONNECTION* aConnection )
{
m_bus_element_connections.insert( aConnection );
}
private:
wxString driverName( SCH_ITEM* aItem ) const;
@@ -251,6 +262,10 @@ public:
/// A cache of escaped netnames from schematic items
mutable std::unordered_map<SCH_ITEM*, wxString> m_driver_name_cache;
/// A cache of connections that are part of this subgraph but that don't have
/// an owning element (i.e. bus members)
std::set<SCH_CONNECTION*> m_bus_element_connections;
};
struct NET_NAME_CODE_CACHE_KEY
+19 -15
View File
@@ -49,19 +49,20 @@ using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
template <typename T_symbol, typename T_field>
DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symbol& aSymbol,
std::vector<T_field>& aFields )
: DIALOG_SIM_MODEL_BASE( aParent ),
m_symbol( aSymbol ),
m_fields( aFields ),
m_libraryModelsMgr( &Prj() ),
m_builtinModelsMgr( &Prj() ),
m_prevModel( nullptr ),
m_curModelType( SIM_MODEL::TYPE::NONE ),
m_scintillaTricks( nullptr ),
m_firstCategory( nullptr ),
m_prevParamGridSelection( nullptr ),
m_lastParamGridWidth( 0 ),
m_inKillFocus( false )
std::vector<T_field>& aFields ) :\
DIALOG_SIM_MODEL_BASE( aParent ),
m_symbol( aSymbol ),
m_fields( aFields ),
m_libraryModelsMgr( &Prj() ),
m_builtinModelsMgr( &Prj() ),
m_prevModel( nullptr ),
m_curModelType( SIM_MODEL::TYPE::NONE ),
m_scintillaTricksCode( nullptr ),
m_scintillaTricksSubckt( nullptr ),
m_firstCategory( nullptr ),
m_prevParamGridSelection( nullptr ),
m_lastParamGridWidth( 0 ),
m_inKillFocus( false )
{
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
@@ -81,7 +82,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symb
m_typeChoice->Clear();
m_scintillaTricks = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
m_scintillaTricksCode = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
m_scintillaTricksSubckt = new SCINTILLA_TRICKS( m_subckt, wxT( "()" ), false );
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
@@ -131,7 +133,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::~DIALOG_SIM_MODEL()
// Delete the GRID_TRICKS.
m_pinAssignmentsGrid->PopEventHandler( true );
delete m_scintillaTricks;
delete m_scintillaTricksCode;
delete m_scintillaTricksSubckt;
}
@@ -663,6 +666,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments( SIM_MODEL* aMode
{
SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( aModel );
m_subckt->SetText( subckt->GetSpiceCode() );
m_subckt->SetEditable( false );
}
else
{
+2 -1
View File
@@ -130,7 +130,8 @@ private:
std::map<SIM_MODEL::DEVICE_T, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType;
SIM_MODEL::TYPE m_curModelType;
SCINTILLA_TRICKS* m_scintillaTricks;
SCINTILLA_TRICKS* m_scintillaTricksCode;
SCINTILLA_TRICKS* m_scintillaTricksSubckt;
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
wxPGProperty* m_prevParamGridSelection;
+10 -4
View File
@@ -6,7 +6,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017-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
@@ -54,10 +54,16 @@ DIALOG_SYMBOL_REMAP::DIALOG_SYMBOL_REMAP( SCH_EDIT_FRAME* aParent ) :
{
m_remapped = false;
if( !wxFileName::IsDirWritable( Prj().GetProjectPath() ) )
wxString projectPath = Prj().GetProjectPath();
if( !wxFileName::IsDirWritable( projectPath ) )
{
DisplayInfoMessage( this, _( "Remapping is not possible because you have insufficient "
"privileges to the project folder '%s'." ) );
wxString msg =
wxString::Format( _( "Remapping is not possible because you have insufficient "
"privileges to the project folder '%s'." ),
projectPath );
DisplayInfoMessage( this, msg );
// Disable the remap button.
m_remapped = true;
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -296,10 +296,10 @@ DIALOG_TEXT_PROPERTIES_BASE::DIALOG_TEXT_PROPERTIES_BASE( wxWindow* parent, wxWi
bSizer11 = new wxBoxSizer( wxHORIZONTAL );
m_hyperlinkCombo = new WX_COMBOBOX( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer11->Add( m_hyperlinkCombo, 1, wxALIGN_CENTER_VERTICAL, 5 );
bSizer11->Add( m_hyperlinkCombo, 1, wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE, 5 );
m_textEntrySizer->Add( bSizer11, wxGBPosition( 9, 1 ), wxGBSpan( 1, 6 ), wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
m_textEntrySizer->Add( bSizer11, wxGBPosition( 9, 1 ), wxGBSpan( 1, 5 ), wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
m_textEntrySizer->AddGrowableCol( 3 );
@@ -2925,7 +2925,7 @@
</object>
<object class="gbsizeritem" expanded="1">
<property name="border">5</property>
<property name="colspan">6</property>
<property name="colspan">5</property>
<property name="column">1</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="row">9</property>
@@ -2937,7 +2937,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE</property>
<property name="proportion">1</property>
<object class="wxBitmapComboBox" expanded="1">
<property name="BottomDockable">1</property>
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
+4 -18
View File
@@ -619,8 +619,6 @@ int ERC_TESTER::TestPinToPin()
}
}
std::set<std::pair<ERC_SCH_PIN_CONTEXT, ERC_SCH_PIN_CONTEXT>> tested;
ERC_SCH_PIN_CONTEXT needsDriver;
bool hasDriver = false;
@@ -638,8 +636,9 @@ int ERC_TESTER::TestPinToPin()
}
}
for( ERC_SCH_PIN_CONTEXT& refPin : pins )
for( auto refIt = pins.begin(); refIt != pins.end(); ++refIt )
{
ERC_SCH_PIN_CONTEXT& refPin = *refIt;
ELECTRICAL_PINTYPE refType = refPin.Pin()->GetType();
if( DrivenPinTypes.count( refType ) )
@@ -663,22 +662,9 @@ int ERC_TESTER::TestPinToPin()
else
hasDriver |= ( DrivingPinTypes.count( refType ) != 0 );
for( ERC_SCH_PIN_CONTEXT& testPin : pins )
for( auto testIt = refIt + 1; testIt != pins.end(); ++testIt )
{
if( testPin == refPin )
continue;
ERC_SCH_PIN_CONTEXT first_pin = refPin;
ERC_SCH_PIN_CONTEXT second_pin = testPin;
if( second_pin < first_pin )
std::swap( first_pin, second_pin );
std::pair<ERC_SCH_PIN_CONTEXT, ERC_SCH_PIN_CONTEXT> pair =
std::make_pair( first_pin, second_pin );
if( auto [ins_pin, inserted ] = tested.insert( pair ); !inserted )
continue;
ERC_SCH_PIN_CONTEXT& testPin = *testIt;
// Multiple pins in the same symbol that share a type,
// name and position are considered
+32 -8
View File
@@ -580,7 +580,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
return StringFromBool( field.IsNameShown() );
case FDC_H_ALIGN:
switch ( field.GetHorizJustify() )
switch ( field.GetEffectiveHorizJustify() )
{
case GR_TEXT_H_ALIGN_LEFT: return _( "Left" );
case GR_TEXT_H_ALIGN_CENTER: return _( "Center" );
@@ -590,7 +590,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
break;
case FDC_V_ALIGN:
switch ( field.GetVertJustify() )
switch ( field.GetEffectiveVertJustify() )
{
case GR_TEXT_V_ALIGN_TOP: return _( "Top" );
case GR_TEXT_V_ALIGN_CENTER: return _( "Center" );
@@ -727,28 +727,52 @@ void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue
break;
case FDC_H_ALIGN:
{
GR_TEXT_H_ALIGN_T horizontalJustification;
if( value == _( "Left" ) )
field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
horizontalJustification = GR_TEXT_H_ALIGN_LEFT;
else if( value == _( "Center" ) )
field.SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
else if( value == _( "Right" ) )
field.SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
horizontalJustification = GR_TEXT_H_ALIGN_RIGHT;
else
wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + value );
// Note that we must set justifications before we can ask if they're flipped. If the old
// justification is center then it won't know (whereas if the new justification is center
// the we don't care).
field.SetHorizJustify( horizontalJustification );
if( field.IsHorizJustifyFlipped() )
field.SetHorizJustify( EDA_TEXT::MapHorizJustify( - horizontalJustification ) );
break;
}
case FDC_V_ALIGN:
{
GR_TEXT_V_ALIGN_T verticalJustification;
if( value == _( "Top" ) )
field.SetVertJustify( GR_TEXT_V_ALIGN_TOP );
verticalJustification = GR_TEXT_V_ALIGN_TOP;
else if( value == _( "Center" ) )
field.SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
verticalJustification = GR_TEXT_V_ALIGN_CENTER;
else if( value == _( "Bottom" ) )
field.SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
else
wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + value);
// Note that we must set justifications before we can ask if they're flipped. If the old
// justification is center then it won't know (whereas if the new justification is center
// the we don't care).
field.SetVertJustify( verticalJustification );
if( field.IsVertJustifyFlipped() )
field.SetVertJustify( EDA_TEXT::MapVertJustify( -verticalJustification ) );
break;
}
case FDC_ITALIC:
field.SetItalic( BoolFromString( value ) );
+11 -2
View File
@@ -103,7 +103,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
{
msg.Printf( _( "Schematic '%s' is already open." ), wx_filename.GetFullName() );
if( !OverrideLock( this, msg ) )
if( !AskOverrideLock( this, msg ) )
return false;
m_file_checker->OverrideLock( false );
@@ -590,6 +590,15 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
if( !AskToSaveChanges() )
return;
if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
{
wxString msg = _( "This operation replaces the contents of the current project.\n\n"
"Do you want to proceed?" );
if( !IsOK( this, msg ) )
return;
}
// Set the project location if none is set or if we are running in standalone mode
bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
wxString path = wxPathOnly( Prj().GetProjectFullName() );
@@ -1234,7 +1243,7 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), aFileName,
m_file_checker->GetUsername(), m_file_checker->GetHostname() );
if( !OverrideLock( this, msg ) )
if( !AskOverrideLock( this, msg ) )
return false;
m_file_checker->OverrideLock();
+6
View File
@@ -118,6 +118,12 @@ public:
KIFONT::FONT* getDrawFont() const override;
bool IsHorizJustifyFlipped() const { return false; }
bool IsVertJustifyFlipped() const { return false; }
GR_TEXT_H_ALIGN_T GetEffectiveHorizJustify() const { return GetHorizJustify(); }
GR_TEXT_V_ALIGN_T GetEffectiveVertJustify() const { return GetVertJustify(); }
/**
* Copy parameters of this field to another field. Pointers are not copied.
*
+5 -1
View File
@@ -106,10 +106,14 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
ACTION_MENU* submenuImport = new ACTION_MENU( false, selTool );
submenuImport->SetTitle( _( "Import" ) );
submenuImport->SetIcon( BITMAPS::import );
submenuImport->Add( _( "Non-KiCad Schematic..." ),
if( Kiface().IsSingle() )
{
submenuImport->Add( _( "Non-KiCad Schematic..." ),
_( "Replace current schematic sheet with one imported from another application" ),
ID_IMPORT_NON_KICAD_SCH,
BITMAPS::import_document );
}
submenuImport->Add( EE_ACTIONS::importFPAssignments, ACTION_MENU::NORMAL, _( "Footprint Assignments..." ) );
fileMenu->Add( submenuImport );
+40 -4
View File
@@ -1037,8 +1037,27 @@ void SCH_LABEL_BASE::Plot( PLOTTER* aPlotter, bool aBackground ) const
{
aPlotter->PlotText( textpos, color, GetShownText( true ), attrs, font );
if( s_poly.size() )
aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
if( GetShape() == LABEL_FLAG_SHAPE::F_DOT )
{
aPlotter->MoveTo( s_poly[0] );
aPlotter->LineTo( s_poly[1] );
int diameter = ( s_poly[2] - s_poly[1] ).EuclideanNorm() * 2;
aPlotter->FilledCircle( s_poly[2], diameter , FILLED, nullptr );
}
else if( GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
{
aPlotter->MoveTo( s_poly[0] );
aPlotter->LineTo( s_poly[1] );
int diameter = ( s_poly[2] - s_poly[1] ).EuclideanNorm() * 2;
aPlotter->ThickCircle( s_poly[2], diameter, penWidth, FILLED, nullptr );
}
else
{
if( !s_poly.empty() )
aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
}
// Plot attributes to a hypertext menu
std::vector<wxString> properties;
@@ -1092,8 +1111,25 @@ void SCH_LABEL_BASE::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aO
CreateGraphicShape( aSettings, s_poly, GetTextPos() + aOffset );
if( !s_poly.empty() )
GRPoly( DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
if( GetShape() == LABEL_FLAG_SHAPE::F_DOT )
{
GRLine( DC, s_poly[0], s_poly[1], penWidth, color );
int radius = ( s_poly[2] - s_poly[1] ).EuclideanNorm();
GRFilledCircle( DC, s_poly[2], radius, penWidth, color, color );
}
else if( GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
{
GRLine( DC, s_poly[0], s_poly[1], penWidth, color );
int radius = ( s_poly[2] - s_poly[1] ).EuclideanNorm();
GRCircle( DC, s_poly[2], radius, penWidth, color );
}
else
{
if( !s_poly.empty() )
GRPoly( DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
}
for( SCH_FIELD& field : m_fields )
field.Print( aSettings, aOffset );
+2
View File
@@ -110,6 +110,8 @@ public:
void SetIsDangling( bool isDangling ) { m_isDangling = isDangling; }
void SetLibPin( LIB_PIN* aLibPin ) { m_libPin = aLibPin; }
/**
* @param aPin Comparison Pin
* @return True if aPin is stacked with this pin
@@ -192,6 +192,11 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
name = FromUTF8();
// Some symbol LIB_IDs have the '/' character escaped which can break derived symbol links.
// The '/' character is no longer an illegal LIB_ID character so it doesn't need to be
// escaped.
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
LIB_ID id;
int bad_pos = id.Parse( name );
@@ -268,6 +273,12 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
}
name = FromUTF8();
// Some symbol LIB_IDs have the '/' character escaped which can break derived
// symbol links. The '/' character is no longer an illegal LIB_ID character so
// it doesn't need to be escaped.
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
auto it = aSymbolLibMap.find( name );
if( it == aSymbolLibMap.end() )
@@ -293,6 +304,11 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
name = FromUTF8();
// Some symbol LIB_IDs have the '/' character escaped which can break derived
// symbol links. The '/' character is no longer an illegal LIB_ID character so
// it doesn't need to be escaped.
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
if( !name.StartsWith( m_symbolName ) )
{
error.Printf( _( "Invalid symbol unit name prefix %s" ), name.c_str() );
@@ -2593,6 +2609,11 @@ SCH_SYMBOL* SCH_SEXPR_PARSER::parseSchematicSymbol()
}
libName = FromUTF8();
// Some symbol LIB_IDs or lib_name have the '/' character escaped which can break
// symbol links. The '/' character is no longer an illegal LIB_ID character so
// it doesn't need to be escaped.
libName.Replace( "{slash}", "/" );
NeedRIGHT();
break;
}
@@ -2606,6 +2627,11 @@ SCH_SYMBOL* SCH_SEXPR_PARSER::parseSchematicSymbol()
LIB_ID libId;
wxString name = FromUTF8();
// Some symbol LIB_IDs have the '/' character escaped which can break
// symbol links. The '/' character is no longer an illegal LIB_ID character so
// it doesn't need to be escaped.
name.Replace( "{slash}", "/" );
int bad_pos = libId.Parse( name );
if( bad_pos >= 0 )
@@ -353,6 +353,8 @@ void SCH_LEGACY_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen,
aScreen->Append( loadText( aReader ) );
else if( strCompare( "BusAlias", line ) )
aScreen->AddBusAlias( loadBusAlias( aReader, aScreen ) );
else if( strCompare( "Kmarq", line ) )
continue; // Ignore legacy (until 2009) ERC marker entry
else if( strCompare( "$EndSCHEMATC", line ) )
return;
else
+5
View File
@@ -1174,12 +1174,14 @@ void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
item->Plot( aPlotter, background );
}
// Plot the background items
for( const SCH_ITEM* item : other )
{
aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
item->Plot( aPlotter, background );
}
// Plot the foreground items
for( const SCH_ITEM* item : other )
{
aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
@@ -1193,7 +1195,10 @@ void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
aPlotter->SetCurrentLineWidth( std::max( sym->GetPenWidth(), defaultPenWidth ) );
for( SCH_FIELD field : sym->GetFields() )
{
field.ClearRenderCache();
field.Plot( aPlotter, false );
}
sym->PlotPins( aPlotter );
+113 -20
View File
@@ -177,9 +177,6 @@ SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
m_onBoard = aSymbol.m_onBoard;
m_DNP = aSymbol.m_DNP;
if( aSymbol.m_part )
SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part.get() ) );
const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
m_transform = aSymbol.m_transform;
@@ -191,6 +188,18 @@ SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
for( SCH_FIELD& field : m_fields )
field.SetParent( this );
m_pins.clear();
// Copy (and re-parent) the pins
for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
{
m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
m_pins.back()->SetParent( this );
}
if( aSymbol.m_part )
SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part ) );
m_fieldsAutoplaced = aSymbol.m_fieldsAutoplaced;
m_schLibSymbolName = aSymbol.m_schLibSymbolName;
}
@@ -333,49 +342,104 @@ wxString SCH_SYMBOL::GetDatasheet() const
void SCH_SYMBOL::UpdatePins()
{
std::map<wxString, wxString> altPinMap;
std::map<wxString, KIID> pinUuidMap;
std::map<wxString, wxString> altPinMap;
std::map<wxString, std::set<SCH_PIN*>> pinUuidMap;
std::set<SCH_PIN*> unassignedSchPins;
std::set<LIB_PIN*> unassignedLibPins;
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
pinUuidMap[ pin->GetNumber() ] = pin->m_Uuid;
pinUuidMap[ pin->GetNumber() ].insert( pin.get() );
unassignedSchPins.insert( pin.get() );
if( !pin->GetAlt().IsEmpty() )
altPinMap[ pin->GetNumber() ] = pin->GetAlt();
}
m_pins.clear();
m_pinMap.clear();
if( !m_part )
return;
unsigned i = 0;
std::vector<LIB_PIN*> pins = m_part->GetAllLibPins();
for( LIB_PIN* libPin : pins )
{
// NW: Don't filter by unit: this data-structure is used for all instances,
// some if which might have different units.
// some of which might have different units.
if( libPin->GetConvert() && m_convert && m_convert != libPin->GetConvert() )
continue;
m_pins.push_back( std::make_unique<SCH_PIN>( libPin, this ) );
SCH_PIN* pin = nullptr;
auto ii = pinUuidMap.find( libPin->GetNumber() );
if( ii != pinUuidMap.end() )
const_cast<KIID&>( m_pins.back()->m_Uuid ) = ii->second;
if( ii == pinUuidMap.end() || ii->second.empty() )
{
unassignedLibPins.insert( libPin );
continue;
}
auto it = ii->second.begin();
pin = *it;
ii->second.erase( it );
pin->SetLibPin( libPin );
pin->SetPosition( libPin->GetPosition() );
unassignedSchPins.erase( pin );
auto iii = altPinMap.find( libPin->GetNumber() );
if( iii != altPinMap.end() )
m_pins.back()->SetAlt( iii->second );
pin->SetAlt( iii->second );
m_pinMap[ libPin ] = i;
m_pinMap[ libPin ] = pin;
}
++i;
// Add any pins that were not found in the symbol
for( LIB_PIN* libPin : unassignedLibPins )
{
SCH_PIN* pin = nullptr;
// First try to re-use an existing pin
if( !unassignedSchPins.empty() )
{
auto it = unassignedSchPins.begin();
pin = *it;
unassignedSchPins.erase( it );
}
else
{
// This is a pin that was not found in the symbol, so create a new one.
pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( libPin, this ) ) ).get();
}
m_pinMap[ libPin ] = pin;
pin->SetLibPin( libPin );
pin->SetPosition( libPin->GetPosition() );
pin->SetNumber( libPin->GetNumber() );
auto iii = altPinMap.find( libPin->GetNumber() );
if( iii != altPinMap.end() )
pin->SetAlt( iii->second );
}
// If we have any pins left in the symbol that were not found in the library, remove them.
for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
{
auto it2 = unassignedSchPins.find( it1->get() );
if( it2 != unassignedSchPins.end() )
{
it1 = m_pins.erase( it1 );
unassignedSchPins.erase( it2 );
}
else
{
++it1;
}
}
}
@@ -1057,8 +1121,13 @@ std::vector<LIB_PIN*> SCH_SYMBOL::GetAllLibPins() const
SCH_PIN* SCH_SYMBOL::GetPin( LIB_PIN* aLibPin ) const
{
wxASSERT( m_pinMap.count( aLibPin ) );
return m_pins[ m_pinMap.at( aLibPin ) ].get();
auto it = m_pinMap.find( aLibPin );
if( it != m_pinMap.end() )
return it->second;
wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
return nullptr;
}
@@ -1666,7 +1735,17 @@ BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) con
BOX2I SCH_SYMBOL::GetBodyBoundingBox() const
{
return doGetBoundingBox( false, false );
try
{
return doGetBoundingBox( false, false );
}
catch( const boost::bad_pointer& exc )
{
// This may be overkill and could be an assertion but we are more likely to
// find any boost pointer container errors this way.
wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
return BOX2I();
}
}
@@ -2202,6 +2281,17 @@ void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground ) const
tempPin->SetFlags( IS_DANGLING );
}
for( LIB_ITEM& item : tempSymbol.GetDrawItems() )
{
if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
{
// Use SCH_FIELD's text resolver
SCH_FIELD dummy( (SCH_ITEM*) this, -1 );
dummy.SetText( text->GetText() );
text->SetText( dummy.GetShownText( false ) );
}
}
TRANSFORM temp = GetTransform();
aPlotter->StartBlock( nullptr );
@@ -2210,8 +2300,11 @@ void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground ) const
tempSymbol.Plot( aPlotter, GetUnit(), GetConvert(), local_background, m_pos, temp,
GetDNP() );
for( const SCH_FIELD& field : m_fields )
for( SCH_FIELD field : m_fields )
{
field.ClearRenderCache();
field.Plot( aPlotter, local_background );
}
}
if( m_DNP )
+1 -1
View File
@@ -800,7 +800,7 @@ private:
std::unique_ptr< LIB_SYMBOL > m_part; ///< a flattened copy of the LIB_SYMBOL
///< from the PROJECT's libraries.
std::vector<std::unique_ptr<SCH_PIN>> m_pins; ///< a SCH_PIN for every LIB_PIN (all units)
std::unordered_map<LIB_PIN*, unsigned> m_pinMap; ///< library pin pointer : SCH_PIN's index
std::unordered_map<LIB_PIN*, SCH_PIN*> m_pinMap; ///< library pin pointer : SCH_PIN's index
bool m_isInNetlist; ///< True if the symbol should appear in the netlist
bool m_inBom; ///< True to include in bill of materials export.
+1
View File
@@ -617,6 +617,7 @@ std::string NGSPICE::findCmPath() const
"/../../../../../Contents/PlugIns/sim/ngspice",
"../Plugins/sim/ngspice",
#endif
"../eeschema/ngspice",
"../lib/ngspice",
"../../lib/ngspice",
"lib/ngspice",
+17 -17
View File
@@ -73,10 +73,11 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
}
if( m_model.GetSpiceInfo().inlineTypeString != ""
&& m_model.GetType() != SIM_MODEL::TYPE::V ) // DC-only sources are already processed
&& m_model.GetType() != SIM_MODEL::TYPE::V // DC-only sources are already processed
&& m_model.GetType() != SIM_MODEL::TYPE::I )
{
std::string args = "";
switch( m_model.GetType() )
{
case SIM_MODEL::TYPE::V_PWL:
@@ -136,31 +137,30 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
args.append( getParamValueString( "tcapt", "0" ) + " " );
args.append( getParamValueString( "temit", "0" ) + " " );
break;
case SIM_MODEL::TYPE::V_RANDUNIFORM:
case SIM_MODEL::TYPE::I_RANDUNIFORM:
{
/* JEY TODO
args.append( "1 " );
args.append( getParamValueString( "dt", "0" ) + " " );
args.append( getParamValueString( "td", "0" ) + " " );
std::string min = getParamValueString( "min", "0" );
std::string max = getParamValueString( "max", "0" );
SIM_VALUE_FLOAT min = dynamic_cast<SIM_VALUE_FLOAT&>( m_model.FindParam( "max" )->value );
args.append( min + " " );
args.append( max + " " );
if( !min.ToString().empty() )
min.FromString( "0" );
double minVal = std::stod( min );
double maxVal = std::stod( max );
SIM_VALUE_FLOAT max = dynamic_cast<SIM_VALUE_FLOAT&>( m_model.FindParam( "min" )->value );
double rangeVal = maxVal - minVal;
double offsetVal = ( maxVal + minVal ) / 2;
if( !max.ToString().empty() )
max.FromString( "0" );
std::string range = std::to_string( rangeVal );
std::string offset = std::to_string( offsetVal );
SIM_VALUE_FLOAT range = max - min;
SIM_VALUE_FLOAT offset = ( max + min ) / SIM_VALUE_FLOAT( 2 );
args.append( range.ToSpiceString() + " " );
args.append( offset.ToSpiceString() + " " );
*/
args.append( range + " " );
args.append( offset + " " );
break;
}
@@ -790,7 +790,7 @@ std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SOURCE::makeWhiteNoiseParamInfos(
}
std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SOURCE::makePinkNoiseParamInfos( std::string aPrefix,
std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SOURCE::makePinkNoiseParamInfos( std::string aPrefix,
std::string aUnit )
{
std::vector<PARAM::INFO> paramInfos;
+19 -16
View File
@@ -92,29 +92,32 @@ bool SIM_STRING_PROPERTY::OnEvent( wxPropertyGrid* propgrid, wxWindow* wnd_prima
{
wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary );
if( textEntry )
wxCHECK( textEntry, false );
wxString oldStr = m_eval.OriginalText();
if( oldStr.length() && oldStr != textEntry->GetValue() )
{
wxString oldStr = m_eval.OriginalText();
if( oldStr.length() && oldStr != textEntry->GetValue() )
{
SetValueInEvent( oldStr );
textEntry->SetValue( oldStr );
}
m_needsEval = true;
return true;
SetValueInEvent( oldStr );
textEntry->SetValue( oldStr );
}
m_needsEval = true;
return true;
}
else if( event.GetEventType() == wxEVT_KILL_FOCUS && allowEval() )
{
wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary );
if( textEntry && m_eval.Process( textEntry->GetValue() ) )
wxCHECK( textEntry, false );
wxString strValue = textEntry->GetValue();
if( !strValue.IsEmpty() && m_eval.Process( strValue ) )
{
double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
if( isnan( value ) || SIM_VALUE::Equal( value, textEntry->GetValue().ToStdString() ) )
if( std::isnan( value ) || SIM_VALUE::Equal( value, strValue.ToStdString() ) )
{
// Don't mess up user formatting if eval'ing didn't actually change the value.
}
@@ -122,10 +125,10 @@ bool SIM_STRING_PROPERTY::OnEvent( wxPropertyGrid* propgrid, wxWindow* wnd_prima
{
SetValueInEvent( m_eval.Result() );
}
m_needsEval = false;
return true;
}
m_needsEval = false;
return true;
}
else if( event.GetEventType() == wxEVT_KEY_DOWN )
{
+4 -3
View File
@@ -193,9 +193,10 @@ namespace SPICE_GRAMMAR
spiceUnit>>> {};
struct modelUnit : sor<dotModelAko,
dotModel,
dotSubckt> {};
struct modelUnit : seq<star<commentLine>,
sor<dotModelAko,
dotModel,
dotSubckt>> {};
// Intentionally no if_must<>.
+5 -5
View File
@@ -170,7 +170,7 @@ SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
ReCreateVToolbar();
ReCreateOptToolbar();
updateTitle();
UpdateTitle();
UpdateSymbolMsgPanelInfo();
RebuildSymbolUnitsList();
@@ -558,7 +558,7 @@ bool SYMBOL_EDIT_FRAME::CanCloseSymbolFromSchematic( bool doClose )
if( doClose )
{
SetCurSymbol( nullptr, false );
updateTitle();
UpdateTitle();
}
return true;
@@ -849,7 +849,7 @@ void SYMBOL_EDIT_FRAME::OnModify()
m_treePane->GetLibTree()->RefreshLibTree();
if( !GetTitle().StartsWith( "*" ) )
updateTitle();
UpdateTitle();
}
@@ -1224,7 +1224,7 @@ void SYMBOL_EDIT_FRAME::ShowChangedLanguage()
GetCanvas()->Refresh();
}
updateTitle();
UpdateTitle();
}
@@ -1518,7 +1518,7 @@ void SYMBOL_EDIT_FRAME::LoadSymbolFromSchematic( SCH_SYMBOL* aSymbol )
OnToggleSymbolTree( evt );
}
updateTitle();
UpdateTitle();
RebuildSymbolUnitsList();
SetShowDeMorgan( GetCurSymbol()->HasConversion() );
UpdateSymbolMsgPanelInfo();
+6 -6
View File
@@ -247,6 +247,12 @@ public:
UpdateSymbolMsgPanelInfo();
}
/**
* Update the main window title bar with the current library name and read only status
* of the library.
*/
void UpdateTitle();
bool IsSymbolFromSchematic() const
{
// If we've already vetted closing this window, then we have no symbol anymore
@@ -427,12 +433,6 @@ private:
*/
bool saveLibrary( const wxString& aLibrary, bool aNewFile );
/**
* Update the main window title bar with the current library name and read only status
* of the library.
*/
void updateTitle();
/**
* Set the current active library to \a aLibrary.
*
+27 -18
View File
@@ -56,7 +56,7 @@ SYMBOL_SAVEAS_TYPE SYMBOL_LEGACYFILEDLG_SAVE_AS::m_option = SYMBOL_SAVEAS_TYPE::
#endif
void SYMBOL_EDIT_FRAME::updateTitle()
void SYMBOL_EDIT_FRAME::UpdateTitle()
{
wxString title;
@@ -98,7 +98,7 @@ void SYMBOL_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
if( !selectedLib.empty() )
SetCurLib( selectedLib );
updateTitle();
UpdateTitle();
}
@@ -124,14 +124,20 @@ bool SYMBOL_EDIT_FRAME::saveCurrentSymbol()
}
else
{
LIB_ID libId = GetCurSymbol()->GetLibId();
const wxString& libName = libId.GetLibNickname();
const wxString& symbolName = libId.GetLibItemName();
const wxString& libName = GetCurSymbol()->GetLibId().GetLibNickname();
if( m_libMgr->FlushSymbol( symbolName, libName ) )
if( m_libMgr->IsLibraryReadOnly( libName ) )
{
m_libMgr->ClearSymbolModified( symbolName, libName );
return true;
wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
libName );
wxString msg2 = _( "You must save to a different location." );
if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
return saveLibrary( libName, true );
}
else
{
return saveLibrary( libName, false );
}
}
}
@@ -298,7 +304,7 @@ bool SYMBOL_EDIT_FRAME::LoadOneLibrarySymbolAux( LIB_SYMBOL* aEntry, const wxStr
GetInfoBar()->Dismiss();
}
updateTitle();
UpdateTitle();
RebuildSymbolUnitsList();
SetShowDeMorgan( GetCurSymbol()->HasConversion() );
@@ -493,7 +499,7 @@ void SYMBOL_EDIT_FRAME::Save()
if( IsSymbolTreeShown() )
m_treePane->GetLibTree()->RefreshLibTree();
updateTitle();
UpdateTitle();
}
@@ -605,6 +611,7 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
LIB_ID old_lib_id = symbol->GetLibId();
wxString symbolName = old_lib_id.GetLibItemName();
wxString libraryName = old_lib_id.GetLibNickname();
bool valueFollowsName = symbol->GetValueField().GetText() == symbolName;
bool done = false;
std::unique_ptr<EDA_LIST_DIALOG> dlg;
@@ -677,6 +684,9 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
LIB_SYMBOL new_symbol( *symbol );
new_symbol.SetName( symbolName );
if( valueFollowsName )
new_symbol.GetValueField().SetText( symbolName );
m_libMgr->UpdateSymbol( &new_symbol, libraryName );
SyncLibraries( false );
m_treePane->GetLibTree()->SelectLibId( LIB_ID( libraryName, new_symbol.GetName() ) );
@@ -713,7 +723,7 @@ void SYMBOL_EDIT_FRAME::UpdateAfterSymbolProperties( wxString* aOldName )
RebuildSymbolUnitsList();
SetShowDeMorgan( GetCurSymbol()->Flatten()->HasConversion() );
updateTitle();
UpdateTitle();
// N.B. The view needs to be rebuilt first as the Symbol Properties change may invalidate
// the view pointers by rebuilting the field table
@@ -1179,12 +1189,7 @@ bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
{
// If saving under existing name fails then do a Save As..., and if that
// fails then cancel close action.
if( !m_libMgr->IsLibraryReadOnly( libNickname ) )
{
if( saveLibrary( libNickname, false ) )
continue;
}
else
if( m_libMgr->IsLibraryReadOnly( libNickname ) )
{
msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
msg2 = _( "You must save to a different location." );
@@ -1210,6 +1215,10 @@ bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
continue;
}
}
else if( saveLibrary( libNickname, false ) )
{
continue;
}
if( !saveLibrary( libNickname, true ) )
retv = false;
@@ -1217,7 +1226,7 @@ bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
}
}
updateTitle();
UpdateTitle();
return retv;
}
@@ -97,7 +97,7 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromRedoList()
RebuildSymbolUnitsList();
SetShowDeMorgan( symbol->HasConversion() );
updateTitle();
UpdateTitle();
RebuildView();
OnModify();
@@ -145,7 +145,7 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromUndoList()
RebuildSymbolUnitsList();
SetShowDeMorgan( symbol->HasConversion() );
updateTitle();
UpdateTitle();
RebuildView();
OnModify();
+2 -2
View File
@@ -884,8 +884,8 @@ void SYMBOL_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& event )
void SYMBOL_VIEWER_FRAME::SetSelectedLibrary( const wxString& aLibraryName,
const wxString& aSubLibName )
{
if( m_currentSymbol.GetUniStringLibNickname() == aLibraryName &&
wxString( m_currentSymbol.GetSubLibraryName() ) == aSubLibName )
if( m_currentSymbol.GetUniStringLibNickname() == aLibraryName
&& m_currentSymbol.GetSubLibraryName().wx_str() == aSubLibName )
return;
m_currentSymbol.SetLibNickname( aLibraryName );
+17 -20
View File
@@ -1127,6 +1127,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
}
SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( item );
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
@@ -1134,36 +1135,32 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
{
dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos );
}
else if( text )
else if( field )
{
if( SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( text ) )
BOX2I box = field->GetBoundingBox();
EDA_ANGLE orient = field->GetTextAngle();
if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
{
if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
if( static_cast<SCH_SYMBOL*>( field->GetParent() )->GetTransform().y1 )
{
symbol = static_cast<SCH_SYMBOL*>( field->GetParent() );
VECTOR2I relPos = pos - symbol->GetPosition();
relPos = symbol->GetTransform().InverseTransform().TransformCoordinate( relPos );
pos = relPos + symbol->GetPosition();
poss = SEG( pos, pos );
if( orient.IsHorizontal() )
orient = ANGLE_VERTICAL;
else
orient = ANGLE_HORIZONTAL;
}
}
field->GetEffectiveTextShape( false, box, orient )->Collide( poss, INT_MAX / 2,
&dist );
}
else if( text )
{
text->GetEffectiveTextShape( false )->Collide( poss, INT_MAX / 2, &dist );
}
else if( symbol )
{
try
{
bbox = symbol->GetBodyBoundingBox();
}
catch( const boost::bad_pointer& exc )
{
// This may be overkill and could be an assertion but we are more likely to
// find any boost pointer container errors this way.
wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
}
bbox = symbol->GetBodyBoundingBox();
SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
+12 -19
View File
@@ -355,41 +355,34 @@ int SYMBOL_EDITOR_CONTROL::RenameSymbol( const TOOL_EVENT& aEvent )
}
wxString oldName = symbolName;
LIB_SYMBOL* libSymbol = nullptr;
LIB_SYMBOL* libSymbol = libMgr.GetBufferedSymbol( oldName, libName );
bool isCurrentSymbol = editFrame->IsCurrentSymbol( libId );
if( editFrame->IsCurrentSymbol( libId ) )
{
// Update buffered copy
libSymbol = libMgr.GetBufferedSymbol( oldName, libName );
libSymbol->SetName( newName );
libSymbol->SetName( newName );
if( libSymbol->GetFieldById( VALUE_FIELD )->GetText() == oldName )
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
libMgr.UpdateSymbolAfterRename( libSymbol, newName, libName );
libMgr.UpdateSymbolAfterRename( libSymbol, newName, libName );
libMgr.SetSymbolModified( newName, libName );
// Now update canvasy copy
if( isCurrentSymbol )
{
libSymbol = editFrame->GetCurSymbol();
libSymbol->SetName( newName );
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
if( libSymbol->GetFieldById( VALUE_FIELD )->GetText() == oldName )
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
editFrame->RebuildView();
editFrame->OnModify();
editFrame->UpdateTitle();
// N.B. The view needs to be rebuilt first as the Symbol Properties change may
// invalidate the view pointers by rebuilting the field table
editFrame->UpdateMsgPanel();
}
else
{
libSymbol = libMgr.GetBufferedSymbol( oldName, libName );
libSymbol->SetName( newName );
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
libMgr.UpdateSymbolAfterRename( libSymbol, newName, libName );
libMgr.SetSymbolModified( newName, libName );
}
wxDataViewItem treeItem = libMgr.GetAdapter()->FindItem( libId );
editFrame->UpdateLibraryTree( treeItem, libSymbol );
+13 -13
View File
@@ -199,24 +199,24 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFileName )
* Now (2014) Ucamco (the company which manages the Gerber format) encourages use of .gbr
* only and the Gerber X2 file format.
*/
filetypes = _( "Gerber files" ) + AddFileExtListToFilter( { "G*", "PHO" } ) + wxT( "|" );
filetypes = _( "Gerber files" ) + AddFileExtListToFilter( { "g*", "pho" } ) + wxT( "|" );
/* Special gerber filetypes */
filetypes += _( "Top layer" ) + AddFileExtListToFilter( { "GTL" } ) + wxT( "|" );
filetypes += _( "Bottom layer" ) + AddFileExtListToFilter( { "GBL" } ) + wxT( "|" );
filetypes += _( "Bottom solder resist" ) + AddFileExtListToFilter( { "GBS" } ) + wxT( "|" );
filetypes += _( "Top solder resist" ) + AddFileExtListToFilter( { "GTS" } ) + wxT( "|" );
filetypes += _( "Bottom overlay" ) + AddFileExtListToFilter( { "GBO" } ) + wxT( "|" );
filetypes += _( "Top overlay" ) + AddFileExtListToFilter( { "GTO" } ) + wxT( "|" );
filetypes += _( "Bottom paste" ) + AddFileExtListToFilter( { "GBP" } ) + wxT( "|" );
filetypes += _( "Top paste" ) + AddFileExtListToFilter( { "GTP" } ) + wxT( "|" );
filetypes += _( "Keep-out layer" ) + AddFileExtListToFilter( { "GKO" } ) + wxT( "|" );
filetypes += _( "Top layer" ) + AddFileExtListToFilter( { "gtl" } ) + wxT( "|" );
filetypes += _( "Bottom layer" ) + AddFileExtListToFilter( { "gbl" } ) + wxT( "|" );
filetypes += _( "Bottom solder resist" ) + AddFileExtListToFilter( { "gbs" } ) + wxT( "|" );
filetypes += _( "Top solder resist" ) + AddFileExtListToFilter( { "gts" } ) + wxT( "|" );
filetypes += _( "Bottom overlay" ) + AddFileExtListToFilter( { "gbo" } ) + wxT( "|" );
filetypes += _( "Top overlay" ) + AddFileExtListToFilter( { "gto" } ) + wxT( "|" );
filetypes += _( "Bottom paste" ) + AddFileExtListToFilter( { "gbp" } ) + wxT( "|" );
filetypes += _( "Top paste" ) + AddFileExtListToFilter( { "gtp" } ) + wxT( "|" );
filetypes += _( "Keep-out layer" ) + AddFileExtListToFilter( { "gko" } ) + wxT( "|" );
filetypes += _( "Mechanical layers" )
+ AddFileExtListToFilter(
{ "GM1", "GM2", "GM3", "GM4", "GM5", "GM6", "GM7", "GM8", "GM9" } )
{ "gm1", "gm2", "gm3", "gm4", "gm5", "gm6", "gm7", "gm8", "gm9" } )
+ wxT( "|" );
filetypes += _( "Top Pad Master" ) + AddFileExtListToFilter( { "GPT" } ) + wxT( "|" );
filetypes += _( "Bottom Pad Master" ) + AddFileExtListToFilter( { "GPB" } ) + wxT( "|" );
filetypes += _( "Top Pad Master" ) + AddFileExtListToFilter( { "gpt" } ) + wxT( "|" );
filetypes += _( "Bottom Pad Master" ) + AddFileExtListToFilter( { "gpb" } ) + wxT( "|" );
// All filetypes
filetypes += AllFilesWildcard();
+1 -1
View File
@@ -86,7 +86,7 @@ protected:
* Display a dialog indicating the file is already open, with an option to reset the lock.
* @return true if the lock was reset.
*/
bool OverrideLock( wxWindow* aParent, const wxString& aMessage );
bool AskOverrideLock( wxWindow* aParent, const wxString& aMessage );
/**
+2 -1
View File
@@ -238,7 +238,8 @@ public:
* false to build a list of shape for a not rotated text ("native" shapes).
*/
std::shared_ptr<SHAPE_COMPOUND> GetEffectiveTextShape( bool aTriangulate = true,
bool aUseTextRotation = true ) const;
const BOX2I& aBBox = BOX2I(),
const EDA_ANGLE& aAngle = ANGLE_0 ) const;
/**
* Test if \a aPoint is within the bounds of this object.
+5
View File
@@ -207,6 +207,11 @@ public:
return true;
}
bool IsLockedByMe()
{
return m_username == wxGetUserId() && m_hostname == wxGetHostName();
}
/**
* @return Current username. If we own the lock, this is us. Otherwise, this is the user that does own it
*/
+13 -1
View File
@@ -38,11 +38,11 @@
#include <search_stack.h>
#include <settings/environment.h>
#include <wx/filename.h>
#include <wx/snglinst.h>
#undef pid_t
#include <pybind11/embed.h>
class wxSingleInstanceChecker;
class wxApp;
class wxMenu;
class wxWindow;
@@ -313,6 +313,14 @@ public:
*/
bool IsGUI();
/**
* Allows access to the wxSingleInstanceChecker to test for other running KiCads
*/
std::unique_ptr<wxSingleInstanceChecker>& SingleInstance()
{
return m_pgm_checker;
}
/**
* wxWidgets on MSW tends to crash if you spool up more than one print job at a time.
*/
@@ -347,6 +355,10 @@ protected:
std::unique_ptr<SCRIPTING> m_python_scripting;
/// Checks if there is another copy of Kicad running at the same time
std::unique_ptr<wxSingleInstanceChecker> m_pgm_checker;
wxString m_bin_dir; /// full path to this program
wxString m_kicad_env; /// The KICAD system environment variable.
+10 -4
View File
@@ -550,13 +550,19 @@ public:
protected:
/**
* Generic fallback: arc rendered as a polyline.
* Note also aCentre and aRadius are double to avoid creating rounding issues due
* to the fact a arc is defined in Kicad by a start point, a end point and third point
* not angles and radius.
* In some plotters (i.e. dxf) whe need a good precision when calculating an arc
* without error introduced by rounding, to avoid moving the end points,
* usually important in outlines when plotting an arc given by center, radius and angles
*/
virtual void Arc( const VECTOR2I& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill,
virtual void Arc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH );
virtual void ThickArc( const VECTOR2I& aCentre, const EDA_ANGLE& StAngle,
const EDA_ANGLE& EndAngle, int aRadius, int aWidth,
virtual void ThickArc( const VECTOR2D& aCentre, const EDA_ANGLE& StAngle,
const EDA_ANGLE& EndAngle, double aRadius, int aWidth,
OUTLINE_MODE aTraceMode, void* aData );
// These are marker subcomponents
+2 -2
View File
@@ -211,8 +211,8 @@ public:
}
protected:
virtual void Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill,
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
void plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
+4 -4
View File
@@ -272,12 +272,12 @@ public:
APERTURE::APERTURE_TYPE aType, int aApertureAttribute );
protected:
virtual void Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill,
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
virtual void ThickArc( const VECTOR2I& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
virtual void ThickArc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
OUTLINE_MODE aTraceMode, void* aData ) override;
/**
+2 -2
View File
@@ -145,8 +145,8 @@ protected:
* aEndAngle is end angle the arc.
* Radius is the radius of the arc.
*/
virtual void Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill,
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
/**
+4 -4
View File
@@ -422,8 +422,8 @@ protected:
OUTLINE_NODE* addOutlineNode( OUTLINE_NODE* aParent, int aActionHandle,
const wxString& aTitle );
virtual void Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius,
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius,
FILL_T aFill, int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
/// convert a wxString unicode string to a char string compatible with the accepted
@@ -623,8 +623,8 @@ public:
void* aData = nullptr ) override;
protected:
virtual void Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, int aRadius,
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius,
FILL_T aFill, int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
/**
+5 -1
View File
@@ -136,6 +136,7 @@ struct LAYER_PRESET
layers = LSET::AllLayersMask();
renderLayers = GAL_SET::DefaultVisible();
readOnly = false;
flipBoard = false;
}
LAYER_PRESET( const wxString& aName, const LSET& aVisibleLayers ) :
@@ -145,6 +146,7 @@ struct LAYER_PRESET
{
renderLayers = GAL_SET::DefaultVisible();
readOnly = false;
flipBoard = false;
}
LAYER_PRESET( const wxString& aName, const LSET& aVisibleLayers, const GAL_SET& aVisibleObjects,
@@ -154,7 +156,8 @@ struct LAYER_PRESET
renderLayers( aVisibleObjects ),
activeLayer( aActiveLayer )
{
readOnly = false;
readOnly = false;
flipBoard = false;
}
bool LayersMatch( const LAYER_PRESET& aOther )
@@ -165,6 +168,7 @@ struct LAYER_PRESET
wxString name; ///< A name for this layer set
LSET layers; ///< Board layers that are visible
GAL_SET renderLayers; ///< Render layers (e.g. object types) that are visible
bool flipBoard; ///< True if the flip board is enabled
PCB_LAYER_ID activeLayer; ///< Optional layer to set active when this preset is loaded
bool readOnly; ///< True if this is a read-only (built-in) preset
};
+2 -1
View File
@@ -45,7 +45,8 @@ typedef std::pair<KIID, wxString> FILE_INFO_PAIR;
*/
enum LAST_PATH_TYPE : unsigned int
{
LAST_PATH_NETLIST = 0,
LAST_PATH_FIRST = 0,
LAST_PATH_NETLIST = LAST_PATH_FIRST,
LAST_PATH_STEP,
LAST_PATH_IDF,
LAST_PATH_VRML,
+4
View File
@@ -184,6 +184,10 @@ DIALOG_PCM::DIALOG_PCM( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER
DIALOG_PCM::~DIALOG_PCM()
{
Unbind( wxEVT_CLOSE_WINDOW, &DIALOG_PCM::OnCloseWindow, this );
m_sdbSizer1Cancel->Unbind( wxEVT_UPDATE_UI, &DIALOG_PCM::OnUpdateEventButtons, this );
m_sdbSizer1Apply->Unbind( wxEVT_UPDATE_UI, &DIALOG_PCM::OnUpdateEventButtons, this );
m_pcm->SaveInstalledPackages();
m_pcm->SetDialogWindow( nullptr );
m_pcm->RunBackgroundUpdate();
+6 -4
View File
@@ -428,8 +428,9 @@ const bool PLUGIN_CONTENT_MANAGER::CacheRepository( const wxString& aRepositoryI
wxString url = std::get<2>( *repository_tuple );
nlohmann::json js;
PCM_REPOSITORY current_repo;
nlohmann::json js;
PCM_REPOSITORY current_repo;
PCM_REPOSITORY& current_repo_ref = current_repo;
std::shared_ptr<PROGRESS_REPORTER> reporter;
@@ -522,12 +523,13 @@ const bool PLUGIN_CONTENT_MANAGER::CacheRepository( const wxString& aRepositoryI
packages_cache_stream << std::setw( 4 ) << js << std::endl;
m_repository_cache[aRepositoryId] = std::move( current_repo );
current_repo_ref = m_repository_cache[aRepositoryId];
}
if( current_repo.resources )
if( current_repo_ref.resources )
{
// Check resources file date, redownload if needed
PCM_RESOURCE_REFERENCE& resources = *current_repo.resources;
PCM_RESOURCE_REFERENCE& resources = *current_repo_ref.resources;
wxFileName resource_file( repo_cache.GetPath(), wxT( "resources.zip" ) );
+3 -2
View File
@@ -123,10 +123,11 @@ bool PROJECT_TREE_ITEM::Rename( const wxString& name, bool check )
if( newFile == GetFileName() )
return false;
// If required, prompt the user if the filename extension has changed:
wxString ext = PROJECT_TREE_PANE::GetFileExt( GetType() );
wxRegEx reg( wxT( "^.*\\" ) + ext + wxT( "$" ), wxRE_ICASE );
wxString full_ext = wxT( "." ) + ext;
if( check && !ext.IsEmpty() && !reg.Matches( newFile ) )
if( check && !ext.IsEmpty() && !newFile.Lower().EndsWith( full_ext.Lower() ) )
{
wxMessageDialog dialog( m_parent, _( "Changing file extension will change file type.\n"
"Do you want to continue ?" ),
@@ -40,7 +40,7 @@
* or inside of the curve? (Generally speaking filled shape errors go on the inside
* and knockout errors go on the outside. This preserves minimum clearances.)
*/
enum ERROR_LOC { ERROR_OUTSIDE, ERROR_INSIDE };
enum ERROR_LOC { ERROR_OUTSIDE = 0, ERROR_INSIDE };
/**
* @return the number of segments to approximate a arc by segments
+2 -2
View File
@@ -3,7 +3,7 @@
*
* Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
* Copyright (C) CERN
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@@ -58,7 +58,7 @@ void kimathLogDebug( const char* aFormatString, ... )
void kimathLogOverflow( double v, const char* aTypeName )
{
wxString typeName( aTypeName );
wxLogWarning( wxString::Format( wxT( "Overflow converting value %f to %s." ), v, typeName ) );
wxFAIL_MSG( wxString::Format( wxT( "\n\nOverflow converting value %f to %s." ), v, typeName ) );
}
+6 -4
View File
@@ -5,6 +5,7 @@
* Copyright (C) 2002 Claudio Girardi <claudio.girardi@ieee.org>
* Copyright (C) 2005, 2006 Stefan Jahn <stefan@lkcc.org>
* Modified for Kicad: 2018 Jean-Pierre Charras <jp.charras at wanadoo.fr>
* Copyright (C) 1992-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
@@ -516,18 +517,19 @@ void MICROSTRIP::showAnalyze()
*/
void MICROSTRIP::calcSynthesize()
{
double const er_eff = m_parameters[EPSILON_EFF_PRM];
double angl_dest, z0_dest;
z0_dest = m_parameters[Z0_PRM];
angl_dest = m_parameters[ANG_L_PRM];
double z0_dest = m_parameters[Z0_PRM];
double angl_dest = m_parameters[ANG_L_PRM];
/* calculate width and use for initial value in Newton's method */
m_parameters[PHYS_WIDTH_PRM] = synth_width();
minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) );
m_parameters[Z0_PRM] = z0_dest;
m_parameters[ANG_L_PRM] = angl_dest;
double const er_eff = m_parameters[EPSILON_EFF_PRM];
m_parameters[PHYS_LEN_PRM] = C0 / m_parameters[FREQUENCY_PRM] / sqrt( er_eff * mur_eff )
* m_parameters[ANG_L_PRM] / 2.0 / M_PI; /* in m */
calcAnalyze();
m_parameters[Z0_PRM] = z0_dest;
m_parameters[ANG_L_PRM] = angl_dest;
m_parameters[PHYS_LEN_PRM] = C0 / m_parameters[FREQUENCY_PRM] / sqrt( er_eff * mur_eff )
+6 -3
View File
@@ -30,6 +30,9 @@
#include "stripline.h"
#include "units.h"
// const to convert a attenuation / loss from log to decibel
const double LOG2DB = 20.0 / log( 10.0 );
STRIPLINE::STRIPLINE() : TRANSLINE()
{
m_Name = "StripLine";
@@ -38,7 +41,7 @@ STRIPLINE::STRIPLINE() : TRANSLINE()
// -------------------------------------------------------------------
// calculate characteristic impedance and conductor loss
// calculate characteristic impedance and conductor loss (in log/meter)
double STRIPLINE::lineImpedance( double height, double& ac )
{
double ZL;
@@ -95,8 +98,8 @@ void STRIPLINE::calcAnalyze()
m_parameters[Z0_PRM] = 2.0
/ ( 1.0 / lineImpedance( 2.0 * a + t, ac1 )
+ 1.0 / lineImpedance( 2.0 * ( h - a ) - t, ac2 ) );
m_parameters[LOSS_CONDUCTOR_PRM] = m_parameters[PHYS_LEN_PRM] * 0.5 * ( ac1 + ac2 );
m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM]
m_parameters[LOSS_CONDUCTOR_PRM] = LOG2DB * m_parameters[PHYS_LEN_PRM] * ( ac1 + ac2 );
m_parameters[LOSS_DIELECTRIC_PRM] = LOG2DB * m_parameters[PHYS_LEN_PRM]
* ( M_PI / C0 ) * m_parameters[FREQUENCY_PRM]
* sqrt( m_parameters[EPSILONR_PRM] )
* m_parameters[TAND_PRM];
+13 -10
View File
@@ -97,15 +97,18 @@ BOARD::BOARD() :
m_layers[layer].m_type = LT_UNDEFINED;
}
m_SolderMask = new ZONE( this );
m_SolderMask->SetLayerSet( LSET().set( F_Mask ).set( B_Mask ) );
// Creates a zone to show sloder mask bridges created by a min web value
// it it just to show them
m_SolderMaskBridges = new ZONE( this );
m_SolderMaskBridges->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::INVISIBLE_BORDER );
m_SolderMaskBridges->SetLayerSet( LSET().set( F_Mask ).set( B_Mask ) );
int infinity = ( std::numeric_limits<int>::max() / 2 ) - pcbIUScale.mmToIU( 1 );
m_SolderMask->Outline()->NewOutline();
m_SolderMask->Outline()->Append( VECTOR2I( -infinity, -infinity ) );
m_SolderMask->Outline()->Append( VECTOR2I( -infinity, +infinity ) );
m_SolderMask->Outline()->Append( VECTOR2I( +infinity, +infinity ) );
m_SolderMask->Outline()->Append( VECTOR2I( +infinity, -infinity ) );
m_SolderMask->SetMinThickness( 0 );
m_SolderMaskBridges->Outline()->NewOutline();
m_SolderMaskBridges->Outline()->Append( VECTOR2I( -infinity, -infinity ) );
m_SolderMaskBridges->Outline()->Append( VECTOR2I( -infinity, +infinity ) );
m_SolderMaskBridges->Outline()->Append( VECTOR2I( +infinity, +infinity ) );
m_SolderMaskBridges->Outline()->Append( VECTOR2I( +infinity, -infinity ) );
m_SolderMaskBridges->SetMinThickness( 0 );
BOARD_DESIGN_SETTINGS& bds = GetDesignSettings();
@@ -141,7 +144,7 @@ BOARD::~BOARD()
m_zones.clear();
delete m_SolderMask;
delete m_SolderMaskBridges;
for( FOOTPRINT* footprint : m_footprints )
delete footprint;
@@ -1916,7 +1919,7 @@ std::tuple<int, double, double> BOARD::GetTrackLength( const PCB_TRACK& aTrack )
VECTOR2I loc;
// We may not collide even if we passed the bounding-box hit test
if( pad->GetEffectivePolygon()->Collide( trackSeg, 0, nullptr, &loc ) )
if( pad->GetEffectivePolygon( ERROR_INSIDE )->Collide( trackSeg, 0, nullptr, &loc ) )
{
// Part 1: length of the seg to the intersection with the pad poly
if( hitStart )
+1 -1
View File
@@ -1193,7 +1193,7 @@ public:
std::vector<ZONE*> m_DRCCopperZones;
int m_DRCMaxClearance;
int m_DRCMaxPhysicalClearance;
ZONE* m_SolderMask;
ZONE* m_SolderMaskBridges; // A container to build bridges on solder mask layers
std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> m_ZoneIsolatedIslandsMap;
private:
+1 -1
View File
@@ -448,7 +448,7 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i
if( zone->IsFilled() )
{
const SHAPE_POLY_SET* zoneFill = zone->GetFill( ToLAYER_ID( aLayer ) );
const SHAPE_LINE_CHAIN& padHull = pad->GetEffectivePolygon()->Outline( 0 );
const SHAPE_LINE_CHAIN& padHull = pad->GetEffectivePolygon( ERROR_INSIDE )->Outline( 0 );
for( const VECTOR2I& pt : zoneFill->COutline( islandIdx ).CPoints() )
{
+2 -1
View File
@@ -140,7 +140,8 @@ bool isCopperOutside( const FOOTPRINT* aFootprint, SHAPE_POLY_SET& aShape )
{
SHAPE_POLY_SET poly = aShape.CloneDropTriangulation();
poly.BooleanIntersection( *pad->GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST );
poly.BooleanIntersection( *pad->GetEffectivePolygon( ERROR_INSIDE ),
SHAPE_POLY_SET::PM_FAST );
if( poly.OutlineCount() == 0 )
{
+1
View File
@@ -294,6 +294,7 @@ bool DIALOG_COPPER_ZONE::TransferDataToWindow()
case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: m_OutlineDisplayCtrl->SetSelection( 0 ); break;
case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: m_OutlineDisplayCtrl->SetSelection( 1 ); break;
case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: m_OutlineDisplayCtrl->SetSelection( 2 ); break;
case ZONE_BORDER_DISPLAY_STYLE::INVISIBLE_BORDER: break; // Not used for standard zones
}
m_outlineHatchPitch.SetValue( m_settings.m_BorderHatchPitch );
@@ -178,6 +178,7 @@ bool DIALOG_NON_COPPER_ZONES_EDITOR::TransferDataToWindow()
case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: m_OutlineDisplayCtrl->SetSelection( 0 ); break;
case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: m_OutlineDisplayCtrl->SetSelection( 1 ); break;
case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: m_OutlineDisplayCtrl->SetSelection( 2 ); break;
case ZONE_BORDER_DISPLAY_STYLE::INVISIBLE_BORDER: break; // Not used for standard zones
}
m_outlineHatchPitch.SetValue( m_settings.m_BorderHatchPitch );
@@ -156,6 +156,7 @@ bool DIALOG_RULE_AREA_PROPERTIES::TransferDataToWindow()
switch( m_zonesettings.m_ZoneBorderDisplayStyle )
{
case ZONE_BORDER_DISPLAY_STYLE::INVISIBLE_BORDER: // Not used for standard zones. Here use NO_HATCH
case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: m_OutlineDisplayCtrl->SetSelection( 0 ); break;
case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: m_OutlineDisplayCtrl->SetSelection( 1 ); break;
case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: m_OutlineDisplayCtrl->SetSelection( 2 ); break;
+8 -5
View File
@@ -29,6 +29,8 @@
#include <core/kicad_algo.h>
#include <pcbnew.h>
#include <pcb_edit_frame.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <board.h>
#include <collectors.h>
#include <footprint.h>
@@ -486,6 +488,8 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
if( !removedLayers.empty() )
{
m_frame->GetToolManager()->RunAction( PCB_ACTIONS::selectionClear );
PCB_LAYER_COLLECTOR collector;
for( PCB_LAYER_ID layer_id : removedLayers )
@@ -545,11 +549,10 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
}
}
for( PCB_TRACK* via : m_pcb->Tracks() )
{
if( via->HasHole() )
via->SetLayerSet( via->GetLayerSet() | LSET::InternalCuMask() );
}
// Tracks do not change their layer
// Vias layers are defined by the starting layer and the ending layer, so
// they are not modified by adding a layer.
// So do nothing for tracks/vias
modified = true;
}
@@ -741,7 +741,8 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
for( auto& [ zone, rtree ] : board->m_CopperZoneRTreeCache )
{
if( !rtree->GetObjectsAt( location, aLayer, aMinWidth ).empty()
if( rtree
&& !rtree->GetObjectsAt( location, aLayer, aMinWidth ).empty()
&& zone->HitTestFilledArea( aLayer, location, aMinWidth ) )
{
contributingItems.push_back( zone );
@@ -948,6 +948,9 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( )
auto testGraphicAgainstZone =
[&]( BOARD_ITEM* item )
{
if( item->Type() == PCB_BITMAP_T )
return;
if( !IsCopperLayer( item->GetLayer() ) )
return;
@@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021-2022 KiCad Developers.
* Copyright (C) 2021-2023 KiCad Developers.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -216,9 +216,11 @@ bool shapesNeedUpdate( const FP_SHAPE* a, const FP_SHAPE* b )
TEST( a->GetStart0(), b->GetStart0() );
TEST( a->GetEnd0(), b->GetEnd0() );
// Arc center is calculated and so may have round-off errors when parents are
// differentially rotated.
if( ( a->GetCenter0() - b->GetCenter0() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0001 ) )
// Arc center is calculated to the nearest 100nm increment and may have round-off errors
// when parents are differentially rotated. See CalcArcCenter() function in
// ./libs/kimath/src/trigo.cpp.
if( ( std::abs( a->GetCenter0().x - b->GetCenter0().x ) > pcbIUScale.mmToIU( 0.0002 ) ) ||
( std::abs( a->GetCenter0().y - b->GetCenter0().y ) > pcbIUScale.mmToIU( 0.0002 ) ) )
return true;
break;
+2 -2
View File
@@ -112,7 +112,7 @@ private:
void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* aItem )
{
ZONE* solderMask = m_board->m_SolderMask;
ZONE* solderMask = m_board->m_SolderMaskBridges;
if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
{
@@ -207,7 +207,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* aItem )
void DRC_TEST_PROVIDER_SOLDER_MASK::buildRTrees()
{
ZONE* solderMask = m_board->m_SolderMask;
ZONE* solderMask = m_board->m_SolderMaskBridges;
LSET layers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
const size_t progressDelta = 500;
+34 -3
View File
@@ -55,9 +55,31 @@ inline double diameter_in_mm( double ius )
// return a pen size to plot markers and having a readable shape
inline int getMarkerBestPenSize( int aMarkerDiameter )
// clamped to be >= MIN_SIZE_MM to avoid too small line width
static int getMarkerBestPenSize( int aMarkerDiameter )
{
return aMarkerDiameter / 10;
int bestsize = aMarkerDiameter / 10;
const double MIN_SIZE_MM = 0.1;
bestsize = std::max( bestsize, pcbIUScale.mmToIU( MIN_SIZE_MM ) );
return bestsize;
}
// return a pen size to plot outlines for oval holes
inline int getSketchOvalBestPenSize()
{
const double SKETCH_LINE_WIDTH_MM = 0.1;
return pcbIUScale.mmToIU( SKETCH_LINE_WIDTH_MM );
}
// return a default pen size to plot items with no specific line thickness
inline int getDefaultPenSize()
{
const double DEFAULT_LINE_WIDTH_MM = 0.2;
return pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH_MM );
}
@@ -171,7 +193,7 @@ bool GENDRILL_WRITER_BASE::genDrillMapFile( const wxString& aFullFileName, PLOT_
plotter->SetColorMode( false );
KIGFX::PCB_RENDER_SETTINGS renderSettings;
renderSettings.SetDefaultPenWidth( pcbIUScale.mmToIU( 0.2 ) );
renderSettings.SetDefaultPenWidth( getDefaultPenSize() );
plotter->SetRenderSettings( &renderSettings );
@@ -474,7 +496,16 @@ bool GENDRILL_WRITER_BASE::plotDrillMarks( PLOTTER* aPlotter )
aPlotter->Marker( pos, hole.m_Hole_Diameter, hole.m_Tool_Reference - 1 );
if( hole.m_Hole_Shape != 0 )
{
aPlotter->SetCurrentLineWidth( getSketchOvalBestPenSize() );
// FlashPadOval uses also the render settings default pen size, so we need
// to initialize it:
KIGFX::RENDER_SETTINGS* renderSettings = aPlotter->RenderSettings();
int curr_default_pensize = renderSettings->GetDefaultPenWidth();
renderSettings->SetDefaultPenWidth( getSketchOvalBestPenSize() );
aPlotter->FlashPadOval( pos, hole.m_Hole_Size, hole.m_Hole_Orient, SKETCH, nullptr );
renderSettings->SetDefaultPenWidth( curr_default_pensize );
}
}
aPlotter->SetCurrentLineWidth( -1 );
+10 -9
View File
@@ -132,6 +132,7 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
brd_plotter.SetLayerSet( LSET( aLayer ) );
int cmp_count = 0;
bool allowUtf8 = true;
const bool quoteOption = false;
// Plot components data: position, outlines, pad1 and other pads.
for( FOOTPRINT* footprint : fp_list )
@@ -141,9 +142,9 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CMP_POSITION );
// Add object attribute: component reference to flash (mainly useful for users)
// using quoted UTF8 string
// using not quoted UTF8 string
wxString ref = ConvertNotAllowedCharsInGerber( footprint->Reference().GetShownText( false ),
allowUtf8, true );
allowUtf8, quoteOption );
gbr_metadata.SetCmpReference( ref );
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
@@ -164,15 +165,15 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
// Add component value info:
pnpAttrib.m_Value = ConvertNotAllowedCharsInGerber( footprint->Value().GetShownText( false ),
allowUtf8, true );
allowUtf8, quoteOption );
// Add component footprint info:
wxString fp_info = FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
pnpAttrib.m_Footprint = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
pnpAttrib.m_Footprint = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, quoteOption );
// Add footprint lib name:
fp_info = FROM_UTF8( footprint->GetFPID().GetLibNickname().c_str() );
pnpAttrib.m_LibraryName = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
pnpAttrib.m_LibraryName = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, quoteOption );
gbr_metadata.m_NetlistMetadata.SetExtraData( pnpAttrib.FormatCmpPnPMetadata() );
@@ -247,9 +248,9 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
gbr_metadata.SetApertureAttrib(
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_PAD1_POSITION );
gbr_metadata.SetPadName( pad1->GetNumber(), allowUtf8, true );
gbr_metadata.SetPadName( pad1->GetNumber(), allowUtf8, quoteOption );
gbr_metadata.SetPadPinFunction( pad1->GetPinFunction(), allowUtf8, true );
gbr_metadata.SetPadPinFunction( pad1->GetPinFunction(), allowUtf8, quoteOption );
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_PAD );
@@ -286,9 +287,9 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER
if( !pad->IsOnLayer( aLayer ) )
continue;
gbr_metadata.SetPadName( pad->GetNumber(), allowUtf8, true );
gbr_metadata.SetPadName( pad->GetNumber(), allowUtf8, quoteOption );
gbr_metadata.SetPadPinFunction( pad->GetPinFunction(), allowUtf8, true );
gbr_metadata.SetPadPinFunction( pad->GetPinFunction(), allowUtf8, quoteOption );
// Flashes a round, 0 sized round shape at pad position
plotter.FlashPadCircle( pad->GetPosition(), other_pads_mark_size, FILLED,
+1
View File
@@ -322,6 +322,7 @@ void EXPORTER_STEP::determinePcbThickness()
break;
case BS_ITEM_TYPE_COPPER:
case BS_ITEM_TYPE_SOLDERMASK:
if( item->IsEnabled() )
thickness += item->GetThickness();
+14 -2
View File
@@ -53,6 +53,7 @@
#include <widgets/wx_progress_reporters.h>
#include <settings/settings_manager.h>
#include <paths.h>
#include <pgm_base.h>
#include <project/project_file.h>
#include <project/project_local_settings.h>
#include <project/net_settings.h>
@@ -611,12 +612,23 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
std::unique_ptr<LOCKFILE> lock = std::make_unique<LOCKFILE>( fullFileName );
if( !lock->Locked() )
if( !lock->Valid() && lock->IsLockedByMe() )
{
// If we cannot acquire the lock but we appear to be the one who
// locked it, check to see if there is another KiCad instance running.
// If there is not, then we can override the lock. This could happen if
// KiCad crashed or was interrupted
if( !Pgm().SingleInstance()->IsAnotherRunning() )
lock->OverrideLock();
}
if( !lock->Valid() )
{
msg.Printf( _( "PCB '%s' is already open by '%s' at '%s'." ), wx_filename.GetFullName(),
lock->GetUsername(), lock->GetHostname() );
if( !OverrideLock( this, msg ) )
if( !AskOverrideLock( this, msg ) )
return false;
lock->OverrideLock();
+125 -6
View File
@@ -947,6 +947,51 @@ const BOX2I FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisible
}
const BOX2I FOOTPRINT::GetLayerBoundingBox( LSET aLayers ) const
{
std::vector<PCB_TEXT*> texts;
const BOARD* board = GetBoard();
bool isFPEdit = board && board->IsFootprintHolder();
// Start with an uninitialized bounding box
BOX2I bbox;
for( BOARD_ITEM* item : m_drawings )
{
if( m_privateLayers.test( item->GetLayer() ) && !isFPEdit )
continue;
if( ( aLayers & item->GetLayerSet() ).none() )
continue;
// We want the bitmap bounding box just in the footprint editor
// so it will start with the correct initial zoom
if( item->Type() == PCB_BITMAP_T && !isFPEdit )
continue;
bbox.Merge( item->GetBoundingBox() );
}
for( PAD* pad : m_pads )
{
if( ( aLayers & pad->GetLayerSet() ).none() )
continue;
bbox.Merge( pad->GetBoundingBox() );
}
for( ZONE* zone : m_fp_zones )
{
if( ( aLayers & zone->GetLayerSet() ).none() )
continue;
bbox.Merge( zone->GetBoundingBox() );
}
return bbox;
}
SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const
{
const BOARD* board = GetBoard();
@@ -1103,23 +1148,97 @@ void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_I
bool FOOTPRINT::IsOnLayer( PCB_LAYER_ID aLayer ) const
{
// If we have any pads, fall back on normal checking
if( !m_pads.empty() )
return m_layer == aLayer;
for( PAD* pad : m_pads )
{
if( pad->IsOnLayer( aLayer ) )
return true;
}
// No pads? Check if this entire footprint exists on the given layer
for( FP_ZONE* zone : m_fp_zones )
{
if( !zone->IsOnLayer( aLayer ) )
return false;
if( zone->IsOnLayer( aLayer ) )
return true;
}
if( m_reference->IsOnLayer( aLayer ) || m_value->IsOnLayer( aLayer ) )
return true;
for( BOARD_ITEM* item : m_drawings )
{
if( item->IsOnLayer( aLayer ) )
return true;
}
return false;
}
bool FOOTPRINT::HitTestOnLayer( const VECTOR2I& aPosition, PCB_LAYER_ID aLayer, int aAccuracy ) const
{
for( PAD* pad : m_pads )
{
if( pad->IsOnLayer( aLayer ) && pad->HitTest( aPosition, aAccuracy ) )
return true;
}
for( ZONE* zone : m_fp_zones )
{
if( zone->IsOnLayer( aLayer ) && zone->HitTest( aPosition, aAccuracy ) )
return true;
}
for( BOARD_ITEM* item : m_drawings )
{
if( !item->IsOnLayer( aLayer ) )
if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer )
&& item->HitTest( aPosition, aAccuracy ) )
{
return true;
}
}
return false;
}
bool FOOTPRINT::HitTestOnLayer( const BOX2I& aRect, bool aContained, PCB_LAYER_ID aLayer, int aAccuracy ) const
{
std::vector<BOARD_ITEM*> items;
for( PAD* pad : m_pads )
{
if( pad->IsOnLayer( aLayer ) )
items.push_back( pad );
}
for( FP_ZONE* zone : m_fp_zones )
{
if( zone->IsOnLayer( aLayer ) )
items.push_back( zone );
}
for( BOARD_ITEM* item : m_drawings )
{
if( item->Type() != PCB_TEXT_T && item->IsOnLayer( aLayer ) )
items.push_back( item );
}
// If we require the elements to be contained in the rect and any of them are not,
// we can return false;
// Conversely, if we just require any of the elements to have a hit, we can return true
// when the first one is found.
for( BOARD_ITEM* item : items )
{
if( !aContained && item->HitTest( aRect, aContained, aAccuracy ) )
return true;
else if( aContained && !item->HitTest( aRect, aContained, aAccuracy ) )
return false;
}
return true;
// If we didn't exit in the loop, that means that we did not return false for aContained or
// we did not return true for !aContained. So we can just return the bool with a test of
// whether there were any elements or not.
return !items.empty() && aContained;
}
+18 -3
View File
@@ -167,6 +167,11 @@ public:
const BOX2I GetBoundingBox() const override;
const BOX2I GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const;
/**
* Return the bounding box of the footprint on a given set of layers
*/
const BOX2I GetLayerBoundingBox( LSET aLayers ) const;
VECTOR2I GetCenter() const override
{
return GetBoundingBox( false, false ).GetCenter();
@@ -329,9 +334,7 @@ public:
bool IsFlipped() const { return GetLayer() == B_Cu; }
/**
* A special IsOnLayer for footprints: return true if the footprint contains only items on the
* given layer, even if that layer is not one of the valid footprint layers F_Cu and B_Cu.
* This allows selection of "graphic" footprints that contain only silkscreen, for example.
* @copydoc BOARD_ITEM::IsOnLayer
*/
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
@@ -518,6 +521,18 @@ public:
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
/**
* Test if the point hits one or more of the footprint elements on a given layer.
*
* @param aPosition is the point to test
* @param aAccuracy is the hit test accuracy
* @param aLayer is the layer to test
* @return true if aPosition hits a footprint element on aLayer
*/
bool HitTestOnLayer( const VECTOR2I& aPosition, PCB_LAYER_ID aLayer, int aAccuracy = 0 ) const;
bool HitTestOnLayer( const BOX2I& aRect, bool aContained, PCB_LAYER_ID aLayer, int aAccuracy = 0 ) const;
/**
* @return reference designator text.
*/
+3 -1
View File
@@ -38,6 +38,7 @@
#include <tools/board_editor_control.h>
#include <board.h>
#include <footprint.h>
#include <pcb_group.h>
#include <board_commit.h>
#include <footprint_edit_frame.h>
#include <wildcards_and_files_ext.h>
@@ -764,7 +765,8 @@ void PCB_EDIT_FRAME::ExportFootprintsToLibrary( bool aStoreInNewLib, const wxStr
pi->FootprintSave( libPath, fpCopy );
// Remove reference to the group before deleting
fpCopy->SetParentGroup( nullptr );
if( PCB_GROUP* parentGroup = fpCopy->GetParentGroup() )
parentGroup->RemoveItem( fpCopy );
delete fpCopy;
}
+61 -7
View File
@@ -176,16 +176,42 @@ void FP_SHAPE::SetCenter0( const VECTOR2I& aCenter )
}
void FP_SHAPE::CalcArcAngles0( EDA_ANGLE& aStartAngle0, EDA_ANGLE& aEndAngle0 ) const {
VECTOR2D startRadial( GetStart0() - GetCenter0() );
VECTOR2D endRadial( GetEnd0() - GetCenter0() );
aStartAngle0 = EDA_ANGLE( startRadial );
aEndAngle0 = EDA_ANGLE( endRadial );
if( aEndAngle0 == aStartAngle0 )
aEndAngle0 = aStartAngle0 + ANGLE_360; // ring, not null
while( aEndAngle0 < aStartAngle0 )
aEndAngle0 += ANGLE_360;
}
EDA_ANGLE FP_SHAPE::GetArcAngle0() const
{
EDA_ANGLE startAngle0;
EDA_ANGLE endAngle0;
CalcArcAngles0( startAngle0, endAngle0 );
return endAngle0 - startAngle0;
}
VECTOR2I FP_SHAPE::GetArcMid0() const
{
// If none of the input data have changed since we loaded the arc,
// keep the original mid point data to minimize churn
if( m_arcMidData_0.start == m_start && m_arcMidData_0.end == m_end
&& m_arcMidData_0.center == m_arcCenter )
if( m_arcMidData_0.start == m_start0 && m_arcMidData_0.end == m_end0
&& m_arcMidData_0.center == m_arcCenter0 )
return m_arcMidData_0.mid;
VECTOR2I mid0 = m_start0;
RotatePoint( mid0, m_arcCenter0, -GetArcAngle() / 2.0 );
RotatePoint( mid0, m_arcCenter0, -GetArcAngle0() / 2.0 );
return mid0;
}
@@ -198,21 +224,49 @@ void FP_SHAPE::SetArcAngleAndEnd0( const EDA_ANGLE& aAngle, bool aCheckNegativeA
RotatePoint( m_end0, m_arcCenter0, -angle.Normalize720() );
if( aCheckNegativeAngle && aAngle < ANGLE_0 )
{
std::swap( m_start0, m_end0 );
m_endsSwapped = true;
}
}
void FP_SHAPE::SetCachedArcData0( const VECTOR2I& aStart0, const VECTOR2I& aMid0,
const VECTOR2I& aEnd0, const VECTOR2I& aCenter0 )
{
m_arcMidData_0.start = aStart0;
m_arcMidData_0.end = aEnd0;
m_arcMidData_0.center = aCenter0;
m_arcMidData_0.mid = aMid0;
}
void FP_SHAPE::SetArcGeometry0( const VECTOR2I& aStart0, const VECTOR2I& aMid0,
const VECTOR2I& aEnd0 )
{
m_arcMidData_0 = {};
m_start0 = aStart0;
m_end0 = aEnd0;
m_arcCenter0 = CalcArcCenter( aStart0, aMid0, aEnd0 );
const VECTOR2I new_mid = GetArcMid0();
m_arcMidData_0.center = m_arcCenter0;
m_arcMidData_0.end = m_end0;
m_arcMidData_0.mid = aMid0;
m_arcMidData_0.start = m_start0;
m_endsSwapped = false;
SetCachedArcData0( aStart0, aMid0, aEnd0, m_arcCenter0 );
/*
* If the input winding doesn't match our internal winding, the calculated midpoint will end
* up on the other side of the arc. In this case, we need to flip the start/end points and
* flag this change for the system.
*/
VECTOR2D dist( new_mid - aMid0 );
VECTOR2D dist2( new_mid - m_arcCenter0 );
if( dist.SquaredEuclideanNorm() > dist2.SquaredEuclideanNorm() )
{
std::swap( m_start0, m_end0 );
m_endsSwapped = true;
}
}

Some files were not shown because too many files have changed in this diff Show More