Compare commits

...

193 Commits

Author SHA1 Message Date
Chris Hennes 930dd9a762 Addon Manager: Fix bug in updater 2022-12-06 20:35:37 -06:00
Uwe fc12f15ee4 [Win installer] some uninstaller improvements
- remove two registry path deletions that were never performed since the paths do not exist
- remove registry key that stores the main window parameters (size and position) when the option to remove also the user settings is on (because this affects all FreeCAD installations)
- also change a name to uppercase (does not matter but Win 10 uses uppercase, so we should do the same to avoid confusions)
2022-12-05 02:06:46 +01:00
Uwe aaee1b5e39 this is FreeCAD 0.20.2 2022-12-05 00:02:59 +01:00
Uwe 4fef2ad448 [Win installer] improve file deletion script 2022-12-05 00:00:58 +01:00
Uwe 726ddc71f9 [Win installer] prepare for FC 0.20.2 2022-12-04 23:33:45 +01:00
Uwe 9415d2d0c4 [PD] Pad/pocket: fix wrong error message
- the error can also occur when the mode it not UpToFace (ToFirst or ToLast)
- also add note when Reversed checkbox is enabled since this is no obvious (as discussed in the forum)
- also some whitespace unification and include sorting
2022-12-04 05:38:49 +01:00
Uwe bbfe3aedce [PD] FeatureSketchBased: fix orthogonal check
- same fix as #7879
- also fix wording on an error message and improve a variable name
2022-12-04 05:33:40 +01:00
Roy-043 524bda9547 Arch: Fix missing Windows in Arch Reference of BuildingPart 2022-12-02 00:52:10 +01:00
Roy-043 ac182bf9d9 Arch: Fix Arch_Space text position 2022-12-01 12:35:19 +01:00
Roy-043 05789429cf Arch: fix cutplane color (#7859)
* Arch: fix cutplane color

* Update ArchCutPlane.py
2022-11-30 08:53:52 +01:00
Yorik van Havre 15482dcad6 Merge pull request #7885 from Roy-043/Draft-fix-clone-DiffuseColor
Draft: fix clone DiffuseColor
2022-11-30 08:51:53 +01:00
Yorik van Havre effe30ba69 Start: Set minimum height for notes panel 2022-11-30 01:24:14 +01:00
wandererfan 1bcb7275db [TD]backport fix for no Detail without BaseView 2022-11-29 02:17:14 +01:00
Chris Hennes 9bf0c5890f Addon Manager: Fix bad formatting in error handler 2022-11-27 19:41:17 -06:00
flachyjoe d17c9e35d5 [Spreadsheet] Fix alias setting for empty cells
Fix #7841
2022-11-27 19:36:42 -06:00
wmayer 2605b54d89 Sketch: use the focal distance to determine a correct scale factor for SoDatumLabel
This fixes #7860: Dimensions get unreadable (small) if a 2nd sketch is visible
and fixes #7082: Dimension size on perspective view scales "backwards"
2022-11-24 10:25:10 +01:00
Uwe 1621bd0deb [skip ci] [Part] TopoShapePyImp: fix formatting mistake
- introduced with c29228d7
2022-11-22 03:26:20 +01:00
Uwe fd6c8382ee [Part] manually backport PR #7824 2022-11-22 03:19:49 +01:00
Uwe f177aa6467 [skip ci] .clang-format: shorthand loops
- disallow as we did before we had this format file
2022-11-22 03:13:55 +01:00
Uwe c29228d785 [Part] manually backport 09dccb70 2022-11-22 03:08:25 +01:00
Yorik van Havre eec4a5975c Merge pull request #7821 from Roy-043/Draft-fix-arcFromSpline
Draft: fix arcFromSpline midpoint bug
2022-11-21 14:59:57 +01:00
Uwe 10902d7d4f Revert "Gui: ActionGroup also get its tooltip title updated"
This reverts commit fcaa312616.
2022-11-21 12:34:08 +01:00
0penBrain fcaa312616 Gui: ActionGroup also get its tooltip title updated 2022-11-21 04:09:58 +01:00
0penBrain a713eafc95 Gui: ActionGroup also get its tooltip title updated 2022-11-21 04:07:57 +01:00
Rexbas acc94f3baf Gui: Stop Revit rotation and zoom on scroll release
- Stops the rotation when scroll is released but SHIFT is still pressed
- Stops zooming when scroll is released but CTRL is still pressed
2022-11-21 04:02:58 +01:00
wmayer 710a470706 App: fix endless-loop in DocumentObject::getParents 2022-11-20 12:27:38 +01:00
wmayer 087cdd8169 Gui: fix endless-loop in View3DInventorSelection::checkGroupOnTop 2022-11-20 12:09:06 +01:00
Bernd Hahnebach fd544b4ba9 FEM: gmsh binary location on osx, add comment 2022-11-20 01:24:08 +01:00
Bernd Hahnebach 887fac2ab1 FEM: add standard path for gmsh on osx 2022-11-20 01:24:08 +01:00
wmayer 5223aff0fb Base: [skip ci] fix readability-identifier-length 2022-11-20 01:20:58 +01:00
luz paz 757af860be [Sketcher] fix header uniformity
Make uniform all Sketcher headers.
2022-11-20 01:19:31 +01:00
luz paz feec92c94a [Arch] fix header uniformity
Make uniforum all Arch headers
2022-11-20 01:17:03 +01:00
wmayer c5723f1f89 Arch: replace tabs with spaces 2022-11-20 01:15:45 +01:00
0penBrain 3e0bd9e34a [Typo]Sketcher: 'Clone' is the first command of CompCopy, match the tooltip 2022-11-20 01:03:39 +01:00
wmayer af4c8ffa82 App: fix memory leak and consistently use Py::asObject() in DocumentObserverPython 2022-11-20 00:58:52 +01:00
wmayer 866e20543d clang-tidy: disable 'readability-redundant-access-specifiers' because clang-tidy fails to distinguish between 'public' vs. 'public Q_SLOTS' 2022-11-20 00:55:38 +01:00
wmayer 7d9b3445a7 App: [skip ci] fix memory leak (copied from master) 2022-11-14 19:51:29 +01:00
vernzimm c63cb3d9dc Gui: Add default JPEG save quality (#7737)
* Update SoFCOffscreenRenderer.cpp

Set jpg screenshot capture to 100% quality vs qimage defaulting to -1

* Add default quality to JPG export

Fixed original version and use quality 90% as compromise between file size and fidelity.
2022-11-11 22:50:43 +01:00
Uwe ae653d1d5c backport .clang-format file from master 2022-11-11 05:19:58 +01:00
wmayer 3e981e0712 PD: fix crash in TaskRevolutionParameters::addAxisToCombo
and some warnings reported by GH actions
2022-11-10 14:10:32 +01:00
wmayer c849e9970e PD: [skip ci] improve the exception text 2022-11-10 14:10:32 +01:00
Uwe 31fe74b3a7 [PD] TaskDlgRevolutionParameters: fix some CI warnings
- reported here: https://github.com/FreeCAD/FreeCAD/pull/7667/commits/f0a0e563
- and here: https://github.com/FreeCAD/FreeCAD/pull/7719/commits/8f3f17f8
2022-11-10 14:10:32 +01:00
luz paz 56d29f212b Arch: remove trailing whitespace in importWebGL.py 2022-11-10 14:09:19 +01:00
wmayer 6f302d33fe Gui: backport class WrapperManager to fix possible crashes when using PySide 2022-11-10 09:32:25 +01:00
Roy-043 7d457f189d Draft: test_modification.py: modified test and added test (#7741)
The old test_offset_closed function was renamed to test_offset_rectangle_with_face.
It is now also a regression test for: #7670

The added test_offset_closed_with_reversed_edge function is a regression test for: #5496
2022-11-09 13:33:29 +01:00
Yorik van Havre b601ed911c Merge pull request #7670 from Roy-043/Draft-Fix-rectangle-with-face-offset-bug
Draft: Fix rectangle with face offset bug
2022-11-09 13:32:06 +01:00
Uwe 3aac13eacf Revert "Gui: fix possible crash when running the garbage collector after creating a shiboken wrapper"
This reverts commit a06533392b.
2022-11-09 13:23:47 +01:00
Uwe c8042bed16 Revert "Gui: [skip ci] fix build failure if shiboken support is disabled"
This reverts commit d60a737ae8.
2022-11-09 13:23:37 +01:00
wmayer d60a737ae8 Gui: [skip ci] fix build failure if shiboken support is disabled 2022-11-09 13:05:16 +01:00
wmayer a06533392b Gui: fix possible crash when running the garbage collector after creating a shiboken wrapper 2022-11-09 13:03:32 +01:00
Uwe 3569b135bb [Gui] CommandWindow.cpp: manually backport a change to fix compilation 2022-11-09 03:09:40 +01:00
Chris Hennes d1ad3b4926 Addon Manager: Add try/except to integer conversion 2022-11-08 10:30:38 -06:00
Uwe 59177020a6 Revert "Part: TestPartApp.py add tolerance to PartTestShapeRotate"
This reverts commit 31b3358291.
2022-11-07 02:31:17 +01:00
wmayer f238295c2d PD: unit test to check offset of sub-shape binder (PR #7445) 2022-11-06 14:15:56 +01:00
wmayer 68ac5c1c8c Gui: [skip ci] fix possible crash in FilterStatusBar::eventFilter() 2022-11-06 14:07:34 +01:00
wmayer 9647ac5fdd Gui: handle std::exception and Base::Exception inside DlgPreferencesImp::createPageInGroup to avoid that the preferences dialog won't be shown at all 2022-11-06 14:05:01 +01:00
wmayer a36c87c71d PD: use Base::StateLocker to simplify handling of blockUpdate and make it exception-safe 2022-11-06 14:03:01 +01:00
wmayer 9a053b860d PD: fixes #7629: Keep sketch visible during revolution tasks 2022-11-06 14:01:17 +01:00
Roy-043 31b3358291 Part: TestPartApp.py add tolerance to PartTestShapeRotate 2022-11-06 13:59:24 +01:00
Roy-043 459790624f Part: Fix typo in regression_tests.py 2022-11-06 13:58:18 +01:00
Uwe 664bc12c9a [PD] Helix: assure source Sketch is visible when in selection mode
- same as https://github.com/FreeCAD/FreeCAD/commit/18781bcf6 but for Helices (fixes #7629 also for helices)
- also modernize Qt connection
2022-11-06 13:51:03 +01:00
Uwe bc3a3d3c8c [Gui] SplashScreen: modernize Qt connection
- was reported as warning by our CI
2022-11-06 13:49:34 +01:00
Chris Hennes 83f4b2c293 Addon Manager: Catch unicode decode failures 2022-11-05 09:44:43 -05:00
Flachy Joe 0bd3f9d8a9 [PartDesign] Improve Helix calculation for straight shape (#7674) 2022-11-04 13:32:58 +01:00
wmayer a22a8a00a1 PD: [skip ci] disable undo/redo for the tmp. document created by the SubShapeBinder 2022-10-27 14:35:47 +02:00
wmayer 1833ae86de Gui: if an expression is set for Euler angles in the placement dialog then evaluate the expression instead of determining the angles from the rotation
See forum thread: https://forum.freecadweb.org/viewtopic.php?f=3&t=72522
2022-10-26 18:18:33 +02:00
Yorik van Havre 75c515691d Merge pull request #7616 from Roy-043/Draft-Make-Std_TransformManip-work-for-Draft_Point
Draft: Make Std_TransformManip work for Draft_Point
2022-10-26 18:17:40 +02:00
luz paz 4b191ff830 Spreadsheet: [skip ci] fix doxygen typo 2022-10-26 02:50:30 +02:00
wmayer dd35d0d035 App: fixes issue #7628: Crash after creating Sketch for Body
The problem is that inside Transaction::addObjectNew() a transaction object is deleted before removing it from the container. When deleting the corresponding transactional object (i.e. a DocumentObject or ViewProvider)
it can happen that it e.g. calls Transaction::addOrRemoveProperty() that now finds the dangling pointer in the container.

The safe way is to first remove the object from the container before deleting it.
2022-10-25 03:10:45 +02:00
wmayer d66b34050d Gui: cppcoreguidelines-pro-type-reinterpret-cast
Replace an unsafe reinterpret_cast with the safer static_cast
2022-10-25 01:18:54 +02:00
Roy-043 641fd1b287 Sketcher: Correct icon for Sketcher_CreatePointFillet 2022-10-25 01:15:01 +02:00
wmayer 3f48031cb4 CMake: [skip ci] fix deprecation warning about policy CMP0072 2022-10-25 01:14:27 +02:00
Uwe 142e796244 [skip CI] [FEM] equation.py: fix a tooltip
- the highest priority is computed first, the Wiki page is already correct
2022-10-25 01:13:22 +02:00
Bernd Hahnebach 9c5ff9164e FEM: get LGTM silent 2022-10-25 01:12:29 +02:00
luz paz 92b8d8a690 Fix source comment typo 2022-10-25 01:11:09 +02:00
Stefan Klug 293856b705 PartDesign: Remove duplicate comment 2022-10-25 01:10:33 +02:00
Stefan Klug 326ec081ce [Bugfix] PartDesign: Fix HoleCutDepth not being recalculated correctly
HoleCutDepth is reset to 0 to force a recalculation of te depth when
HoleCutType is set to a new value.
But the line
	pcHole->HoleCutCustomValues.setValue(false)
also forces a recalculation. So the depth was recalculated with the old
value in HoleCutType which was not expected behaviour.
2022-10-23 04:11:17 +02:00
0penBrain cf6e561e5a [Bugfix]Spreadsheet: fix multi-screen management of QtColorPicker
+ set parent when instantiating
2022-10-21 09:31:55 -05:00
wmayer f7f717db9e fix build failure 2022-10-16 11:46:48 +02:00
wmayer 1f08f07d38 Gui: depending on parameter settings open a transaction when changing visibility or selectability 2022-10-15 21:39:56 +02:00
wmayer b7f66680ab App: fixes #7277: Write to network drive fails on Windows 2022-10-14 02:26:50 +02:00
Roy-043 3473e5d424 Draft: Fix alignment of angular dimension arrows in svg.py 2022-10-14 01:49:18 +02:00
Yorik van Havre 00a8a784ec Merge pull request #7591 from Roy-043/Arch-Improve-handling-of-window-hosts
Arch: Improve handling of window hosts
2022-10-14 01:46:08 +02:00
Ajinkya Dahale 8443756ff5 [Sketcher] [planegcs] Add references for equations
Some equations were mentioned by just the number without telling the resource they were from. The book was found couple years ago but not mentioned here.
2022-10-14 01:45:28 +02:00
Yorik van Havre 35a61883e1 Merge pull request #7576 from Roy-043/releases/FreeCAD-0-20
Draft+Arch: Fix crash related to SoBrepEdgeSet
2022-10-11 14:22:34 +02:00
Roy-043 1fc9b07a2e Draft+Arch: Fix crash related to SoBrepEdgeSet 2022-10-07 21:16:11 +02:00
wandererfan a4f29eb509 [TD]encode Xml characters in spreadsheet 2022-10-06 03:02:39 +02:00
Uwe 570aac5399 [FEM] ViewProviderFemConstrain*: remove unused includes - part 2/2
- also sort includes
- also fix warnings about too long lines
2022-10-04 00:08:45 +02:00
Uwe cb8926155c [FEM] ViewProviderFemConstrain*: remove unused includes - part 1
- also sort includes
- also fix warnings about too long lines
2022-10-04 00:08:45 +02:00
Uwe c8f0338ae1 [FEM] ViewProviderFem*: remove unused includes
- also sort includes
2022-10-04 00:08:00 +02:00
Uwe 20a19b3245 [FEM] ViewProvider*: remove unused includes
- also sort includes
2022-10-04 00:06:14 +02:00
looooo 07900daa07 add_definitions(-DSALOME_USE_64BIT_IDS) for smesh via config 2022-10-03 23:11:21 +02:00
Uwe ae0ff4f405 [FEM] TaskFemConstrain*: remove unused includes
- also sort includes
2022-10-03 05:42:41 +02:00
Uwe 8f2e08758d [FEM] TaskPostBoxes.cpp: re-add an include
- (strange that it compiled on MSVC without even a warning)
2022-10-03 05:42:41 +02:00
Uwe a9d1b557ed [FEM] Task*: remove unused includes
- also sort includes
2022-10-03 05:42:41 +02:00
Uwe e81a31f638 [FEM] Dlg* etc.: remove unused includes
- also sort includes
2022-10-03 05:42:41 +02:00
Uwe a01202aaa7 [FEM] FemResult* to end: remove unused includes
- also sort includes
2022-10-03 05:42:40 +02:00
Uwe 81b94827ee [FEM] FemPost*: remove unused includes
- also sort includes
2022-10-03 05:42:12 +02:00
Uwe d8bc205b75 [FEM] FemMesh*: remove unused includes
- also sort includes
2022-10-03 05:42:12 +02:00
Uwe 77b5fd9a5d [skip CI] [Part] TaskFaceColors.cpp: whitespace 2022-10-03 05:25:31 +02:00
Uwe d64ba16bbf [Part] Task*: remove unused includes - part 2/2
- also some sorting
2022-10-03 05:25:31 +02:00
Uwe c6b3d2f688 [Part] Task*: remove unused includes - part 1
- also some sorting
2022-10-03 05:24:51 +02:00
Uwe 344f88cb05 [Part] So*: remove unused includes
- also some sorting
2022-10-03 05:23:08 +02:00
Uwe 1e2806095c [Part] Dlg*: remove unused includes - part 2/2
- also some sorting
2022-10-03 05:23:08 +02:00
Uwe 2db76146a7 [Part] Dlg*: remove unused includes - part 1
- also some sorting
2022-10-03 05:22:49 +02:00
Uwe 6b3fefa166 [FEM] App, FemConstraint*: remove unused includes - part 2/2
- also sort includes
2022-10-03 00:13:15 +02:00
Uwe f7111e00a4 [FEM] App, FemConstraint*: remove unused includes - part 1
- also sort includes
2022-10-03 00:13:15 +02:00
Stanislav 8fc35c5981 i18n: Manually update language files from Crowdin (#7540)
* Manual update from Crowdin
2022-10-02 18:21:46 +02:00
0penBrain 987ec6d705 [Bugfix]Gui: TinkerCAD mouse mode was always stopping RMB propagation 2022-10-01 04:39:22 +02:00
fandaL 1d80800838 FEM:fix remaining result object in memory in femmesh2mesh 2022-10-01 04:34:53 +02:00
wmayer d8d521150d Gui: change Selection.getCompleteSelection() to return a list of SelectionObject instead of DocumentObject (see 10e9e3b9b5) 2022-09-30 14:56:40 +02:00
0penBrain 766f787d84 Sketcher: fix misleading indentation 2022-09-24 16:06:24 +02:00
0penBrain e13e09b888 [Bugfix]Sketcher/Point-on-object: do not substitute constraint if conditions are not OK 2022-09-24 16:06:24 +02:00
Yorik van Havre a52eb0d4b9 Merge pull request #7359 from Roy-043/Draft-Improve-In-Command-shortcut-Undo-implementation
Draft: Improve In-Command-shortcut Undo implementation
2022-09-24 05:17:20 +02:00
marioalexis 8458569bda Gui: Allow None parameter again in drag and drop methods in Python ViewProviderPy class 2022-09-24 05:12:08 +02:00
wmayer 6e187c3b0e Spreadsheet: Handle language change event for context-menu 2022-09-19 02:41:55 +02:00
Uwe de8de44276 Revert "[PD] sync wedge code to master"
This reverts commit a019468c4a.
2022-09-19 02:17:46 +02:00
Uwe a019468c4a [PD] sync wedge code to master 2022-09-18 12:33:14 +02:00
Ethan Chappel 9b20f21792 Gui: Add format parameter for wedgeXmin 2022-09-18 12:08:23 +02:00
0penBrain dcb8738f55 Gui: when customizing shortcuts, warn user if command isn't in use with message box 2022-09-15 13:22:14 +02:00
Uwe 5c0cc8dc8a [Sketcher] rename a variable to please spellchecker
- also some code style improvements
2022-09-14 10:25:58 +02:00
Ajinkya Dahale 46cd5a3809 [Sketcher] Fix Typo in comment
threated -> treated
2022-09-14 09:17:35 +02:00
0penBrain bc5c7f80df [Bugfix]Sketcher: prevent dangling state of Shift key if key released out of Quarter 2022-09-14 09:13:41 +02:00
Roy-043 914520becb Draft: Fix flatten wire 2022-09-14 01:33:45 +02:00
Roy-043 ecce035d2d Draft: Fix alignment of angular dimension arrows 2022-09-13 02:36:23 +02:00
Roy-043 a00912ba77 Arch: Fix baseface generation for walls with a trace that self-intersects, has T-connections or that overlaps 2022-09-13 02:31:39 +02:00
Yorik van Havre 18952f7a4b Merge pull request #7354 from Roy-043/Draft-add-tolerance-to-boundbox-check-in-intersections.py
Draft: add tolerance to BoundBox check in intersections.py
2022-09-13 02:04:12 +02:00
Uwe c47bbd0cfe Revert "Mod: [skip ci] fix some MSVC warnings"
This reverts commit 0d5ec23d1f.
2022-09-12 03:34:42 +02:00
Markus Lampert 9364930948 Fixed handling of App::PropertyPercent in SetupSheet save/load 2022-09-12 03:08:23 +02:00
sliptonic 71d47a137d Merge pull request #7454 from sliptonic/PathFeedRateBug
Fix bug when testing verticallity during PathFeedRate generation
2022-09-12 03:06:39 +02:00
VM4Dim de1abd6719 [StartPage] Fix Wiki Link to Reverse_Engineering WB Page 2022-09-12 03:03:28 +02:00
wmayer 0d5ec23d1f Mod: [skip ci] fix some MSVC warnings 2022-09-12 03:01:20 +02:00
wmayer 506dc005f4 Mesh: [skip ci] add missing headers to PCH 2022-09-12 03:00:40 +02:00
0penBrain 754d82428f [Bugfix]Gui: ensure message boxes appear and stay on top of main window 2022-09-12 02:55:59 +02:00
Roy-043 81fcd18e8d Draft: Fix workingplane auto alignment to Front view 2022-09-12 02:42:19 +02:00
marioalexis 3a41e39de8 Gui: Prevent crash when trying to create ExpressionBinding without arguments 2022-09-12 02:29:11 +02:00
wmayer 1d074847b6 Base: implement default constructor and open() function for Base::ifstream and Base::ofstream 2022-09-12 02:27:05 +02:00
IFo Hancroft 83badab7c0 Update org.freecadweb.FreeCAD.xml 2022-09-11 22:27:13 +02:00
IFo Hancroft 2f49c0979f Fixes filetype icon not showing
Fixes the icon of .FCStd files not showing because the xml element was
called icon instead of generic-icon
2022-09-11 22:27:13 +02:00
wmayer c0d54e0a49 Gui: [skip ci] fix UTF-8 handling of icon resources 2022-09-11 22:19:09 +02:00
wmayer 5b9cfb2d32 App: fix possible dangling pointer in Document::removeObject() 2022-09-11 22:15:43 +02:00
luz paz 44783edf98 Follow-up typo fixes 2022-09-11 22:14:45 +02:00
0penBrain 09dd45aa7a [Bugfix]Sketcher: some user colors aren't taken into account 2022-09-11 22:08:33 +02:00
0penBrain fe085edd79 [Bugfix]Gui: allow set up expression even if property value is currently being edited 2022-09-11 22:08:32 +02:00
wmayer cba832d1e6 Mod: replace std::ifstream/std::ofstream with Base::ifstream/Base::ofstream 2022-09-11 21:58:43 +02:00
wandererfan 58d028b4ba [TD]fix misspelled preference key 2022-09-11 21:50:05 +02:00
wandererfan e6f9974235 [Part]fix makeWireString for Win & Py > 3.09 2022-09-11 21:44:56 +02:00
sliptonic 0793fcccca Merge pull request #7438 from Syres916/patch-54
[Path] Change Default Drilling Retraction from G99 to G98
2022-09-11 21:42:47 +02:00
wmayer 9d5b46196e PD: [skip ci] fix UTF-8 handling in Hole feature 2022-09-11 21:33:40 +02:00
wmayer 1ccdc547a9 TD: fix UTF-8 handling in LineGroup 2022-09-11 21:33:40 +02:00
0penBrain 5de0153a36 PartDesign: improve offset handling of SubShapeBinder 2022-09-11 21:19:27 +02:00
wmayer 639546574e Py: make FreeCAD 0.v20 to compile with Py3.11
As requested in this thread: https://forum.freecadweb.org/viewtopic.php?p=622230#p622230
2022-08-30 15:26:12 +02:00
Syres916 882ba47de7 [0.20] [AddonManager] Minor Bugfix with Mod folder
https://forum.freecadweb.org/viewtopic.php?p=617191#p617191
2022-08-24 23:39:02 -05:00
Chris Hennes ad6353995e Addon Manager: Fix bug in dependency resolver 2022-08-24 15:25:16 -05:00
Chris Hennes a95fa37d3e AddonManager: Fix bug in dependency resolver. 2022-08-24 10:23:38 -05:00
jbaehr 56d6a02b1b Fix MacOS-X build of FreeCAD-0.20.1 (#7389)
* Fix build on MacOS-X 10.14: missing cmath header
(This undoes a small part of commit 9ec0bcdcf2,
which seems a bit too agressive. Without the cmath header the build fails
using Apple clang version 11.0.0 (clang-1100.0.33.17) on Mojave)

* Fix build on MacOS-X 10.14: missing Xerces include dir
2022-08-24 00:47:35 +05:00
Uwe b14a90946b [FEM] Elmer: fix flux equation
- the Flux solver must be executed before Heat and Electrostatic
- the analysis can have multiple Flux equations -> write a unique solver name to case.sif
- the Flux equation can currently only take 2 possible values. Therefore provide them as enum
2022-08-16 03:53:09 +02:00
Uwe adf84d0ecf [FEM] potential constraint: change default value
- in practice one wants to apply potentials to faces via this constraint, therefore enable to set a potential by default, also assure that the initial unit is V
2022-08-15 02:43:33 +02:00
Uwe 64c79f51db [FEM] potential constraint: allow to set expression for value 2022-08-15 02:43:32 +02:00
Uwe 3bb9491fba [FEM] [skip CI] Elmer writer: fix indentation mistake
- found by Pylint checker
2022-08-14 20:53:11 +02:00
Uwe 046f0384f4 [Gui] revert setting unit factor for F/m
- see https://github.com/FreeCAD/FreeCAD/commit/9db5dff7#r81159352
2022-08-14 20:52:47 +02:00
Uwe 279a2c3fb2 [FEM] permittivity: improve code
- in commit 9db5dff7 I hard-coded the permittivity incorrectly
2022-08-14 19:21:43 +02:00
Uwe fa62b41622 [FEM] fix handling of vacuum permittivity
- fix message that permittivity object was not handled
- set an expression, otherwise the user gets only "0.000" for the default of 8.8e-12
- use as unit the common "F/m" (this is also more user-friendly than "s^4*A^2 / (m^3*kg)")
- fix a ToDo
2022-08-14 19:21:43 +02:00
Uwe dfac3dbe27 [FEM] Elmer example: remove wrong permittivity
- a permittivity of 1 F/m is not physical, also not for testing. In fact overwriting a constant is not good practice for an example
2022-08-14 18:48:11 +02:00
Uwe 3cdbd61e9c [FEM] Elmer: writer: get rid of unnecessary function
- fixes the ToDo
- also remove unnecessary comment
2022-08-14 18:47:44 +02:00
Uwe ee3e46d8d1 [FEM] Elmer: handle pressure for fluids
- Elmer allows external pressure on fluid boundaries as well as for solids
2022-08-14 18:47:16 +02:00
Uwe aeab707a92 [FEM] change default pressure
- a default of 1 GPa for a pressure onto a face is not suitable. use 1 bar (100 kPa) instead
2022-08-14 07:17:49 +02:00
Uwe 0cf4b544f0 [FEM] Elmer: fix initial flow velocity
- we must allow must be several velocities because there can be several fluid bodies
- don't output flow velocity for solid bodies
2022-08-14 06:51:50 +02:00
Uwe 5129e62ed2 [FEM] [skip CI] remove an obsolete comment
- since a while there is no green hook but a QuantitySpinBox
2022-08-14 06:51:07 +02:00
Uwe fe76983fd3 [FEM] [skip CI] Elmer: add copyright
-  heavily edited these files so I am to blame now too ;-)
2022-08-14 06:50:40 +02:00
grubertechnic 394f74cf9e [TechDraw] fix up button in TaskProjGroup 2022-08-14 06:49:54 +02:00
Uwe 6d621563aa [FEM] Elmer: sort solver methods for better overview 2022-08-14 06:41:55 +02:00
Uwe fbbe82ebfd [FEM] [skip CI] fix non-Unicode character
- made problems with text editors -> change file to UTF-8
2022-08-14 06:37:33 +02:00
Uwe fb98d8611a [FEM] Elmer: fix for the Idrs method
- while adding support for the IDRS method I forgot to implement its mandatory parameter
2022-08-14 01:52:39 +02:00
Uwe 74f63c8293 [FEM] Elmer: set constraints for solver systems
- set constraints according to the Elmer docs (no conversion necessary, existing properties just stay integers)
2022-08-14 01:52:39 +02:00
Uwe 5511405272 [FEM] Elmer: just sorting to keep the overview 2022-08-14 01:52:39 +02:00
Wanderer Fan 398076fdde [TD]hatch file default handling 2022-08-14 01:50:45 +02:00
luz paz 0974cab1a4 [FEM] Substitute underscore for whitespace in CalculiX solver output
Fixes #7360  
Forum thread: forum.freecadweb.org/viewtopic.php?p=617376#p617376
2022-08-13 16:43:08 +02:00
Uwe d615b466d7 [FEM] Elmer: only output a property if necessary 2022-08-13 14:39:46 +02:00
Uwe 3fa1f515ee [FEM] Elmer: fix heat flux handling
- the heat flux in the temperature constraint is not the heat flux from the heatflux constraint. The latter is in W/m² while the first one is W/mesh node
2022-08-13 05:57:48 +02:00
Uwe 7d9855c849 [FEM] Elmer: add support to turn off solvers
- with this property the linear solver is turned off. As consequence one can this way also disable the execution of an equation without the need to delete the equation object

- also add missing preconditioners
2022-08-13 05:56:33 +02:00
Uwe 51deef0dcd [FEM] Elmer: add tooltips 2022-08-13 04:10:21 +02:00
Uwe 2e068fe4a8 Revert "[TD]fix LineFormat ctor line color"
This reverts commit 497600f8d0.
2022-08-13 04:09:44 +02:00
Uwe 7fb4ac2634 [FEM] Flow constraints: fix wrong tooltips 2022-08-13 03:42:13 +02:00
Wanderer Fan 497600f8d0 [TD]fix LineFormat ctor line color 2022-08-13 03:40:44 +02:00
wmayer 6b1e7a3546 Gui: clear combo boxes before re-filling them, fix handling of icon size in preferences pack 2022-08-13 03:37:14 +02:00
Uwe 8af35dc211 [FEM] Elmer: fix handling if fluids + solid materials
- as already reported in the forum, it was not possible to make a flow simulation when there is also solid material.
2022-08-12 06:19:48 +02:00
Uwe 877e77c09d [FEM] Selection: fix error for 2D shapes
- 2D shapes have no "Shape" attribute. This attribute was accessed before checked it it exists
2022-08-12 06:19:48 +02:00
Uwe 5a179983a2 [FEM] Elmer: allow lower relaxation factor
- despite the Elmer docs say 0.01 is the lover limit, for fluids like water, one might need down to 1e-4
2022-08-12 06:19:48 +02:00
wmayer 41f7c5f6c5 Gui: don't show non-existing and unusual directories in file dialog 2022-08-12 01:53:40 +02:00
Tobias Frost 0a61c568a6 Replace edit-cut.svg
Replace 2 instances of edit-cut.svg with the version from the tango icon
library to reslove license issue. Closes #7347.

Tango Icon Library used: http://tango.freedesktop.org/releases/tango-icon-theme-0.8.90.tar.gz
Location within the tarball:
./tango-icon-theme-0.8.90/scalable/actions/edit-cut.svg
2022-08-11 17:00:01 +02:00
wmayer a22a43b927 Draft: fix snapper icons
* Add convenience function to get 3D views from MDI area
* Use 'inherits' instead of 'QMetaObject.className()' to check more reliably for sub-classes
2022-08-11 16:58:44 +02:00
Wanderer Fan 3ee4ffc404 [TD]fix multiple dimension drag 2022-08-11 16:57:16 +02:00
384 changed files with 4488 additions and 3967 deletions
+66
View File
@@ -0,0 +1,66 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: DontAlign
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: MultiLine
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 100
CompactNamespaces: false
ContinuationIndentWidth: 4
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never
+4 -1
View File
@@ -1,5 +1,8 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,concurrency-*'
Checks: 'clang-diagnostic-*,clang-analyzer-*,boost-*,bugprone-*,
performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,
concurrency-*,-modernize-use-trailing-return-type, -modernize-use-nodiscard,
-readability-redundant-access-specifiers'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
+3 -3
View File
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR)
# relates to FindOpenGL module
# and cache variables OPENGL_gl_LIBRARY, OPENGL_glu_LIBRARY
if (POLICY CMP0072)
cmake_policy(SET CMP0072 OLD)
set(OpenGL_GL_PREFERENCE LEGACY)
endif(POLICY CMP0072)
find_program(CCACHE_PROGRAM ccache) #This check should occur before project()
@@ -18,9 +18,9 @@ project(FreeCAD)
set(PACKAGE_VERSION_NAME "Vulcan")
set(PACKAGE_VERSION_MAJOR "0")
set(PACKAGE_VERSION_MINOR "20")
set(PACKAGE_VERSION_PATCH "1")
set(PACKAGE_VERSION_PATCH "2")
set(PACKAGE_VERSION_SUFFIX "") # either "dev" for development snapshot or "" (empty string)
set(FREECAD_VERSION_PATCH "1") # number of patch release (e.g. "4" for the 0.18.4 release)
set(FREECAD_VERSION_PATCH "2") # number of patch release (e.g. "4" for the 0.18.4 release)
set(FREECAD_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}")
set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}")
@@ -121,6 +121,10 @@ macro(SetupSalomeSMESH)
find_package(SMESH CONFIG)
set (SMESH_INCLUDE_DIR ${SMESH_INCLUDE_PATH})
set(EXTERNAL_SMESH_LIBS ${SMESH_LIBRARIES})
# If this definition is not set, linker errors will occur against SMESH on 64 bit machines.
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(-DSALOME_USE_64BIT_IDS)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
if(NOT SMESH_FOUND)
message(ERROR "================\n"
"SMESH not found.\n"
+32 -10
View File
@@ -2614,15 +2614,37 @@ bool Document::saveToFile(const char* filename) const
bool policy = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetBool("BackupPolicy",true);
//realpath is canonical filename i.e. without symlink
auto canonical_path = [](const char* filename) {
try {
#ifdef FC_OS_WIN32
QString utf8Name = QString::fromUtf8(filename);
auto realpath = fs::weakly_canonical(fs::absolute(fs::path(utf8Name.toStdWString())));
std::string nativePath = QString::fromStdWString(realpath.native()).toStdString();
QString utf8Name = QString::fromUtf8(filename);
auto realpath = fs::weakly_canonical(fs::absolute(fs::path(utf8Name.toStdWString())));
std::string nativePath = QString::fromStdWString(realpath.native()).toStdString();
#else
auto realpath = fs::weakly_canonical(fs::absolute(fs::path(filename)));
std::string nativePath = realpath.native();
auto realpath = fs::weakly_canonical(fs::absolute(fs::path(filename)));
std::string nativePath = realpath.native();
#endif
// In case some folders in the path do not exist
auto parentPath = realpath.parent_path();
fs::create_directories(parentPath);
return nativePath;
}
catch (const std::exception&) {
#ifdef FC_OS_WIN32
QString utf8Name = QString::fromUtf8(filename);
auto parentPath = fs::absolute(fs::path(utf8Name.toStdWString())).parent_path();
#else
auto parentPath = fs::absolute(fs::path(filename)).parent_path();
#endif
fs::create_directories(parentPath);
return std::string(filename);
}
};
//realpath is canonical filename i.e. without symlink
std::string nativePath = canonical_path(filename);
// make a tmp. file where to save the project data first and then rename to
// the actual file name. This may be useful if overwriting an existing file
@@ -2636,10 +2658,6 @@ bool Document::saveToFile(const char* filename) const
Base::FileInfo tmp(fn);
// In case some folders in the path do not exist
auto parentPath = realpath.parent_path();
fs::create_directories(parentPath);
// open extra scope to close ZipWriter properly
{
Base::ofstream file(tmp, std::ios::out | std::ios::binary);
@@ -4225,6 +4243,10 @@ void Document::removeObject(const char* sName)
}
}
// In case the object gets deleted the pointer must be nullified
if (tobedestroyed) {
tobedestroyed->pcNameInDocument = nullptr;
}
d->objectMap.erase(pos);
}
+53 -27
View File
@@ -96,11 +96,9 @@ DocumentObject::~DocumentObject(void)
}
}
App::DocumentObjectExecReturn *DocumentObject::recompute(void)
void DocumentObject::printInvalidLinks() const
{
//check if the links are valid before making the recompute
if(!GeoFeatureGroupExtension::areLinksValid(this)) {
#if 1
try {
// Get objects that have invalid link scope, and print their names.
// Truncate the invalid object list name strings for readability, if they happen to be very long.
std::vector<App::DocumentObject*> invalid_linkobjs;
@@ -114,28 +112,44 @@ App::DocumentObjectExecReturn *DocumentObject::recompute(void)
scopenames += "... ";
break;
}
scopenames += scope.first->getNameInDocument();
scopenames += " ";
}
if (objnames.length() > 80) {
objnames += "... ";
break;
}
}
if (objnames.empty()) {
objnames = "N/A";
} else {
}
else {
objnames.pop_back();
}
if (scopenames.empty()) {
scopenames = "N/A";
} else {
}
else {
scopenames.pop_back();
}
Base::Console().Warning("%s: Link(s) to object(s) '%s' go out of the allowed scope '%s'. Instead, the linked object(s) reside within '%s'.\n", getTypeId().getName(), objnames.c_str(), getNameInDocument(), scopenames.c_str());
#else
return new App::DocumentObjectExecReturn("Links go out of the allowed scope", this);
#endif
Base::Console().Warning("%s: Link(s) to object(s) '%s' go out of the allowed scope '%s'. Instead, the linked object(s) reside within '%s'.\n",
getTypeId().getName(), objnames.c_str(), getNameInDocument(), scopenames.c_str());
}
catch (const Base::Exception& e) {
e.ReportException();
}
}
App::DocumentObjectExecReturn *DocumentObject::recompute()
{
//check if the links are valid before making the recompute
if (!GeoFeatureGroupExtension::areLinksValid(this)) {
printInvalidLinks();
}
// set/unset the execution bit
@@ -887,31 +901,43 @@ std::vector<std::string> DocumentObject::getSubObjects(int reason) const {
return ret;
}
std::vector<std::pair<App::DocumentObject *,std::string> > DocumentObject::getParents(int depth) const {
std::vector<std::pair<App::DocumentObject *,std::string> > ret;
if(!getNameInDocument() || !GetApplication().checkLinkDepth(depth))
std::vector<std::pair<App::DocumentObject *,std::string>> DocumentObject::getParents(int depth) const {
std::vector<std::pair<App::DocumentObject *, std::string>> ret;
if (!getNameInDocument() || !GetApplication().checkLinkDepth(depth, false)) {
return ret;
}
std::string name(getNameInDocument());
name += ".";
for(auto parent : getInList()) {
if(!parent || !parent->getNameInDocument())
continue;
if(!parent->hasChildElement() &&
!parent->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId()))
continue;
if(!parent->getSubObject(name.c_str()))
for (auto parent : getInList()) {
if (!parent || !parent->getNameInDocument()) {
continue;
}
auto links = GetApplication().getLinksTo(parent,App::GetLinkRecursive);
if (!parent->hasChildElement() &&
!parent->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId())) {
continue;
}
if (!parent->getSubObject(name.c_str())) {
continue;
}
auto links = GetApplication().getLinksTo(parent, App::GetLinkRecursive);
links.insert(parent);
for(auto parent : links) {
auto parents = parent->getParents(depth+1);
if(parents.empty())
parents.emplace_back(parent,std::string());
for(auto &v : parents)
ret.emplace_back(v.first,v.second+name);
for (auto parent : links) {
auto parents = parent->getParents(depth + 1);
if (parents.empty()) {
parents.emplace_back(parent, std::string());
}
for (auto &v : parents) {
ret.emplace_back(v.first, v.second + name);
}
}
}
return ret;
}
+3
View File
@@ -614,6 +614,9 @@ protected:
/// get called when a property status has changed
virtual void onPropertyStatusChanged(const Property &prop, unsigned long oldStatus) override;
private:
void printInvalidLinks() const;
/// python object of this class and all descendent
protected: // attributes
Py::SmartPtr PythonObject;
+1 -1
View File
@@ -23,7 +23,7 @@
#include "PreCompiled.h"
// inclution of the generated files (generated out of PropertyContainerPy.xml)
// inclusion of the generated files (generated out of PropertyContainerPy.xml)
#include "DocumentObjectExtensionPy.h"
#include "DocumentObjectExtensionPy.cpp"
+25 -25
View File
@@ -123,7 +123,7 @@ void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -137,7 +137,7 @@ void DocumentObserverPython::slotDeletedDocument(const App::Document& Doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -151,7 +151,7 @@ void DocumentObserverPython::slotRelabelDocument(const App::Document& Doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -165,7 +165,7 @@ void DocumentObserverPython::slotActivateDocument(const App::Document& Doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -179,7 +179,7 @@ void DocumentObserverPython::slotUndoDocument(const App::Document& Doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyUndoDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -194,7 +194,7 @@ void DocumentObserverPython::slotRedoDocument(const App::Document& Doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyRedoDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -260,7 +260,7 @@ void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc,
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = Doc.getPropertyName(&Prop);
@@ -280,7 +280,7 @@ void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = Doc.getPropertyName(&Prop);
@@ -300,7 +300,7 @@ void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -314,7 +314,7 @@ void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& Obj)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -329,7 +329,7 @@ void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& O
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = Obj.getPropertyName(&Prop);
@@ -350,7 +350,7 @@ void DocumentObserverPython::slotChangedObject(const App::DocumentObject& Obj,
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = Obj.getPropertyName(&Prop);
@@ -370,7 +370,7 @@ void DocumentObserverPython::slotRecomputedObject(const App::DocumentObject& Obj
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
Base::pyCall(pyRecomputedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -384,7 +384,7 @@ void DocumentObserverPython::slotRecomputedDocument(const App::Document& doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyRecomputedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -398,7 +398,7 @@ void DocumentObserverPython::slotBeforeRecomputeDocument(const App::Document& do
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyBeforeRecomputeDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -412,7 +412,7 @@ void DocumentObserverPython::slotOpenTransaction(const App::Document& doc, std::
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
args.setItem(1, Py::String(str));
Base::pyCall(pyOpenTransaction.ptr(),args.ptr());
}
@@ -427,7 +427,7 @@ void DocumentObserverPython::slotCommitTransaction(const App::Document& doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyCommitTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -441,7 +441,7 @@ void DocumentObserverPython::slotAbortTransaction(const App::Document& doc)
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyAbortTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
@@ -456,7 +456,7 @@ void DocumentObserverPython::slotAppendDynamicProperty(const App::Property& Prop
try {
auto container = Prop.getContainer();
Py::Tuple args(2);
args.setItem(0, Py::Object(container->getPyObject(), true));
args.setItem(0, Py::asObject(container->getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = container->getPropertyName(&Prop);
@@ -477,7 +477,7 @@ void DocumentObserverPython::slotRemoveDynamicProperty(const App::Property& Prop
try {
auto container = Prop.getContainer();
Py::Tuple args(2);
args.setItem(0, Py::Object(container->getPyObject(), true));
args.setItem(0, Py::asObject(container->getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = container->getPropertyName(&Prop);
@@ -498,7 +498,7 @@ void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, con
try {
auto container = Prop.getContainer();
Py::Tuple args(2);
args.setItem(0, Py::Object(container->getPyObject(), true));
args.setItem(0, Py::asObject(container->getPyObject()));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = container->getPropertyName(&Prop);
@@ -518,7 +518,7 @@ void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc, con
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
args.setItem(1, Py::String(file));
Base::pyCall(pyStartSaveDocument.ptr(),args.ptr());
}
@@ -533,7 +533,7 @@ void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, co
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
args.setItem(1, Py::String(file));
Base::pyCall(pyFinishSaveDocument.ptr(),args.ptr());
}
@@ -548,7 +548,7 @@ void DocumentObserverPython::slotBeforeAddingDynamicExtension(const App::Extensi
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(1, Py::String(extension));
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(),args.ptr());
}
@@ -563,7 +563,7 @@ void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionConta
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(1, Py::String(extension));
Base::pyCall(pyAddedDynamicExtension.ptr(),args.ptr());
}
+1 -1
View File
@@ -25,7 +25,7 @@
#include "Application.h"
// inclution of the generated files (generated out of PropertyContainerPy.xml)
// inclusion of the generated files (generated out of PropertyContainerPy.xml)
#include <App/ExtensionPy.h>
#include <App/ExtensionPy.cpp>
+1 -1
View File
@@ -34,7 +34,7 @@
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
// inclution of the generated files (generated out of PropertyContainerPy.xml)
// inclusion of the generated files (generated out of PropertyContainerPy.xml)
#include "PropertyContainerPy.h"
#include "PropertyContainerPy.cpp"
-1
View File
@@ -1034,7 +1034,6 @@ PyObject *PropertyLinkSub::getPyObject(void)
Py::Tuple tup(2);
Py::List list(static_cast<int>(_cSubList.size()));
if (_pcLinkSub) {
_pcLinkSub->getPyObject();
tup[0] = Py::asObject(_pcLinkSub->getPyObject());
for(unsigned int i = 0;i<_cSubList.size(); i++)
list[i] = Py::String(_cSubList[i]);
+5 -2
View File
@@ -194,9 +194,12 @@ void Transaction::addObjectNew(TransactionalObject *Obj)
auto pos = index.find(Obj);
if (pos != index.end()) {
if (pos->second->status == TransactionObject::Del) {
delete pos->second;
delete pos->first;
// first remove the item from the container before deleting it
auto second = pos->second;
auto first = pos->first;
index.erase(pos);
delete second;
delete first;
}
else {
pos->second->status = TransactionObject::New;
+4 -1
View File
@@ -32,7 +32,9 @@
#include "Builder3D.h"
#include "Console.h"
#include "Exception.h"
#include "FileInfo.h"
#include "Matrix.h"
#include "Stream.h"
#include "Tools.h"
@@ -320,7 +322,8 @@ void Builder3D::saveToLog()
void Builder3D::saveToFile(const char* FileName)
{
result << "} ";
std::ofstream file(FileName);
Base::FileInfo fi(FileName);
Base::ofstream file(fi);
if(!file)
throw FileException("Builder3D::saveToFile(): Can not open file...");
+6
View File
@@ -266,7 +266,13 @@ std::stringstream &LogLevel::prefix(std::stringstream &str, const char *src, int
PyFrameObject* frame = PyEval_GetFrame();
if (frame) {
line = PyFrame_GetLineNumber(frame);
#if PY_VERSION_HEX < 0x030b0000
src = PyUnicode_AsUTF8(frame->f_code->co_filename);
#else
PyCodeObject* code = PyFrame_GetCode(frame);
src = PyUnicode_AsUTF8(code->co_filename);
Py_DECREF(code);
#endif
}
}
if (print_src && src && src[0]) {
+56
View File
@@ -524,6 +524,7 @@ void InterpreterSingleton::addPythonPath(const char* Path)
list.append(Py::String(Path));
}
#if PY_VERSION_HEX < 0x030b0000
const char* InterpreterSingleton::init(int argc,char *argv[])
{
if (!Py_IsInitialized()) {
@@ -566,6 +567,61 @@ const char* InterpreterSingleton::init(int argc,char *argv[])
PyGILStateLocker lock;
return Py_EncodeLocale(Py_GetPath(),nullptr);
}
#else
namespace {
void initInterpreter(int argc,char *argv[])
{
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
status = PyConfig_SetBytesArgv(&config, argc, argv);
if (PyStatus_Exception(status)) {
throw Base::RuntimeError("Failed to set config");
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
throw Base::RuntimeError("Failed to init from config");
}
PyConfig_Clear(&config);
Py_Initialize();
const char* virtualenv = getenv("VIRTUAL_ENV");
if (virtualenv) {
PyRun_SimpleString(
"# Check for virtualenv, and activate if present.\n"
"# See https://virtualenv.pypa.io/en/latest/userguide/#using-virtualenv-without-bin-python\n"
"import os\n"
"import sys\n"
"base_path = os.getenv(\"VIRTUAL_ENV\")\n"
"if not base_path is None:\n"
" activate_this = os.path.join(base_path, \"bin\", \"activate_this.py\")\n"
" exec(open(activate_this).read(), {'__file__':activate_this})\n"
);
}
}
}
const char* InterpreterSingleton::init(int argc,char *argv[])
{
try {
if (!Py_IsInitialized()) {
initInterpreter(argc, argv);
PythonStdOutput::init_type();
this->_global = PyEval_SaveThread();
}
PyGILStateLocker lock;
return Py_EncodeLocale(Py_GetPath(),nullptr);
}
catch (const Base::Exception& e) {
e.ReportException();
throw;
}
}
#endif
void InterpreterSingleton::replaceStdOutput()
{
+1 -1
View File
@@ -28,7 +28,7 @@
#include "Persistence.h"
#include "Writer.h"
// inclution of the generated files (generated By PersitancePy.xml)
// inclusion of the generated files (generated By PersitancePy.xml)
#include "PersistencePy.h"
#include "PersistencePy.cpp"
+4
View File
@@ -60,7 +60,11 @@ PyObjectBase::PyObjectBase(void* p,PyTypeObject *T)
, baseProxy(nullptr)
, attrDict(nullptr)
{
#if PY_VERSION_HEX < 0x030b0000
Py_TYPE(this) = T;
#else
this->ob_type = T;
#endif
_Py_NewReference(this);
#ifdef FC_LOGPYOBJECTS
Base::Console().Log("PyO+: %s (%p)\n",T->tp_name, this);
+9 -1
View File
@@ -15,8 +15,10 @@ is provided on an as is basis, without warranties of any kind.
#include <string.h>
#include <assert.h>
#include <compile.h>
#include <eval.h>
#include <frameobject.h>
#if PY_VERSION_HEX < 0x030b0000
#include <eval.h>
#endif
/*****************************************************************************
@@ -310,7 +312,13 @@ void PP_Fetch_Error_Text()
if(!frame)
return;
int line = PyFrame_GetLineNumber(frame);
#if PY_VERSION_HEX < 0x030b0000
const char *file = PyUnicode_AsUTF8(frame->f_code->co_filename);
#else
PyCodeObject* code = PyFrame_GetCode(frame);
const char *file = PyUnicode_AsUTF8(code->co_filename);
Py_DECREF(code);
#endif
#ifdef FC_OS_WIN32
const char *_f = strstr(file, "\\src\\");
#else
+22 -12
View File
@@ -339,17 +339,22 @@ class FileInfo;
class ofstream : public std::ofstream
{
public:
ofstream() = default;
ofstream(const FileInfo& fi, ios_base::openmode mode =
std::ios::out | std::ios::trunc)
#ifdef _MSC_VER
: std::ofstream(fi.toStdWString().c_str(), mode)
: std::ofstream(fi.toStdWString().c_str(), mode) {}
#else
: std::ofstream(fi.filePath().c_str(), mode)
: std::ofstream(fi.filePath().c_str(), mode) {}
#endif
~ofstream() override = default;
void open(const FileInfo& fi, ios_base::openmode mode =
std::ios::out | std::ios::trunc) {
#ifdef _MSC_VER
std::ofstream::open(fi.toStdWString().c_str(), mode);
#else
std::ofstream::open(fi.filePath().c_str(), mode);
#endif
{
}
virtual ~ofstream()
{
}
};
@@ -362,17 +367,22 @@ public:
class ifstream : public std::ifstream
{
public:
ifstream() = default;
ifstream(const FileInfo& fi, ios_base::openmode mode =
std::ios::in)
#ifdef _MSC_VER
: std::ifstream(fi.toStdWString().c_str(), mode)
: std::ifstream(fi.toStdWString().c_str(), mode) {}
#else
: std::ifstream(fi.filePath().c_str(), mode)
: std::ifstream(fi.filePath().c_str(), mode) {}
#endif
~ifstream() override = default;
void open(const FileInfo& fi, ios_base::openmode mode =
std::ios::in) {
#ifdef _MSC_VER
std::ifstream::open(fi.toStdWString().c_str(), mode);
#else
std::ifstream::open(fi.filePath().c_str(), mode);
#endif
{
}
virtual ~ifstream()
{
}
};
+12 -12
View File
@@ -87,9 +87,9 @@ const char* UnitsApi::getDescription(UnitSystem system)
}
}
UnitsSchemaPtr UnitsApi::createSchema(UnitSystem s)
UnitsSchemaPtr UnitsApi::createSchema(UnitSystem system)
{
switch (s) {
switch (system) {
case UnitSystem::SI1:
return std::make_unique<UnitsSchemaInternal>();
case UnitSystem::SI2:
@@ -115,14 +115,14 @@ UnitsSchemaPtr UnitsApi::createSchema(UnitSystem s)
return nullptr;
}
void UnitsApi::setSchema(UnitSystem s)
void UnitsApi::setSchema(UnitSystem system)
{
if (UserPrefSystem) {
UserPrefSystem->resetSchemaUnits(); // for schemas changed the Quantity constants
}
UserPrefSystem = createSchema(s);
currentSystem = s;
UserPrefSystem = createSchema(system);
currentSystem = system;
// for wrong value fall back to standard schema
if (!UserPrefSystem) {
@@ -133,21 +133,21 @@ void UnitsApi::setSchema(UnitSystem s)
UserPrefSystem->setSchemaUnits(); // if necessary a unit schema can change the constants in Quantity (e.g. mi=1.8km rather then 1.6km).
}
QString UnitsApi::toString(const Base::Quantity& q, const QuantityFormat& f)
QString UnitsApi::toString(const Base::Quantity& quantity, const QuantityFormat& format)
{
QString value = QString::fromLatin1("'%1 %2'").arg(q.getValue(), 0, f.toFormat(), f.precision)
.arg(q.getUnit().getString());
QString value = QString::fromLatin1("'%1 %2'").arg(quantity.getValue(), 0, format.toFormat(), format.precision)
.arg(quantity.getUnit().getString());
return value;
}
QString UnitsApi::toNumber(const Base::Quantity& q, const QuantityFormat& f)
QString UnitsApi::toNumber(const Base::Quantity& quantity, const QuantityFormat& format)
{
return toNumber(q.getValue(), f);
return toNumber(quantity.getValue(), format);
}
QString UnitsApi::toNumber(double d, const QuantityFormat& f)
QString UnitsApi::toNumber(double value, const QuantityFormat& format)
{
QString number = QString::fromLatin1("%1").arg(d, 0, f.toFormat(), f.precision);
QString number = QString::fromLatin1("%1").arg(value, 0, format.toFormat(), format.precision);
return number;
}
+1
View File
@@ -29,6 +29,7 @@
#include <QString>
#include "UnitsSchemaInternal.h"
#include <cmath>
using namespace Base;
+1
View File
@@ -29,6 +29,7 @@
#include <QString>
#include "UnitsSchemaMKS.h"
#include <cmath>
using namespace Base;
+1 -1
View File
@@ -203,7 +203,7 @@ bool BitmapFactoryInst::findPixmapInCache(const char* name, QPixmap& px) const
QIcon BitmapFactoryInst::iconFromTheme(const char* name, const QIcon& fallback)
{
QString iconName = QString::fromLatin1(name);
QString iconName = QString::fromUtf8(name);
QIcon icon = QIcon::fromTheme(iconName, fallback);
if (icon.isNull()) {
QPixmap px = pixmap(name);
+7
View File
@@ -657,8 +657,15 @@ void Command::printPyCaller() {
if(!frame)
return;
int line = PyFrame_GetLineNumber(frame);
#if PY_VERSION_HEX < 0x030b0000
const char *file = PyUnicode_AsUTF8(frame->f_code->co_filename);
printCaller(file?file:"<no file>",line);
#else
PyCodeObject* code = PyFrame_GetCode(frame);
const char* file = PyUnicode_AsUTF8(code->co_filename);
printCaller(file?file:"<no file>",line);
Py_DECREF(code);
#endif
}
void Command::printCaller(const char *file, int line) {
+42 -5
View File
@@ -87,6 +87,37 @@ using namespace Gui;
using Gui::Dialog::DlgSettingsImageImp;
namespace bp = boost::placeholders;
namespace {
// A helper class to open a transaction when changing properties of view providers.
// It uses the same parameter key as the PropertyView to control the behaviour.
class TransactionView {
Gui::Document* document;
public:
static bool getDefault() {
auto hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/PropertyView");
return hGrp->GetBool("AutoTransactionView", false);
}
TransactionView(Gui::Document* doc, const char* name, bool enable = getDefault())
: document(doc)
{
if (document && enable) {
document->openCommand(name);
}
else {
document = nullptr;
}
}
~TransactionView() {
if (document) {
document->commitCommand();
}
}
};
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DEF_STD_CMD_AC(StdOrthographicCamera)
@@ -863,6 +894,7 @@ StdCmdToggleVisibility::StdCmdToggleVisibility()
void StdCmdToggleVisibility::activated(int iMsg)
{
Q_UNUSED(iMsg);
TransactionView transaction(getActiveGuiDocument(), QT_TRANSLATE_NOOP("Command", "Toggle visibility"));
Selection().setVisible(SelectionSingleton::VisToggle);
}
@@ -898,16 +930,21 @@ void StdCmdToggleSelectability::activated(int iMsg)
std::vector<App::DocumentObject*> sel = Selection().getObjectsOfType
(App::DocumentObject::getClassTypeId(), (*it)->getName());
if (sel.empty()) {
continue;
}
for (std::vector<App::DocumentObject*>::const_iterator ft=sel.begin();ft!=sel.end();++ft) {
ViewProvider *pr = pcDoc->getViewProviderByName((*ft)->getNameInDocument());
TransactionView transaction(pcDoc, QT_TRANSLATE_NOOP("Command", "Toggle selectability"));
for (const auto & ft : sel) {
ViewProvider *pr = pcDoc->getViewProviderByName(ft->getNameInDocument());
if (pr && pr->isDerivedFrom(ViewProviderGeometryObject::getClassTypeId())){
if (static_cast<ViewProviderGeometryObject*>(pr)->Selectable.getValue())
doCommand(Gui,"Gui.getDocument(\"%s\").getObject(\"%s\").Selectable=False"
, (*it)->getName(), (*ft)->getNameInDocument());
, (*it)->getName(), ft->getNameInDocument());
else
doCommand(Gui,"Gui.getDocument(\"%s\").getObject(\"%s\").Selectable=True"
, (*it)->getName(), (*ft)->getNameInDocument());
, (*it)->getName(), ft->getNameInDocument());
}
}
}
@@ -3702,7 +3739,7 @@ public:
addCommand(new StdTreeDrag(),cmds.size());
addCommand(new StdTreeSelection(),cmds.size());
};
}
virtual const char* className() const {return "StdCmdTreeViewActions";}
};
+7 -6
View File
@@ -367,16 +367,17 @@ Action * StdCmdToolBarMenu::createAction()
class FilterStatusBar : public QObject
{
// Q_OBJECT
// Q_OBJECT
public:
FilterStatusBar(Action * action):QObject(action) {this->action = action;}
// virtual ~FilterStatusBar() {}
FilterStatusBar(Action* action) :QObject(action) { this->action = action; }
// virtual ~FilterStatusBar() {}
protected:
Action * action;
bool eventFilter(QObject *obj, QEvent *event)
Action* action;
bool eventFilter(QObject* obj, QEvent* event) override
{
if (getMainWindow()->findChild<QStatusBar *>() != nullptr && obj == getMainWindow()->statusBar() && ((event->type() == QEvent::Hide) || (event->type() == QEvent::Show))) {
if (getMainWindow() && getMainWindow()->findChild<QStatusBar*>() && obj == getMainWindow()->statusBar() &&
((event->type() == QEvent::Hide) || (event->type() == QEvent::Show))) {
this->action->setChecked(getMainWindow()->statusBar()->isVisible());
}
return false;
+6 -1
View File
@@ -259,6 +259,8 @@ void DlgGeneralImp::loadSettings()
model->sort(0);
int current = getMainWindow()->iconSize().width();
current = hGrp->GetInt("ToolbarIconSize", current);
ui->toolbarIconSize->clear();
ui->toolbarIconSize->addItem(tr("Small (%1px)").arg(16), QVariant((int)16));
ui->toolbarIconSize->addItem(tr("Medium (%1px)").arg(24), QVariant((int)24));
ui->toolbarIconSize->addItem(tr("Large (%1px)").arg(32), QVariant((int)32));
@@ -270,6 +272,7 @@ void DlgGeneralImp::loadSettings()
}
ui->toolbarIconSize->setCurrentIndex(index);
ui->treeMode->clear();
ui->treeMode->addItem(tr("Combo View"));
ui->treeMode->addItem(tr("TreeView and PropertyView"));
ui->treeMode->addItem(tr("Both"));
@@ -308,6 +311,7 @@ void DlgGeneralImp::loadSettings()
}
// now add all unique items
ui->StyleSheets->clear();
ui->StyleSheets->addItem(tr("No style sheet"), QString::fromLatin1(""));
for (QMap<QString, QString>::iterator it = cssFiles.begin(); it != cssFiles.end(); ++it) {
ui->StyleSheets->addItem(it.key(), it.value());
@@ -333,7 +337,8 @@ void DlgGeneralImp::loadSettings()
}
}
if (index > -1) ui->StyleSheets->setCurrentIndex(index);
if (index > -1)
ui->StyleSheets->setCurrentIndex(index);
}
void DlgGeneralImp::changeEvent(QEvent *e)
+5
View File
@@ -328,6 +328,11 @@ void DlgCustomKeyboardImp::on_editShortcut_textChanged(const QString& sc)
Command* cmd = cCmdMgr.getCommandByName(name.constData());
if (cmd && !cmd->getAction()) {
Base::Console().Warning("Command %s not in use yet\n", cmd->getName());
QMessageBox::warning(this,
tr("Command not in use yet"),
tr("The command '%1' is loaded but not in use yet, so it can't be assigned a new shortcut.\n"
"To enable assignment, please make '%2' the active workbench").arg(data.toString(),ui->categoryBox->currentText()),
QMessageBox::Ok);
ui->buttonAssign->setEnabled(false); // command not in use
return;
}
+1 -1
View File
@@ -409,7 +409,7 @@ void DlgMacroExecuteImp::on_deleteButton_clicked()
MacroItem * mitem = static_cast<MacroItem *>(item);
if (mitem->systemWide) {
QMessageBox::critical(qApp->activeWindow(), QObject::tr("Delete macro"),
QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Delete macro"),
QObject::tr("Not allowed to delete system-wide macros"));
return;
}
+17 -8
View File
@@ -176,15 +176,24 @@ QTabWidget* DlgPreferencesImp::createTabForGroup(const std::string &groupName)
*/
void DlgPreferencesImp::createPageInGroup(QTabWidget *tabWidget, const std::string &pageName)
{
PreferencePage* page = WidgetFactory().createPreferencePage(pageName.c_str());
if (page) {
tabWidget->addTab(page, page->windowTitle());
page->loadSettings();
page->setProperty("GroupName", tabWidget->property("GroupName"));
page->setProperty("PageName", QVariant(QString::fromStdString(pageName)));
try {
PreferencePage* page = WidgetFactory().createPreferencePage(pageName.c_str());
if (page) {
tabWidget->addTab(page, page->windowTitle());
page->loadSettings();
page->setProperty("GroupName", tabWidget->property("GroupName"));
page->setProperty("PageName", QVariant(QString::fromStdString(pageName)));
}
else {
Base::Console().Warning("%s is not a preference page\n", pageName.c_str());
}
}
else {
Base::Console().Warning("%s is not a preference page\n", pageName.c_str());
catch (const Base::Exception& e) {
Base::Console().Error("Base exception thrown for '%s'\n", pageName.c_str());
e.ReportException();
}
catch (const std::exception& e) {
Base::Console().Error("C++ exception thrown for '%s' (%s)\n", pageName.c_str(), e.what());
}
}
+4 -2
View File
@@ -53,13 +53,15 @@ void ExpressionBindingPy::init_type()
PyObject *ExpressionBindingPy::PyMake(struct _typeobject *, PyObject * args, PyObject *)
{
Py::Tuple tuple(args);
PyObject* pyObj;
if (!PyArg_ParseTuple(args,"O", &pyObj))
return nullptr;
ExpressionBinding* expr = nullptr;
PythonWrapper wrap;
wrap.loadWidgetsModule();
QWidget* obj = dynamic_cast<QWidget*>(wrap.toQObject(tuple.getItem(0)));
QWidget* obj = dynamic_cast<QWidget*>(wrap.toQObject(Py::Object(pyObj)));
if (obj) {
do {
QuantitySpinBox* sb = qobject_cast<QuantitySpinBox*>(obj);
+24 -30
View File
@@ -92,6 +92,27 @@ void FileDialog::onSelectedFilter(const QString& /*filter*/)
}
}
QList<QUrl> FileDialog::fetchSidebarUrls()
{
QStringList list;
list << QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
list << QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
list << QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
list << QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
list << getWorkingDirectory();
list << restoreLocation();
list << QDir::currentPath();
QList<QUrl> urls;
for (const auto& it : list) {
if (QFileInfo::exists(it)) {
urls << QUrl::fromLocalFile(it);
}
}
return urls;
}
bool FileDialog::hasSuffix(const QString& ext) const
{
QRegExp rx(QString::fromLatin1("\\*.(%1)\\W").arg(ext));
@@ -181,18 +202,9 @@ QString FileDialog::getSaveFileName (QWidget * parent, const QString & caption,
// before showing the file dialog.
QString file;
if (DialogOptions::dontUseNativeFileDialog()) {
QList<QUrl> urls;
QList<QUrl> urls = fetchSidebarUrls();
options |= QFileDialog::DontUseNativeDialog;
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MusicLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation));
urls << QUrl::fromLocalFile(getWorkingDirectory());
urls << QUrl::fromLocalFile(restoreLocation());
urls << QUrl::fromLocalFile(QDir::currentPath());
FileDialog dlg(parent);
dlg.setWindowTitle(windowTitle);
@@ -263,18 +275,9 @@ QString FileDialog::getOpenFileName(QWidget * parent, const QString & caption, c
QString file;
if (DialogOptions::dontUseNativeFileDialog()) {
QList<QUrl> urls;
QList<QUrl> urls = fetchSidebarUrls();
options |= QFileDialog::DontUseNativeDialog;
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MusicLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation));
urls << QUrl::fromLocalFile(getWorkingDirectory());
urls << QUrl::fromLocalFile(restoreLocation());
urls << QUrl::fromLocalFile(QDir::currentPath());
FileDialog dlg(parent);
dlg.setWindowTitle(windowTitle);
@@ -324,18 +327,9 @@ QStringList FileDialog::getOpenFileNames (QWidget * parent, const QString & capt
QStringList files;
if (DialogOptions::dontUseNativeFileDialog()) {
QList<QUrl> urls;
QList<QUrl> urls = fetchSidebarUrls();
options |= QFileDialog::DontUseNativeDialog;
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MusicLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
urls << QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation));
urls << QUrl::fromLocalFile(getWorkingDirectory());
urls << QUrl::fromLocalFile(restoreLocation());
urls << QUrl::fromLocalFile(QDir::currentPath());
FileDialog dlg(parent);
dlg.setWindowTitle(windowTitle);
+1
View File
@@ -86,6 +86,7 @@ private Q_SLOTS:
private:
bool hasSuffix(const QString&) const;
static QList<QUrl> fetchSidebarUrls();
static QString workingDirectory;
};
+34 -22
View File
@@ -2,26 +2,34 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
id="svg23883"
sodipodi:version="0.32"
inkscape:version="0.43+devel"
inkscape:version="0.46"
version="1.0"
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
sodipodi:docname="edit-cut.svg"
inkscape:export-filename="/home/garrett/edit-cut.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
inkscape:export-ydpi="90"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs23885">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 24 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="48 : 24 : 1"
inkscape:persp3d-origin="24 : 16 : 1"
id="perspective70" />
<linearGradient
inkscape:collect="always"
id="linearGradient2269">
@@ -362,14 +370,26 @@
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
gridempspacing="4"
gridtolerance="0.5px"
inkscape:window-width="1011"
inkscape:window-height="1110"
inkscape:window-x="378"
inkscape:window-y="0"
inkscape:window-height="818"
inkscape:window-x="177"
inkscape:window-y="30"
stroke="#a40000"
inkscape:showpageshadow="false" />
inkscape:showpageshadow="false">
<inkscape:grid
id="GridFromPre046Settings"
type="xygrid"
originx="0px"
originy="0px"
spacingx="1px"
spacingy="1px"
color="#0000ff"
empcolor="#0000ff"
opacity="0.2"
empopacity="0.4"
empspacing="4" />
</sodipodi:namedview>
<metadata
id="metadata23888">
<rdf:RDF>
@@ -392,7 +412,7 @@
</rdf:Bag>
</dc:subject>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/" />
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
<dc:contributor>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
@@ -400,21 +420,13 @@
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-nc-sa/2.0/">
rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Attribution" />
<cc:prohibits
rdf:resource="http://web.resource.org/cc/CommercialUse" />
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

+4
View File
@@ -652,6 +652,10 @@ void Placement::bindObject()
ui->yawAngle ->bind(App::ObjectIdentifier::parse(obj, propertyName + std::string(".Rotation.Yaw")));
ui->pitchAngle->bind(App::ObjectIdentifier::parse(obj, propertyName + std::string(".Rotation.Pitch")));
ui->rollAngle ->bind(App::ObjectIdentifier::parse(obj, propertyName + std::string(".Rotation.Roll")));
ui->yawAngle->evaluateExpression();
ui->pitchAngle->evaluateExpression();
ui->rollAngle->evaluateExpression();
}
}
+15 -2
View File
@@ -563,6 +563,14 @@ void PythonDebugger::hideDebugMarker(const QString& fn)
}
}
#if PY_VERSION_HEX < 0x030900B1
static PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
{
Py_INCREF(frame->f_code);
return frame->f_code;
}
#endif
// http://www.koders.com/cpp/fidBA6CD8A0FE5F41F1464D74733D9A711DA257D20B.aspx?s=PyEval_SetTrace
// http://code.google.com/p/idapython/source/browse/trunk/python.cpp
// http://www.koders.com/cpp/fid191F7B13CF73133935A7A2E18B7BF43ACC6D1784.aspx?s=PyEval_SetTrace
@@ -578,7 +586,9 @@ int PythonDebugger::tracer_callback(PyObject *obj, PyFrameObject *frame, int wha
//no = frame->f_tstate->recursion_depth;
//std::string funcname = PyString_AsString(frame->f_code->co_name);
QString file = QString::fromUtf8(PyUnicode_AsUTF8(frame->f_code->co_filename));
PyCodeObject* code = PyFrame_GetCode(frame);
QString file = QString::fromUtf8(PyUnicode_AsUTF8(code->co_filename));
Py_DECREF(code);
switch (what) {
case PyTrace_CALL:
self->depth++;
@@ -592,7 +602,10 @@ int PythonDebugger::tracer_callback(PyObject *obj, PyFrameObject *frame, int wha
//PyObject *str;
//str = PyObject_Str(frame->f_code->co_filename);
//no = frame->f_lineno;
int line = PyCode_Addr2Line(frame->f_code, frame->f_lasti);
PyCodeObject* f_code = PyFrame_GetCode(frame);
int f_lasti = PyFrame_GetLineNumber(frame);
int line = PyCode_Addr2Line(f_code, f_lasti);
Py_DECREF(f_code);
//if (str) {
// Base::Console().Message("PROFILING: %s:%d\n", PyString_AsString(str), frame->f_lineno);
// Py_DECREF(str);
+119 -11
View File
@@ -23,6 +23,9 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <limits>
# include <unordered_map>
# include <list>
# include <QApplication>
# include <QDir>
# include <QIcon>
# include <QWidget>
@@ -121,6 +124,7 @@ PyTypeObject** SbkPySide2_QtWidgetsTypes=nullptr;
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
@@ -149,7 +153,7 @@ PyObject* toPythonFuncQuantityTyped(Base::Quantity cpx) {
PyObject* toPythonFuncQuantity(const void* cpp)
{
return toPythonFuncQuantityTyped(*reinterpret_cast<const Base::Quantity*>(cpp));
return toPythonFuncQuantityTyped(*static_cast<const Base::Quantity*>(cpp));
}
void toCppPointerConvFuncQuantity(PyObject* pyobj,void* cpp)
@@ -217,6 +221,108 @@ void registerTypes()
// --------------------------------------------------------
namespace Gui {
template<typename qttype>
PyTypeObject *getPyTypeObjectForTypeName();
/*!
* \brief The WrapperManager class
* This is a helper class that records the Python wrappers of a QObject and invalidates
* them when the QObject is about to be destroyed.
* This is to make sure that if the Python wrapper doesn't own the QObject it won't be notified
* if the QObject is destroyed.
* \code
* ui = Gui.UiLoader()
* lineedit = ui.createWidget("QLineEdit")
* lineedit.deleteLater()
* # Make sure this won't crash
* lineedit.show()
* \endcode
*/
class WrapperManager : public QObject
{
std::unordered_map<QObject*, std::list<Py::Object>> wrappers;
public:
static WrapperManager& instance()
{
static WrapperManager singleton;
return singleton;
}
/*!
* \brief addQObject
* \param obj
* \param pyobj
* Add the QObject and its Python wrapper to the list.
*/
void addQObject(QObject* obj, PyObject* pyobj)
{
if (wrappers.find(obj) == wrappers.end()) {
QObject::connect(obj, &QObject::destroyed, this, &WrapperManager::destroyed);
}
auto& pylist = wrappers[obj];
if (std::find_if(pylist.cbegin(), pylist.cend(), [pyobj](const Py::Object& py) { return py.ptr() == pyobj; }) == pylist.end()) {
pylist.emplace_back(pyobj);
}
}
private:
/*!
* \brief destroyed
* \param obj
* The listed QObject is about to be destroyed. Invalidate its Python wrappers now.
*/
void destroyed(QObject* obj = nullptr)
{
if (obj) {
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
auto key = wrappers.find(obj);
if (key != wrappers.end()) {
Base::PyGILStateLocker lock;
for (const auto& it : key->second) {
auto value = it.ptr();
Shiboken::Object::setValidCpp(reinterpret_cast<SbkObject*>(value), false);
}
wrappers.erase(key);
}
#endif
}
}
void clear()
{
Base::PyGILStateLocker lock;
wrappers.clear();
}
void wrapQApplication()
{
// We have to explicitly hold a reference to the wrapper of the QApplication
// as otherwise it can happen that when running the gc the program crashes
// The code snippet below caused a crash on older versions:
// mw = Gui.getMainWindow()
// mw.style()
// import gc
// gc.collect()
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
PyTypeObject * type = getPyTypeObjectForTypeName<QApplication>();
if (type) {
auto sbk_type = reinterpret_cast<SbkObjectType*>(type);
std::string typeName = "QApplication";
PyObject* pyobj = Shiboken::Object::newObject(sbk_type, qApp, false, false, typeName.c_str());
addQObject(qApp, pyobj);
}
#endif
}
WrapperManager()
{
connect(QApplication::instance(), &QCoreApplication::aboutToQuit,
this, &WrapperManager::clear);
wrapQApplication();
}
~WrapperManager() = default;
};
template<typename qttype>
Py::Object qt_wrapInstance(qttype object, const char* className,
const char* shiboken, const char* pyside,
@@ -353,19 +459,19 @@ QObject* PythonWrapper::toQObject(const Py::Object& pyobject)
if (Shiboken::Object::checkType(pyobject.ptr())) {
SbkObject* sbkobject = reinterpret_cast<SbkObject *>(pyobject.ptr());
void* cppobject = Shiboken::Object::cppPointer(sbkobject, type);
return reinterpret_cast<QObject*>(cppobject);
return static_cast<QObject*>(cppobject);
}
}
#else
// Access shiboken2/PySide2 via Python
//
void* ptr = qt_getCppPointer(pyobject, "shiboken2", "getCppPointer");
return reinterpret_cast<QObject*>(ptr);
return static_cast<QObject*>(ptr);
#endif
#if 0 // Unwrapping using sip/PyQt
#ifdef HAVE_PYQT // Unwrapping using sip/PyQt
void* ptr = qt_getCppPointer(pyobject, "sip", "unwrapinstance");
return reinterpret_cast<QObject*>(ptr);
return static_cast<QObject*>(ptr);
#endif
return nullptr;
@@ -379,14 +485,14 @@ QGraphicsItem* PythonWrapper::toQGraphicsItem(PyObject* pyPtr)
if (Shiboken::Object::checkType(pyPtr)) {
SbkObject* sbkobject = reinterpret_cast<SbkObject*>(pyPtr);
void* cppobject = Shiboken::Object::cppPointer(sbkobject, type);
return reinterpret_cast<QGraphicsItem*>(cppobject);
return static_cast<QGraphicsItem*>(cppobject);
}
}
#else
// Access shiboken2/PySide2 via Python
//
void* ptr = qt_getCppPointer(Py::asObject(pyPtr), "shiboken2", "getCppPointer");
return reinterpret_cast<QGraphicsItem*>(ptr);
return static_cast<QGraphicsItem*>(ptr);
#endif
return nullptr;
}
@@ -435,7 +541,7 @@ QIcon *PythonWrapper::toQIcon(PyObject *pyobj)
if (Shiboken::Object::checkType(pyobj)) {
SbkObject* sbkobject = reinterpret_cast<SbkObject *>(pyobj);
void* cppobject = Shiboken::Object::cppPointer(sbkobject, type);
return reinterpret_cast<QIcon*>(cppobject);
return static_cast<QIcon*>(cppobject);
}
}
#else
@@ -466,7 +572,7 @@ QDir* PythonWrapper::toQDir(PyObject* pyobj)
if (Shiboken::Object::checkType(pyobj)) {
SbkObject* sbkobject = reinterpret_cast<SbkObject*>(pyobj);
void* cppobject = Shiboken::Object::cppPointer(sbkobject, type);
return reinterpret_cast<QDir*>(cppobject);
return static_cast<QDir*>(cppobject);
}
}
#else
@@ -491,6 +597,7 @@ Py::Object PythonWrapper::fromQObject(QObject* object, const char* className)
else
typeName = object->metaObject()->className();
PyObject* pyobj = Shiboken::Object::newObject(sbk_type, object, false, false, typeName.c_str());
WrapperManager::instance().addQObject(object, pyobj);
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap object");
@@ -499,7 +606,7 @@ Py::Object PythonWrapper::fromQObject(QObject* object, const char* className)
//
return qt_wrapInstance<QObject*>(object, className, "shiboken2", "PySide2.QtCore", "wrapInstance");
#endif
#if 0 // Unwrapping using sip/PyQt
#ifdef HAVE_PYQT // Unwrapping using sip/PyQt
Q_UNUSED(className);
return qt_wrapInstance<QObject*>(object, "QObject", "sip", "PyQt5.QtCore", "wrapinstance");
#endif
@@ -519,6 +626,7 @@ Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
else
typeName = widget->metaObject()->className();
PyObject* pyobj = Shiboken::Object::newObject(sbk_type, widget, false, false, typeName.c_str());
WrapperManager::instance().addQObject(widget, pyobj);
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap widget");
@@ -529,7 +637,7 @@ Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
return qt_wrapInstance<QWidget*>(widget, className, "shiboken2", "PySide2.QtWidgets", "wrapInstance");
#endif
#if 0 // Unwrapping using sip/PyQt
#ifdef HAVE_PYQT // Unwrapping using sip/PyQt
Q_UNUSED(className);
return qt_wrapInstance<QWidget*>(widget, "QWidget", "sip", "PyQt5.QtWidgets", "wrapinstance");
#endif
+7
View File
@@ -412,6 +412,13 @@ QString Gui::QuantitySpinBox::expressionText() const
return QString();
}
void QuantitySpinBox::evaluateExpression()
{
if (isBound() && getExpression()) {
showValidExpression(Number::SetIfNumber);
}
}
void Gui::QuantitySpinBox::setNumberExpression(App::NumberExpression* expr)
{
lineEdit()->setText(getUserString(expr->getQuantity()));
+1
View File
@@ -108,6 +108,7 @@ public:
/// Gets the expression as a string
QString expressionText() const;
void evaluateExpression();
/// Set the number portion selected
void selectNumber();
+7 -2
View File
@@ -256,8 +256,6 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev)
newmode = NavigationStyle::SELECTION;
break;
case BUTTON1DOWN|BUTTON2DOWN:
newmode = NavigationStyle::PANNING;
break;
case BUTTON3DOWN:
newmode = NavigationStyle::PANNING;
break;
@@ -273,6 +271,13 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent * const ev)
break;
default:
// Reset mode to SELECTION when button 3 is released
// This stops the DRAGGING when button 3 is released but SHIFT is still pressed
// This stops the ZOOMING when button 3 is released but CTRL is still pressed
if ((curmode == NavigationStyle::DRAGGING || curmode == NavigationStyle::ZOOMING)
&& !this->button3down) {
newmode = NavigationStyle::SELECTION;
}
break;
}
+8 -2
View File
@@ -2357,8 +2357,14 @@ PyObject *SelectionSingleton::sGetCompleteSelection(PyObject * /*self*/, PyObjec
sel = Selection().getCompleteSelection(toEnum(resolve));
Py::List list;
for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
list.append(Py::asObject(it->pObject->getPyObject()));
for (const auto & it : sel) {
SelectionObject obj(SelectionChanges(SelectionChanges::AddSelection,
it.DocName,
it.FeatName,
it.SubName,
it.TypeName,
it.x, it.y, it.z));
list.append(Py::asObject(obj.getPyObject()));
}
return Py::new_reference_to(list);
}
+1 -1
View File
@@ -120,7 +120,7 @@ void SoFCOffscreenRenderer::writeToImageFile(const char* filename, const char* c
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG");
image.save(&buffer, "JPG", 90);
writeJPEGComment(com, ba);
QFile file(QString::fromUtf8(filename));
+1 -1
View File
@@ -639,7 +639,7 @@ void AboutDialog::showLibraryInformation()
out << "</ul>\n</body>\n</html>";
textField->setHtml(html);
connect(textField, SIGNAL(anchorClicked(QUrl)), this, SLOT(linkActivated(QUrl)));
connect(textField, &QTextBrowser::anchorClicked, this, &AboutDialog::linkActivated);
}
void AboutDialog::showCollectionInformation()
+10 -8
View File
@@ -114,7 +114,7 @@ SbBool TinkerCADNavigationStyle::processSoEvent(const SoEvent * const ev)
const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
const int button = event->getButton();
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
SbBool canOpenPopupMenu = false;
SbBool shortRMBclick = false;
switch (button) {
case SoMouseButtonEvent::BUTTON1:
@@ -144,7 +144,7 @@ SbBool TinkerCADNavigationStyle::processSoEvent(const SoEvent * const ev)
float dci = float(QApplication::doubleClickInterval())/1000.0f;
// time between press and release event
if (tmp.getValue() < dci) {
canOpenPopupMenu = true;
shortRMBclick = true;
}
}
@@ -156,14 +156,16 @@ SbBool TinkerCADNavigationStyle::processSoEvent(const SoEvent * const ev)
processed = true;
}
else if (!press && (curmode == NavigationStyle::DRAGGING)) {
if (!viewer->isEditing() && canOpenPopupMenu) {
// If we are in drag mode but mouse hasn't been moved open the context-menu
if (this->isPopupMenuEnabled()) {
this->openPopupMenu(event->getPosition());
if (shortRMBclick) {
newmode = NavigationStyle::IDLE;
if (!viewer->isEditing()) {
// If we are in drag mode but mouse hasn't been moved open the context-menu
if (this->isPopupMenuEnabled()) {
this->openPopupMenu(event->getPosition());
}
processed = true;
}
}
newmode = NavigationStyle::IDLE;
processed = true;
}
break;
case SoMouseButtonEvent::BUTTON3:
+14 -2
View File
@@ -813,12 +813,24 @@ void View3DInventorViewer::checkGroupOnTop(const SelectionChanges &Reason) {
std::vector<ViewProvider*> groups;
auto grpVp = vp;
std::set<ViewProvider*> visited;
for(auto childVp=vp;;childVp=grpVp) {
auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(childVp->getObject());
if(!grp || !grp->getNameInDocument()) break;
if(!grp || !grp->getNameInDocument()) {
break;
}
grpVp = dynamic_cast<ViewProviderDocumentObject*>(
Application::Instance->getViewProvider(grp));
if(!grpVp) break;
if(!grpVp) {
break;
}
// avoid endless-loops
if (!visited.insert(childVp).second) {
break;
}
auto childRoot = grpVp->getChildRoot();
auto modeSwitch = grpVp->getModeSwitch();
auto idx = modeSwitch->whichChild.getValue();
+1 -1
View File
@@ -27,7 +27,7 @@
# include <sstream>
#endif
// inclution of the generated files (generated out of PropertyContainerPy.xml)
// inclusion of the generated files (generated out of PropertyContainerPy.xml)
#include "ViewProviderExtensionPy.h"
#include "ViewProviderExtensionPy.cpp"
#include "ViewProviderDocumentObject.h"
+11 -11
View File
@@ -59,10 +59,10 @@ Check if the object is visible.</UserDocu>
</Methode>
<Methode Name="canDragObject">
<Documentation>
<UserDocu>canDragObject(obj) -> bool\n
<UserDocu>canDragObject(obj=None) -> bool\n
Check whether the child object can be removed by dragging.
If 'obj' is not given, check without filter by any particular object.\n
obj : App.DocumentObject\n Object to be dragged. Optional.</UserDocu>
obj : App.DocumentObject or None\n Object to be dragged.</UserDocu>
</Documentation>
</Methode>
<Methode Name="dragObject">
@@ -74,25 +74,25 @@ obj : App.DocumentObject\n Object to be dragged.</UserDocu>
</Methode>
<Methode Name="canDropObject" Keyword="true">
<Documentation>
<UserDocu>canDropObject(obj, owner, subname, elem) -> bool\n
<UserDocu>canDropObject(obj=None, owner=None, subname, elem=None) -> bool\n
Check whether the child object can be added by dropping.
If 'obj' is not given, check without filter by any particular object.\n
obj : App.DocumentObject\n Object to be dropped. Optional.
owner : App.DocumentObject\n Parent object of the dropping object. Optional.
obj : App.DocumentObject or None\n Object to be dropped.
owner : App.DocumentObject or None\n Parent object of the dropping object.
subname : str\n Subname reference to the dropping object. Optional.
elem : sequence of str\n Non-objects subelements selected when the object is
being dropped. Optional.</UserDocu>
elem : sequence of str or None\n Non-objects subelements selected when the object is
being dropped.</UserDocu>
</Documentation>
</Methode>
<Methode Name="dropObject" Keyword="true">
<Documentation>
<UserDocu>dropObject(obj, owner, subname, elem) -> str\n
<UserDocu>dropObject(obj, owner=None, subname, elem=None) -> str\n
Add a child object by dropping.\n
obj : App.DocumentObject\n Object to be dropped.
owner : App.DocumentObject\n Parent object of the dropping object. Optional.
owner : App.DocumentObject or None\n Parent object of the dropping object.
subname : str\n Subname reference to the dropping object. Optional.
elem : sequence of str\n Non-objects subelements selected when the object is
being dropped. Optional.</UserDocu>
elem : sequence of str or None\n Non-objects subelements selected when the object is
being dropped.</UserDocu>
</Documentation>
</Methode>
<Methode Name="canDragAndDropObject">
+43 -22
View File
@@ -161,17 +161,23 @@ PyObject* ViewProviderPy::isVisible(PyObject *args)
PyObject* ViewProviderPy::canDragObject(PyObject *args)
{
PyObject *obj = nullptr;
if (!PyArg_ParseTuple(args, "|O!", &App::DocumentObjectPy::Type, &obj))
PyObject *obj = Py_None;
if (!PyArg_ParseTuple(args, "|O", &obj))
return nullptr;
PY_TRY {
bool ret;
if (!obj)
if (obj == Py_None) {
ret = getViewProviderPtr()->canDragObjects();
else
}
else {
if (!PyObject_TypeCheck(obj, &App::DocumentObjectPy::Type)) {
PyErr_SetString(PyExc_TypeError, "'obj' must be a App::DocumentObject or None");
return nullptr;
}
ret = getViewProviderPtr()->canDragObject(
static_cast<App::DocumentObjectPy*>(obj)->getDocumentObjectPtr());
}
return Py::new_reference_to(Py::Boolean(ret));
}
@@ -180,14 +186,12 @@ PyObject* ViewProviderPy::canDragObject(PyObject *args)
PyObject* ViewProviderPy::canDropObject(PyObject *args, PyObject *kw)
{
PyObject *obj = nullptr;
PyObject *owner = nullptr;
PyObject *pyElements = nullptr;
PyObject *obj = Py_None;
PyObject *owner = Py_None;
PyObject *pyElements = Py_None;
const char *subname = nullptr;
static char* kwlist[] = {"obj","owner","subname","elem",nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kw, "|O!O!sO", kwlist,
&App::DocumentObjectPy::Type,&obj, &App::DocumentObjectPy::Type, &owner,
&subname, &pyElements))
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOsO", kwlist, &obj, &owner, &subname, &pyElements))
return nullptr;
PY_TRY {
@@ -195,18 +199,30 @@ PyObject* ViewProviderPy::canDropObject(PyObject *args, PyObject *kw)
App::DocumentObject* pcObject;
App::DocumentObject* pcOwner = nullptr;
App::PropertyStringList elements;
if (!obj && (owner || pyElements || subname)) {
if (obj == Py_None && (owner != Py_None || pyElements != Py_None || subname)) {
PyErr_SetString(PyExc_ValueError, "'obj' must be specified if 'owner', 'subname' or 'elem' is given");
return nullptr;
}
if(!obj) {
if(obj == Py_None) {
ret = getViewProviderPtr()->canDropObjects();
return Py::new_reference_to(Py::Boolean(ret));
}
pcObject = static_cast<App::DocumentObjectPy*>(obj)->getDocumentObjectPtr();
if (owner)
else {
if (!PyObject_TypeCheck(obj, &App::DocumentObjectPy::Type)) {
PyErr_SetString(PyExc_TypeError, "'obj' must be a App::DocumentObject or None");
return nullptr;
}
pcObject = static_cast<App::DocumentObjectPy*>(obj)->getDocumentObjectPtr();
}
if (owner != Py_None) {
if (!PyObject_TypeCheck(owner, &App::DocumentObjectPy::Type)) {
PyErr_SetString(PyExc_TypeError, "'owner' must be a App::DocumentObject or None");
return nullptr;
}
pcOwner = static_cast<App::DocumentObjectPy*>(owner)->getDocumentObjectPtr();
if (pyElements) {
}
if (pyElements != Py_None) {
try {
elements.setPyObject(pyElements);
}
@@ -238,22 +254,27 @@ PyObject* ViewProviderPy::canDragAndDropObject(PyObject *args)
PyObject* ViewProviderPy::dropObject(PyObject *args, PyObject *kw)
{
PyObject *obj;
PyObject *owner = nullptr;
PyObject *pyElements = nullptr;
PyObject *owner = Py_None;
PyObject *pyElements = Py_None;
const char *subname = nullptr;
static char* kwlist[] = {"obj","owner","subname","elem",nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kw, "O!|O!sO", kwlist,
&App::DocumentObjectPy::Type,&obj, &App::DocumentObjectPy::Type, &owner,
&subname, &pyElements))
if (!PyArg_ParseTupleAndKeywords(args, kw, "O!|OsO", kwlist,
&App::DocumentObjectPy::Type, &obj, &owner, &subname, &pyElements))
return nullptr;
PY_TRY {
auto pcObject = static_cast<App::DocumentObjectPy*>(obj)->getDocumentObjectPtr();
App::DocumentObject *pcOwner = nullptr;
App::PropertyStringList elements;
if (owner)
if (owner != Py_None) {
if (!PyObject_TypeCheck(owner, &App::DocumentObjectPy::Type)) {
PyErr_SetString(PyExc_TypeError, "'owner' must be a App::DocumentObject or None");
return nullptr;
}
pcOwner = static_cast<App::DocumentObjectPy*>(owner)->getDocumentObjectPtr();
if (pyElements) {
}
if (pyElements != Py_None) {
try {
elements.setPyObject(pyElements);
}
@@ -747,6 +747,7 @@ void PropertyEditor::contextMenuEvent(QContextMenuEvent *) {
case MA_Expression:
if(contextIndex == currentIndex()) {
Base::FlagToggler<> flag(binding);
closeEditor();
openEditor(contextIndex);
}
break;
+15 -13
View File
@@ -25,6 +25,7 @@
# ***************************************************************************
import os
import functools
import shutil
import stat
import tempfile
@@ -573,7 +574,7 @@ class CommandAddonManager:
self.startup_sequence.append(self.load_macro_metadata)
selection = pref.GetString("SelectedAddon", "")
if selection:
self.startup_sequence.insert(2, lambda: self.select_addon(selection))
self.startup_sequence.insert(2, functools.partial(self.select_addon, selection))
pref.SetString("SelectedAddon", "")
if ADDON_MANAGER_DEVELOPER_MODE:
self.startup_sequence.append(self.validate)
@@ -954,16 +955,17 @@ class CommandAddonManager:
def __init__(self, repo: Addon, all_repos: List[Addon]):
deps = Addon.Dependencies()
repo_name_dict = dict()
repo_name_dict = {}
for r in all_repos:
repo_name_dict[repo.name] = r
repo_name_dict[repo.display_name] = r
repo_name_dict[r.name] = r
repo_name_dict[r.display_name] = r
repo.walk_dependency_tree(repo_name_dict, deps)
self.external_addons = []
for dep in deps.required_external_addons:
if dep.status() == Addon.Status.NOT_INSTALLED:
self.external_addons.append(dep)
self.external_addons.append(dep.name)
# Now check the loaded addons to see if we are missing an internal workbench:
wbs = [wb.lower() for wb in FreeCADGui.listWorkbenches()]
@@ -1131,10 +1133,10 @@ class CommandAddonManager:
self.dependency_dialog.buttonBox.button(
QtWidgets.QDialogButtonBox.Yes
).clicked.connect(lambda: self.dependency_dialog_yes_clicked(repo))
).clicked.connect(functools.partial(self.dependency_dialog_yes_clicked, repo))
self.dependency_dialog.buttonBox.button(
QtWidgets.QDialogButtonBox.Ignore
).clicked.connect(lambda: self.dependency_dialog_ignore_clicked(repo))
).clicked.connect(functools.partial(self.dependency_dialog_ignore_clicked, repo))
self.dependency_dialog.buttonBox.button(
QtWidgets.QDialogButtonBox.Cancel
).setDefault(True)
@@ -1176,7 +1178,7 @@ class CommandAddonManager:
# No missing deps, just install
self.install(repo)
def dependency_dialog_yes_clicked(self, repo: Addon) -> None:
def dependency_dialog_yes_clicked(self, installing_repo: Addon) -> None:
# Get the lists out of the dialog:
addons = []
for row in range(self.dependency_dialog.listWidgetAddons.count()):
@@ -1201,15 +1203,15 @@ class CommandAddonManager:
addons, python_required, python_optional
)
self.dependency_installation_worker.no_python_exe.connect(
lambda: self.no_python_exe(repo)
functools.partial(self.no_python_exe, installing_repo)
)
self.dependency_installation_worker.no_pip.connect(
lambda command: self.no_pip(command, repo)
functools.partial(self.no_pip, repo=installing_repo)
)
self.dependency_installation_worker.failure.connect(
self.dependency_installation_failure
)
self.dependency_installation_worker.success.connect(lambda: self.install(repo))
self.dependency_installation_worker.success.connect(functools.partial(self.install,installing_repo))
self.dependency_installation_dialog = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information,
translate("AddonsInstaller", "Installing dependencies"),
@@ -1373,10 +1375,10 @@ class CommandAddonManager:
self.update_all_worker.progress_made.connect(self.update_progress_bar)
self.update_all_worker.status_message.connect(self.show_information)
self.update_all_worker.success.connect(
lambda repo: self.subupdates_succeeded.append(repo)
self.subupdates_succeeded.append
)
self.update_all_worker.failure.connect(
lambda repo: self.subupdates_failed.append(repo)
self.subupdates_failed.append
)
self.update_all_worker.finished.connect(self.on_update_all_completed)
self.update_all_worker.start()
+11 -1
View File
@@ -240,7 +240,17 @@ if HAVE_QTNETWORK:
) # This may still be QNetworkProxy.NoProxy
elif userProxyCheck:
host, _, port_string = proxy_string.rpartition(":")
port = 0 if not port_string else int(port_string)
try:
port = 0 if not port_string else int(port_string)
except ValueError:
FreeCAD.Console.PrintError(
translate(
"AddonsInstaller",
"Failed to convert the specified proxy port '{}' to a port number",
).format(port_string)
+ "\n"
)
port = 0
# For now assume an HttpProxy, but eventually this should be a parameter
proxy = QtNetwork.QNetworkProxy(
QtNetwork.QNetworkProxy.HttpProxy, host, port
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -261,7 +261,7 @@ class Macro(object):
FreeCAD.Console.PrintWarning(
translate(
"AddonsInstaller",
"Unable to open macro code URL {rawcodeurl}",
"Unable to open macro code URL {}",
).format(self.raw_code_url)
+ "\n"
)
+16 -3
View File
@@ -972,7 +972,10 @@ class InstallWorkbenchWorker(QtCore.QThread):
return
basedir = FreeCAD.getUserAppDataDir()
moddir = basedir + os.sep + "Mod"
if basedir[-1:] != os.sep:
moddir = basedir + os.sep + "Mod"
else:
moddir = basedir + "Mod"
if not os.path.exists(moddir):
os.makedirs(moddir)
target_dir = moddir + os.sep + self.repo.name
@@ -1551,7 +1554,12 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
repo.display_name
)
)
f = io.StringIO(data.data().decode("utf8"))
try:
f = io.StringIO(data.data().decode("utf8"))
except UnicodeDecodeError as e:
FreeCAD.Console.PrintWarning(str(e))
FreeCAD.Console.PrintWarning(f" in package {repo.name}\n")
return
while True:
line = f.readline()
if not line:
@@ -1600,7 +1608,12 @@ class UpdateMetadataCacheWorker(QtCore.QThread):
"Downloaded requirements.txt for {}",
).format(repo.display_name)
)
f = io.StringIO(data.data().decode("utf8"))
try:
f = io.StringIO(data.data().decode("utf8"))
except UnicodeDecodeError as e:
FreeCAD.Console.PrintWarning(str(e))
FreeCAD.Console.PrintWarning(f" in package {repo.name}\n")
return
lines = f.readlines()
for line in lines:
break_chars = " <>=~!+#"
+3 -2
View File
@@ -457,7 +457,7 @@ class BuildingPart(ArchIFC.IfcProduct):
shapes = []
solidindex = 0
materialstable = {}
for child in Draft.get_group_contents(obj):
for child in Draft.get_group_contents(obj, walls=True):
if not Draft.get_type(child) in ["Space"]:
if hasattr(child,'Shape') and child.Shape:
shapes.append(child.Shape)
@@ -660,6 +660,7 @@ class ViewProviderBuildingPart:
self.sep.addChild(self.dst)
self.lco = coin.SoCoordinate3()
self.sep.addChild(self.lco)
import PartGui # Required for "SoBrepEdgeSet" (because a BuildingPart is not a Part::FeaturePython object).
lin = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
if lin:
lin.coordIndex.setValues([0,1,-1,2,3,-1,4,5,-1])
@@ -733,7 +734,7 @@ class ViewProviderBuildingPart:
"recursively get the colors of objects inside this BuildingPart"
colors = []
for child in Draft.get_group_contents(obj):
for child in Draft.get_group_contents(obj, walls=True):
if not Draft.get_type(child) in ["Space"]:
if hasattr(child,'Shape') and (hasattr(child.ViewObject,"DiffuseColor") or hasattr(child.ViewObject,"ShapeColor")):
if hasattr(child.ViewObject,"DiffuseColor") and len(child.ViewObject.DiffuseColor) == len(child.Shape.Faces):
+3 -4
View File
@@ -20,7 +20,7 @@
#* *
#*****************************************************************************
import FreeCAD,ArchCommands
import FreeCAD, Draft, ArchCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
@@ -61,12 +61,11 @@ def cutComponentwithPlane(archObject, cutPlane, sideFace):
if cutVolume:
obj = FreeCAD.ActiveDocument.addObject("Part::Feature","CutVolume")
obj.Shape = cutVolume
obj.ViewObject.ShapeColor = (1.00,0.00,0.00)
obj.ViewObject.Transparency = 75
if "Additions" in archObject.Object.PropertiesList:
ArchCommands.removeComponents(obj,archObject.Object)
ArchCommands.removeComponents(obj, archObject.Object) # Also changes the obj colors.
return None
else:
Draft.format_object(obj, archObject.Object)
cutObj = FreeCAD.ActiveDocument.addObject("Part::Cut","CutPlane")
cutObj.Base = archObject.Object
cutObj.Tool = obj
+21
View File
@@ -1,3 +1,24 @@
#***************************************************************************
#* Copyright (c) 2020 Yorik van Havre <yorik@uncreated.net> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
"""View providers and UI elements for the Ifc classes."""
import FreeCAD, ArchIFC
+1
View File
@@ -1053,6 +1053,7 @@ class _ViewProviderSectionPlane:
self.drawstyle = coin.SoDrawStyle()
self.drawstyle.style = coin.SoDrawStyle.LINES
self.lcoords = coin.SoCoordinate3()
import PartGui # Required for "SoBrepEdgeSet" (because a SectionPlane is not a Part::FeaturePython object).
ls = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
ls.coordIndex.setValues(0,57,[0,1,-1,2,3,4,5,-1,6,7,8,9,-1,10,11,-1,12,13,14,15,-1,16,17,18,19,-1,20,21,-1,22,23,24,25,-1,26,27,28,29,-1,30,31,-1,32,33,34,35,-1,36,37,38,39,-1,40,41,42,43,44])
self.txtcoords = coin.SoTransform()
+2
View File
@@ -672,11 +672,13 @@ class _ViewProviderSpace(ArchComponent.ViewProviderComponent):
if hasattr(vobj,"FirstLine"):
scale = vobj.FirstLine.Value/vobj.FontSize.Value
self.header.scaleFactor.setValue([scale,scale,scale])
self.onChanged(vobj, "TextPosition")
elif (prop == "FirstLine"):
if hasattr(self,"header") and hasattr(vobj,"FontSize") and hasattr(vobj,"FirstLine"):
scale = vobj.FirstLine.Value/vobj.FontSize.Value
self.header.scaleFactor.setValue([scale,scale,scale])
self.onChanged(vobj, "TextPosition")
elif prop == "TextColor":
if hasattr(self,"color") and hasattr(vobj,"TextColor"):
+54 -54
View File
@@ -110,7 +110,7 @@ def makeStairs(baseobj=None,length=None,width=None,height=None,steps=None,name="
stairs[i].Base = baseobjI
if (len(baseobjI.Shape.Edges) > 1):
stepsI = 1 #'landing' if 'multi-edges' currently
stepsI = 1 #'landing' if 'multi-edges' currently
elif steps:
stepsI = steps
else:
@@ -121,7 +121,7 @@ def makeStairs(baseobj=None,length=None,width=None,height=None,steps=None,name="
additions.append(stairs[i])
stairs[i].LastSegment = stairs[i-1]
else:
if len(stairs) > 1: # i.e. length >1, have a 'master' staircase created
if len(stairs) > 1: # i.e. length >1, have a 'master' staircase created
stairs[0].Base = stairs[1]
i += 1
if lenSelection > 1:
@@ -161,25 +161,25 @@ def makeRailing(stairs):
if side == "L":
outlineLR = stair.OutlineLeft
outlineLRAll = stair.OutlineLeftAll
stairs0RailingLR = "RailingLeft" # stairs0OutlineWireLR = "OutlineWireLeft"
stairRailingLR = "RailingLeft" # stairOutlineWireLR = "OutlineWireLeft"
stairs0RailingLR = "RailingLeft" # stairs0OutlineWireLR = "OutlineWireLeft"
stairRailingLR = "RailingLeft" # stairOutlineWireLR = "OutlineWireLeft"
elif side == "R":
outlineLR = stair.OutlineRight
outlineLRAll = stair.OutlineRightAll
stairs0RailingLR = "RailingRight" # stairs0OutlineWireLR = "OutlineWireRight"
stairRailingLR = "RailingRight" # stairOutlineWireLR = "OutlineWireRight"
stairs0RailingLR = "RailingRight" # stairs0OutlineWireLR = "OutlineWireRight"
stairRailingLR = "RailingRight" # stairOutlineWireLR = "OutlineWireRight"
if outlineLR or outlineLRAll:
lrRail = ArchPipe.makePipe(baseobj=None,diameter=0,length=0,placement=None,name="Rail")
if outlineLRAll:
#lrRail.Base = lrRailWire # no need to set here as _Stairs will do
setattr(stair, stairRailingLR, lrRail.Name) # setattr(stair, stairOutlineWireLR, lrRailWire.Name)
#lrRail.Base = lrRailWire # no need to set here as _Stairs will do
setattr(stair, stairRailingLR, lrRail.Name) # setattr(stair, stairOutlineWireLR, lrRailWire.Name)
railList = stairs[0].Additions
railList.append(lrRail)
stairs[0].Additions = railList
break
elif outlineLR:
#lrRail.Base = lrRailWire # no need to set here as _Stairs will do
setattr(stair, stairRailingLR, lrRail.Name) # setattr(stair, stairOutlineWireLR, lrRailWire.Name)
#lrRail.Base = lrRailWire # no need to set here as _Stairs will do
setattr(stair, stairRailingLR, lrRail.Name) # setattr(stair, stairOutlineWireLR, lrRailWire.Name)
railList = stair.Additions
railList.append(lrRail)
stair.Additions = railList
@@ -188,7 +188,7 @@ def makeRailing(stairs):
sel = FreeCADGui.Selection.getSelection()
sel0 = sel[0]
stairs = []
if Draft.getType(sel[0]) == "Stairs": # TODO currently consider 1st selected object, then would tackle multiple objects ?
if Draft.getType(sel[0]) == "Stairs": # TODO currently consider 1st selected object, then would tackle multiple objects ?
stairs.append(sel0)
if Draft.getType(sel0.Base) == "Stairs":
stairs.append(sel0.Base)
@@ -469,7 +469,7 @@ class _Stairs(ArchComponent.Component):
if isinstance(edge.Curve,(Part.LineSegment,Part.Line)):
# preparing for multi-edges landing / segment staircase
if obj.NumberOfSteps > 1:
self.makeStraightStairsWithLanding(obj,edge) # all cases use makeStraightStairsWithLanding()
self.makeStraightStairsWithLanding(obj,edge) # all cases use makeStraightStairsWithLanding()
# preparing for multi-edges landing / segment staircase
if obj.NumberOfSteps == 1:
@@ -528,9 +528,9 @@ class _Stairs(ArchComponent.Component):
if railWireL:
# Migration
if Draft.getType(railingLeftObject.Base) != "Part": # None or not "Part"
if Draft.getType(railingLeftObject.Base) != "Part": # None or not "Part"
railingLeftWireObject = FreeCAD.ActiveDocument.addObject("Part::Feature","RailingWire")
if railingLeftObject.Base: # if has railingLeftObject.Base but that != "Part"
if railingLeftObject.Base: # if has railingLeftObject.Base but that != "Part"
railingLeftObject.Document.removeObject(railingLeftObject.Base.Name) # Delete the previous Base object... # Not Using FreeCAD.ActiveDocument...
railingLeftObject.Base = railingLeftWireObject
# update the Base object shape
@@ -657,7 +657,7 @@ class _Stairs(ArchComponent.Component):
return stepWire, stepFace
@staticmethod # obj become stairsObj
@staticmethod # obj become stairsObj
def returnOutlines(stairsObj, edges, align="Left", mode=None, widthFirstSegment=zeroMM, widthOtherSegments=[], treadThickness=zeroMM,
railStartRiser=zeroMM, offsetHLeft=zeroMM, offsetHRight=zeroMM, offsetVLeft=zeroMM, offsetVRight=zeroMM, widthFirstSegmentDefault=False):
@@ -669,7 +669,7 @@ class _Stairs(ArchComponent.Component):
v, vLength, vWidth, vBase = [], [], [], []
p1, p2, p3, p4, pArc, pArc1, pArc2 = [], [], [], [], [], [], [] # p1o, p2o - Not used
p1, p2, p3, p4, pArc, pArc1, pArc2 = [], [], [], [], [], [], [] # p1o, p2o - Not used
outline, outlineP1P2, outlineP3P4, outlineP1P2Closed, outlineP3P4Closed, outlineP1P2Ordered = [], [], [], [], [], []
if not isinstance(edges, list):
@@ -679,10 +679,10 @@ class _Stairs(ArchComponent.Component):
for i, edge in enum_edges:
isLine = isinstance(edge.Curve,(Part.Line, Part.LineSegment))
isArc = isinstance(edge.Curve,Part.Circle) # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
isArc = isinstance(edge.Curve,Part.Circle) # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
''' (1) append v (vec) '''
v.append(DraftGeomUtils.vec(edge)) # TODO check all function below ok with curve?
v.append(DraftGeomUtils.vec(edge)) # TODO check all function below ok with curve?
''' (2) get netWidthI '''
@@ -709,7 +709,7 @@ class _Stairs(ArchComponent.Component):
#vBase2vec = (vBase2-vBase[i]) # - would not be correct if Align is not Left
''' (1a) calc & append vLength - Need v (vec) '''
vLength.append(Vector(v[i].x,v[i].y,v[i].z)) # TODO check all function below ok with curve? # TODO vLength in this f() is 3d
vLength.append(Vector(v[i].x,v[i].y,v[i].z)) # TODO check all function below ok with curve? # TODO vLength in this f() is 3d
''' (1b, 2a) calc & append vWidth - Need vLength, netWidthI '''
@@ -720,7 +720,7 @@ class _Stairs(ArchComponent.Component):
dvec = vLength[i].cross(Vector(0,0,1))
elif isArc:
#dvec = edge.Vertexes[0].Point.sub(edge.Curve.Center) # TODO - how to determine direction? - Reference from ArchWall; used tangentAt instead
#dvec = edge.Vertexes[0].Point.sub(edge.Curve.Center) # TODO - how to determine direction? - Reference from ArchWall; used tangentAt instead
#dvec1 = edge.Vertexes[1].Point.sub(edge.Curve.Center)
dvec = edge.tangentAt(edge.FirstParameter).cross(Vector(0,0,1))
dvec1 = edge.tangentAt(edge.LastParameter).cross(Vector(0,0,1))
@@ -742,7 +742,7 @@ class _Stairs(ArchComponent.Component):
vBase[i] = vBase[i].add(Vector(0,0,railStartRiser.Value))
if isArc:
vBase1 = vBase1.add(Vector(0,0,offsetVLeft.Value)) # TODO - if arc is flight (sloping then), arc would be ellipse, so the following become incorrect?
vBase1 = vBase1.add(Vector(0,0,offsetVLeft.Value)) # TODO - if arc is flight (sloping then), arc would be ellipse, so the following become incorrect?
vBase1 = vBase1.add(Vector(0,0,railStartRiser.Value))
vBase2 = vBase2.add(Vector(0,0,offsetVLeft.Value))
vBase2 = vBase2.add(Vector(0,0,railStartRiser.Value))
@@ -783,7 +783,7 @@ class _Stairs(ArchComponent.Component):
''' (3c, 2c/2d) from [p1, p2, p3, p4] - calc outlineP1P2, outlineP3P4 '''
if i > 0:
lastEdge = edges[i-1] # thisEdge = edge
lastEdge = edges[i-1] # thisEdge = edge
p1last = p1[i-1]
p2last = p2[i-1]
p3last = p3[i-1]
@@ -801,7 +801,7 @@ class _Stairs(ArchComponent.Component):
lastEdgeIsLineSegmentBool = isinstance(lastEdge.Curve,(Part.Line, Part.LineSegment))
thisEdgeIsLineSegmentBool = isinstance(edge.Curve,(Part.Line, Part.LineSegment))
lastEdgeIsCircleBool = isinstance(lastEdge.Curve,(Part.Circle)) # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
lastEdgeIsCircleBool = isinstance(lastEdge.Curve,(Part.Circle)) # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
thisEdgeIsCircleBool = isinstance(edge.Curve,(Part.Circle))
intersectionP1P2, intersectionP3P4 = _Stairs.findLineArcIntersections(p1last, p2last, p3last, p4last, p1this, p2this, p3this, p4this, lastEdgeIsLineSegmentBool, thisEdgeIsLineSegmentBool,
@@ -821,24 +821,24 @@ class _Stairs(ArchComponent.Component):
outline.append(p1[0])
pArc1.append(None)
pArc2 = pArc2[::-1] # pArcReverse = pArc2[::-1]
pArc2 = pArc2[::-1] # pArcReverse = pArc2[::-1]
pArc2.append(None)
pArc.extend(pArc1)
pArc.extend(pArc2) # pArc.extend(pArcReverse)
pArc.extend(pArc2) # pArc.extend(pArcReverse)
firstEdgeIsLineSegmentBool = isinstance(edges[0].Curve,(Part.Line, Part.LineSegment))
firstEdgeIsCircleBool = isinstance(edges[0].Curve,(Part.Circle)) # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
firstEdgeIsCircleBool = isinstance(edges[0].Curve,(Part.Circle)) # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
if mode in ["OrderedClose", "OrderedCloseAndOrderedOpen"]: # seem only using 'OrderedClose'
if mode in ["OrderedClose", "OrderedCloseAndOrderedOpen"]: # seem only using 'OrderedClose'
intersectionP1P2, intersectionP3P4 = _Stairs.findLineArcIntersections(p1this, p2this, p3this, p4this, p1[0], p2[0], p3[0], p4[0], thisEdgeIsLineSegmentBool, firstEdgeIsLineSegmentBool,
thisEdgeIsCircleBool, firstEdgeIsCircleBool, pArc1this, pArc2this, pArc1[0], pArc2[0])
outlineP1P2Closed = list(outlineP1P2)
outlineP1P2Closed[0] = intersectionP1P2 #intersection[0]
outlineP1P2Closed[i+1] = intersectionP1P2 #intersection[0]
outlineP1P2Closed[0] = intersectionP1P2 #intersection[0]
outlineP1P2Closed[i+1] = intersectionP1P2 #intersection[0]
outlineP3P4Closed = list(outlineP3P4)
outlineP3P4Closed[0] = intersectionP3P4 #intersection[0]
outlineP3P4Closed[i+1] = intersectionP3P4 #intersection[0]
outlineP3P4Closed[0] = intersectionP3P4 #intersection[0]
outlineP3P4Closed[i+1] = intersectionP3P4 #intersection[0]
if mode in ["OrderedOpen", "OrderedCloseAndOrderedOpen"]:
if i > 0: # Multi-edge, otherwise no use
@@ -889,24 +889,24 @@ class _Stairs(ArchComponent.Component):
return intersectionsP1P2[0], intersectionsP3P4[0]
else:
if lastEdgeIsCircleBool:
edge1 = Part.Arc(p1last,pArc1last,p2last).toShape() # edge1 = Part.Arc(p1[i-1],pArc1[i-1],p2[i-1]).toShape()
edge1a = Part.Arc(p3last,pArc2last,p4last).toShape() # edge1a = Part.Arc(p3[i-1],pArc2[i-1],p4[i-1]).toShape()
edge1 = Part.Arc(p1last,pArc1last,p2last).toShape() # edge1 = Part.Arc(p1[i-1],pArc1[i-1],p2[i-1]).toShape()
edge1a = Part.Arc(p3last,pArc2last,p4last).toShape() # edge1a = Part.Arc(p3[i-1],pArc2[i-1],p4[i-1]).toShape()
else:
edge1 = Part.LineSegment(p1last,p2last).toShape() # edge1 = Part.LineSegment(p1[i-1],p2[i-1]).toShape()
edge1a = Part.LineSegment(p3last,p4last).toShape() # edge1a = Part.LineSegment(p3[i-1],p4[i-1]).toShape()
edge1 = Part.LineSegment(p1last,p2last).toShape() # edge1 = Part.LineSegment(p1[i-1],p2[i-1]).toShape()
edge1a = Part.LineSegment(p3last,p4last).toShape() # edge1a = Part.LineSegment(p3[i-1],p4[i-1]).toShape()
if thisEdgeIsCircleBool: # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
edge2 = Part.Arc(p1this,pArc1this,p2this).toShape() # edge2 = Part.Arc(p1[i],pArc1[i],p2[i]).toShape()
edge2a = Part.Arc(p3this,pArc2this,p4this).toShape() # edge2a = Part.Arc(p3[i],pArc2[i],p4[i]).toShape()
if thisEdgeIsCircleBool: # why it is Part.Circle for an Arc Edge? - why Part.ArcOfCircle Not Working?
edge2 = Part.Arc(p1this,pArc1this,p2this).toShape() # edge2 = Part.Arc(p1[i],pArc1[i],p2[i]).toShape()
edge2a = Part.Arc(p3this,pArc2this,p4this).toShape() # edge2a = Part.Arc(p3[i],pArc2[i],p4[i]).toShape()
else:
edge2 = Part.LineSegment(p1this,p2this).toShape() # edge2 = Part.LineSegment(p1[i],p2[i]).toShape()
edge2a = Part.LineSegment(p3this,p4this).toShape() # edge2a = Part.LineSegment(p3[i],p4[i]).toShape()
edge2 = Part.LineSegment(p1this,p2this).toShape() # edge2 = Part.LineSegment(p1[i],p2[i]).toShape()
edge2a = Part.LineSegment(p3this,p4this).toShape() # edge2a = Part.LineSegment(p3[i],p4[i]).toShape()
intersections = DraftGeomUtils.findIntersection(edge1, edge2, True,True)
enum_intersections = enumerate(intersections)
distList = []
for n, intersectionI in enum_intersections:
distList.append((intersectionI-p1this).Length) # distList.append((intersectionI-p1[i]).Length)) # TODO just use p1[i] for test; may be p2[i-1]...?
distList.append((intersectionI-p1this).Length) # distList.append((intersectionI-p1[i]).Length)) # TODO just use p1[i] for test; may be p2[i-1]...?
# TODO - To test and follow up if none intersection is found
nearestIntersectionIndex = distList.index(min(distList))
@@ -916,7 +916,7 @@ class _Stairs(ArchComponent.Component):
enum_intersections = enumerate(intersections)
distList = []
for n, intersectionI in enum_intersections:
distList.append((intersectionI-p4this).Length) # distList.append((intersectionI-p4[i]).Length)) # TODO just use p4[i] for test; may be p3[i-1]...?
distList.append((intersectionI-p4this).Length) # distList.append((intersectionI-p4[i]).Length)) # TODO just use p4[i] for test; may be p3[i-1]...?
nearestIntersectionIndex = distList.index(min(distList))
nearestIntersectionP3P4 = intersections[nearestIntersectionIndex]
return nearestIntersectionP1P2, nearestIntersectionP3P4
@@ -925,12 +925,12 @@ class _Stairs(ArchComponent.Component):
def vbaseFollowLastSegment(obj, vBase):
if obj.LastSegment:
lastSegmentAbsTop = obj.LastSegment.AbsTop
vBase = Vector(vBase.x, vBase.y,lastSegmentAbsTop.z) # use Last Segment top's z-coordinate
vBase = Vector(vBase.x, vBase.y,lastSegmentAbsTop.z) # use Last Segment top's z-coordinate
return vBase
# Add flag (temporarily?) for indicating which method call this to determine whether the landing has been 're-based' before or not
def makeStraightLanding(self,obj,edge,numberofsteps=None, callByMakeStraightStairsWithLanding=False): # what is use of numberofsteps ?
def makeStraightLanding(self,obj,edge,numberofsteps=None, callByMakeStraightStairsWithLanding=False): # what is use of numberofsteps ?
"builds a landing from a straight edge"
# general data
@@ -1129,14 +1129,14 @@ class _Stairs(ArchComponent.Component):
lastSegmentAbsTop = obj.LastSegment.AbsTop
print("lastSegmentAbsTop is: ")
print(lastSegmentAbsTop)
vBase = Vector(vBase.x, vBase.y,lastSegmentAbsTop.z) # use Last Segment top's z-coordinate
vBase = Vector(vBase.x, vBase.y,lastSegmentAbsTop.z) # use Last Segment top's z-coordinate
obj.AbsTop = vBase.add(Vector(0,0,h))
vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value))
a = math.atan(vHeight.Length/vLength.Length)
vBasedAligned = self.align(vBase,obj.Align,vWidth)
vRiserThickness = DraftVecUtils.scaleTo(vLength,obj.RiserThickness.Value) # 50)
vRiserThickness = DraftVecUtils.scaleTo(vLength,obj.RiserThickness.Value) # 50)
# steps and risers
for i in range(numberofsteps-1):
@@ -1162,17 +1162,17 @@ class _Stairs(ArchComponent.Component):
''' risers - add to steps or pseudosteps in the meantime before adding self.risers / self.pseudorisers '''
#vResHeight = vHeight.add(Vector(0,0,-abs(obj.TreadThickness.Value)))
r2 = r1.add(DraftVecUtils.neg(vHeight)) #vResHeight
r2 = r1.add(DraftVecUtils.neg(vHeight)) #vResHeight
if i == 0:
r2 = r2.add(Vector(0,0,abs(obj.TreadThickness.Value)))
r3 = r2.add(vWidth)
r4 = r3.add(vHeight) #vResHeight
r4 = r3.add(vHeight) #vResHeight
if i == 0:
r4 = r4.add(Vector(0,0,-abs(obj.TreadThickness.Value)))
riser = Part.Face(Part.makePolygon([r1,r2,r3,r4,r1]))
if obj.RiserThickness.Value:
riser = riser.extrude(vRiserThickness) #Vector(0,100,0))
riser = riser.extrude(vRiserThickness) #Vector(0,100,0))
self.steps.append(riser)
else:
self.pseudosteps.append(riser)
@@ -1320,12 +1320,12 @@ class _Stairs(ArchComponent.Component):
else:
reslength = edge.Length - obj.Width.Value
treadDepth = float(reslength)/(obj.NumberOfSteps-2) # why needs 'float'?
treadDepth = float(reslength)/(obj.NumberOfSteps-2) # why needs 'float'?
obj.TreadDepth = treadDepth
vLength = DraftVecUtils.scaleTo(v,treadDepth)
else:
reslength = edge.Length
treadDepth = float(reslength)/(obj.NumberOfSteps-1) # why needs 'float'?
treadDepth = float(reslength)/(obj.NumberOfSteps-1) # why needs 'float'?
obj.TreadDepth = treadDepth
vLength = DraftVecUtils.scaleTo(v,treadDepth)
else:
@@ -1355,7 +1355,7 @@ class _Stairs(ArchComponent.Component):
if obj.LastSegment:
lastSegmentAbsTop = obj.LastSegment.AbsTop
p1 = Vector(p1.x, p1.y,lastSegmentAbsTop.z) # use Last Segment top's z-coordinate
p1 = Vector(p1.x, p1.y,lastSegmentAbsTop.z) # use Last Segment top's z-coordinate
obj.AbsTop = p1.add(Vector(0,0,h))
p2 = p1.add(DraftVecUtils.scale(vLength,landing-1).add(Vector(0,0,landing*hstep)))
@@ -1414,8 +1414,8 @@ class _Stairs(ArchComponent.Component):
obj.OutlineLeft = outlineRailL # outlineL # outlineP1P2
obj.OutlineRight = outlineRailR # outlineR # outlineP3P4
self.OutlineRailArcLeft = pArcRailL #obj.OutlineRailArcLeft = pArcRailL
self.OutlineRailArcRight = pArcRailR #obj.OutlineRailArcRight = pArcRailR
self.OutlineRailArcLeft = pArcRailL #obj.OutlineRailArcLeft = pArcRailL
self.OutlineRailArcRight = pArcRailR #obj.OutlineRailArcRight = pArcRailR
outlineLeftAll, outlineRightAll, outlineRailArcLeftAll, outlineRailArcRightAll = [], [], [], []
+9 -11
View File
@@ -1351,7 +1351,7 @@ class _Wall(ArchComponent.Component):
if not DraftVecUtils.isNull(dvec):
dvec.normalize()
sh = None
face = None
curAligns = aligns[0]
off = obj.Offset.Value
@@ -1399,7 +1399,7 @@ class _Wall(ArchComponent.Component):
normal=normal,
basewireOffset=off)
sh = DraftGeomUtils.bind(w1,w2)
face = DraftGeomUtils.bind(w1, w2, per_segment=True)
elif curAligns == "Right":
dvec = dvec.negative()
@@ -1440,7 +1440,7 @@ class _Wall(ArchComponent.Component):
normal=normal,
basewireOffset=off)
sh = DraftGeomUtils.bind(w1,w2)
face = DraftGeomUtils.bind(w1, w2, per_segment=True)
#elif obj.Align == "Center":
elif curAligns == "Center":
@@ -1473,18 +1473,16 @@ class _Wall(ArchComponent.Component):
alignList=aligns,
normal=normal,
basewireOffset=off)
sh = DraftGeomUtils.bind(w1,w2)
face = DraftGeomUtils.bind(w1, w2, per_segment=True)
del widths[0:edgeNum]
del aligns[0:edgeNum]
if sh:
if face:
if layers and (layers[i] < 0):
# layers with negative values are not drawn
continue
sh.fix(0.1,0,1) # fixes self-intersecting wires
f = Part.Face(sh)
if baseface:
# To allow exportIFC.py to work properly on
@@ -1505,14 +1503,14 @@ class _Wall(ArchComponent.Component):
# - 1st finding : if a rectangle + 1 line, can't removesSplitter properly...
# - 2nd finding : if 2 faces do not touch, can't form a shell; then, subsequently for remaining faces even though touch each faces, can't form a shell
baseface.append(f)
baseface.append(face)
# The above make Refine methods below (in else) useless, regardless removeSpitters yet to be improved for cases do not work well
''' Whether layers or not, all baseface.append(f) '''
''' Whether layers or not, all baseface.append(face) '''
else:
baseface = [f]
baseface = [face]
''' Whether layers or not, all baseface = [f] '''
''' Whether layers or not, all baseface = [face] '''
if baseface:
base,placement = self.rebase(baseface)
+2 -2
View File
@@ -651,8 +651,8 @@ class _Window(ArchComponent.Component):
if hasattr(self,prop):
if getattr(self,prop) != getattr(obj,prop):
touchhosts = True
if touchhosts and hasattr(obj,"Hosts"):
for host in obj.Hosts:
if touchhosts and hasattr(self, "Hosts") and hasattr(obj, "Hosts"):
for host in set(self.Hosts + obj.Hosts): # use set to remove duplicates
# mark host to recompute so it can detect this object
host.touch()
if prop in ["Width","Height","Frame"]:
+1 -1
View File
@@ -184,7 +184,7 @@ def createStructuralMember(ifcfile, ifcbin, obj):
# - no profile properties are taken into account
# - no materials properties are takein into account
# -
# create geometry
# create geometry
verts = [None for _ in range(len(edges)+1)]
verts[0] = tuple(edges[0].Vertexes[ 0].Point.multiply(scaling))
verts[1] = tuple(edges[0].Vertexes[-1].Point.multiply(scaling))
+34 -34
View File
@@ -650,14 +650,14 @@ def getHTMLTemplate():
def export( exportList, filename, colors = None, camera = None ):
"""Exports objects to an html file"""
global disableCompression, base, baseFloat
data = { 'camera':{}, 'file':{}, 'objects':[] }
if not FreeCADGui and not camera:
camera = OfflineRenderingUtils.getCamera(FreeCAD.ActiveDocument.FileName)
if camera:
# REF: https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Arch/OfflineRenderingUtils.py
camnode = OfflineRenderingUtils.getCoinCamera(camera)
@@ -674,17 +674,17 @@ def export( exportList, filename, colors = None, camera = None ):
data['camera']['focalDistance'] = v.getCameraNode().focalDistance.getValue()
data['camera']['position_x'] = v.viewPosition().Base.x
data['camera']['position_y'] = v.viewPosition().Base.y
data['camera']['position_z'] = v.viewPosition().Base.z
data['camera']['position_z'] = v.viewPosition().Base.z
# Take the objects out of groups
objectslist = Draft.get_group_contents(exportList, walls=True, addgroups=False)
# objectslist = Arch.pruneIncluded(objectslist)
for obj in objectslist:
# Pull all obj data before we dig down the links
label = obj.Label
color = '#cccccc';
opacity = 1.0
if FreeCADGui:
@@ -692,8 +692,8 @@ def export( exportList, filename, colors = None, camera = None ):
opacity = int((100 - obj.ViewObject.Transparency)/5) / 20 # 0>>1 with step of 0.05
elif colors:
if label in colors:
color = Draft.getrgb(colors[label], testbw = False)
color = Draft.getrgb(colors[label], testbw = False)
validObject = False
if obj.isDerivedFrom('Mesh::Feature'):
mesh = obj.Mesh
@@ -720,26 +720,26 @@ def export( exportList, filename, colors = None, camera = None ):
mesh.Placement = linkPlacement
validObject = True
break
if not validObject: continue
objdata = { 'name': label, 'color': color, 'opacity': opacity, 'verts':'', 'facets':'', 'wires':[], 'faceColors':[], 'facesToFacets':[], 'floats':[] }
if obj.isDerivedFrom('Part::Feature'):
deviation = 0.5
if FreeCADGui:
deviation = obj.ViewObject.Deviation
# obj.ViewObject.DiffuseColor is length=1 when all faces are the same color, length=len(faces) for when they're not
if len(obj.ViewObject.DiffuseColor) == len(objShape.Faces):
for fc in obj.ViewObject.DiffuseColor:
objdata['faceColors'].append( Draft.getrgb(fc, testbw = False) )
# get verts and facets for ENTIRE object
shapeData = objShape.tessellate( deviation )
mesh = Mesh.Mesh(shapeData)
if len(objShape.Faces) > 1:
# Map each Facet created by tessellate() to a Face so that it can be colored correctly using faceColors
# This is done by matching the results of a tessellate() on EACH FACE to the overall tessellate stored in shapeData
@@ -759,8 +759,8 @@ def export( exportList, filename, colors = None, camera = None ):
FreeCAD.Console.PrintMessage("Facet to Face Mismatch.\n")
objdata['facesToFacets'] = []
break
# map each of the face facets to the shape facets and make a list of shape facet indices that belong to this face
# map each of the face facets to the shape facets and make a list of shape facet indices that belong to this face
facetList = []
for ff in faceData[1]: # face facets
found = False
@@ -774,9 +774,9 @@ def export( exportList, filename, colors = None, camera = None ):
FreeCAD.Console.PrintMessage("Facet List Mismatch.\n")
objdata['facesToFacets'] = []
break
objdata['facesToFacets'].append( baseEncode(facetList) )
wires = [] # Add wires
for f in objShape.Faces:
for w in f.Wires:
@@ -787,7 +787,7 @@ def export( exportList, filename, colors = None, camera = None ):
wire.append( '{:.5f}'.format(v.y) )
wire.append( '{:.5f}'.format(v.z) )
wires.append( wire )
if not disableCompression:
for w in range( len(wires) ):
for wv in range( len(wires[w]) ):
@@ -802,7 +802,7 @@ def export( exportList, filename, colors = None, camera = None ):
wires[w][wv] = len(objdata['floats'])-1
wires[w] = baseEncode(wires[w])
objdata['wires'] = wires
vIndex = {}
verts = []
for p in range( len(mesh.Points) ):
@@ -810,7 +810,7 @@ def export( exportList, filename, colors = None, camera = None ):
verts.append( '{:.5f}'.format(mesh.Points[p].Vector.x) )
verts.append( '{:.5f}'.format(mesh.Points[p].Vector.y) )
verts.append( '{:.5f}'.format(mesh.Points[p].Vector.z) )
# create floats list to compress verts and wires being written into the JS
if not disableCompression:
for v in range( len(verts) ):
@@ -824,13 +824,13 @@ def export( exportList, filename, colors = None, camera = None ):
objdata['floats'].append( verts[v] )
verts[v] = len(objdata['floats'])-1
objdata['verts'] = baseEncode(verts)
facets = []
for f in mesh.Facets:
for i in f.PointIndices:
facets.append( vIndex[i] )
objdata['facets'] = baseEncode(facets)
# compress floats
if not disableCompression:
# use ratio of 7x base13 to 4x base90 because 13^7 ~ 90^4
@@ -848,20 +848,20 @@ def export( exportList, filename, colors = None, camera = None ):
floatStr += base[ quotient % baseCt ]
quotient = int(quotient / baseCt)
objdata['floats'] = floatStr
data['objects'].append( objdata )
html = getHTMLTemplate()
html = html.replace('$pagetitle',FreeCAD.ActiveDocument.Label)
version = FreeCAD.Version()
html = html.replace('$version',version[0] + '.' + version[1] + '.' + version[2])
# Remove data compression in JS
data['compressed'] = not disableCompression
data['base'] = base
data['baseFloat'] = baseFloat
html = html.replace('$data', json.dumps(data, separators=(',', ':')) ) # Shape Data
if six.PY2:
@@ -874,11 +874,11 @@ def export( exportList, filename, colors = None, camera = None ):
def baseEncode( arr ):
"""Compresses an array of ints into a base90 string"""
global disableCompression, base
if disableCompression: return arr
if len(arr) == 0: return ''
longest = 0
output = []
baseCt = len(base)
+1 -16
View File
@@ -151,13 +151,8 @@ inCommandShortcuts = {
translate("draft","Cycle snap object"),
None
],
"NearSnap": [
Draft.getParam("inCommandShortcutNearSnap", "N"),
translate("draft","Toggle near snap on/off"),
None
],
"Undo": [
Draft.getParam("inCommandShortcutNearSnap", "/"),
Draft.getParam("inCommandShortcutUndo", "/"),
translate("draft","Undo last segment"),
None
],
@@ -1671,9 +1666,6 @@ class DraftToolBar:
elif txt.upper().startswith(inCommandShortcuts["Snap"][0]):
self.togglesnap()
spec = True
elif txt.upper().startswith(inCommandShortcuts["NearSnap"][0]):
self.togglenearsnap()
spec = True
elif txt.upper().startswith(inCommandShortcuts["Increase"][0]):
self.toggleradius(1)
spec = True
@@ -2097,13 +2089,6 @@ class DraftToolBar:
def togglesnap(self):
FreeCADGui.doCommand('FreeCADGui.runCommand("Draft_Snap_Lock")')
def togglenearsnap(self):
if hasattr(FreeCADGui,"Snapper"):
if hasattr(FreeCADGui.Snapper,"toolbarButtons"):
for b in FreeCADGui.Snapper.toolbarButtons:
if b.objectName() == "SnapButtonpassive":
b.toggle()
def toggleradius(self,val):
if hasattr(FreeCADGui,"Snapper"):
par = Draft.getParam("snapRange", 8)
@@ -76,13 +76,20 @@
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Continue</string>
</property>
</widget>
</item>
<item row="0" column="3">
<item row="0" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_3">
<property name="enabled">
<bool>true</bool>
@@ -119,14 +126,21 @@
</property>
</widget>
</item>
<item row="0" column="4">
<item row="0" column="5">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="0" column="5">
<item row="0" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_4">
<property name="enabled">
<bool>true</bool>
@@ -163,6 +177,13 @@
</property>
</widget>
</item>
<item row="0" column="8">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
@@ -207,14 +228,14 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="1" column="3">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Subelement Mode</string>
</property>
</widget>
</item>
<item row="1" column="3">
<item row="1" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_11">
<property name="enabled">
<bool>true</bool>
@@ -251,14 +272,14 @@
</property>
</widget>
</item>
<item row="1" column="4">
<item row="1" column="6">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Fill</string>
</property>
</widget>
</item>
<item row="1" column="5">
<item row="1" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_12">
<property name="enabled">
<bool>true</bool>
@@ -339,14 +360,14 @@
</property>
</widget>
</item>
<item row="2" column="2">
<item row="2" column="3">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Select Edge</string>
</property>
</widget>
</item>
<item row="2" column="3">
<item row="2" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_13">
<property name="enabled">
<bool>true</bool>
@@ -383,14 +404,14 @@
</property>
</widget>
</item>
<item row="2" column="4">
<item row="2" column="6">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Add Hold</string>
</property>
</widget>
</item>
<item row="2" column="5">
<item row="2" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_15">
<property name="enabled">
<bool>true</bool>
@@ -471,14 +492,14 @@
</property>
</widget>
</item>
<item row="3" column="2">
<item row="3" column="3">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Wipe</string>
</property>
</widget>
</item>
<item row="3" column="3">
<item row="3" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_14">
<property name="enabled">
<bool>true</bool>
@@ -515,14 +536,14 @@
</property>
</widget>
</item>
<item row="3" column="4">
<item row="3" column="6">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Set WP</string>
</property>
</widget>
</item>
<item row="3" column="5">
<item row="3" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_16">
<property name="enabled">
<bool>true</bool>
@@ -603,14 +624,14 @@
</property>
</widget>
</item>
<item row="4" column="2">
<item row="4" column="3">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Global</string>
</property>
</widget>
</item>
<item row="4" column="3">
<item row="4" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_21">
<property name="enabled">
<bool>true</bool>
@@ -647,7 +668,51 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="4" column="6">
<widget class="QLabel" name="label_28">
<property name="text">
<string>Undo</string>
</property>
</widget>
</item>
<item row="4" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_22">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>/</string>
</property>
<property name="maxLength">
<number>1</number>
</property>
<property name="placeholderText">
<string/>
</property>
<property name="clearButtonEnabled" stdset="0">
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>inCommandShortcutUndo</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Draft</cstring>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Snap</string>
@@ -691,14 +756,14 @@
</property>
</widget>
</item>
<item row="5" column="2">
<item row="5" column="3">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Increase Radius</string>
</property>
</widget>
</item>
<item row="5" column="3">
<item row="5" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_19">
<property name="enabled">
<bool>true</bool>
@@ -735,14 +800,14 @@
</property>
</widget>
</item>
<item row="5" column="4">
<item row="5" column="6">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Decrease Radius</string>
</property>
</widget>
</item>
<item row="5" column="5">
<item row="5" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_17">
<property name="enabled">
<bool>true</bool>
@@ -823,14 +888,14 @@
</property>
</widget>
</item>
<item row="6" column="2">
<item row="6" column="3">
<widget class="QLabel" name="label_25">
<property name="text">
<string>Restrict Y</string>
</property>
</widget>
</item>
<item row="6" column="3">
<item row="6" column="4">
<widget class="Gui::PrefLineEdit" name="lineEdit_20">
<property name="enabled">
<bool>true</bool>
@@ -867,14 +932,14 @@
</property>
</widget>
</item>
<item row="6" column="4">
<item row="6" column="6">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Restrict Z</string>
</property>
</widget>
</item>
<item row="6" column="5">
<item row="6" column="7">
<widget class="Gui::PrefLineEdit" name="lineEdit_18">
<property name="enabled">
<bool>true</bool>
+4 -2
View File
@@ -345,13 +345,15 @@ class Plane:
self.u = Vector(0, -1, 0)
self.v = Vector(0, 0, 1)
elif upvec:
self.v = upvec
self.u = upvec.cross(self.axis)
self.u.normalize()
self.v = self.axis.cross(self.u)
self.v.normalize()
self.u = self.v.cross(self.axis)
else:
self.v = axis.cross(Vector(1, 0, 0))
self.v.normalize()
self.u = DraftVecUtils.rotate(self.v, -math.pi/2, self.axis)
self.u.normalize()
offsetVector = Vector(axis)
offsetVector.multiply(offset)
self.position = point.add(offsetVector)
+6 -3
View File
@@ -72,9 +72,12 @@ def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
newwire = None
delete = None
if utils.get_type(obj).startswith("Part::") or utils.get_type(obj).startswith("Sketcher::"):
copy = True
if (copy is False
and (utils.get_type(obj).startswith("Sketcher::")
or utils.get_type(obj).startswith("Part::")
or utils.get_type(obj).startswith("PartDesign::"))): # For PartDesign_SubShapeBinders which can reference sketches.
print("the offset tool is currently unable to offset a non-Draft object directly - Creating a copy")
copy = True
def getRect(p,obj):
"""returns length,height,placement"""
@@ -199,7 +202,7 @@ def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
try:
if p:
newobj = make_wire(p)
newobj.Closed = obj.Shape.isClosed()
newobj.Closed = DraftGeomUtils.isReallyClosed(obj.Shape)
except Part.OCCError:
pass
if (not newobj) and newwire:
+8 -9
View File
@@ -544,14 +544,18 @@ def get_svg(obj,
p2 = get_proj(prx.p2, plane)
p3 = get_proj(prx.p3, plane)
arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
arrowlength = 4*obj.ViewObject.ArrowSize.Value
halfarrowlength = 2 * arrowsize
arrowangle = 2 * math.asin(halfarrowlength / prx.circle.Curve.Radius)
if hasattr(obj.ViewObject, "FlipArrows") \
and obj.ViewObject.FlipArrows:
arrowangle = -arrowangle
_v1a = prx.circle.valueAt(prx.circle.FirstParameter
+ arrowlength)
+ arrowangle)
_v1b = prx.circle.valueAt(prx.circle.FirstParameter)
_v2a = prx.circle.valueAt(prx.circle.LastParameter
- arrowlength)
- arrowangle)
_v2b = prx.circle.valueAt(prx.circle.LastParameter)
u1 = get_proj(_v1a - _v1b, plane)
@@ -559,11 +563,6 @@ def get_svg(obj,
angle1 = -DraftVecUtils.angle(u1)
angle2 = -DraftVecUtils.angle(u2)
if hasattr(obj.ViewObject, "FlipArrows"):
if obj.ViewObject.FlipArrows:
angle1 = angle1 + math.pi
angle2 = angle2 + math.pi
svg += get_arrow(obj,
obj.ViewObject.ArrowType,
p2, arrowsize, stroke, linewidth,
@@ -580,7 +579,7 @@ def get_svg(obj,
t = prx.circle.tangentAt(prx.circle.FirstParameter
+ _diff/2.0)
t = get_proj(t, plane)
tangle = DraftVecUtils.angle(t)
tangle = -DraftVecUtils.angle(t)
if (tangle <= -math.pi/2) or (tangle > math.pi/2):
tangle = tangle + math.pi
+2 -2
View File
@@ -33,6 +33,7 @@ import FreeCAD as App
import DraftVecUtils
from draftgeoutils.general import geomType
from draftgeoutils.edges import findMidpoint
# Delay import of module until first use because it is heavy
Part = lz.LazyLoader("Part", globals(), "Part")
@@ -134,8 +135,7 @@ def arcFromSpline(edge):
else:
# circle
p1 = edge.Vertexes[0].Point
ml = edge.Length/2
p2 = edge.valueAt(ml)
p2 = findMidpoint(edge)
ray = p2.sub(p1)
ray.scale(0.5, 0.5, 0.5)
center = p1.add(ray)
+42 -16
View File
@@ -110,32 +110,58 @@ def is_coplanar(faces, tol=-1):
isCoplanar = is_coplanar
def bind(w1, w2):
"""Bind 2 wires by their endpoints and returns a face."""
if not w1 or not w2:
print("DraftGeomUtils: unable to bind wires")
return None
def bind(w1, w2, per_segment=False):
"""Bind 2 wires by their endpoints and returns a face.
if w1.isClosed() and w2.isClosed():
d1 = w1.BoundBox.DiagonalLength
d2 = w2.BoundBox.DiagonalLength
if d1 > d2:
# w2.reverse()
return Part.Face([w1, w2])
else:
# w1.reverse()
return Part.Face([w2, w1])
else:
If per_segment is True and the wires have the same number of edges, the
wires are processed per segment: a separate face is created for each pair
of edges (one from w1 and one from w2), and the faces are then fused. This
avoids problems with walls based on wires that selfintersect, or that have
a loop that ends in a T-connection (f.e. a wire shaped like a number 6).
"""
def create_face(w1, w2):
try:
w3 = Part.LineSegment(w1.Vertexes[0].Point,
w2.Vertexes[0].Point).toShape()
w4 = Part.LineSegment(w1.Vertexes[-1].Point,
w2.Vertexes[-1].Point).toShape()
return Part.Face(Part.Wire(w1.Edges+[w3] + w2.Edges+[w4]))
return Part.Face(Part.Wire(w1.Edges + [w3] + w2.Edges + [w4]))
except Part.OCCError:
print("DraftGeomUtils: unable to bind wires")
return None
if not w1 or not w2:
print("DraftGeomUtils: unable to bind wires")
return None
if (per_segment
and len(w1.Edges) > 1
and len(w1.Edges) == len(w2.Edges)):
faces = []
for (edge1, edge2) in zip(w1.Edges, w2.Edges):
face = create_face(edge1, edge2)
if face is None:
return None
faces.append(face)
# return concatenate(faces[0].fuse(faces[1:])) # Also works.
return faces[0].fuse(faces[1:]).removeSplitter().Faces[0]
elif w1.isClosed() and w2.isClosed():
d1 = w1.BoundBox.DiagonalLength
d2 = w2.BoundBox.DiagonalLength
if d1 < d2:
w1, w2 = w2, w1
# return Part.Face(w1).cut(Part.Face(w2)).Faces[0] # Only works if wires do not self-intersect.
try:
face = Part.Face([w1, w2])
face.fix(1e-7, 0, 1)
return face
except Part.OCCError:
print("DraftGeomUtils: unable to bind wires")
return None
else:
return create_face(w1, w2)
def cleanFaces(shape):
"""Remove inner edges from coplanar faces."""
+4 -2
View File
@@ -107,7 +107,9 @@ def findIntersection(edge1, edge2,
# First, check bound boxes
if (isinstance(edge1, Part.Edge) and isinstance(edge2, Part.Edge)
and (not infinite1) and (not infinite2)):
if not edge1.BoundBox.intersect(edge2.BoundBox):
bb1 = edge1.BoundBox
bb1.enlarge(pow(10, -precision())) # enlarge one box to account for rounding errors
if not bb1.intersect(edge2.BoundBox):
return [] # bound boxes don't intersect
# First, try to use distToShape if possible
@@ -117,7 +119,7 @@ def findIntersection(edge1, edge2,
sol = []
if round(dist, precision()) == 0:
for p in pts:
if p not in sol:
if p[0] not in sol:
sol.append(p[0])
return sol
+2 -1
View File
@@ -33,6 +33,7 @@ import DraftVecUtils
from draftgeoutils.general import geomType, vec
from draftgeoutils.geometry import get_normal
from draftgeoutils.wires import isReallyClosed
from draftgeoutils.intersections import wiresIntersect, connect
# Delay import of module until first use because it is heavy
@@ -237,7 +238,7 @@ def offsetWire(wire, dvec, bind=False, occ=False,
if norm is None:
norm = App.Vector(0, 0, 1)
closed = wire.isClosed()
closed = isReallyClosed(wire)
nedges = []
if occ:
length = abs(dvec.Length)
+45 -23
View File
@@ -32,7 +32,6 @@ import lazy_loader.lazy_loader as lz
import FreeCAD as App
import DraftVecUtils
import WorkingPlane
import FreeCAD as App
from draftgeoutils.general import geomType, vec, precision
from draftgeoutils.geometry import get_normal
@@ -157,26 +156,27 @@ def findWiresOld(edges):
return result[1]
def flattenWire(wire):
"""Force a wire to get completely flat along its normal."""
n = get_normal(wire)
# for backward compatibility with previous getNormal implementation
if n is None:
n = App.Vector(0, 0, 1)
def flattenWire(wire, origin=None, normal=None):
"""Force a wire to be flat on a plane defined by an origin and a normal.
If origin or normal are None they are derived from the wire.
"""
if normal is None:
normal = get_normal(wire)
# for backward compatibility with previous getNormal implementation
if normal is None:
normal = App.Vector(0, 0, 1)
if origin is None:
origin = wire.Vertexes[0].Point
o = wire.Vertexes[0].Point
plane = WorkingPlane.plane()
plane.alignToPointAndAxis(o, n, 0)
verts = [o]
for v in wire.Vertexes[1:]:
verts.append(plane.projectPoint(v.Point))
plane.alignToPointAndAxis(origin, normal, 0)
points = [plane.projectPoint(vert.Point) for vert in wire.Vertexes]
if wire.isClosed():
verts.append(o)
w = Part.makePolygon(verts)
points.append(points[0])
new_wire = Part.makePolygon(points)
return w
return new_wire
def superWire(edgeslist, closed=False):
@@ -270,10 +270,32 @@ def isReallyClosed(wire):
return False
# If more than 1 edge, further test below
v1 = wire.Edges[0].Vertexes[0].Point # v1 = wire.Vertexes[0].Point
v2 = wire.Edges[length-1].Vertexes[1].Point # v2 = wire.Vertexes[-1].Point
if DraftVecUtils.equals(v1, v2):
return True
e1 = wire.Edges[0]
e2 = wire.Edges[length-1]
if DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[1].Point):
if length == 2:
return DraftVecUtils.equals(e1.Vertexes[1].Point, e2.Vertexes[0].Point)
else:
return True
if DraftVecUtils.equals(e1.Vertexes[1].Point, e2.Vertexes[0].Point):
if length == 2:
return DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[1].Point)
else:
return True
if DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point):
if length == 2:
return DraftVecUtils.equals(e1.Vertexes[1].Point, e2.Vertexes[1].Point)
else:
return True
if DraftVecUtils.equals(e1.Vertexes[1].Point, e2.Vertexes[1].Point):
if length == 2:
return DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)
else:
return True
return False
@@ -432,8 +454,8 @@ def get_placement_perpendicular_to_wire(wire):
def get_extended_wire(wire, offset_start, offset_end):
"""Return a wire trimmed (negative offset) or extended (positive offset) at its first vertex, last vertex or both ends.
"""Return a wire trimmed (negative offset) or extended (positive offset) at its first vertex, last vertex or both ends.
get_extended_wire(wire, -100.0, 0.0) -> returns a copy of the wire with its first 100 mm removed
get_extended_wire(wire, 0.0, 100.0) -> returns a copy of the wire extended by 100 mm after it's last vertex
"""
+16 -17
View File
@@ -1136,13 +1136,18 @@ class Snapper:
# This should be in device-independent pixels
return 32
def get_quarter_widget(self, mw):
views = []
for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget):
if w.inherits("SIM::Coin3D::Quarter::QuarterWidget"):
views.append(w)
return views
def device_pixel_ratio(self):
device_pixel_ratio = 1
mw = Gui.getMainWindow()
for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget):
if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget":
if int(QtCore.qVersion().split('.')[0]) > 4:
device_pixel_ratio = w.devicePixelRatio()
for w in self.get_quarter_widget(Gui.getMainWindow()):
if int(QtCore.qVersion().split('.')[0]) > 4:
device_pixel_ratio = w.devicePixelRatio()
return device_pixel_ratio
def get_cursor_with_tail(self, base_icon_name, tail_icon_name=None):
@@ -1174,16 +1179,12 @@ class Snapper:
def setCursor(self, mode=None):
"""Set or reset the cursor to the given mode or resets."""
if self.selectMode:
mw = Gui.getMainWindow()
for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget):
if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget":
w.unsetCursor()
for w in self.get_quarter_widget(Gui.getMainWindow()):
w.unsetCursor()
self.cursorMode = None
elif not mode:
mw = Gui.getMainWindow()
for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget):
if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget":
w.unsetCursor()
for w in self.get_quarter_widget(Gui.getMainWindow()):
w.unsetCursor()
self.cursorMode = None
else:
if mode != self.cursorMode:
@@ -1192,10 +1193,8 @@ class Snapper:
if not (mode == 'passive'):
tail_icon_name = self.cursors[mode]
cur = self.get_cursor_with_tail(base_icon_name, tail_icon_name)
mw = Gui.getMainWindow()
for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget):
if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget":
w.setCursor(cur)
for w in self.get_quarter_widget(Gui.getMainWindow()):
w.setCursor(cur)
self.cursorMode = mode
def restack(self):
+16 -12
View File
@@ -78,7 +78,7 @@ def make_clone(obj, delta=None, forcedraft=False):
if utils.get_type(obj[0]) == "BuildingPart":
cl = Arch.makeComponent()
else:
try: # new-style maek function
try: # new-style make function
cl = getattr(Arch, "make_" + obj[0].Proxy.Type.lower())()
except Exception:
try: # old-style make function
@@ -100,11 +100,11 @@ def make_clone(obj, delta=None, forcedraft=False):
except Exception:
pass
if App.GuiUp:
gui_utils.format_object(cl,base)
cl.ViewObject.DiffuseColor = base.ViewObject.DiffuseColor
if utils.get_type(obj[0]) in ["Window","BuildingPart"]:
ToDo.delay(Arch.recolorize,cl)
gui_utils.select(cl)
gui_utils.format_object(cl, base)
# Workaround to trigger update of DiffuseColor:
ToDo.delay(lambda col: setattr(cl.ViewObject, "DiffuseColor", col),
cl.ViewObject.DiffuseColor)
gui_utils.select(cl)
return cl
# fall back to Draft clone mode
if not cl:
@@ -112,19 +112,23 @@ def make_clone(obj, delta=None, forcedraft=False):
cl.addExtension("Part::AttachExtensionPython")
cl.Label = prefix + obj[0].Label
Clone(cl)
if App.GuiUp:
ViewProviderClone(cl.ViewObject)
cl.Objects = obj
if delta:
cl.Placement.move(delta)
elif (len(obj) == 1) and hasattr(obj[0],"Placement"):
cl.Placement = obj[0].Placement
gui_utils.format_object(cl,obj[0])
if hasattr(cl,"LongName") and hasattr(obj[0],"LongName"):
cl.LongName = obj[0].LongName
if App.GuiUp and (len(obj) > 1):
cl.ViewObject.Proxy.resetColors(cl.ViewObject)
gui_utils.select(cl)
if App.GuiUp:
ViewProviderClone(cl.ViewObject)
gui_utils.format_object(cl, obj[0])
if len(obj) > 1 or hasattr(obj[0], "Group"):
cl.ViewObject.Proxy.resetColors(cl.ViewObject)
# Workaround to trigger update of DiffuseColor:
# Note: only works if obj contains 1 object.
ToDo.delay(lambda col: setattr(cl.ViewObject, "DiffuseColor", col),
cl.ViewObject.DiffuseColor)
gui_utils.select(cl)
return cl
+10 -3
View File
@@ -60,9 +60,16 @@ class Point(DraftObject):
import Part
shape = Part.Vertex(App.Vector(0, 0, 0))
obj.Shape = shape
obj.Placement.Base = App.Vector(obj.X.Value,
obj.Y.Value,
obj.Z.Value)
if obj.Placement.Base != App.Vector(obj.X, obj.Y, obj.Z):
obj.Placement.Base = App.Vector(obj.X, obj.Y, obj.Z)
def onChanged(self, obj, prop):
if prop == "Placement" \
and obj.Placement.Base != App.Vector(obj.X, obj.Y, obj.Z):
base = obj.Placement.Base
obj.X = base.x
obj.Y = base.y
obj.Z = base.z
# Alias for compatibility with v0.18 and earlier
+39 -9
View File
@@ -112,13 +112,13 @@ class DraftModification(unittest.TestCase):
"'{}' failed".format(operation))
def test_offset_open(self):
"""Create a wire, then produce an offset copy."""
"""Create an open wire, then produce an offset copy."""
operation = "Draft Offset"
_msg(" Test '{}'".format(operation))
a = Vector(0, 2, 0)
b = Vector(2, 4, 0)
c = Vector(5, 2, 0)
_msg(" Wire")
_msg(" Open wire")
_msg(" a={0}, b={1}".format(a, b))
_msg(" c={0}".format(c))
wire = Draft.make_wire([a, b, c])
@@ -130,22 +130,52 @@ class DraftModification(unittest.TestCase):
obj = Draft.offset(wire, offset, copy=True)
self.assertTrue(obj, "'{}' failed".format(operation))
def test_offset_closed(self):
"""Create a rectangle, then produce an offset copy."""
def test_offset_closed_with_reversed_edge(self):
"""Create a closed wire with a reversed edge, then produce an offset copy."""
# Regression test for:
# https://github.com/FreeCAD/FreeCAD/pull/5496
operation = "Draft Offset"
_msg(" Test '{}'".format(operation))
length = 4
width = 2
_msg(" Rectangle")
_msg(" Closed wire with reversed edge")
a = Vector(0, 0, 0)
b = Vector(10, 0, 0)
c = Vector(10, 4, 0)
d = Vector(0, 4, 0)
edges = [Part.makeLine(a, b),
Part.makeLine(b, c),
Part.makeLine(c, d),
Part.makeLine(a, d)]
wire = Part.Wire(edges)
obj = App.ActiveDocument.addObject("Part::Feature")
obj.Shape = wire
offset = Vector(0, -1, 0)
new = Draft.offset(obj, offset, copy=True)
self.assertTrue(len(new.Points) == 4, "'{}' failed".format(operation))
def test_offset_rectangle_with_face(self):
"""Create a rectangle with a face, then produce an offset copy."""
# Regression test for:
# https://github.com/FreeCAD/FreeCAD/pull/7670
operation = "Draft Offset"
_msg(" Test '{}'".format(operation))
length = 10
width = 4
_msg(" Rectangle with face")
_msg(" length={0}, width={1}".format(length, width))
rect = Draft.make_rectangle(length, width)
rect.MakeFace = True
App.ActiveDocument.recompute()
offset = Vector(-1, -1, 0)
offset = Vector(0, -1, 0)
_msg(" Offset")
_msg(" vector={}".format(offset))
obj = Draft.offset(rect, offset, copy=True)
self.assertTrue(obj, "'{}' failed".format(operation))
App.ActiveDocument.recompute()
obj_is_ok = (obj.Shape.CenterOfGravity == Vector(5, 2, 0)
and obj.Length == 12
and obj.Height == 6)
self.assertTrue(obj_is_ok, "'{}' failed".format(operation))
def test_trim(self):
"""Trim a line. NOT IMPLEMENTED."""
@@ -39,6 +39,9 @@ class ViewProviderBezCurve(ViewProviderWire):
def __init__(self, vobj):
super(ViewProviderBezCurve, self).__init__(vobj)
def setupContextMenu(self, vobj, menu):
return
# Alias for compatibility with v0.18 and earlier
_ViewProviderBezCurve = ViewProviderBezCurve
@@ -39,6 +39,9 @@ class ViewProviderBSpline(ViewProviderWire):
def __init__(self, vobj):
super(ViewProviderBSpline, self).__init__(vobj)
def setupContextMenu(self, vobj, menu):
return
# Alias for compatibility with v0.18 and earlier
_ViewProviderBSpline = ViewProviderBSpline
+12 -6
View File
@@ -56,22 +56,28 @@ class ViewProviderClone:
colors = []
for o in groups.get_group_contents(vobj.Object.Objects):
if o.isDerivedFrom("Part::Feature"):
if len(o.ViewObject.DiffuseColor) > 1:
if len(o.ViewObject.DiffuseColor) == len(o.Shape.Faces):
colors.extend(o.ViewObject.DiffuseColor)
else:
c = o.ViewObject.ShapeColor
c = (c[0],c[1],c[2],o.ViewObject.Transparency/100.0)
colors += [c] * len(o.Shape.Faces) # TODO: verify this line
c = (c[0], c[1], c[2], o.ViewObject.Transparency / 100.0)
colors += [c] * len(o.Shape.Faces)
elif o.hasExtension("App::GeoFeatureGroupExtension"):
for so in vobj.Object.Group:
for so in o.Group:
if so.isDerivedFrom("Part::Feature"):
if len(so.ViewObject.DiffuseColor) > 1:
if len(so.ViewObject.DiffuseColor) == len(so.Shape.Faces):
colors.extend(so.ViewObject.DiffuseColor)
else:
c = so.ViewObject.ShapeColor
c = (c[0],c[1],c[2],so.ViewObject.Transparency/100.0)
c = (c[0], c[1], c[2], so.ViewObject.Transparency / 100.0)
colors += [c] * len(so.Shape.Faces)
if colors:
first_color = colors[0]
for next_color in colors[1:]:
if next_color != first_color:
break
else:
colors = [first_color]
vobj.DiffuseColor = colors
@@ -32,6 +32,7 @@ They inherit their behavior from the base Annotation viewprovider.
# \ingroup draftviewproviders
# \brief Provides the viewprovider code for the Dimension objects.
import math
import pivy.coin as coin
import lazy_loader.lazy_loader as lz
from PySide.QtCore import QT_TRANSLATE_NOOP
@@ -396,6 +397,7 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
self.marksDimOvershoot = coin.SoSeparator()
self.marksExtOvershoot = coin.SoSeparator()
self.drawstyle = coin.SoDrawStyle()
import PartGui # Required for "SoBrepEdgeSet" (because a dimension is not a Part::FeaturePython object).
self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
self.coords = coin.SoCoordinate3()
@@ -958,6 +960,7 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
self.marks = coin.SoSeparator()
self.drawstyle = coin.SoDrawStyle()
self.coords = coin.SoCoordinate3()
import PartGui # Required for "SoBrepEdgeSet" (because a dimension is not a Part::FeaturePython object).
self.arc = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
self.node = coin.SoGroup()
@@ -1117,27 +1120,32 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
self.coord2.point.setValue(p3)
# Calculate small chords to make arrows look better
arrowlength = 4 * vobj.ArrowSize.Value
u1 = (self.circle.valueAt(first + arrowlength)
- self.circle.valueAt(first)).normalize()
u2 = (self.circle.valueAt(last)
- self.circle.valueAt(last - arrowlength)).normalize()
if hasattr(vobj, "FlipArrows") and vobj.FlipArrows:
u1 = u1.negative()
u2 = u2.negative()
if vobj.ArrowSize.Value !=0 \
and hasattr(vobj, "ScaleMultiplier") \
and vobj.ScaleMultiplier != 0:
halfarrowlength = 2 * vobj.ArrowSize.Value * vobj.ScaleMultiplier
arrowangle = 2 * math.asin(halfarrowlength / radius)
w2 = self.circle.Curve.Axis
w1 = w2.negative()
u1 = (self.circle.valueAt(first + arrowangle)
- self.circle.valueAt(first)).normalize()
u2 = (self.circle.valueAt(last)
- self.circle.valueAt(last - arrowangle)).normalize()
if hasattr(vobj, "FlipArrows") and vobj.FlipArrows:
u1 = u1.negative()
u2 = u2.negative()
v1 = w1.cross(u1)
v2 = w2.cross(u2)
_plane_rot_1 = DraftVecUtils.getPlaneRotation(u1, v1, w1)
_plane_rot_2 = DraftVecUtils.getPlaneRotation(u2, v2, w2)
q1 = App.Placement(_plane_rot_1).Rotation.Q
q2 = App.Placement(_plane_rot_2).Rotation.Q
w2 = self.circle.Curve.Axis
w1 = w2.negative()
self.trans1.rotation.setValue((q1[0], q1[1], q1[2], q1[3]))
self.trans2.rotation.setValue((q2[0], q2[1], q2[2], q2[3]))
v1 = w1.cross(u1)
v2 = w2.cross(u2)
_plane_rot_1 = DraftVecUtils.getPlaneRotation(u1, v1, w1)
_plane_rot_2 = DraftVecUtils.getPlaneRotation(u2, v2, w2)
q1 = App.Placement(_plane_rot_1).Rotation.Q
q2 = App.Placement(_plane_rot_2).Rotation.Q
self.trans1.rotation.setValue((q1[0], q1[1], q1[2], q1[3]))
self.trans2.rotation.setValue((q2[0], q2[1], q2[2], q2[3]))
# Set text position and rotation
self.tbase = midp
@@ -1194,7 +1202,7 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
self.remove_dim_arrows()
self.draw_dim_arrows(vobj)
self.updateData(obj, "Start")
self.updateData(obj, None)
# obj.touch()
elif prop == "FontSize" and "ScaleMultiplier" in properties:
@@ -1222,9 +1230,11 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
elif (prop in ("ArrowSize", "ArrowType")
and "ScaleMultiplier" in properties
and hasattr(self, "node") and hasattr(self, "p2")):
self.updateData(obj, None)
self.remove_dim_arrows()
self.draw_dim_arrows(vobj)
# obj.touch()
else:
self.updateData(obj, None)
@@ -39,4 +39,8 @@ class ViewProviderFillet(ViewProviderWire):
def __init__(self, vobj):
super(ViewProviderFillet, self).__init__(vobj)
def setupContextMenu(self, vobj, menu):
return
## @}
@@ -207,6 +207,8 @@ class ViewProviderLabel(ViewProviderDraftAnnotation):
self.drawstyle = coin.SoDrawStyle()
self.drawstyle.style = coin.SoDrawStyle.LINES
import PartGui # Required for "SoBrepEdgeSet" (because a label is not a Part::FeaturePython object).
self.lcoords = coin.SoCoordinate3()
self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
+32 -19
View File
@@ -39,11 +39,13 @@ from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD as App
import FreeCADGui as Gui
import DraftVecUtils
import DraftGeomUtils
import draftgeoutils.wires as wires
import draftutils.utils as utils
import draftutils.gui_utils as gui_utils
from draftutils.messages import _msg
from draftutils.translate import translate
from draftviewproviders.view_base import ViewProviderDraft
@@ -146,32 +148,43 @@ class ViewProviderWire(ViewProviderDraft):
return [self.Object.Base,self.Object.Tool]
return []
def setupContextMenu(self,vobj,menu):
def setupContextMenu(self, vobj, menu):
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Edit.svg"),
"Flatten this wire",
translate("draft", "Flatten"),
menu)
QtCore.QObject.connect(action1,
QtCore.SIGNAL("triggered()"),
self.flatten)
menu.addAction(action1)
def flatten(self):
if hasattr(self,"Object"):
if len(self.Object.Shape.Wires) == 1:
fw = DraftGeomUtils.flattenWire(self.Object.Shape.Wires[0])
points = [v.Point for v in fw.Vertexes]
if len(points) == len(self.Object.Points):
if points != self.Object.Points:
App.ActiveDocument.openTransaction("Flatten wire")
Gui.doCommand("FreeCAD.ActiveDocument." +
self.Object.Name +
".Points=" +
str(points).replace("Vector", "FreeCAD.Vector").replace(" " , ""))
App.ActiveDocument.commitTransaction()
def flatten(self): # Only to be used for Draft_Wires.
if not hasattr(self, "Object"):
return
else:
_flat = "This Wire is already flat"
_msg(QT_TRANSLATE_NOOP("Draft", _flat))
if hasattr(App, "DraftWorkingPlane"):
App.DraftWorkingPlane.setup()
origin = App.DraftWorkingPlane.position
normal = App.DraftWorkingPlane.axis
# Align the grid for visual feedback:
if hasattr(Gui, "Snapper"):
Gui.Snapper.setTrackers()
else:
origin = App.Vector(0, 0, 0)
normal = App.Vector(0, 0, 1)
flat_wire = wires.flattenWire(self.Object.Shape.Wires[0],
origin=origin,
normal=normal)
doc = App.ActiveDocument
doc.openTransaction(translate("draft", "Flatten"))
self.Object.Placement = App.Placement()
self.Object.Points = [vert.Point for vert in flat_wire.Vertexes]
self.Object.Closed = flat_wire.isClosed()
doc.recompute()
doc.commitTransaction()
# Alias for compatibility with v0.18 and earlier
@@ -73,7 +73,7 @@ class ViewProviderWorkingPlaneProxy:
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
c = param.GetUnsigned("ColorHelpers",674321151)
vobj.LineColor = (float((c>>24)&0xFF)/255.0,float((c>>16)&0xFF)/255.0,float((c>>8)&0xFF)/255.0,0.0)
vobj.Proxy = self
vobj.RestoreView = True
vobj.RestoreState = True
@@ -133,6 +133,7 @@ class ViewProviderWorkingPlaneProxy:
self.drawstyle = coin.SoDrawStyle()
self.drawstyle.style = coin.SoDrawStyle.LINES
self.lcoords = coin.SoCoordinate3()
import PartGui # Required for "SoBrepEdgeSet" (because a WorkingPlaneProxy is not a Part::FeaturePython object).
ls = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
ls.coordIndex.setValues(0,28,[0,1,-1,2,3,4,5,-1,6,7,-1,8,9,10,11,-1,12,13,-1,14,15,16,17,-1,18,19,20,21])
sep = coin.SoSeparator()
+1
View File
@@ -10,6 +10,7 @@ include_directories(
${OCC_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${PYTHON_INCLUDE_DIRS}
${XercesC_INCLUDE_DIRS}
)
link_directories(${OCC_LIBRARY_DIR})
+1
View File
@@ -13,6 +13,7 @@ include_directories(
${PYTHON_INCLUDE_DIRS}
${OCC_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${XercesC_INCLUDE_DIRS}
)
link_directories(${OCC_LIBRARY_DIR})
+18 -19
View File
@@ -22,25 +22,13 @@
#include "PreCompiled.h"
#include <SMESH_Version.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <CXX/Extensions.hxx>
#include <SMESH_Version.h>
#include "FemMeshPy.h"
#include "FemMesh.h"
#include "FemMeshProperty.h"
#include "FemAnalysis.h"
#include "FemMeshObject.h"
#include "FemMeshShapeObject.h"
#include "FemMeshShapeNetgenObject.h"
#include "FemSetElementsObject.h"
#include "FemSetFacesObject.h"
#include "FemSetGeometryObject.h"
#include "FemSetNodesObject.h"
#include "HypothesisPy.h"
#include "FemConstraintBearing.h"
#include "FemConstraintFixed.h"
#include "FemConstraintForce.h"
@@ -56,17 +44,28 @@
#include "FemConstraintFluidBoundary.h"
#include "FemConstraintTransform.h"
#include "FemConstraintSpring.h"
#include "FemMesh.h"
#include "FemMeshObject.h"
#include "FemMeshProperty.h"
#include "FemMeshPy.h"
#include "FemMeshShapeObject.h"
#include "FemMeshShapeNetgenObject.h"
#include "FemResultObject.h"
#include "FemSetElementsObject.h"
#include "FemSetFacesObject.h"
#include "FemSetGeometryObject.h"
#include "FemSetNodesObject.h"
#include "FemSolverObject.h"
#include "HypothesisPy.h"
#ifdef FC_USE_VTK
#include "FemPostPipeline.h"
#include "FemPostFilter.h"
#include "FemPostFunction.h"
#include "PropertyPostDataObject.h"
# include "FemPostFilter.h"
# include "FemPostFunction.h"
# include "FemPostPipeline.h"
# include "PropertyPostDataObject.h"
#endif
namespace Fem {
extern PyObject* initModule();
}
+20 -34
View File
@@ -21,62 +21,48 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cmath> //OvG: Required for log10
# include <TopoDS.hxx>
# include <BRepGProp_Face.hxx>
# include <gp_Vec.hxx>
# include <gp_Pnt.hxx>
# include <gp_Pln.hxx>
# include <gp_Cylinder.hxx>
# include <gp_Ax3.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <GCPnts_AbscissaPoint.hxx>
# include <Adaptor3d_IsoCurve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <GProp_GProps.hxx>
# include <BRepGProp.hxx>
# include <TopoDS_Vertex.hxx>
# include <BRepClass_FaceClassifier.hxx>
# include <BRep_Tool.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <BRepGProp.hxx>
# include <BRepGProp_Face.hxx>
# include <ShapeAnalysis.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
# include <GeomAPI_IntCS.hxx>
# include <Geom_Plane.hxx>
# include <BRepClass_FaceClassifier.hxx>
# include <GCPnts_AbscissaPoint.hxx>
# include <Geom_Line.hxx>
# include <Geom_Plane.hxx>
# include <GeomAPI_IntCS.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
# include <gp_Cylinder.hxx>
# include <gp_Pln.hxx>
# include <gp_Pnt.hxx>
# include <gp_Vec.hxx>
# include <GProp_GProps.hxx>
# include <Precision.hxx>
# include <Standard_Version.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Vertex.hxx>
# if OCC_VERSION_HEX < 0x070600
# include <Adaptor3d_HSurface.hxx>
# include <BRepAdaptor_HSurface.hxx>
# include <Adaptor3d_HSurface.hxx>
# include <BRepAdaptor_HSurface.hxx>
# endif
#endif
#include "FemConstraint.h"
#include "FemTools.h"
#include <App/DocumentObjectPy.h>
#include <App/FeaturePythonPyImp.h>
#include <App/OriginFeature.h>
#include <Mod/Part/App/PartFeature.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include "FemConstraint.h"
#include "FemTools.h"
using namespace Fem;
// maybe in the c++ standard later, older compiler don't have round()
#if _MSC_VER <= 1700
double round(double r) {
return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
}
#endif
#if OCC_VERSION_HEX >= 0x070600
using Adaptor3d_HSurface = Adaptor3d_Surface;
using BRepAdaptor_HSurface = BRepAdaptor_Surface;
+3 -4
View File
@@ -21,17 +21,16 @@
* *
***************************************************************************/
#ifndef FEM_CONSTRAINT_H
#define FEM_CONSTRAINT_H
#include <Base/Vector3D.h>
#include <App/FeaturePython.h>
#include <App/DocumentObject.h>
#include <App/FeaturePython.h>
#include <App/PropertyLinks.h>
#include <App/PropertyGeo.h>
#include <Base/Vector3D.h>
#include <Mod/Fem/FemGlobal.h>
namespace Fem {
/**
+4 -10
View File
@@ -21,23 +21,18 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <gp_Pnt.hxx>
#include <gp_Pln.hxx>
#include <gp_Lin.hxx>
#include <TopoDS.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <Precision.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <TopoDS.hxx>
#endif
#include <Mod/Part/App/PartFeature.h>
#include "FemConstraintBearing.h"
#include <Mod/Part/App/PartFeature.h>
#include <Base/Console.h>
using namespace Fem;
@@ -64,7 +59,6 @@ App::DocumentObjectExecReturn *ConstraintBearing::execute(void)
void ConstraintBearing::onChanged(const App::Property* prop)
{
//Base::Console().Error("ConstraintBearing: onChanged %s\n", prop->getName());
// Note: If we call this at the end, then the symbol is not oriented correctly initially
// because the NormalDirection has not been calculated yet
Constraint::onChanged(prop);
+1 -2
View File
@@ -21,16 +21,15 @@
* *
***************************************************************************/
#ifndef FEM_CONSTRAINTBEARING_H
#define FEM_CONSTRAINTBEARING_H
#include <App/DocumentObject.h>
#include <App/PropertyLinks.h>
#include <App/PropertyGeo.h>
#include "FemConstraint.h"
namespace Fem
{
+1 -11
View File
@@ -21,21 +21,11 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <Precision.hxx>
#include <TopoDS.hxx>
#include <gp_Lin.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#endif
#include "FemConstraintContact.h"
using namespace Fem;
PROPERTY_SOURCE(Fem::ConstraintContact, Fem::Constraint)
+1 -11
View File
@@ -23,21 +23,11 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <Precision.hxx>
#include <TopoDS.hxx>
#include <gp_Lin.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#endif
#include "FemConstraintDisplacement.h"
using namespace Fem;
PROPERTY_SOURCE(Fem::ConstraintDisplacement, Fem::Constraint)
-20
View File
@@ -21,30 +21,10 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <gp_Pnt.hxx>
#include <gp_Pln.hxx>
#include <gp_Lin.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Adaptor3d_IsoCurve.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS.hxx>
#include <BRepClass_FaceClassifier.hxx>
#include <BRep_Tool.hxx>
#include <Precision.hxx>
#endif
#include "FemConstraintFixed.h"
#include <Mod/Part/App/PartFeature.h>
#include <Base/Console.h>
using namespace Fem;
-3
View File
@@ -24,9 +24,6 @@
#ifndef FEM_CONSTRAINTFIXED_H
#define FEM_CONSTRAINTFIXED_H
#include <App/DocumentObject.h>
#include <App/PropertyGeo.h>
#include "FemConstraint.h"
+3 -10
View File
@@ -21,23 +21,16 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <gp_Pnt.hxx>
#include <gp_Pln.hxx>
#include <gp_Lin.hxx>
#include <TopoDS.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <Precision.hxx>
# include <Precision.hxx>
#endif
#include <Base/Console.h>
#include "FemConstraintFluidBoundary.h"
#include <Mod/Part/App/PartFeature.h>
#include <Base/Console.h>
using namespace Fem;

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