├── transportationwb
├── test.md
├── __init__.py
├── traffic
│ ├── __init__.py
│ └── Test_traffic.py
├── readme.md
├── mydoxypy.py
├── tests
│ └── GeometryTests
│ │ ├── test_support.py
│ │ └── test_geometry.py
├── myStyle.css
├── makefile
├── TestCommand.py
├── startTests.py
├── Test_All.py
├── Doxyfile
├── embed_test
│ ├── mainwindow2.py
│ ├── mainwindow.ui
│ ├── mainwindow.py
│ ├── mainwindow3.py
│ └── ui_mainwindow.py
├── usecases.md
├── menues.md
├── createTestdata.py
├── vehicle
│ ├── Test_vehicle.py
│ └── __init__.py
├── say.py
├── Test_miki.py
├── videos.md
├── Test_labeltools.py
├── gentests.py
├── transversmercator.py
├── sketch_manager.py
├── clipplane.py
└── property_creator.ui
├── Resources
├── icons
│ └── vehicle_01.png
├── data
│ ├── alignment
│ │ ├── il2_curves.xlsx
│ │ ├── IL_2_Verify.FCStd
│ │ ├── IL_2_Verify.FCStd1
│ │ ├── SugarGroveRd.FCStd
│ │ ├── SugarGroveRoad.png
│ │ ├── SugarGroveRd.FCStd1
│ │ ├── arc_xml_construction_sample.FCStd
│ │ ├── spiral_curve_back_calculator.xlsx
│ │ ├── Transition curves in Road Design.odt
│ │ ├── arc_xml_construction_sample.FCStd1
│ │ ├── hc_bd_deg.csv
│ │ ├── hc_bd_rad.csv
│ │ ├── hc_ne_deg.csv
│ │ ├── hc_ne_r.csv
│ │ ├── geo_test.csv
│ │ ├── Sugar_Grove_Rd_Horizontal_NE.csv
│ │ ├── Sugar_Grove_Rd_Horizontal.csv
│ │ ├── il2_curves.csv
│ │ ├── mainline_demo.csv
│ │ ├── il2_vc.csv
│ │ ├── il2_ss_vc.csv
│ │ ├── SugarGroveRd_mixed.xml
│ │ ├── SugarGroveRd.xml
│ │ ├── HC_IL2_Rev4.csv
│ │ └── complete_demo.csv
│ ├── drainage
│ │ ├── box_culvert.FCStd
│ │ ├── box_culvert.FCStd1
│ │ └── box_culvert1.FCStd1
│ ├── landXML-meter.xml
│ └── landXML-foot.xml
└── snippets
│ ├── test_controller.py
│ ├── OpenOfficeBridge.py
│ ├── Task
│ └── TaskViewDelegate_template.py
│ ├── python_templates
│ ├── Task
│ │ └── TaskViewDelegate_template.py
│ ├── cmd_template.py
│ └── fpo_template.py
│ ├── cmd_template.py
│ ├── Observer.py
│ ├── FeedbackSketcherUtils.py
│ └── fpo_template.py
├── Corridor
├── Templates
│ └── pavement
│ │ └── default_pavement.FCStd
├── loft
│ ├── tasks
│ │ ├── interval_task_panel.ui
│ │ └── IntervalViewDelegate.py
│ └── EditIntervals.py
├── template
│ ├── SketchTemplate.py
│ └── ViewTemplateLibrary.py
└── alignment
│ ├── ImportVerticalCurve.py
│ └── AlignmentGroup.Py
├── .gitignore
├── README.md
├── Project
├── Tasks
│ └── alignment
│ │ ├── import_alignment_task_panel.ui
│ │ ├── DraftAlignmentTask.py
│ │ ├── ImportAlignmentViewDelegate.py
│ │ ├── ImportXmlSubtask.py
│ │ └── ImportAlignmentModel.py
├── Commands
│ ├── AlignmentTracker.py
│ ├── ImportAlignmentCmd.py
│ └── NewProjectCmd.py
├── Support
│ ├── Singleton.py
│ ├── Const.py
│ ├── Units.py
│ ├── Properties.py
│ ├── DocumentProperties.py
│ └── WidgetModel.py
├── ProjectObserver.py
└── XML
│ └── KeyMaps.py
└── Geometry
├── Spiral.py
├── Line.py
└── Support.py
/transportationwb/test.md:
--------------------------------------------------------------------------------
1 | Test page: Das ist eine Testseite
2 | ================================
3 |
4 | huhuhu
5 |
--------------------------------------------------------------------------------
/Resources/icons/vehicle_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/icons/vehicle_01.png
--------------------------------------------------------------------------------
/Resources/data/alignment/il2_curves.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/il2_curves.xlsx
--------------------------------------------------------------------------------
/Resources/data/drainage/box_culvert.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/drainage/box_culvert.FCStd
--------------------------------------------------------------------------------
/Resources/data/alignment/IL_2_Verify.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/IL_2_Verify.FCStd
--------------------------------------------------------------------------------
/Resources/data/alignment/IL_2_Verify.FCStd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/IL_2_Verify.FCStd1
--------------------------------------------------------------------------------
/Resources/data/alignment/SugarGroveRd.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/SugarGroveRd.FCStd
--------------------------------------------------------------------------------
/Resources/data/alignment/SugarGroveRoad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/SugarGroveRoad.png
--------------------------------------------------------------------------------
/Resources/data/drainage/box_culvert.FCStd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/drainage/box_culvert.FCStd1
--------------------------------------------------------------------------------
/Resources/data/drainage/box_culvert1.FCStd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/drainage/box_culvert1.FCStd1
--------------------------------------------------------------------------------
/Resources/data/alignment/SugarGroveRd.FCStd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/SugarGroveRd.FCStd1
--------------------------------------------------------------------------------
/transportationwb/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | '''tranportation workbench history '''
3 |
4 | date=" So 25. Mär 14:33:02 CEST 2018 "
5 | version=112
6 |
--------------------------------------------------------------------------------
/Corridor/Templates/pavement/default_pavement.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Corridor/Templates/pavement/default_pavement.FCStd
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | .vscode/
3 | test.py
4 | _*
5 | *~
6 | pylintrc
7 | freecad-transportation-wb-docu/
8 | transportationwb/corridor/alignment/data/~$il2_curves.xlsx
9 | *~lock*
--------------------------------------------------------------------------------
/Resources/data/alignment/arc_xml_construction_sample.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/arc_xml_construction_sample.FCStd
--------------------------------------------------------------------------------
/Resources/data/alignment/spiral_curve_back_calculator.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/spiral_curve_back_calculator.xlsx
--------------------------------------------------------------------------------
/Resources/data/alignment/Transition curves in Road Design.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/Transition curves in Road Design.odt
--------------------------------------------------------------------------------
/Resources/data/alignment/arc_xml_construction_sample.FCStd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelgraff/freecad-transportation-wb/HEAD/Resources/data/alignment/arc_xml_construction_sample.FCStd1
--------------------------------------------------------------------------------
/transportationwb/traffic/__init__.py:
--------------------------------------------------------------------------------
1 | '''traffic simulation tools
2 |
3 | swept path calculation
4 |
5 | drive forward
6 | drive backward
7 |
8 | '''
9 |
10 | print "traffice version "
11 |
--------------------------------------------------------------------------------
/Resources/data/alignment/hc_bd_deg.csv:
--------------------------------------------------------------------------------
1 | random_col,my_bearing,random_col,my_distance,curve.degree
2 | 12345,123.45,4545,123.45,555
3 | 54321,543.21,5454,543.21,444
4 | 45678,456.78,7878,456.78,888
5 | 87654,876.54,8787,876.54,777
6 |
--------------------------------------------------------------------------------
/Resources/data/alignment/hc_bd_rad.csv:
--------------------------------------------------------------------------------
1 | random_col,my_bearing,random_col,my_distance,curve.radius
2 | 12345,123.45,4545,123.45,555
3 | 54321,543.21,5454,543.21,444
4 | 45678,456.78,7878,456.78,888
5 | 87654,876.54,8787,876.54,777
6 |
--------------------------------------------------------------------------------
/Resources/data/alignment/hc_ne_deg.csv:
--------------------------------------------------------------------------------
1 | random_col,my_easting,random_col,my_northing,curve.degree
2 | 12345,123.45,4545,123.45,555
3 | 54321,543.21,5454,543.21,444
4 | 45678,456.78,7878,456.78,888
5 | 87654,876.54,8787,876.54,777
6 |
--------------------------------------------------------------------------------
/Resources/data/alignment/hc_ne_r.csv:
--------------------------------------------------------------------------------
1 | "random_col,my_easting,random_col,my_northing,curve_radius"
2 | "12345,123.45,4545,123.45,555"
3 | "54321,543.21,5454,543.21,444"
4 | "45678,456.78,7878,456.78,888"
5 | "87654,876.54,8787,876.54,777"
6 |
--------------------------------------------------------------------------------
/Resources/data/alignment/geo_test.csv:
--------------------------------------------------------------------------------
1 | NORTHING,EASTING,BEARING,DISTANCE,DEGREE,RADIUS,BACK,FORWARD,PARENT_ID,ID
2 | ,,,,,,,50000,,Sugar Grove Road
3 | ,,139.3986,930,,670,,,,
4 | ,,89.0825,1850,,670,,,,
5 | ,,180.5808,1680,,670,,,,
6 | ,,137.29639,644.048,,0,,,,
7 |
--------------------------------------------------------------------------------
/transportationwb/readme.md:
--------------------------------------------------------------------------------
1 |
2 | This is the main page for the transportation Workbench.
3 |
4 | - [Documentation pages](pages.html)
5 | - [Use Cases](md_usecases.html)
6 | - [Menus](md_menues.html)
7 | - [Videos](md_videos.html)
8 |
9 |
10 |
11 | Links
12 | =====
13 |
14 |
15 | - [Federal Highway Administration (FHWA)] (https://www.fhwa.dot.gov/)
16 |
--------------------------------------------------------------------------------
/Resources/snippets/test_controller.py:
--------------------------------------------------------------------------------
1 | from pivy import coin
2 | import FreeCAD
3 | import FreeCADGui
4 |
5 | def handler(arg):
6 | FreeCAD.Console.PrintMessage("dragger moved")
7 |
8 | dragger = coin.SoTranslate1Dragger()
9 | view = FreeCADGui.ActiveDocument.ActiveView
10 | sg = view.getSceneGraph()
11 | sg.addChild(dragger)
12 | view.addDraggerCallback(dragger, "addFinishCallback", handler)
--------------------------------------------------------------------------------
/transportationwb/mydoxypy.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | #print 'Number of arguments:', len(sys.argv), 'arguments.'
4 | #print 'Argument List:', str(sys.argv)
5 |
6 | ignore=True
7 | with open(sys.argv[1]) as fp:
8 | for i,line in enumerate(fp):
9 | if not ignore:
10 | print line.rstrip()
11 | else:
12 | if not line.startswith('#'):
13 | print line.rstrip()
14 | ignore=False
15 |
--------------------------------------------------------------------------------
/transportationwb/tests/GeometryTests/test_support.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from Geometry import Support
4 | import unittest
5 |
6 | class Test_Support(unittest.TestCase):
7 |
8 | def test_vector_from_angle(self):
9 |
10 | self.assertIsNone(
11 | Support.vector_from_angle('1fdsa.0'),
12 | 'Supprt.vector_from_angle() fails non-float test'
13 | )
--------------------------------------------------------------------------------
/transportationwb/tests/GeometryTests/test_geometry.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from Geometry import *
3 |
4 | def suite():
5 | suite = unittest.TestSuite()
6 |
7 | suite.addTest(unittest.defaultTestLoader.loadTestsFromName('transportationwb.tests.GeometryTests.test_support'))
8 |
9 | return suite
10 |
11 | def execute():
12 | runner = unittest.TextTestRunner()
13 | runner.run(suite())
--------------------------------------------------------------------------------
/transportationwb/myStyle.css:
--------------------------------------------------------------------------------
1 | .image
2 | {
3 | text-align: left;
4 | }
5 |
6 | .aaa
7 | {
8 | float: left;
9 | text-align: left;
10 | border-right: 2px solid #fff;
11 | border-bottom: 4px solid #fff;
12 | }
13 |
14 | .bbb
15 | {
16 | border: 1px solid red;
17 |
18 | }
19 |
20 |
21 | div.image {
22 | border: 1px solid green;
23 | float: left !important;
24 | display:inline!important;
25 | }
26 |
27 |
28 | h1 {
29 | clear:both;
30 | }
31 |
--------------------------------------------------------------------------------
/transportationwb/makefile:
--------------------------------------------------------------------------------
1 | gendoc:
2 |
3 | pepa:
4 | autopep8 --ignore=W191,E101,E111 labeltools.py >t.py
5 | #pylint -E labeltools.py
6 | #pylint labeltools.py
7 |
8 |
9 | pep:
10 | #autopep8 --ignore=W191,E101,E111 miki_g.py >t.py
11 | #pylint -E miki_g.py
12 | pylint miki_g.py
13 |
14 | gendoc:
15 | doxygen
16 |
17 |
18 | genlog:
19 | echo 'date="' `date` '"' >>__init__.py
20 | echo 'version='`git rev-list --all --count` >>__init__.py
21 |
22 |
23 | format:
24 | autopep8 -i Test_labeltools.py
25 |
--------------------------------------------------------------------------------
/transportationwb/TestCommand.py:
--------------------------------------------------------------------------------
1 | import FreeCAD as App
2 | import FreeCADGui as Gui
3 | import Part
4 |
5 |
6 | class TestCommand():
7 | '''
8 | A command for testing
9 | '''
10 | def __init__(self):
11 | pass
12 |
13 | def GetResources(self):
14 | """
15 | Icon resources.
16 | """
17 |
18 | return {'Pixmap' : '',
19 | 'Accel' : '',
20 | 'MenuText': "Test Command",
21 | 'ToolTip' : "Command for testing",
22 | 'CmdType' : "ForEdit"}
23 |
24 | def Activated(self):
25 | pass
26 |
27 | Gui.addCommand('TestCommand', TestCommand())
--------------------------------------------------------------------------------
/transportationwb/startTests.py:
--------------------------------------------------------------------------------
1 | # testall
2 |
3 |
4 | def startTests():
5 |
6 | import QtUnitGui
7 | import transportationwb
8 | import transportationwb.Test_top
9 | reload(transportationwb.Test_top)
10 | #current work tests
11 | QtUnitGui.addTest("transportationwb.Test_top")
12 | #generated tests by gentest.py
13 | QtUnitGui.addTest("transportationwb.Test_top_gen")
14 |
15 | QtUnitGui.addTest("transportationwb.Test_labeltools")
16 | QtUnitGui.addTest("transportationwb.Test_miki")
17 | QtUnitGui.addTest("transportationwb.traffic.Test_traffic")
18 | QtUnitGui.addTest("transportationwb.vehicle.Test_vehicle")
19 | QtUnitGui.addTest("transportationwb.Test_All.Col1")
20 |
--------------------------------------------------------------------------------
/Resources/data/alignment/Sugar_Grove_Rd_Horizontal_NE.csv:
--------------------------------------------------------------------------------
1 | NORTHING,EASTING,BEARING,DISTANCE,DEGREE,RADIUS,BACK,FORWARD,PARENT_ID,ID
2 | ,,,,,,,50000,,Sugar Grove Road
3 | -706.107527295728,605.237275699633,139.3986,930,,670,,,,
4 | -676.484010996592,2455.00008408401,89.0825,1850,,670,,,,
5 | -2356.39769654456,2437.97043028129,180.5808,1680,,670,,,,
6 | -2829.69045164815,2874.76763067348,137.29639,644.048,,0,,,,
7 | -641.542,632.8773,,,,,,1000,,Penrose Road W
8 | ,,,,,,50909,1000,Sugar Grove Road,
9 | -707.541739849086,493.629607922706,244.64028,154.097,,175,,,,
10 | -707.541739849086,-65.3963920772944,270,559.026,,0,,,,
11 | -662.4901,2900.3838,,,,,,2000,,Penrose Road E
12 | ,,,,,,52586.22,3008.866,Sugar Grove Road,
13 | -662.4901,2470.7258,270,429.658,,175,,,,
14 | -883.2349,2247.23112780924,224.9725,312.032,,0,,,,
15 |
--------------------------------------------------------------------------------
/Resources/data/landXML-meter.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/transportationwb/Test_All.py:
--------------------------------------------------------------------------------
1 |
2 | import FreeCAD
3 | import sys
4 | import unittest
5 |
6 |
7 | def Col1():
8 | suite = unittest.TestSuite()
9 | suite.addTest(unittest.defaultTestLoader.loadTestsFromName("transportationwb.Test_labeltools"))
10 | suite.addTest(unittest.defaultTestLoader.loadTestsFromName("transportationwb.Test_miki"))
11 | suite.addTest(unittest.defaultTestLoader.loadTestsFromName("transportationwb.traffic.Test_traffic"))
12 | suite.addTest(unittest.defaultTestLoader.loadTestsFromName("transportationwb.vehicle.Test_vehicle"))
13 | # if (FreeCAD.GuiUp == 1):
14 | # suite.addTest(unittest.defaultTestLoader.loadTestsFromName("nurbswb.TestNurbsGui"))
15 | return suite
16 |
17 |
18 | #def Col2():
19 | # suite = unittest.TestSuite()
20 | # suite.addTest(unittest.defaultTestLoader.loadTestsFromName("nurbswb.TestNurbs"))
21 | # return suite
22 |
--------------------------------------------------------------------------------
/Resources/data/landXML-foot.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/transportationwb/traffic/Test_traffic.py:
--------------------------------------------------------------------------------
1 | # Unit test for the transportationwb.traffic module
2 |
3 |
4 | import FreeCAD, os, unittest, FreeCADGui, transportationwb
5 |
6 | class TrafficTest(unittest.TestCase):
7 | '''testcade blabla'''
8 |
9 | def setUp(self):
10 | # setting a new document to hold the tests
11 | if FreeCAD.ActiveDocument:
12 | if FreeCAD.ActiveDocument.Name != "TransportationTest":
13 | FreeCAD.newDocument("TransportationTest")
14 | else:
15 | FreeCAD.newDocument("TransportationTest")
16 |
17 | FreeCAD.setActiveDocument("TransportationTest")
18 |
19 | def testPivy(self):
20 | FreeCAD.Console.PrintLog ('Checking Pivy...\n')
21 | from pivy import coin
22 | c = coin.SoCube()
23 | FreeCADGui.ActiveDocument.ActiveView.getSceneGraph().addChild(c)
24 | self.failUnless(c,"Pivy is not working properly")
25 |
26 |
27 |
28 | def tearDown(self):
29 | # FreeCAD.closeDocument("TransportationTest")
30 | pass
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/transportationwb/Doxyfile:
--------------------------------------------------------------------------------
1 | FILTER_SOURCE_FILES = YES
2 | INPUT_FILTER = "python /home/thomas/.FreeCAD/Mod/freecad-transportation-wb/transportationwb//mydoxypy.py"
3 | INPUT_FILTER = "python mydoxypy.py"
4 |
5 | PROJECT_NAME = "Transportation Workbench for FreeCAD"
6 |
7 | # EXCLUDE_SYMBOLS = __init__
8 |
9 | ENABLE_PREPROCESSING = YES
10 | # PREDEFINED = DOXYGEN_SHOULD_SKIP_THISY
11 |
12 | QUIET = YES
13 |
14 | OUTPUT_DIRECTORY = ../freecad-transportation-wb-docu
15 | GENERATE_LATEX = NO
16 |
17 |
18 | INPUT = traffic/__init__.py
19 | # INPUT += traffic/Test_traffic.py
20 |
21 | INPUT += vehicle/__init__.py
22 | # INPUT += traffic/Test_traffic.py
23 |
24 | INPUT += miki_g.py
25 | INPUT += beziersketch.py
26 | INPUT += labeltools.py
27 | #INPUT += t.py
28 | INPUT += clipplane.py
29 | INPUT += createTestdata.py
30 |
31 | INPUT += usecases.md menues.md videos.md
32 | INPUT += test.md
33 |
34 | INPUT += readme.md
35 | USE_MDFILE_AS_MAINPAGE = readme.md
36 |
37 | IMAGE_PATH = ../../icons
38 |
39 | HTML_EXTRA_STYLESHEET = myStyle.css
40 |
41 |
--------------------------------------------------------------------------------
/transportationwb/embed_test/mainwindow2.py:
--------------------------------------------------------------------------------
1 | import sys
2 | #sys.path.append("")
3 |
4 | from PySide import QtCore, QtGui
5 | import FreeCADGui
6 |
7 | class MainWindow(QtGui.QMainWindow):
8 | def __init__(self, parent = None):
9 | super(MainWindow, self).__init__(parent)
10 | from PySide import QtNetwork
11 | # Webkit is used to create icons from SVG files. This could cause a deadlock
12 | # when setting up the internally used network interface. Doing this before
13 | # creating the icons fixes the issue.
14 | QtNetwork.QNetworkConfigurationManager()
15 |
16 | def showEvent(self, event):
17 | FreeCADGui.showMainWindow()
18 | self.setCentralWidget(FreeCADGui.getMainWindow())
19 | # Need version >= 0.16.5949
20 | class BlankWorkbench(FreeCADGui.Workbench):
21 | MenuText = "Blank"
22 | ToolTip = "Blank workbench"
23 | def Initialize(self):
24 | self.appendMenu("Menu",["Std_New", "Part_Box"])
25 | return
26 | def GetClassName(self):
27 | return "Gui::PythonBlankWorkbench"
28 | FreeCADGui.addWorkbench(BlankWorkbench)
29 | FreeCADGui.activateWorkbench("BlankWorkbench")
30 |
31 | app=QtGui.QApplication(sys.argv)
32 | mw=MainWindow()
33 | mw.resize(1200,800)
34 | mw.show()
35 | app.exec_()
--------------------------------------------------------------------------------
/transportationwb/usecases.md:
--------------------------------------------------------------------------------
1 | Use Cases
2 | =========
3 |
4 | ## To do
5 | - [ ] collect use cases
6 | - [ ] describe and illustrate them
7 | - [ ] connect to details of the used dialogs and interaction videos
8 |
9 | # Import Data into a project
10 |
11 | The simplest way to get some real data into the project is
12 | the use of the geodat workbench to import openstreetmap data.
13 |
14 | For testing purposes there are 3 location in the Demo menu.
15 | Eichleite is a street with strong curves and a height difference of near 100 meters.
16 | It is an interesting real testcase for swept paths. The street is forbidden for long vehicles.
17 |
18 | After calling the methods some groups are created. The GRP paths contains all paths found,
19 | the GRP highways contains street objects.
20 | The center of the area square is the origin and corresponds to the lat long values used in the scripts.
21 |
22 | For other locations use the geodat workbench's "Import OSM Map".
23 |
24 | ## import terrain
25 |
26 |
27 | ## import gpx-track
28 |
29 | # Design
30 |
31 | ## create a street segment
32 |
33 | ## create a crossing
34 |
35 | # Simulation
36 |
37 | ## simulate a swept path along a street segment
38 |
39 |
40 |
41 | [link to Google!](http://google.com)
42 |
43 | [Home!](index.html)
44 | [Doku pages!](pages.html)
45 |
46 |
47 | https://help.github.com/articles/basic-writing-and-formatting-syntax
48 |
--------------------------------------------------------------------------------
/transportationwb/menues.md:
--------------------------------------------------------------------------------
1 | Menus
2 | =====
3 | This pages contains the description of all menu entries for the workbench and how they are to use.
4 |
5 | # Transportation
6 | # Simulation
7 | # Terrain
8 | # Demos
9 | Here are some methods to create different kinds of dialogs.
10 | This menu is temporary for developer to provide some coding examples
11 | for dialogs
12 | ## Dialog in a mainWindow
13 | ## Dialog in Combo view tab
14 | A dialog is created in the Combo view window behind the Tasks Tab.
15 | ## Dialog dockable to a Dockwindow
16 | ## Dialog with common widgets
17 | ## Dialog with functionality to run an animation
18 |
19 | There are some methods to import real data from openstreetmap
20 | using geodat workbench
21 |
22 | ## create Eichleite
23 | ## create Woosung
24 | ## create Japanese Knot
25 |
26 | # Curves
27 | ##create a Bezier Sketch
28 | ##create a simple Bezier sketch
29 | A simple Bezier sketch is a curve defined by 4 poles.
30 | Two poles are the endpoints of the curve and the others are used to
31 | configure the tangents from the endpoints.
32 | ##create Marker
33 | creates a Label on a selected curve
34 | ##combine Curves
35 | combine two 2D curves to a 3D curve
36 | # Labels
37 | ##create Geolocation
38 | ##create Stationing
39 | ##create Placement
40 | ##create all Labels
41 | creates Labels for all elements (faces, edges, vertexes) of a selected object.
42 | Unused Labels can be deleted in a next step.
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Freecad Transportation Workbench
2 | Python transportation engineeering workbench for FreeCAD
3 |
4 | This workbench is being developed to provide functionality specific to transportation engineering (road and rail).
5 |
6 | ## Usage
7 | Examples coming soon. Will include screencast and screenshots.
8 |
9 | ## Installation
10 | Clone the project into the `~/.FreeCAD/Mod/Transportation` folder to use.
11 |
12 | **Note:** This project has a dependency in another FreeCAD workbench, [@microelly2's](https://github.com/microelly2) [Nurbs Workbench](https://github.com/microelly2/freecad-nurbs). A symlink exists which points to it in the Transportation source.
13 |
14 | You can satisfy this dependency one of two ways:
15 |
16 | 1. Clone the Nurbs workbench into the `~/.FreeCAD/Mod/nurbs` folder
17 | 2. Delete the symlink and copy the `freecad-nurbs/sketcher/feedbacksketch.py` file to the `~/.FreeCAD/Mod/Transportation` folder.
18 |
19 | ## Feedback
20 | Discuss this Workbench on the FreeCAD forum thread dedicated to this topic:
21 | [Civil engineering feature implementation (Transportation Engineering)](https://forum.freecadweb.org/viewtopic.php?f=8&t=22277).
22 |
23 | FYI, this thread was born of a parent thread:
24 | [Civil Engineering Design functions](https://forum.freecadweb.org/viewtopic.php?f=8&t=6973)
25 |
26 | ## Developer
27 | Joel Graff (@graffy76) with inspiration and help from the FreeCAD community
28 |
29 |
--------------------------------------------------------------------------------
/transportationwb/createTestdata.py:
--------------------------------------------------------------------------------
1 | '''create some real environments with hard coded coordinates
2 |
3 | these scripts use the geodat workbench.
4 | '''
5 |
6 | def createEichleite():
7 | '''Wilhelmsthal Eichleite Friesener Berg steiler kurviger Anstieg 50.2725064,11.3946793'''
8 | import geodat
9 | from geodat import import_osm
10 |
11 | bk=0.5
12 | b,l = 50.2725064,11.3946793
13 |
14 | progressbar=False
15 | status=False
16 | elevation=False
17 |
18 | if not geodat.import_osm.import_osm2(b,l,bk,progressbar,status,elevation):
19 | geodat.import_osm.import_osm2(b,l,bk,progressbar,status,elevation)
20 |
21 |
22 | def createWoosung():
23 | '''testcase by Joel 41.8846258,-89.5806548'''
24 | import geodat
25 | from geodat import import_osm
26 |
27 | bk=2
28 | b,l = 41.8846258,-89.5806548
29 |
30 | progressbar=False
31 | status=False
32 | elevation=False
33 |
34 | if not geodat.import_osm.import_osm2(b,l,bk,progressbar,status,elevation):
35 | geodat.import_osm.import_osm2(b,l,bk,progressbar,status,elevation)
36 |
37 |
38 |
39 | def createJapaneseKnot():
40 | '''complex highway crossing 35.624446,139.263'''
41 |
42 | import geodat
43 | from geodat import import_osm
44 |
45 | bk=0.5
46 | b,l = 35.624446,139.263
47 |
48 | progressbar=False
49 | status=False
50 | elevation=False
51 |
52 | if not geodat.import_osm.import_osm2(b,l,bk,progressbar,status,elevation):
53 | geodat.import_osm.import_osm2(b,l,bk,progressbar,status,elevation)
54 |
--------------------------------------------------------------------------------
/Project/Tasks/alignment/import_alignment_task_panel.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | TaskPanel
4 |
5 |
6 |
7 | 0
8 | 0
9 | 478
10 | 411
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 | Import Alignment
21 |
22 |
23 | -
24 |
25 |
-
26 |
27 |
28 |
29 | 1
30 | 0
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 | ...
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/transportationwb/vehicle/Test_vehicle.py:
--------------------------------------------------------------------------------
1 | # Unit test for the transportationwb.vehicle module
2 |
3 |
4 | import FreeCAD, os, unittest, FreeCADGui, transportationwb
5 |
6 | class VehicleTest(unittest.TestCase):
7 |
8 | def setUp(self):
9 | # setting a new document to hold the tests
10 | if FreeCAD.ActiveDocument:
11 | if FreeCAD.ActiveDocument.Name != "TransportationTest":
12 | FreeCAD.newDocument("TransportationTest")
13 | else:
14 | FreeCAD.newDocument("TransportationTest")
15 | FreeCAD.setActiveDocument("TransportationTest")
16 |
17 |
18 | def testPivy(self):
19 | FreeCAD.Console.PrintLog ('Checking Pivy...\n')
20 | from pivy import coin
21 | c = coin.SoCube()
22 | FreeCADGui.ActiveDocument.ActiveView.getSceneGraph().addChild(c)
23 | self.failUnless(c,"Pivy is not working properly")
24 |
25 |
26 | def testVehicle(self):
27 | FreeCAD.Console.PrintLog ('Checking createVehicle ...\n')
28 | FreeCAD.Console.PrintMessage ('Checking createVehicle...\n')
29 | import transportationwb
30 | import transportationwb.vehicle
31 | reload(transportationwb.vehicle)
32 | c=transportationwb.vehicle.createVehicle()
33 | self.failUnless(c,"createVehicle is not working properly")
34 |
35 |
36 |
37 | def tearDown(self):
38 | FreeCAD.closeDocument("TransportationTest")
39 | pass
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/transportationwb/embed_test/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 800
10 | 600
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
36 |
37 |
38 |
39 | Embed
40 |
41 |
42 |
43 |
44 | Document
45 |
46 |
47 |
48 |
49 | Cube
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/transportationwb/say.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #-------------------------------------------------
3 | #-- Animation workbench
4 | #--
5 | #-- microelly 2016
6 | #--
7 | #-- GNU Lesser General Public License (LGPL)
8 | #-------------------------------------------------
9 |
10 | import FreeCAD
11 |
12 | import FreeCADGui
13 | App=FreeCAD
14 | Gui=FreeCADGui
15 |
16 | import PySide
17 | from PySide import QtCore, QtGui
18 |
19 | import FreeCAD
20 | import Draft, Part
21 |
22 | import numpy as np
23 | import matplotlib
24 | import matplotlib.pyplot as plt
25 | from matplotlib.pyplot import cm
26 |
27 | import os,random,time,sys,traceback
28 |
29 |
30 |
31 |
32 | def log(s):
33 | logon = False
34 | if logon:
35 | f = open('/tmp/log.txt', 'a')
36 | f.write(str(s) +'\n')
37 | f.close()
38 |
39 | def sayd(s):
40 | if hasattr(FreeCAD,'animation_debug'):
41 | pass
42 | log(str(s))
43 | FreeCAD.Console.PrintMessage(str(s)+"\n")
44 |
45 | def say(s):
46 | log(str(s))
47 | FreeCAD.Console.PrintMessage(str(s)+"\n")
48 |
49 | def sayErr(s):
50 | log(str(s))
51 | FreeCAD.Console.PrintError(str(s)+"\n")
52 |
53 |
54 | def sayW(s):
55 | log(str(s))
56 | FreeCAD.Console.PrintWarning(str(s)+"\n")
57 |
58 |
59 | def errorDialog(msg):
60 | diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical,u"Error Message",msg )
61 | diag.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)
62 | diag.exec_()
63 |
64 |
65 | def sayexc(mess=''):
66 | exc_type, exc_value, exc_traceback = sys.exc_info()
67 | ttt=repr(traceback.format_exception(exc_type, exc_value,exc_traceback))
68 | lls=eval(ttt)
69 | l=len(lls)
70 | l2=lls[(l-3):]
71 | FreeCAD.Console.PrintError(mess + "\n" +"--> ".join(l2))
72 |
--------------------------------------------------------------------------------
/transportationwb/Test_miki.py:
--------------------------------------------------------------------------------
1 | # Unit test for the transportationwb.vehicle module
2 |
3 |
4 | import FreeCAD, os, unittest, FreeCADGui #, transportationwb
5 |
6 | class MikiTestU(unittest.TestCase):
7 |
8 | def setUp(self):
9 | # setting a new document to hold the tests
10 | if FreeCAD.ActiveDocument:
11 | if FreeCAD.ActiveDocument.Name != "TransportationTest":
12 | FreeCAD.newDocument("TransportationTestA")
13 | else:
14 | FreeCAD.newDocument("TransportationTestA")
15 | FreeCAD.setActiveDocument("TransportationTestA")
16 |
17 |
18 | def testMiki(self):
19 | FreeCAD.Console.PrintMessage('!-! Checking miki...\n')
20 | import transportationwb
21 | import transportationwb.miki_g
22 | reload(transportationwb.miki_g)
23 | FreeCAD.Console.PrintMessage('!####! Checking miki...\n')
24 |
25 | c=transportationwb.miki_g.testme()
26 | FreeCAD.Console.PrintMessage('Checking miki...\n' + str(c)+"\n")
27 | self.failUnless(c<>None,"Miki is not working properly")
28 |
29 | c=transportationwb.miki_g.testDialogTab()
30 | FreeCAD.Console.PrintMessage('Checking miki...\n' + str(c)+"\n")
31 | self.failUnless(c<>None,"Miki is not working properly")
32 |
33 | c=transportationwb.miki_g.testDialogMainWindow()
34 | FreeCAD.Console.PrintMessage('Checking miki...\n' + str(c)+"\n")
35 | self.failUnless(c<>None,"Miki is not working properly")
36 |
37 | c=transportationwb.miki_g.testDialogDockWidget()
38 | FreeCAD.Console.PrintMessage('Checking miki...\n' + str(c)+"\n")
39 | self.failUnless(c<>None,"Miki is not working properly")
40 |
41 |
42 | def tearDown(self):
43 | # FreeCAD.closeDocument("TransportationTestA")
44 | pass
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Project/Tasks/alignment/DraftAlignmentTask.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Task to draft an alignment
26 | '''
--------------------------------------------------------------------------------
/Resources/data/alignment/Sugar_Grove_Rd_Horizontal.csv:
--------------------------------------------------------------------------------
1 | NORTHING,EASTING,BEARING,DISTANCE,DEGREE,RADIUS,BACK,FORWARD,PARENT_ID,ID,curve_length,curve tangent,curve delta,radians,cum len,tan len
2 | ,,,,,,,50000,,Sugar Grove Road,,,,,,,
3 | 605.237275699633,-706.107527295728,139.3986,930,,670,,,,,588.381679881022,314.679100637121,50.3161,0.878181611762719,1203.7025792439,615.320899362878
4 | 2455.00008408401,-676.484010996592,89.0825,1850,,670,,,,,1069.95421863494,687.753825063403,91.4983,1.59694659497753,1917.52129293442,847.567074299475
5 | 2437.97043028129,-2356.39769654456,180.5808,1680,,670,,,,,506.155164419716,265.8428311204,43.28441,0.755455469283159,1232.55850823591,726.403343816197
6 | 2874.76763067348,-2829.69045164815,137.29639,644.048,,0,,,,,,,,,378.2051688796,600.76359
7 | ,,,,,,,1000,,Penrose Road W,,,,,4731.98754929383,
8 | ,,,,,,50909,1000,Sugar Grove Road,,,,,,,
9 | 452.322935461379,-756.162903625233,244.64028,154.097,,175,,,,,77.4568569921749,39.3733201436167,25.35972,0.442610611383857,,114.723679856383
10 | -106.703064538621,-756.162903625233,270,559.026,,0,,,,,,,,,,
11 | ,,,,,,,2000,,Penrose Road E,,,,,,
12 | 2247.23112780924,-1148.28677303149,,,,,52586.22,3008.866,Sugar Grove Road,,,,,,,
13 | 2371.03419296732,-1024.60249328073,270,429.658,,175,,,,,137.528672564806,72.5365808362728,45.0275,0.785878128941747,449.560672564806,
14 | 2591.56821113411,-803.856675981262,224.9725,312.032,,0,,,,,,,,,,
15 | ,,,,,,,,,,,,,,,
16 | ,,,,,,,,,,,,,,,
17 | 2455.00008408401,-676.484010996592,,,,,,,,,,,,,,
18 | 1767.33443709678,-680.740875559135,,,,,,,,,,,,,,
19 | 479.896690712462,-467.545897472353,52051.2696535434,534.950346456622,0.798433352920332,,,,,,,,,,,
20 | 2247.23112780924,-1148.28677303149,,,,,,,,,,,,,,
21 | 123.803065158084,123.684279750756,,,,,,,,,,,,,,
22 | -220.534018166788,-220.74581729947,,,,,,,,,,,,,,
23 |
--------------------------------------------------------------------------------
/transportationwb/videos.md:
--------------------------------------------------------------------------------
1 | Videos
2 | ======
3 |
4 |
5 | - [Design of a street curve with Sketcher @youtube 2018/05/16](https://youtu.be/4eFycT6zY7s)
6 | - [Steering simulation ](https://www.youtube.com/watch?v=SBsuudzi0x0)(22.03.2018)
7 | Simulation Ackermann steering swept curves
8 |
9 |
10 | ## Links
11 |
12 | [Home](index.html) + [Documentation pages](pages.html) + [Use Cases](md_usecases.html)
13 |
14 | #japan autobahnkreuz
15 | 35.624446,139.263
16 |
17 | # near woosung
18 | 41.8846258,-89.5806548
19 |
20 | # Eichleite
21 | 50.2725064,11.3946793
22 |
23 | https://www.google.com/maps/place/35%C2%B037'28.0%22N+139%C2%B015'48.0%22E/@35.6244444,139.2611446,17z/data=!4m5!3m4!1s0x0:0x0!8m2!3d35.6244444!4d139.2633333
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Models
35 | ======
36 | Ikarus 180
37 |
38 | Mercedes Economic
39 |
40 |
41 |
42 |
43 | Audi A6
44 |
45 |
--------------------------------------------------------------------------------
/transportationwb/Test_labeltools.py:
--------------------------------------------------------------------------------
1 | # Unit test for the transportationwb.labeltools module
2 |
3 |
4 | import FreeCAD
5 | import unittest
6 |
7 | # pylint: disable=invalid-name
8 |
9 |
10 | class LabeltoolsTest(unittest.TestCase):
11 |
12 | def setUp(self):
13 |
14 | import transportationwb
15 | import transportationwb.labeltools
16 | reload(transportationwb.labeltools)
17 |
18 | if FreeCAD.ActiveDocument:
19 | if FreeCAD.ActiveDocument.Name != "TransportationTest":
20 | FreeCAD.newDocument("TransportationTest")
21 | else:
22 | FreeCAD.newDocument("TransportationTest")
23 | FreeCAD.setActiveDocument("TransportationTest")
24 | self.windows = []
25 |
26 | def testLabelGUI(self):
27 |
28 | if 1:
29 | import transportationwb.labeltools
30 |
31 | c = transportationwb.labeltools.createStationingGUI()
32 | self.windows += [c]
33 |
34 | c = transportationwb.labeltools.createAllLabelsGUI()
35 | self.windows += [c]
36 |
37 | c = transportationwb.labeltools.createGeoLocationGUI()
38 | self.windows += [c]
39 |
40 | c = transportationwb.labeltools.createGraphicLabelGUI()
41 | self.windows += [c]
42 |
43 | def testLabelcmds(self):
44 |
45 | import transportationwb.labeltools
46 |
47 | c = transportationwb.labeltools.createBillBoard()
48 | assert c
49 |
50 | c = transportationwb.labeltools.createLatLonMarker('51.34', '12.56')
51 | assert c
52 |
53 | def testFail(self):
54 | a = 1 / 0
55 | assert a
56 |
57 | def tearDown(self):
58 | FreeCAD.closeDocument("TransportationTest")
59 | for c in self.windows:
60 | c.hide()
61 |
--------------------------------------------------------------------------------
/transportationwb/embed_test/mainwindow.py:
--------------------------------------------------------------------------------
1 | import sys
2 | #sys.path.append("")
3 |
4 | from PySide import QtCore, QtGui
5 | import FreeCAD, FreeCADGui
6 |
7 | from transportationwb.embed_test.ui_mainwindow import Ui_MainWindow
8 |
9 | class MainWindow(QtGui.QMainWindow):
10 | def __init__(self, parent = None):
11 | super(MainWindow, self).__init__(parent)
12 | from PySide import QtNetwork
13 | # Webkit is used to create icons from SVG files. This could cause a deadlock
14 | # when setting up the internally used network interface. Doing this before
15 | # creating the icons fixes the issue.
16 | QtNetwork.QNetworkConfigurationManager()
17 |
18 | def showEvent(self, event):
19 | FreeCADGui.showMainWindow()
20 | self.setCentralWidget(FreeCADGui.getMainWindow())
21 | # Need version >= 0.16.5949
22 | class BlankWorkbench(FreeCADGui.Workbench):
23 | MenuText = "Blank"
24 | ToolTip = "Blank workbench"
25 | def Initialize(self):
26 | return
27 | def GetClassName(self):
28 | return "Gui::BlankWorkbench"
29 | FreeCADGui.addWorkbench(BlankWorkbench)
30 | FreeCADGui.activateWorkbench("BlankWorkbench")
31 |
32 | @QtCore.Slot()
33 | def on_actionEmbed_triggered(self):
34 | return
35 |
36 | @QtCore.Slot()
37 | def on_actionDocument_triggered(self):
38 | FreeCAD.newDocument()
39 |
40 | @QtCore.Slot()
41 | def on_actionCube_triggered(self):
42 | FreeCAD.ActiveDocument.addObject("Part::Box")
43 | FreeCAD.ActiveDocument.recompute()
44 | FreeCADGui.ActiveDocument.ActiveView.fitAll()
45 |
46 | app=QtGui.QApplication(sys.argv)
47 | ui=Ui_MainWindow()
48 | mw=MainWindow()
49 | ui.setupUi(mw)
50 | ui.actionEmbed.setVisible(False)
51 | mw.resize(1200,800)
52 | mw.show()
53 | app.exec_()
--------------------------------------------------------------------------------
/Corridor/loft/tasks/interval_task_panel.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | TaskPanel
4 |
5 |
6 |
7 | 0
8 | 0
9 | 307
10 | 268
11 |
12 |
13 |
14 | Interval Schedule
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 | false
23 |
24 |
25 | true
26 |
27 |
28 |
29 |
30 |
31 | -
32 |
33 |
-
34 |
35 |
36 | Qt::Horizontal
37 |
38 |
39 |
40 | 40
41 | 20
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 | Add
50 |
51 |
52 |
53 | -
54 |
55 |
56 | Remove
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Project/Commands/AlignmentTracker.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 | '''
24 | Tracker for alignment drafting
25 | '''
26 |
27 | from DraftTrackers import Tracker
28 |
29 | class AlignmentTracker(Tracker):
30 | '''
31 | Tracker class for alignment design
32 | '''
33 |
34 | pass
--------------------------------------------------------------------------------
/transportationwb/embed_test/mainwindow3.py:
--------------------------------------------------------------------------------
1 | import sys
2 | #sys.path.append("")
3 |
4 | from PySide import QtCore, QtGui
5 | import FreeCAD, FreeCADGui
6 | import ctypes
7 |
8 | from ui_mainwindow import Ui_MainWindow
9 |
10 | class MainWindow(QtGui.QMainWindow):
11 | def __init__(self, parent = None):
12 | super(MainWindow, self).__init__(parent)
13 | from PySide import QtNetwork
14 | # Webkit is used to create icons from SVG files. This could cause a deadlock
15 | # when setting up the internally used network interface. Doing this before
16 | # creating the icons fixes the issue.
17 | QtNetwork.QNetworkConfigurationManager()
18 |
19 | @QtCore.Slot()
20 | def on_actionEmbed_triggered(self):
21 | FreeCADGui.showMainWindow()
22 | hwnd=self.winId()
23 | PyCObject_AsVoidPtr = ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)(('PyCObject_AsVoidPtr', ctypes.pythonapi))
24 | addr = PyCObject_AsVoidPtr(hwnd)
25 | FreeCADGui.embedToWindow(hex(addr))
26 | # Need version >= 0.16.5949
27 | class BlankWorkbench(FreeCADGui.Workbench):
28 | MenuText = "Blank"
29 | ToolTip = "Blank workbench"
30 | def Initialize(self):
31 | return
32 | def GetClassName(self):
33 | return "Gui::BlankWorkbench"
34 | FreeCADGui.addWorkbench(BlankWorkbench)
35 | FreeCADGui.activateWorkbench("BlankWorkbench")
36 |
37 | @QtCore.Slot()
38 | def on_actionDocument_triggered(self):
39 | FreeCAD.newDocument()
40 |
41 | @QtCore.Slot()
42 | def on_actionCube_triggered(self):
43 | FreeCAD.ActiveDocument.addObject("Part::Box")
44 | FreeCAD.ActiveDocument.recompute()
45 | FreeCADGui.ActiveDocument.ActiveView.fitAll()
46 |
47 | app=QtGui.QApplication(sys.argv)
48 | ui=Ui_MainWindow()
49 | mw=MainWindow()
50 | ui.setupUi(mw)
51 | mw.resize(1200,800)
52 | mw.show()
53 | app.exec_()
--------------------------------------------------------------------------------
/Resources/data/alignment/il2_curves.csv:
--------------------------------------------------------------------------------
1 | Curve,Sta,Length,PI,T1,T2
2 | 1,113100,100,723.45,-1.15,0.3
3 | 2,113215,130,723.79,,-1.5
4 | 3,113430,200,720.57,,-0.91
5 | 4,114050,300,714.95,,-3.39
6 | 5,114880,840,686.84,,0.5
7 | 6,115750,180,691.19,,-0.6
8 | 7,116096,180,689.11,,0.47
9 | 8,116820,320,691.12,,-1.61
10 | 9,117283,500,678.85,,2.34
11 | 10,118020,350,696.07,,-0.8
12 | 11,118800,210,689.83,,0.5
13 | 12,119300,160,692.33,,-0.5
14 | 13,119760,160,690.03,,0.5
15 | 14,120200,160,692.23,,-0.5
16 | 15,120540,160,690.53,,0.5
17 | 16,121150,300,693.58,,-0.54
18 | 17,121850,500,689.81,,0.3
19 | 18,123780,500,695.6,,1.1
20 | 19,124620,800,704.84,,-1.4
21 | 20,125520,500,692.24,,-0.01
22 | 21,130130,500,691.99,,-0.26
23 | 22,131030,500,689.75,,0.1
24 | 23,134020,300,692.77,,1.7
25 | 24,134320,300,697.87,,-0.07
26 | 25,134800,300,697.53,,0.2
27 | 26,135750,300,699.43,,-0.18
28 | 27,136400,300,698.26,,-0.09
29 | 28,137930,300,696.89,,-1.16
30 | 29,138407,200,691.35,,0.56
31 | 30,138890,300,694.04,,-1
32 | 31,139190,300,691.04,,1.32
33 | 32,139490,300,695.01,,-1.29
34 | 33,139820,360,690.74,,0.23
35 | 34,140300,400,691.85,,-0.15
36 | 35,140700,400,691.25,,0.03
37 | 36,141850,300,691.59,,0.25
38 | 37,143500,2000,695.72,,-0.3
39 | 38,145120,1000,690.86,,0.24
40 | 39,146303,200,693.66,,-0.22
41 | 40,146536.33,0,693.15,,0.7
42 | 41,147150,200,695.11,,0.84
43 | 42,147751.22,200,700.16,,0.69
44 | STEQ,148292.43,0,,,
45 | 43,180,600,705.17,,0.2
46 | 44,2940,500,710.69,,-1.93
47 | 45,3661,300,696.78,,-0.75
48 | 46,3993,144,696.42,,1.24
49 | 47,4065,220,697.31,,2.19
50 | 48,4370,390,703.99,,0.2
51 | 49,5570,440,706.4,,2.12
52 | 50,6850,620,733.5,,4.55
53 | 51,7385,450,757.86,,2.77
54 | 52,8635,1800,792.5,,-2.87
55 | 53,9825,580,758.3,,-4.72
56 | 54,10970,1000,704.3,,0.3
57 | 55,12600,300,709.19,,0.03
58 | 56,14750,450,709.74,,3.08
59 | 57,15265,580,725.61,,-0.55
60 | 58,17070,600,71.69,,0.9
61 | 59,18280,800,726.58,,-1.45
62 | 60,19200,600,713.19,,-0.69
63 | 61,19960,300,707.94,,0.5
64 | 62,20260,300,709.44,,-1.36
65 | 63,20560,300,705.35,,1
66 |
--------------------------------------------------------------------------------
/Resources/data/alignment/mainline_demo.csv:
--------------------------------------------------------------------------------
1 | ,BEARING,NORTHING,EASTING,RADIUS,DISTANCE,ID,PARENT_ID,BACK,FORWARD,SPIRAL
2 | ,,0,0,,,Mainline,,,113050,
3 | ,,,,,,,,148292.43,0,
4 | 114383.75,87.64805556,,,1008.7,1791.416859,,,,,
5 | 115243.04,38.83861111,,,2000,613.7386026,,,,,
6 | 116456.78,29.91444444,,,3800,2466.731841,,,,,
7 | 119410.29,349.2408333,,,2300,1867.764662,,,,,
8 | 120017.7,359.3480556,,,4000,643.452579,,,35242.43,,
9 | 120493.91,6.169166667,,,2000,559.8602734,,,20742.76,,
10 | 121385.05,24.43222222,,,1585.53,990.2138983,,,55985.19,,
11 | 122536.31,355.0911111,,,3600,1320.838479,,,55985.184,,
12 | 124488.52,12.97499999,,,6000,2126.327426,,,0.006,,
13 | 125944.07,26.87444444,,,3500,1017.510108,,,1.07E-07,,
14 | 129512.97,36.22222222,,,4000,3458.064833,,,1.07E-05,,
15 | 129952.83,41.205,,,10000,516.0634721,,,,,
16 | 131070.39,38.34055556,,,2000,1218.168726,,,,,
17 | 132520.88,58.22361111,,,3814.39,1578.688482,,,,,
18 | 133459.51,72.32277778,,,2257.87,1174.118968,,,,,
19 | 135030.2,106.8844444,,,1836.457,1875.903176,,,,,663.8898101
20 | 138885.55,69.04861111,,,1520,3467.460005,,,,,
21 | 140062.91,32.20722222,,,2100,917.2014913,,,,,
22 | 142178.09,43.68,,,2500,2815.151589,,,,,
23 | 144158.68,83.66333333,,,3375,1726.118739,,,,,
24 | 146689.32,64.14111111,,,2293.84,2294.867597,,,,,
25 | 2335.46,80.68944444,,,6000,3999.045104,,,,,
26 | 3539.45,88.11611111,,,1800,776.0678555,,,,,
27 | 3973.19,77.9325,,,1800,718.3420265,,,,,
28 | 4458.51,62.48416667,,,20000,497.5683627,,,,,
29 | 5783.34,63.93611111,,,2883.78,1413.070865,,,,,
30 | ,50.4225,,,0,747.074293,,,,,
31 | 6868.92,50.4225,,,2193.485,1045.122534,,,,,725.5594
32 | 10325.67,84.83444444,,,3687.8,3056.256401,,,,,
33 | 12214.42,66.91583333,,,3400,2329.312532,,,,,
34 | 14795.06,33.68861111,,,4656.43,1811.674163,,,,,
35 | 15453.37,38.27138889,,,2855.9299,764.0416766,,,,,
36 | 16349.07,26.60138889,,,4000,1265.204375,,,,,
37 | 17656.01,45.32194444,,,7200,1198.102444,,,,,
38 | 18991.96,53.88055555,,,4149.52,1217.285038,,,,,
39 | 20119.36,42.37416667,,,950,916.4121979,,,,,
40 | 20521.76,66.64361111,,,0,425.2646071,,,,,
41 |
--------------------------------------------------------------------------------
/Resources/data/alignment/il2_vc.csv:
--------------------------------------------------------------------------------
1 | IL 72,,,,
2 | 148292.43,0,,,
3 | 113100,100,723.45,-1.15,0.3
4 | 113215,130,723.79,0.3,-1.5
5 | 113430,200,720.57,-1.5,-0.91
6 | 114050,300,714.95,-0.91,-3.39
7 | 114880,840,686.84,-3.39,0.5
8 | 115750,180,691.19,0.5,-0.6
9 | 116096,180,689.11,-0.6,0.47
10 | 116520,320,691.12,0.47,-1.61
11 | 117283,500,678.85,-1.61,2.34
12 | 118020,350,696.07,2.34,-0.8
13 | 118800,210,689.83,-0.8,0.5
14 | 119300,160,692.33,0.5,-0.5
15 | 119760,160,690.03,-0.5,0.5
16 | 120200,160,692.23,0.5,-0.5
17 | 120540,160,690.53,-0.5,0.5
18 | 121150,300,693.58,0.5,-0.54
19 | 121850,500,689.81,-0.54,0.3
20 | 123780,500,695.6,0.3,1.1
21 | 124620,800,704.84,1.1,-1.4
22 | 125520,500,692.24,-1.4,-0.01
23 | 130130,500,691.99,-0.01,-0.26
24 | 131030,500,689.75,-0.26,0.1
25 | 134020,300,692.77,0.1,1.7
26 | 134320,300,697.87,1.7,-0.07
27 | 134800,300,697.53,-0.07,0.2
28 | 135750,300,699.43,0.2,-0.18
29 | 136400,300,698.26,-0.18,-0.09
30 | 137930,300,696.89,-0.09,-1.16
31 | 138407,200,691.35,-1.16,0.56
32 | 138890,300,694.04,0.56,-1
33 | 139190,300,691.04,-1,1.32
34 | 139490,300,695.01,1.32,-1.29
35 | 139820,360,690.74,-1.29,0.23
36 | 140300,400,691.85,0.23,-0.15
37 | 140700,400,691.25,-0.15,0.03
38 | 141850,300,691.59,0.03,0.25
39 | 143500,2000,695.72,0.25,-0.3
40 | 145120,1000,690.86,-0.3,0.24
41 | 146303,200,693.66,0.24,-0.22
42 | 146725,450,692.29,-0.22,0.664
43 | 147150,200,695.11,0.664,0.84
44 | 147751.22,200,700.16,0.84,0.69
45 | 180,600,705.17,0.69,0.2
46 | 2940,500,710.69,0.2,-1.93
47 | 3661,300,696.78,-1.93,-0.75
48 | 3839.57,57.14,695.45,-0.75,1.24
49 | 4065,220,697.31,1.24,2.19
50 | 4370,390,703.99,2.19,0.2
51 | 5570,440,706.4,0.2,2.12
52 | 6850,620,733.5,2.12,4.55
53 | 7385,450,757.86,4.55,2.77
54 | 8635,1800,792.5,2.77,-2.87
55 | 9825,580,758.3,-2.87,-4.72
56 | 10970,1000,704.3,-4.72,0.3
57 | 12600,300,709.19,0.3,0.03
58 | 14750,450,709.74,0.03,3.08
59 | 15265,580,725.61,3.08,-0.55
60 | 17070,600,715.69,-0.55,0.9
61 | 18280,800,726.58,0.9,-1.45
62 | 19200,600,713.19,-1.45,-0.69
63 | 19960,300,707.94,-0.69,0.5
64 | 20260,300,709.44,0.5,-1.36
65 | 20560,300,705.35,-1.36,1
66 |
--------------------------------------------------------------------------------
/transportationwb/gentests.py:
--------------------------------------------------------------------------------
1 | #create testcases from source file
2 |
3 | head='''
4 | class {}_Test(unittest.TestCase):
5 |
6 | def setUp(self):
7 |
8 | if FreeCAD.ActiveDocument:
9 | if FreeCAD.ActiveDocument.Name != "TransportationTest":
10 | FreeCAD.newDocument("TransportationTest")
11 | else:
12 | FreeCAD.newDocument("TransportationTest")
13 | FreeCAD.setActiveDocument("TransportationTest")
14 |
15 | '''
16 |
17 | foot='''
18 | def tearDown(self):
19 | FreeCAD.closeDocument("TransportationTest")
20 | '''
21 |
22 | def run(out,ifn,fn):
23 | print (ifn,fn)
24 | import re
25 |
26 | res = re.search(r".*/(\S+)\.py", fn)
27 | modul='clipplane'
28 | modul=res.group(1)
29 | # print modul
30 | out.write(head.format(modul))
31 |
32 | fp=open(fn)
33 | anz=0
34 | for i,line in enumerate(fp):
35 | if line.startswith('def'):
36 | res = re.search(r"def\s+(\S+)\((.*)\):\s*", line)
37 | if res:
38 | anz +=1
39 | fun=res.group(1)
40 | args=res.group(2)
41 | print (" ",anz,fun,args)
42 | out.write( " def test_"+fun+"(self):\n")
43 | out.write("\n" )
44 | out.write(" import transportationwb."+modul+"\n")
45 | out.write(" reload (transportationwb."+modul+")\n")
46 | out.write(" rc=transportationwb."+modul+"."+fun+"("+args+")\n")
47 | out.write("\n")
48 | out.write(foot)
49 | return anz
50 |
51 |
52 | def runall(fns):
53 | out=open('/home/thomas/.FreeCAD/Mod/freecad-transportation-wb/transportationwb/Test_top_generated.py', 'w')
54 | out.write('''import FreeCAD\nimport unittest\n''')
55 |
56 | anzsum=0
57 | for i,fn in enumerate(fns):
58 | anzsum += run(out,i,fn)
59 | print ("gesamt",anzsum)
60 |
61 |
62 | #-----------------------------
63 |
64 |
65 | t='''beziersketch.py
66 | bogen_zeichnen.py
67 | clipplane.py
68 | create_circle_sketch.py
69 | geodesic_lines.py
70 | labeltools.py
71 | miki_g.py
72 | mydoxypy.py
73 | say.py
74 | stationing.py
75 | transversmercator.py
76 | '''
77 |
78 | fns=['/home/thomas/.FreeCAD/Mod/freecad-transportation-wb/transportationwb/'+l for l in t.splitlines()]
79 |
80 | runall(fns)
81 |
--------------------------------------------------------------------------------
/Project/Support/Singleton.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Singleton class definition
26 | '''
27 |
28 | class Singleton(type):
29 |
30 | _instances = {}
31 |
32 | def __call__(cls, *args, **kwargs):
33 |
34 | if cls not in cls._instances:
35 | cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
36 |
37 | return cls._instances[cls]
38 |
39 | def instance_of(cls):
40 |
41 | if cls in cls._instances:
42 | return cls._instances[cls]
43 |
44 | return None
--------------------------------------------------------------------------------
/Resources/snippets/OpenOfficeBridge.py:
--------------------------------------------------------------------------------
1 | """
2 | OpenOfficeBridge - Bridge to interact directly with a running instance of open
3 | office, providing key support functions to read / write parameters between
4 | FreeCAD and the Calc application
5 | """
6 |
7 | import uno
8 | import os
9 | import subprocess
10 | import time
11 |
12 | import Sketcher
13 | import FreeCAD as App
14 | import Part
15 | import FreeCADGui as Gui
16 | import FeedbackSketcherUtils
17 | import os
18 |
19 | class DataSource():
20 |
21 | def GetResources(self):
22 |
23 | icon_path = os.path.dirname(os.path.abspath(__file__))
24 |
25 | icon_path += "/icons/new_alignment.svg"
26 |
27 | return {'Pixmap' : icon_path,
28 | 'MenuText': "Data Source",
29 | 'ToolTip' : "Create a data source",
30 | 'CmdType' : "ForEdit"}
31 |
32 | def Activated(self):
33 |
34 | uno_context = uno.getComponentContext()
35 |
36 | url_resolver = uno_context.ServiceManager.createInstanceWithContext( \
37 | "com.sun.star.bridge.UnoUrlResolver", uno_context)
38 |
39 | print ("data source activated")
40 | self.launch = 'soffice --accept="socket,host=localhost,port=2002;urp;"'
41 |
42 | self.start_office()
43 |
44 | return
45 |
46 | def IsActive(self):
47 | return True
48 |
49 | def start_office (self, filepath = None):
50 | """
51 | Initiates an office instance in a separate python process
52 | """
53 |
54 | def _start_instance(filepath, socket = 2002):
55 | """
56 | Starts office listening on a socket
57 | """
58 |
59 | print ("starting instance")
60 |
61 | #quit if this is the main process
62 | if os.fork():
63 | return
64 |
65 | time.sleep(1.0)
66 |
67 | #try:
68 | #after migration to PY3, update calling methods
69 | result = subprocess.run('soffice', shell=True)
70 |
71 | # except OSError as ose:
72 | #raise OSError(ose)
73 |
74 | #print (result)
75 |
76 | _start_instance(self.launch)
77 |
78 | Gui.addCommand('Data Source',DataSource())
79 |
--------------------------------------------------------------------------------
/transportationwb/embed_test/ui_mainwindow.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'mainwindow.ui'
4 | #
5 | # Created: Fri Nov 20 18:03:04 2015
6 | # by: pyside-uic 0.2.13 running on PySide 1.1.0
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_MainWindow(object):
13 | def setupUi(self, MainWindow):
14 | MainWindow.setObjectName("MainWindow")
15 | MainWindow.resize(800, 600)
16 | self.centralwidget = QtGui.QWidget(MainWindow)
17 | self.centralwidget.setObjectName("centralwidget")
18 | MainWindow.setCentralWidget(self.centralwidget)
19 | self.menubar = QtGui.QMenuBar(MainWindow)
20 | self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 25))
21 | self.menubar.setObjectName("menubar")
22 | self.menuFreeCAD = QtGui.QMenu(self.menubar)
23 | self.menuFreeCAD.setObjectName("menuFreeCAD")
24 | MainWindow.setMenuBar(self.menubar)
25 | self.statusbar = QtGui.QStatusBar(MainWindow)
26 | self.statusbar.setObjectName("statusbar")
27 | MainWindow.setStatusBar(self.statusbar)
28 | self.actionEmbed = QtGui.QAction(MainWindow)
29 | self.actionEmbed.setObjectName("actionEmbed")
30 | self.actionDocument = QtGui.QAction(MainWindow)
31 | self.actionDocument.setObjectName("actionDocument")
32 | self.actionCube = QtGui.QAction(MainWindow)
33 | self.actionCube.setObjectName("actionCube")
34 | self.menuFreeCAD.addAction(self.actionEmbed)
35 | self.menuFreeCAD.addAction(self.actionDocument)
36 | self.menuFreeCAD.addAction(self.actionCube)
37 | self.menubar.addAction(self.menuFreeCAD.menuAction())
38 |
39 | self.retranslateUi(MainWindow)
40 | QtCore.QMetaObject.connectSlotsByName(MainWindow)
41 |
42 | def retranslateUi(self, MainWindow):
43 | MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
44 | self.menuFreeCAD.setTitle(QtGui.QApplication.translate("MainWindow", "FreeCAD", None, QtGui.QApplication.UnicodeUTF8))
45 | self.actionEmbed.setText(QtGui.QApplication.translate("MainWindow", "Embed", None, QtGui.QApplication.UnicodeUTF8))
46 | self.actionDocument.setText(QtGui.QApplication.translate("MainWindow", "Document", None, QtGui.QApplication.UnicodeUTF8))
47 | self.actionCube.setText(QtGui.QApplication.translate("MainWindow", "Cube", None, QtGui.QApplication.UnicodeUTF8))
--------------------------------------------------------------------------------
/Project/Support/Const.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Constant class definition
26 | '''
27 |
28 | __title__ = "Const.py"
29 | __author__ = "Joel Graff"
30 | __url__ = "https://www.freecadweb.org"
31 |
32 | class MetaConst(type):
33 | '''
34 | Metaclass to enforce constant-like behaviors
35 | '''
36 |
37 | def __getattr__(cls, key):
38 | '''
39 | Default getter
40 | '''
41 | return cls[key]
42 |
43 | def __setattr__(cls, key, value):
44 | '''
45 | Default setter
46 | '''
47 | raise TypeError
48 |
49 | class Const(object, metaclass=MetaConst):
50 | '''
51 | Const class for subclassing
52 | '''
53 |
54 | def __getattr__(self, name):
55 | '''
56 | Default getter
57 | '''
58 |
59 | return self[name]
60 |
61 | def __setattr__(self, name, value):
62 | '''
63 | Default setter
64 | '''
65 |
66 | raise TypeError
67 |
--------------------------------------------------------------------------------
/Resources/snippets/Task/TaskViewDelegate_template.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | QItemStyledDelegate class for Task QTableView
26 | '''
27 |
28 | from PySide import QtGui, QtCore
29 |
30 | class TaskViewDelegate(QtGui.QStyledItemDelegate):
31 |
32 | def __init__(self, parent=None):
33 |
34 | QtGui.QStyledItemDelegate.__init__(self, parent)
35 | self._is_editing = False
36 |
37 | def createEditor(self, parent, option, index):
38 |
39 | return super(TaskViewDelegate, self).createEditor(parent, option, index)
40 |
41 | def setEditorData(self, editor, index):
42 |
43 | self._is_editing = True
44 |
45 | value = index.data(QtCore.Qt.EditRole) or index.data(QtCore.Qt.DisplayRole)
46 |
47 | if editor.metaObject().className() in ['QSpinBox', 'QDoubleSpinBox']:
48 | editor.setValue(value)
49 | else:
50 | editor.setText(value)
51 |
52 | def setModelData(self, editor, model, index):
53 |
54 | super(TaskViewDelegate, self).setModelData(editor, model, index)
55 |
56 | self._is_editing = False
57 |
58 | def isEditing(self):
59 |
60 | return self._is_editing
--------------------------------------------------------------------------------
/Resources/snippets/python_templates/Task/TaskViewDelegate_template.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | QItemStyledDelegate class for Task QTableView
26 | '''
27 |
28 | from PySide import QtGui, QtCore
29 |
30 | class TaskViewDelegate(QtGui.QStyledItemDelegate):
31 |
32 | def __init__(self, parent=None):
33 |
34 | QtGui.QStyledItemDelegate.__init__(self, parent)
35 | self._is_editing = False
36 |
37 | def createEditor(self, parent, option, index):
38 |
39 | return super(TaskViewDelegate, self).createEditor(parent, option, index)
40 |
41 | def setEditorData(self, editor, index):
42 |
43 | self._is_editing = True
44 |
45 | value = index.data(QtCore.Qt.EditRole) or index.data(QtCore.Qt.DisplayRole)
46 |
47 | if editor.metaObject().className() in ['QSpinBox', 'QDoubleSpinBox']:
48 | editor.setValue(value)
49 | else:
50 | editor.setText(value)
51 |
52 | def setModelData(self, editor, model, index):
53 |
54 | super(TaskViewDelegate, self).setModelData(editor, model, index)
55 |
56 | self._is_editing = False
57 |
58 | def isEditing(self):
59 |
60 | return self._is_editing
--------------------------------------------------------------------------------
/Resources/snippets/cmd_template.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import os
25 | import FreeCAD as App
26 | import FreeCADGui as Gui
27 |
28 | class Command():
29 | '''
30 | Command Description
31 | '''
32 | def __init__(self):
33 | pass
34 |
35 | def GetResources(self):
36 | """
37 | Icon resources.
38 | """
39 |
40 | icon_path = os.path.dirname(os.path.abspath(__file__))
41 |
42 | icon_path += "../../../icons/new_alignment.svg"
43 |
44 | return {'Pixmap' : icon_path,
45 | 'Accel' : '',
46 | 'MenuText': '',
47 | 'ToolTip' : '',
48 | 'CmdType' : 'ForEdit'}
49 |
50 | def _validate_selection(self):
51 | '''
52 | Validate the selected items in the Gui before operating on them
53 | '''
54 |
55 | _items = Gui.Selection.getSelection()
56 |
57 | return _items
58 |
59 | def Activated(self):
60 | '''
61 | Command activation method
62 | '''
63 | result = self._validate_selection()
64 |
65 | if not result:
66 | print('Invalid selection')
67 | return
68 |
69 | return
70 |
71 | Gui.addCommand('Command', Command())
72 |
--------------------------------------------------------------------------------
/Resources/snippets/python_templates/cmd_template.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import os
25 | import FreeCAD as App
26 | import FreeCADGui as Gui
27 |
28 | class Command():
29 | '''
30 | Command Description
31 | '''
32 | def __init__(self):
33 | pass
34 |
35 | def GetResources(self):
36 | """
37 | Icon resources.
38 | """
39 |
40 | icon_path = os.path.dirname(os.path.abspath(__file__))
41 |
42 | icon_path += "../../../icons/new_alignment.svg"
43 |
44 | return {'Pixmap' : icon_path,
45 | 'Accel' : '',
46 | 'MenuText': '',
47 | 'ToolTip' : '',
48 | 'CmdType' : 'ForEdit'}
49 |
50 | def _validate_selection(self):
51 | '''
52 | Validate the selected items in the Gui before operating on them
53 | '''
54 |
55 | _items = Gui.Selection.getSelection()
56 |
57 | return _items
58 |
59 | def Activated(self):
60 | '''
61 | Command activation method
62 | '''
63 | result = self._validate_selection()
64 |
65 | if not result:
66 | print('Invalid selection')
67 | return
68 |
69 | return
70 |
71 | Gui.addCommand('Command', Command())
72 |
--------------------------------------------------------------------------------
/transportationwb/transversmercator.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | '''
4 | TransverseMercator:
5 | "author": "Vladimir Elistratov and gtoonstra",
6 | "wiki_url": "https://github.com/vvoovv/blender-geo/wiki/Import-OpenStreetMap-(.osm)",
7 | "tracker_url": "https://github.com/vvoovv/blender-geo/issues",
8 | '''
9 |
10 | import FreeCAD
11 | import os
12 | import math
13 |
14 | # see conversion formulas at
15 | # http://en.wikipedia.org/wiki/Transverse_Mercator_projection
16 | # and
17 | # http://mathworld.wolfram.com/MercatorProjection.html
18 |
19 | class TransverseMercator:
20 | radius = 6378137
21 | radius = 6378137000
22 |
23 | def __init__(self, **kwargs):
24 | # setting default values
25 | self.lat = 0 # in degrees
26 | self.lon = 0 # in degrees
27 | self.k = 1.0 # scale factor
28 |
29 | for attr in kwargs:
30 | setattr(self, attr, kwargs[attr])
31 | self.latInRadians = math.radians(self.lat)
32 | print "lat in radinans",self.latInRadians
33 |
34 | def fromGeographic(self, lat, lon):
35 | lat = math.radians(lat)
36 | lon = math.radians(lon-self.lon)
37 | B = math.sin(lon) * math.cos(lat)
38 | x = 0.5 * self.k * self.radius * math.log((1+B)/(1-B))
39 | y = self.k * self.radius * ( math.atan(math.tan(lat)/math.cos(lon)) - self.latInRadians )
40 | return (x,y)
41 |
42 | def toGeographic(self, x, y):
43 | x = x/(self.k * self.radius)
44 | y = y/(self.k * self.radius)
45 | D = y + self.latInRadians
46 | lon = math.atan(math.sinh(x)/math.cos(D))
47 | lat = math.asin(math.sin(D)/math.cosh(x))
48 | # print(x,y,lat,lon)
49 |
50 | lon = self.lon + math.degrees(lon)
51 | lat = math.degrees(lat)
52 | return (lat, lon)
53 |
54 |
55 |
56 |
57 |
58 | def getpos(latc,lonc,lat,lon):
59 | '''calculate the xy position for lat lon relative to latc,lonc'''
60 |
61 | tm=TransverseMercator()
62 | tm.lat=latc
63 | tm.lon=lonc
64 | tm.latInRadians = math.radians(latc)
65 |
66 | center=tm.fromGeographic(latc,lonc)
67 |
68 | ll=tm.fromGeographic(lat,lon)
69 | pos=FreeCAD.Vector(ll[0]-center[0],ll[1]-center[1])
70 |
71 | print ("Distance between")
72 | print (latc,lonc)
73 | print (lat,lon)
74 | print ( "in km ",pos.Length/1000000)
75 | #pos *= 0.001
76 | #pos *= 0.01
77 |
78 | return pos
79 |
80 |
81 | def getlatlon(latc,lonc,x,y):
82 |
83 | tm=TransverseMercator()
84 | tm.lat=latc
85 | tm.lon=lonc
86 | tm.latInRadians = math.radians(latc)
87 |
88 | lat,lon=tm.toGeographic(x,y)
89 |
90 | return lat,lon
91 |
92 | '''
93 | v=getpos(51.0,15.0,52.0,15.0)
94 | v2 = v*0.000001
95 | print v2
96 |
97 | getlatlon(51.0,15.0,v.x,v.y)
98 | '''
99 |
--------------------------------------------------------------------------------
/Geometry/Spiral.py:
--------------------------------------------------------------------------------
1 | import FreeCAD as App
2 | import math
3 |
4 | def discretize_spiral(start_coord, bearing, radius, angle, length, interval, interval_type):
5 | '''
6 | Discretizes a spiral curve using the length parameter.
7 | '''
8 |
9 | #generate inbound spiral
10 | #generate circular arc
11 | #generate outbound spiral
12 |
13 | points = []
14 |
15 | length_mm = length * 304.80
16 | radius_mm = radius * 304.80
17 |
18 | bearing_in = App.Vector(math.sin(bearing), math.cos(bearing))
19 |
20 | curve_dir = 1.0
21 |
22 | if angle < 0.0:
23 | curve_dir = -1.0
24 | angle = abs(angle)
25 |
26 | _Xc = ((length_mm**2) / (6.0 * radius_mm))
27 | _Yc = (length_mm - ((length_mm**3) / (40 * radius_mm**2)))
28 |
29 | _dY = App.Vector(bearing_in).multiply(_Yc)
30 | _dX = App.Vector(bearing_in.y, -bearing_in.x, 0.0).multiply(curve_dir).multiply(_Xc)
31 |
32 | theta_spiral = length_mm/(2 * radius_mm)
33 | arc_start = start_coord.add(_dX.add(_dY))
34 | arc_coords = [arc_start]
35 | #arc_coords.extend(_HorizontalAlignment.discretize_arc(arc_start, bearing + (theta_spiral * curve_dir), radius, curve_dir * (angle - (2 * theta_spiral)), interval, interval_type))
36 |
37 | if len(arc_coords) < 2:
38 | print('Invalid central arc defined for spiral')
39 | return None
40 |
41 | segment_length = arc_coords[0].distanceToPoint(arc_coords[1])
42 | segments = int(length_mm / segment_length) + 1
43 |
44 | for _i in range(0, segments):
45 |
46 | _len = float(_i) * segment_length
47 |
48 | _x = (_len ** 3) / (6.0 * radius_mm * length_mm)
49 | _y = _len - ((_len**5) / (40 * (radius_mm ** 2) * (length_mm**2)))
50 |
51 | _dY = App.Vector(bearing_in).multiply(_y)
52 | _dX = App.Vector(bearing_in.y, -bearing_in.x, 0.0).multiply(curve_dir).multiply(_x)
53 |
54 | points.append(start_coord.add(_dY.add(_dX)))
55 |
56 | points.extend(arc_coords)
57 |
58 | exit_bearing = bearing + (angle * curve_dir)
59 | bearing_out = App.Vector(math.sin(exit_bearing), math.cos(exit_bearing), 0.0)
60 |
61 | _dY = App.Vector(bearing_out).multiply(_Yc)
62 | _dX = App.Vector(-bearing_out.y, bearing_out.x, 0.0).multiply(curve_dir).multiply(_Xc)
63 |
64 | end_coord = points[-1].add(_dY.add(_dX))
65 |
66 | temp = [end_coord]
67 |
68 | for _i in range(1, segments):
69 |
70 | _len = float(_i) * segment_length
71 |
72 | if _len > length_mm:
73 | _len = length_mm
74 |
75 | _x = (_len ** 3) / (6.0 * radius_mm * length_mm)
76 | _y = _len - ((_len ** 5) / (40 * (radius_mm ** 2) * (length_mm**2)))
77 |
78 | _dY = App.Vector(-bearing_out).multiply(_y)
79 | _dX = App.Vector(bearing_out.y, -bearing_out.x, 0.0).multiply(curve_dir).multiply(_x)
80 |
81 | temp.append(end_coord.add(_dY.add(_dX)))
82 |
83 | points.extend(temp[::-1])
84 |
85 | return points
--------------------------------------------------------------------------------
/Corridor/loft/tasks/IntervalViewDelegate.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | QItemStyledDelegate class for Task QTableView
26 | '''
27 |
28 | from PySide import QtGui, QtCore
29 |
30 | class IntervalViewDelegate(QtGui.QStyledItemDelegate):
31 |
32 | def __init__(self, parent=None):
33 |
34 | QtGui.QStyledItemDelegate.__init__(self, parent)
35 | self._is_editing = False
36 |
37 | def createEditor(self, parent, option, index):
38 |
39 | return super(IntervalViewDelegate, self).createEditor(parent, option, index)
40 |
41 | def setEditorData(self, editor, index):
42 |
43 | self._is_editing = True
44 |
45 | value = index.data(QtCore.Qt.EditRole) or index.data(QtCore.Qt.DisplayRole)
46 |
47 | if editor.metaObject().className() in ['QSpinBox', 'QDoubleSpinBox']:
48 | editor.setValue(value)
49 | else:
50 | editor.setText(value)
51 |
52 | def setModelData(self, editor, model, index):
53 |
54 | super(IntervalViewDelegate, self).setModelData(editor, model, index)
55 |
56 | self._is_editing = False
57 |
58 | #force a sort if data is set on the second column
59 | #assumption: User is done adding / edditing an interval, so now it's safe to re-sort
60 | if index.column() == 1:
61 | model.sort(2)
62 |
63 | def isEditing(self):
64 |
65 | return self._is_editing
66 |
--------------------------------------------------------------------------------
/Corridor/template/SketchTemplate.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | #http://free-cad.sourceforge.net/SrcDocu/dc/d77/classSketcher_1_1SketchObjectPy.html
4 | #https://forum.freecadweb.org/viewtopic.php?t=6121
5 | #https://forum.freecadweb.org/viewtopic.php?t=12829
6 | import FreeCAD as App
7 | from Project.Support import Properties
8 |
9 | if App.Gui:
10 | import FreeCADGui as Gui
11 |
12 | def create(sketch_object, template_name):
13 | '''
14 | Constructor method foor creating a new sketch template
15 | '''
16 |
17 | obj = App.ActiveDocument.addObject("Sketcher::SketchObjectPython", template_name)
18 |
19 | _o = _Sketch(obj)
20 |
21 | _o.duplicate(sketch_object)
22 |
23 | App.activeDocument().recompute()
24 |
25 | return _o
26 |
27 |
28 | class _Sketch(object):
29 |
30 | def __init__(self, obj):
31 |
32 | obj.Proxy = self
33 | self.Type = self.__class__.__name__
34 | self.Object = None
35 |
36 | _ViewProvider(obj.ViewObject)
37 |
38 | Properties.add(obj, 'LinkList', 'Lofts', 'List of dependent lofts', is_read_only=True, default_value=[])
39 |
40 | self.Object = obj
41 |
42 | def __getstate__(self):
43 | '''
44 | State method for serialization
45 | '''
46 | return self.Type
47 |
48 | def __setstate__(self, state):
49 | '''
50 | State method for serialization
51 | '''
52 | if state:
53 | self.Type = state
54 |
55 | def duplicate(self, sketch):
56 | '''
57 | Duplicate the source sketch in the SketchObjectPython
58 | '''
59 |
60 | for geo in sketch.Geometry:
61 | index = self.Object.addGeometry(geo)
62 | self.Object.setConstruction(index, geo.Construction)
63 |
64 | for constraint in sketch.Constraints:
65 | self.Object.addConstraint(constraint)
66 |
67 | self.Object.Placement = sketch.Placement
68 |
69 | for expr in sketch.ExpressionEngine:
70 | self.Object.setExpression(expr[0], expr[1])
71 |
72 | self.Object.solve()
73 | self.Object.recompute()
74 |
75 | def onChanged(self, obj, prop):
76 |
77 | #avoid call during object initializtion
78 | if not hasattr(self, 'Object'):
79 | return
80 |
81 | self.myExecute(obj)
82 |
83 |
84 | def myExecute(self, obj):
85 |
86 | #if self.Object.Lofts:
87 | pass
88 | # try: fa=App.ActiveDocument.curve
89 | # except: fa=App.ActiveDocument.addObject('Part::Spline','curve')
90 | # fa.Shape=bc.toShape()
91 | # fa.ViewObject.LineColor=(.0,1.0,.0)
92 |
93 | class _ViewProvider():
94 |
95 | def execute(self, obj):
96 | obj.recompute()
97 | #self.myExecute(obj)
98 |
99 | def __init__(self, vobj):
100 | self.Object = vobj.Object
101 | vobj.Proxy = self
102 |
103 | def getIcon(self):
104 | return ''
105 |
106 | def __getstate__(self):
107 | return None
108 |
109 | def __setstate__(self, state):
110 | return None
--------------------------------------------------------------------------------
/Project/ProjectObserver.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import FreeCAD as App
25 | import FreeCADGui
26 |
27 | class ProjectObserver(object):
28 |
29 | docs = {}
30 |
31 | @staticmethod
32 | def get(doc):
33 | '''
34 | Factory method to create an observer attached to doc
35 | If already created, return it
36 | '''
37 |
38 | if not doc in ProjectObserver.docs:
39 | print('building new observer')
40 | ProjectObserver.docs[doc] = ProjectObserver(doc)
41 | App.addDocumentObserver(ProjectObserver.docs[doc])
42 |
43 | return ProjectObserver.docs[doc]
44 |
45 | def __init__(self, doc):
46 |
47 | self.doc = doc
48 | self.targets = {'StartSaveDocument': []}
49 |
50 | def register(self, event_name, callback):
51 | '''
52 | Registration for target objects to be updated for specific tasks
53 | '''
54 |
55 | self.targets[event_name].append(callback)
56 |
57 | def slotStartSaveDocument(self, doc, file):
58 | '''
59 | Administrative work to do before saving a document
60 | '''
61 |
62 | if not doc == self.doc:
63 | return
64 |
65 | for _cb in self.targets['StartSaveDocument']:
66 | _cb()
67 |
68 | def slotDeletedDocument(self, doc):
69 |
70 | if not doc == self.doc:
71 | return
72 |
73 | print('removing observer')
74 | App.removeDocumentObserver(self)
75 |
--------------------------------------------------------------------------------
/Project/Commands/ImportAlignmentCmd.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import os
25 | import FreeCAD as App
26 | import FreeCADGui as Gui
27 |
28 | from Project.Tasks.alignment.ImportAlignmentTask import ImportAlignmentTask
29 |
30 | class ImportAlignmentCmd():
31 | '''
32 | Initiates the ImportAlignmentTask class for 2D horizontal and vertical curves
33 | '''
34 | def __init__(self):
35 |
36 | self.alignment_data = None
37 |
38 | def GetResources(self):
39 | """
40 | Icon resources.
41 | """
42 |
43 | icon_path = os.path.dirname(os.path.abspath(__file__))
44 |
45 | icon_path += "../../../icons/new_alignment.svg"
46 |
47 | return {'Pixmap' : icon_path,
48 | 'Accel' : 'Ctrl+Shift+A',
49 | 'MenuText': 'Import Alignment',
50 | 'ToolTip' : 'Import a horizontal or vertical alignment from CSV',
51 | 'CmdType' : 'ForEdit'}
52 |
53 | def _update_callback(self, alignment_data):
54 | '''
55 | Update callback called when task activities are completed / accepted
56 | '''
57 |
58 | #run create alignment command from here
59 |
60 | print('return!')
61 |
62 | def Activated(self):
63 | '''
64 | Command activation method
65 | '''
66 |
67 | panel = ImportAlignmentTask(self._update_callback)
68 |
69 | Gui.Control.showDialog(panel)
70 |
71 | panel.setup()
72 |
73 | return
74 |
75 | Gui.addCommand('ImportAlignmentCmd', ImportAlignmentCmd())
76 |
--------------------------------------------------------------------------------
/Resources/data/alignment/il2_ss_vc.csv:
--------------------------------------------------------------------------------
1 | Union St,,,,
2 | 40007,,723.61,1.5,-1.5
3 | 40022,,723.38,-1.5,-1
4 | 40036,28,723.24,-1,1.99
5 | IL 72,,,,
6 | 126474,,722.9,-1.5,-1
7 | 126510,60,722.54,-1,-0.7
8 | 126570,60,722.11,-0.7,-1.05
9 | Chestnut St,,,,
10 | 41868,22,714.61,3.84,5.9
11 | 41936,44,717.55,5.9,1
12 | 41965,,717.84,1,2
13 | 42007,,718.68,2,-2
14 | 42020,,718.42,-2,-1
15 | 42060,50,718.02,-1,4.49
16 | 42100,30,720,4.49,1.18
17 | Market St,,,,
18 | 43930,60,712.02,7.66,1.1
19 | 43980,,712.57,1.1,2
20 | 44007,,713.11,2,-2
21 | 44020,,712.85,-2,-1
22 | 44065,40,712.4,-1,5.4
23 | 44138,4,716.34,5.4,1.15
24 | Peru St,,,,
25 | 45979.84,,699.63,1.34,-4.12
26 | E 3rd St,,,,
27 | 47005.98,,690.15,-2,1.34
28 | 46990.43,,689.94,1.34,0.93
29 | 46981.36,,689.86,0.93,0.5
30 | 46969.4,,689.8,0.5,0.416666667
31 | 46967,,689.79,0.416666667,1
32 | 46936,,689.48,1,-8.93
33 | Kysor Dr,,,,
34 | 48224,142,681.92,-0.21,-4
35 | 48037.87,,689.37,-4,-2.01
36 | Luther Dr,,,,
37 | 50979.88,,687.63,2.24,1
38 | 50926,46,687.09,1,-8.2
39 | Old State Rd,,,,
40 | 51980.86,,694.23,2.19,1.09
41 | 51910,80,693.46,1.09,-8
42 | 51730,170,707.86,-8,-4.11
43 | Ashelford Dr,,,,
44 | 53190,155,684.59,0.45,-3.6
45 | 53031,,690.32,-3.6,-2.06
46 | 53019,,690.57,-2.06,2.13
47 | River Dr S,,,,
48 | 54019,,689.74,-2.7,-1.57
49 | 54114,50,688.25,-1.57,-1.35
50 | Mobile Home Access Road,,,,
51 | 1013,,687.39,-2,-1
52 | 1050,60,687.02,-1,5
53 | 1135,110,691.27,5,0.5
54 | 1320,100,692.19,0.5,-0.5
55 | 1440,140,691.59,-0.5,-5
56 | 1545,70,686.34,-5,-0.3
57 | 1650,110,686.03,-0.3,3.44
58 | 1708.38,,688.04,3.44,-3.22
59 | River Dr N Connector,,,,
60 | 55019.02,,692.02,-2.87,-3.63
61 | 55120,90,688.36,-3.63,1.03
62 | Lake Louise Entrance,,,,
63 | 54924,60,692.46,6.47,1.15
64 | 54980.99,,693.11,1.15,-2.87
65 | River Dr N,,,,
66 | 51000,90,689.72,0.63,0.83
67 | Kennedy Hill Rd,,,,
68 | 60019.42,,692.76,3.41,3.39
69 | 60033.21,,693.23,3.39,-1
70 | 60146,135,692.1,-1,2.59
71 | Frontage Rd Connector,,,,
72 | 60052,,697.44,-1.5,-1
73 | 601,96,696.96,-1,1.6
74 | Meridian Rd,,,,
75 | 62007.08,,703.97,1.57,-1.4
76 | 62160,270,702.39,-1.4,4.5
77 | 62645,510,724.22,4.5,0.09
78 | Gold River Ave N,,,,
79 | 63007.06,,710.07,2.58,-2.05
80 | 63050,60,709.75,-2.05,-1.15
81 | Gold River Ave S,,,,
82 | 62800,160,695.94,1.2,8.78
83 | 62930,100,707.36,8.78,4
84 | 62980.82,,709.39,4,2.58
85 | Blue Lake Ave,,,,
86 | 64007.01,,709.26,2.59,2.49
87 | 64019.02,,709.56,2.49,-2
88 | 64031.04,,709.32,-2,-1
89 | 64095,65,708.68,-1,2.99
90 | Willow Run,,,,
91 | 64918,32,700.08,1.24,5.59
92 | 64950,32,701.87,5.59,1
93 | 64980.92,,702.18,1,-5.69
94 | Antler Trail,,,,
95 | 66008.52,,696.49,-2.82,-2.53
96 | 66023.13,,686.12,-2.53,-4
97 | 66086,98,693.61,-4,-1.48
98 | Silver Creek Rd S,,,,
99 | 66886,60,697.83,0.35,1.16
100 | 66968.64,,698.79,1.16,2.25
101 | 66980.78,,699.06,2.25,-5.3
102 | Silver Creek Rd N,,,,
103 | 67822,116,708.57,0.96,9
104 | 67915,70,716.94,9,3.56
105 | 67980.81,,719.28,3.56,-4.06
106 | Prairie Rd N,,,,
107 | 163931.4,,776.24,4.27,-1.11
108 | 164072,200,775.13,-1.11,0.71
109 | Prairie Rd S,,,,
110 | 29916,100,773.64,2.71,2.25
111 | 29980.97,,775.1,2.25,4.01
112 | CEL 201+44.09,,,,
113 | 40028,40028,710.05,4.37,-1
114 | 40173,240,708.6,-1,0.45
115 |
--------------------------------------------------------------------------------
/Resources/snippets/Observer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import FreeCAD as App
25 | import FreeCADGui as Gui
26 | import random
27 |
28 | from Project.Support import Singleton
29 |
30 | def create(doc, callback):
31 | '''
32 | Creation method for _Document class
33 | '''
34 | if _saveObserver.instance() is None:
35 | App.addDocumentObserver(_saveObserver(doc))
36 | else:
37 | _saveObserver.instance().set_document(doc)
38 |
39 | class _saveObserver(metaclass=Singleton.Singleton):
40 |
41 | def __init__(self, doc, callback):
42 |
43 | self.target_doc = doc
44 | self.callback = callback
45 |
46 | def set_document(self, doc):
47 | '''
48 | Set the passed document as the active document for the observer
49 | '''
50 |
51 | self.target_doc = doc
52 |
53 | @staticmethod
54 | def instance():
55 | '''
56 | Return the singleton instance of the class
57 | '''
58 |
59 | return Singleton.Singleton.instance_of(_saveObserver)
60 |
61 | def slotStartSaveDocument(self, doc, value):
62 |
63 | print('calling save document...', doc.Label, value)
64 |
65 | if _saveObserver.instance() is None:
66 | App.removeDocumentObserver(self)
67 | return
68 |
69 | #if the document is deleted, remove the observer
70 | try:
71 | self.target_doc.__doc__
72 | except:
73 | App.removeDocumentObserver(self)
74 | return
75 |
76 | if doc == self.target_doc:
77 | self.target_doc.before_save('slotStartSaveDocument')
78 |
--------------------------------------------------------------------------------
/Resources/data/alignment/SugarGroveRd_mixed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 2437.9704 -2356.3977 0.0
14 |
15 |
16 |
17 |
18 | 2455.0000 -676.4840 0.0
19 |
20 |
21 |
22 |
23 | 605.2372 -706.1075 0.0
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 493.6296 -707.5417 0.0
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 2470.7258 -662.4901 0.0
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/transportationwb/sketch_manager.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | /**************************************************************************
3 | * *
4 | * Copyright (c) 2018 Joel Graff *
5 | * *
6 | * This program is free software; you can redistribute it and/or modify *
7 | * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | * as published by the Free Software Foundation; either version 2 of *
9 | * the License, or (at your option) any later version. *
10 | * for detail see the LICENCE text file. *
11 | * *
12 | * This program is distributed in the hope that it will be useful, *
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | * GNU Library General Public License for more details. *
16 | * *
17 | * You should have received a copy of the GNU Library General Public *
18 | * License along with this program; if not, write to the Free Software *
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | * USA *
21 | * *
22 | **************************************************************************/
23 |
24 | """
25 | SketchManager module based on nurbswb/sketchmanager.py from microelly2
26 | """
27 |
28 | __title__ = "SketchManger.py"
29 | __author__ = "Joel Graff"
30 | __url__ = "https://www.freecadweb.org"
31 |
32 | import FreeCAD as App
33 | import FreeCADGui as Gui
34 |
35 | import Sketcher
36 |
37 | def copy_sketch(sketch, target_name):
38 | '''
39 | kopiert sketch in sketchobjectpython
40 | '''
41 | doc = App.ActiveDocument
42 |
43 | target = doc.addObject('Sketcher::SketchObjectPython', target_name)
44 |
45 | #_ViewProvider(target.ViewObject)
46 |
47 | for geo in sketch.Geometry:
48 | index=target.addGeometry(geo)
49 | target.setConstruction(index, geo.Construction)
50 |
51 | for constraint in sketch.Constraints:
52 | target.addConstraint(constraint)
53 |
54 | target.Placement = sketch.Placement
55 |
56 | target.solve()
57 | target.recompute()
58 | doc.recompute()
59 |
60 | return target
61 |
62 | def load_sketch(lib_path, source_name='Sketch', target_name=None):
63 | '''
64 | load sketch from file into sketcher object with name.
65 | Repalces existing sketch if it exists.
66 | '''
67 |
68 | doc = App.ActiveDocument
69 | library = App.open(lib_path)
70 |
71 | App.setActiveDocument(doc.Name)
72 |
73 | source = library.getObjectsByLabel(source_name)[0]
74 |
75 | if source is None:
76 | print("Cannot find library sketch " + source_name)
77 | return
78 |
79 | if target_name is None:
80 | target_name = source_name
81 |
82 | sketch = copy_sketch(source, target_name)
83 |
84 | sketch.Label = "Copy of " + source_name + "@" + lib_path
85 |
86 | App.closeDocument(library.Label)
87 |
88 | return sketch
89 |
--------------------------------------------------------------------------------
/Resources/data/alignment/SugarGroveRd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 605.2372 -706.1075 0.0
14 |
15 |
16 |
17 |
18 | 2455.0000 -676.4840 0.0
19 |
20 |
21 |
22 |
23 | 2437.9704 -2356.3977 0.0
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 493.6296 -707.5417 0.0
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 2470.7258 -662.4901 0.0
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Geometry/Line.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Line generation tools
26 | '''
27 |
28 | from Geometry import Support
29 |
30 | def get_parameters(line):
31 | '''
32 | Return a fully-defined line
33 | '''
34 |
35 | _coord_truth = [not line.get('Start') is None, not line.get('End') is None]
36 | _param_truth = [not line.get('BearingIn') is None, not line.get('Length') is None]
37 |
38 | #both coordinates defined
39 | _case_one = all(_coord_truth)
40 |
41 | #only one coordinate defined, plus both length and bearing
42 | _case_two = any(_coord_truth) and not all(_coord_truth) and all(_param_truth)
43 |
44 | if _case_one:
45 |
46 | line_vec = line['End'].sub(line['Start'])
47 | _bearing = Support.get_bearing(line_vec)
48 | _length = line_vec.Length
49 |
50 | #test for missing parameters, preserving the existing ones
51 | if line.get('BearingIn'):
52 | if Support.within_tolerance(line['BearingIn'], _bearing):
53 | _bearing = line['BearingIn']
54 |
55 | line['BearingIn'] = line['BearingOut'] = _bearing
56 |
57 | if line.get('Length'):
58 | if Support.within_tolerance(line['Length'], _length):
59 | _length = line['Length']
60 |
61 | line['Length'] = _length
62 |
63 | elif _case_two:
64 |
65 | _vec = Support.vector_from_angle(line['BearingIn']).multiply(line['Length'])
66 |
67 | if line.get('Start'):
68 | line['End'] = line['Start'].add(_vec)
69 | else:
70 | line['Start'] = line['End'].add(_vec)
71 |
72 | else:
73 | print('Unable to calculate line parametters')
74 |
75 | result = None
76 |
77 | if _case_one or _case_two:
78 | result = {**{'Type': 'line'}, **line}
79 |
80 | return result
81 |
--------------------------------------------------------------------------------
/transportationwb/vehicle/__init__.py:
--------------------------------------------------------------------------------
1 | '''simulation of traffic
2 | swept paths, traffic flow, traffic simulator etc.
3 | '''
4 |
5 | import transportationwb
6 | reload (transportationwb)
7 |
8 | print "Transportation WB ",transportationwb.date," Version ", transportationwb.version
9 |
10 | print "vehicle version 0.0"
11 |
12 |
13 |
14 | def createVehicle(model='generic'):
15 | '''creates a car'''
16 | print "Not yet implemented"
17 | # return 1
18 | raise Exception ("Not yet implemented")
19 |
20 |
21 |
22 | def createTrailer(truck=None,model='generic'):
23 | '''creates a Trailer for a selected truck'''
24 | raise Exception ("Not yet implemented")
25 |
26 |
27 |
28 |
29 |
30 | #-------------
31 |
32 |
33 | import transportationwb
34 | import transportationwb.miki_g
35 | reload(transportationwb.miki_g)
36 |
37 | from transportationwb.miki_g import createMikiGui, Controller
38 |
39 |
40 | class VehicleController(Controller):
41 |
42 |
43 | def run(self):
44 | '''example button clicked method'''
45 | print "Button clicked"
46 | print self.root
47 | print self.root.widget
48 |
49 |
50 | def itemClicked(self, item):
51 | '''example for item clicked'''
52 | print item
53 | print item.text()
54 |
55 |
56 |
57 |
58 | def createVehicle(model='generic'):
59 |
60 |
61 |
62 | layout = '''#MainWindow:
63 | VerticalLayoutTab:
64 |
65 | QtGui.QLabel:
66 | setStyleSheet: "QWidget { font: bold 32px;color:brown;}"
67 | setText:"*** Configure Vehicle Demo ***"
68 |
69 | QtGui.QLabel:
70 | setText: "Select Vehicle from Database"
71 | QtGui.QComboBox:
72 | addItem: "Truck"
73 | addItem: "S-Bus"
74 | addItem: "Bicycle"
75 | itemClicked.connect: app.itemClicked
76 |
77 | HorizontalGroup:
78 | setTitle: "Picture of the vehicle"
79 | QtGui.QLabel:
80 | setPixmap: QtGui.QPixmap(FreeCAD.ConfigGet('UserAppData') + '/Mod/freecad-transportation-wb/icons/vehicle_01.png')
81 | HorizontalGroup:
82 | setTitle: "Main parameters"
83 | QtGui.QLabel:
84 | setText: "B"
85 | QtGui.QLineEdit:
86 | setText:"1800"
87 | QtGui.QLabel:
88 | setText: "A"
89 | QtGui.QLineEdit:
90 | setText:"4000"
91 | QtGui.QLabel:
92 | setText: "O"
93 | QtGui.QLineEdit:
94 | setText:"1800"
95 |
96 | QtGui.QLabel:
97 | setText: "C"
98 | QtGui.QLineEdit:
99 | setText:"1800"
100 |
101 | QtGui.QLabel:
102 | setText: "Width"
103 | QtGui.QLineEdit:
104 | setText:"2500"
105 |
106 | HorizontalGroup:
107 | setTitle: "Additional parameters"
108 | VerticalLayout:
109 | HorizontalLayout:
110 | QtGui.QLabel:
111 | setText: "R"
112 | QtGui.QLineEdit:
113 | setText:"1800"
114 | HorizontalLayout:
115 | QtGui.QLabel:
116 | setText: "P"
117 | QtGui.QLineEdit:
118 | setText:"1800"
119 |
120 | VerticalLayout:
121 | HorizontalLayout:
122 | QtGui.QLabel:
123 | setText: "F"
124 | QtGui.QLineEdit:
125 | setText:"1800"
126 | HorizontalLayout:
127 | QtGui.QLabel:
128 | setText: "E"
129 | QtGui.QLineEdit:
130 | setText:"1800"
131 |
132 | VerticalLayout:
133 | HorizontalLayout:
134 | QtGui.QPushButton:
135 | setText: "Run Action"
136 | clicked.connect: app.run
137 | setIcon: QtGui.QIcon('icons:freecad.svg')
138 | setIconSize: QtCore.QSize(20,20)
139 | QtGui.QPushButton:
140 | setText: "Close"
141 | clicked.connect: app.close
142 | setIcon: QtGui.QIcon('icons:edit_Cancel.svg')
143 | setIconSize: QtCore.QSize(20,20)
144 |
145 | setSpacer:
146 | '''
147 |
148 |
149 | mikigui = createMikiGui(layout, VehicleController)
150 | return mikigui
151 |
152 |
153 |
154 | #--------------
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/Corridor/loft/EditIntervals.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import os
25 | import FreeCAD as App
26 | import FreeCADGui as Gui
27 | from Corridor.loft.tasks import IntervalTask
28 |
29 | class EditIntervals():
30 | '''
31 | EditIntervals starts the Edit Intervals task to adjust the section interval schedule for a loft.
32 | '''
33 | def __init__(self):
34 |
35 | self.loft = None
36 |
37 | def GetResources(self):
38 | """
39 | Icon resources.
40 | """
41 |
42 | icon_path = os.path.dirname(os.path.abspath(__file__))
43 |
44 | icon_path += "../../../icons/new_alignment.svg"
45 |
46 | return {'Pixmap' : icon_path,
47 | 'Accel' : '',
48 | 'MenuText': 'Edit Intervals...',
49 | 'ToolTip' : 'Add / remove section intervals along a loft.',
50 | 'CmdType' : 'ForEdit'}
51 |
52 | def update_callback(self, task):
53 | '''
54 | Callback for return from task
55 | '''
56 |
57 | print('updating with: ', task.get_model())
58 | setattr(self.loft.Proxy.Object, 'Interval_Schedule', task.get_model())
59 |
60 | App.ActiveDocument.recompute()
61 |
62 | def _validate_selection(self):
63 | '''
64 | Validate the current selection as a single loft object
65 | '''
66 |
67 | _obj = Gui.Selection.getSelection()[0]
68 |
69 | _is_valid = False
70 |
71 | try:
72 | _is_valid = _obj.Proxy.Type == '_ElementLoft'
73 |
74 | except:
75 | pass
76 |
77 | if _is_valid:
78 | return _obj
79 |
80 | return None
81 |
82 | def Activated(self):
83 |
84 | self.loft = self._validate_selection()
85 |
86 | if not self.loft:
87 | print('Invalid selection')
88 | return
89 |
90 | panel = IntervalTask.IntervalTask(self.update_callback)
91 |
92 | Gui.Control.showDialog(panel)
93 |
94 | panel.setup(self.loft.Proxy.Object.Interval_Schedule, ['Station', 'Interval', 'StationRaw'])
95 |
96 | Gui.addCommand('EditIntervals', EditIntervals())
97 |
--------------------------------------------------------------------------------
/Project/Support/Units.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Helper functions for scripted object properties
26 | '''
27 |
28 | __title__ = "Properties.py"
29 | __author__ = "Joel Graff"
30 | __url__ = "https://www.freecadweb.org"
31 |
32 | import FreeCAD as App
33 | from Project.Support.Const import Const
34 |
35 | def get_doc_units():
36 | '''
37 | Return the units (feet / meters) of active document
38 |
39 | format - format of string (0 = abbreviated, 1 = singular, 2 = plural)
40 | '''
41 | #need to add support for international spellings for metric units
42 |
43 | english = ['ft', 'foot', 'feet']
44 | metric = ['m', 'meter', 'meters']
45 |
46 | if App.ParamGet('User parameter:BaseApp/Preferences/Units').GetInt('UserSchema') == 7:
47 | return english
48 |
49 | return metric
50 |
51 | def is_metric_doc():
52 | '''
53 | Returns true if the passed document is using metric units
54 | '''
55 |
56 | return 'm' in get_doc_units()
57 |
58 | def scale_factor():
59 | '''
60 | Return the scale factor to convert the document units to mm
61 | '''
62 |
63 | if get_doc_units()[0] == 'ft':
64 | return 304.80
65 |
66 | return 1000.0
67 |
68 | class UnitNames(Const):
69 | '''
70 | Unit names, including international variations
71 | '''
72 | metric_units = [ 'mm', 'cm', 'dm', 'm', 'km',
73 | 'millimeter', 'millimeters', 'centimeter', 'centimeters',
74 | 'decimeter', 'decimeters', 'meter', 'meters', 'kilometer', 'kilometers',
75 | 'millimetre', 'millimetres', 'centimetre', 'centimetres',
76 | 'decimetre', 'decimetres', 'metre', 'metres', 'kilometre', 'kilometres'
77 | ]
78 |
79 | @staticmethod
80 | def IsMetric(unit_name):
81 | '''
82 | Given a string token representing a system of units,
83 | return whether or not it is a metric system
84 | '''
85 |
86 | return unit_name.lower() in UnitNames.metric_units
87 |
88 | class ToMetric(Const):
89 | '''
90 | The ToMetric class returns constants which define the metric equivalent of
91 | specific non-metric unit lengths
92 | '''
93 |
94 | Foot = 0.3048
95 | SurveyFoot = 12.0 / 39.37
96 | ClarkeFoot = 12 / 39.370432
97 |
--------------------------------------------------------------------------------
/Resources/snippets/FeedbackSketcherUtils.py:
--------------------------------------------------------------------------------
1 | #**************************************************************************
2 | # * *
3 | # * Copyright (c) 2017 Joel Graff *
4 | # * *
5 | # * This program is free software; you can redistribute it and/or modify *
6 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
7 | # * as published by the Free Software Foundation; either version 2 of *
8 | # * the License, or (at your option) any later version. *
9 | # * for detail see the LICENCE text file. *
10 | # * *
11 | # * This program is distributed in the hope that it will be useful, *
12 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 | # * GNU Library General Public License for more details. *
15 | # * *
16 | # * You should have received a copy of the GNU Library General Public *
17 | # * License along with this program; if not, write to the Free Software *
18 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
19 | # * USA *
20 | # * *
21 | # **************************************************************************
22 |
23 | # FeedbackSketcherUtils - A series of utilities to augment the feedback
24 | # sketcher class
25 |
26 |
27 | import feedbacksketch
28 | import FreeCAD
29 |
30 | def _addGroup (fbs,grpname):
31 |
32 | #construct the property group for the supplied property
33 |
34 | if hasattr (fbs,'active'+grpname):
35 | return
36 |
37 | fbs.addProperty ("App::PropertyBool",'active'+grpname, grpname, )
38 | fbs.addProperty ("App::PropertyLink",'base'+grpname, grpname, )
39 | fbs.addProperty ("App::PropertyStringList",'get'+grpname, grpname, )
40 | fbs.addProperty ("App::PropertyStringList",'set'+grpname, grpname, )
41 | fbs.addProperty ("App::PropertyStringList",'seton'+grpname, grpname, )
42 | fbs.addProperty ("App::PropertyStringList",'setoff'+grpname, grpname, )
43 |
44 |
45 | def _buildFbs (name):
46 |
47 | #construct feedback sketch
48 |
49 | fbs = FreeCAD.ActiveDocument.addObject ("Sketcher::SketchObjectPython",name)
50 |
51 | feedbacksketch.FeedbackSketch (fbs)
52 |
53 | return fbs
54 |
55 |
56 | def _addProperties (fbs, clients):
57 |
58 | #add base and client properties to feedback sketch
59 |
60 | fbs.addProperty ("App::PropertyBool",'active', 'Base', )
61 | fbs.addProperty ("App::PropertyStringList",'bases', 'Base', )
62 |
63 | fbs.bases = clients
64 |
65 | for b in fbs.bases:
66 | _addGroup (fbs,b)
67 | setattr(fbs, "active"+b, True)
68 |
69 | return fbs
70 |
71 | def _createClients (clientList):
72 |
73 | clients=[]
74 |
75 | for client in clientList:
76 | clients.append (FreeCAD.ActiveDocument.addObject (
77 | "Sketcher::SketchObjectPython", client))
78 |
79 | return clients
80 |
81 | def _assignClients (fbs, clients):
82 |
83 | for client in clients:
84 | setattr (fbs, "base"+client.Label, client)
85 |
86 | def buildFeedbackSketch (sketchName, clientList):
87 |
88 | #construct a feedback sketch using the supplied sketch name
89 | #with clients in the supplied client list
90 |
91 | fbs = _buildFbs (sketchName)
92 | fbs = _addProperties (fbs, clientList)
93 | clients = _createClients (clientList)
94 | _assignClients (fbs, clients)
95 |
96 | result = [fbs]
97 | result.extend (clients)
98 |
99 | return result
100 |
--------------------------------------------------------------------------------
/Project/Tasks/alignment/ImportAlignmentViewDelegate.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | QItemStyledDelegate class for Task QTableView
26 | '''
27 |
28 | from PySide import QtGui, QtCore
29 |
30 | class ImportAlignmentViewDelegate(QtGui.QStyledItemDelegate):
31 |
32 | def __init__(self, model, parent=None):
33 |
34 | QtGui.QStyledItemDelegate.__init__(self, parent)
35 | self._is_editing = False
36 | self.combo_box = None
37 | self.model = ['']
38 | self.model.extend(model)
39 |
40 | def paint(self, painter, option, index):
41 |
42 | painter.save()
43 |
44 | painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
45 | painter.setBrush(QtGui.QColor(215, 215, 215))
46 | painter.drawRect(option.rect)
47 |
48 | if index.isValid():
49 | painter.setPen(QtGui.QPen(QtGui.QColor(128, 128, 128)))
50 | value = index.data(QtCore.Qt.DisplayRole)
51 | painter.drawText(option.rect, QtCore.Qt.AlignCenter, value)
52 |
53 | painter.restore()
54 |
55 | def createEditor(self, parent, option, index):
56 |
57 | if index.row() > 0:
58 | return super(ImportAlignmentViewDelegate, self).createEditor(parent, option, index)
59 |
60 | self.combo_box = QtGui.QComboBox(parent)
61 |
62 | self.combo_box.addItems(self.model)
63 |
64 | value = index.data(QtCore.Qt.DisplayRole)
65 |
66 | self.combo_box.setCurrentIndex(self.combo_box.findText(value))
67 |
68 | return self.combo_box
69 |
70 | def setEditorData(self, editor, index):
71 |
72 | self._is_editing = True
73 |
74 | value = index.data(QtCore.Qt.EditRole) or index.data(QtCore.Qt.DisplayRole)
75 |
76 | editor_class = editor.metaObject().className()
77 |
78 | if editor_class == 'QComboBox':
79 | return
80 |
81 | if editor_class in ['QSpinBox', 'QDoubleSpinBox']:
82 | editor.setValue(value)
83 | elif editor_class == 'QComboBox':
84 | editor.setCurrentIndex()
85 | else:
86 | editor.setText(value)
87 |
88 | def setModelData(self, editor, model, index):
89 |
90 | QtGui.QStyledItemDelegate(self).setModelData(editor, model, index)
91 | #super(ImportAlignmentViewDelegate, self).setModelData(editor, model, index)
92 |
93 | self._is_editing = False
94 |
95 | def isEditing(self):
96 |
97 | return self._is_editing
98 |
--------------------------------------------------------------------------------
/Resources/data/alignment/HC_IL2_Rev4.csv:
--------------------------------------------------------------------------------
1 | 87.648,rad/dist,dir,deg,m,sec,deg_dec,BEARING,curve_tan,curve length,tangent,NORTHING,EASTING,RADIUS,DISTANCE,ID,PARENT_ID,BACK,FORWARD
2 | ,Alignment datum,,,,,,,,,,0,0,,,IL 2,,,113050
3 | ,Station equation,,,,,,,,,,,,,,,,148292.43,0
4 | 114383.75,1008.7,L,48,48,34,48.80944444,87.64805556,457.6668591,859.2969155,,,,1008.7,1791.416859,,,,
5 | 115243.04,2000,L,8,55,27,8.924166667,38.83861111,156.0717435,311.5121827,0,,,2000,613.7386026,,,,
6 | 116456.78,3800,L,40,40,25,40.67361111,29.91444444,1408.438397,2697.576044,902.2217005,,,3800,2466.731841,,,,
7 | 119410.29,2300,R,10,6,26,10.10722222,349.2408333,203.3926648,405.7299037,255.9336002,,,2300,1867.764662,,,,
8 | 120017.7,4000,R,6,49,16,6.821111111,359.3480556,238.3833142,476.2033901,201.6766,,,4000,643.452579,,,35242.43,
9 | 120493.91,2000,R,18,15,47,18.26305556,6.169166667,321.4769591,637.500902,1.00E-07,,,2000,559.8602734,,,20742.76,
10 | 121385.05,1585.53,L,29,20,28,29.34111111,24.43222222,415.0852392,811.9483196,253.6517,,,1585.53,990.2138983,,,55985.19,
11 | 122536.31,3600,R,17,53,2,17.88388889,355.0911111,566.4453399,1123.677879,339.3078999,,,3600,1320.838479,,,55985.184,
12 | 124488.52,6000,R,13,53,58,13.89944444,12.97499999,731.3634865,1455.546418,828.5185996,,,6000,2126.327426,,,0.006,
13 | 125944.07,3500,R,9,20,52,9.347777778,26.87444444,286.1466219,571.0232499,-4.00E-07,,,3500,1017.510108,,,1.07E-07,
14 | 129512.97,4000,R,4,58,58,4.982777778,36.22222222,174.0414606,347.8635125,2996.8808,,,4000,3458.064833,,,1.07E-05,
15 | 129952.83,10000,L,2,51,52,2.864444444,41.205,250.0220115,499.9398679,92,,,10000,516.0634721,,,,
16 | 131070.39,2000,R,19,52,59,19.88305556,38.34055556,350.5498146,694.0495698,617.5968999,,,2000,1218.168726,,,,
17 | 132520.88,3814.39,R,14,5,57,14.09916667,58.22361111,471.6992677,938.633191,756.4393997,,,3814.39,1578.688482,,,,
18 | 133459.51,2257.87,R,34,33,42,34.56166667,72.32277778,702.4197007,1361.980777,-4.00E-07,,,2257.87,1174.118968,,,,
19 | 135030.2,2815,L,37,50,9,37.83583333,106.8844444,964.7734753,1858.913025,208.71,,,2815,1875.903176,,,,
20 | 138885.55,1520,L,36,50,29,36.84138889,69.04861111,506.2465299,977.3653764,1996.44,,,1520,3467.460005,,,,
21 | 140062.91,2100,R,11,28,22,11.47277778,32.20722222,210.9549614,420.4992679,200,,,2100,917.2014913,,,,
22 | 142178.09,2500,R,39,59,0,39.98333333,43.68,909.5138281,1744.602031,1694.6828,,,2500,2815.151589,,,,
23 | 144158.68,3375,L,19,31,20,19.52222222,83.66333333,580.6049112,1149.953811,235.9999997,,,3375,1726.118739,,,,
24 | 146689.32,2293.84,R,16,32,54,16.54833333,64.14111111,333.5788858,662.5135263,1380.6838,,,2293.84,2294.867597,,,,
25 | 2335.46,6000,R,7,25,36,7.426666667,80.68944444,389.4047185,777.7187147,3276.0615,,,6000,3999.045104,,,,
26 | 3539.45,1800,L,10,11,1,10.18361111,88.11611111,160.386237,319.9275785,226.2769,,,1800,776.0678555,,,,
27 | 3973.19,1800,L,15,26,54,15.44833333,77.9325,244.1426895,485.323705,313.8131,,,1800,718.3420265,,,,
28 | 4458.51,20000,R,1,27,7,1.451944444,62.48416667,253.4256732,506.8242221,0,,,20000,497.5683627,,,,
29 | 5783.34,2883.78,L,13,30,49,13.51361111,63.93611111,341.6651922,680.1597217,817.9799996,,,2883.78,1413.070865,,,,
30 | 6868.92,3375,R,34,24,43,34.41194444,50.4225,1045.122534,2027.030847,405.4091008,,,3375,1792.196827,,,,
31 | 10325.67,3687.8,L,17,55,7,17.91861111,84.83444444,581.4054671,1153.318004,1429.7284,,,3687.8,3056.256401,,,,
32 | 12214.42,3400,L,33,13,38,33.22722222,66.91583333,1014.463565,1971.743059,733.4434999,,,3400,2329.312532,,,,
33 | 14795.06,4656.43,R,4,34,58,4.582777778,33.68861111,186.3205982,372.4425099,610.8899998,,,4656.43,1811.674163,,,,
34 | 15453.37,2855.9299,L,11,40,12,11.67,38.27138889,291.8574785,581.6955841,285.8635999,,,2855.9299,764.0416766,,,,
35 | 16349.07,4000,R,18,43,14,18.72055556,26.60138889,659.3468965,1306.941329,314,,,4000,1265.204375,,,,
36 | 17656.01,7200,R,8,33,31,8.558611111,45.32194444,538.7555474,1075.506792,1.00E-07,,,7200,1198.102444,,,,
37 | 18991.96,4149.52,L,11,30,23,11.50638889,53.88055555,418.0683907,833.3247446,260.4610999,,,4149.52,1217.285038,,,,
38 | 20119.36,950,R,24,16,10,24.26944444,42.37416667,204.2646071,402.4026275,294.0792001,,,950,916.4121979,,,,
39 | 20521.76,221,NE,66,38,37,66.64361111,66.64361111,,,221,,,0,425.2646071,,,,
40 |
--------------------------------------------------------------------------------
/Project/Support/Properties.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Helper functions for scripted object properties
26 | '''
27 |
28 | __title__ = "Properties.py"
29 | __author__ = "Joel Graff"
30 | __url__ = "https://www.freecadweb.org"
31 |
32 | import FreeCAD as App
33 |
34 | def add(obj, p_type, name, desc, default_value=None, is_read_only=False, is_hidden=False):
35 |
36 | '''
37 | Build FPO properties
38 |
39 | p_type The property type, either formal ('App::PropertyFloat') or shortended ('Float')
40 | name The Property name as "GROUP.NAME" If group is omitted, the default is 'Base'
41 | desc Tooltip description string
42 | default_value Default property value
43 | isReadOnly Boolean property (read-only = True)
44 | '''
45 |
46 | tple = name.split('.')
47 |
48 | p_name = tple[0]
49 | p_group = 'Base'
50 |
51 | if len(tple) == 2:
52 | p_name = tple[1]
53 | p_group = tple[0]
54 |
55 | if p_type in [
56 | 'Length',
57 | 'Distance',
58 | 'Percent',
59 | 'Angle',
60 | 'Link',
61 | 'LinkList',
62 | 'Float',
63 | 'FloatList',
64 | 'Bool',
65 | 'String',
66 | 'StringList',
67 | 'Vector',
68 | 'VectorList',
69 | 'Integer',
70 | 'Enumeration',
71 | 'FileIncluded'
72 | ]:
73 | p_type = 'App::Property' + p_type
74 |
75 | else:
76 | print('Invalid property type specified: ', p_type)
77 | return None
78 |
79 | p_name = p_name.replace(' ', '_')
80 |
81 | obj.addProperty(p_type, p_name, p_group, desc)
82 |
83 | App.ActiveDocument.recompute()
84 |
85 | prop = obj.getPropertyByName(p_name)
86 |
87 |
88 | if p_type in [
89 | 'App::PropertyBool',
90 | 'App::PropertyPercent',
91 | 'App::PropertyLinkList',
92 | 'App::PropertyLink',
93 | 'App::PropertyString',
94 | 'App::PropertyStringList',
95 | 'App::PropertyFloatList',
96 | 'App::PropertyVector',
97 | 'App::PropertyVectorList',
98 | 'App::PropertyInteger',
99 | 'App::PropertyEnumeration',
100 | 'App::PropertyFloat',
101 | 'App::PropertyFileIncluded'
102 |
103 | ]:
104 | setattr(obj, p_name, default_value)
105 |
106 | else:
107 | prop.Value = default_value
108 |
109 | editor_mode = 0
110 |
111 | if is_read_only:
112 | editor_mode += 1
113 |
114 | if is_hidden:
115 | editor_mode += 2
116 |
117 | obj.setEditorMode(p_name, editor_mode)
118 |
119 | return prop
120 |
--------------------------------------------------------------------------------
/Corridor/template/ViewTemplateLibrary.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import Draft
25 | import Part
26 | import os
27 | import time
28 | import FreeCAD as App
29 | import FreeCADGui as Gui
30 | from Corridor.template import TemplateLibrary, SketchTemplate
31 |
32 | class ViewTemplateLibrary():
33 | '''
34 | View library class.
35 | Open the template library for selecting templates
36 | '''
37 | def __init__(self):
38 | pass
39 |
40 | def GetResources(self):
41 | """
42 | Icon resources.
43 | """
44 |
45 | icon_path = os.path.dirname(os.path.abspath(__file__))
46 |
47 | icon_path += "../../../icons/new_alignment.svg"
48 |
49 | return {'Pixmap' : icon_path,
50 | 'Accel' : "Ctrl+Alt+G",
51 | 'MenuText': "Open Template Library",
52 | 'ToolTip' : "Open the template library",
53 | 'CmdType' : "ForEdit"}
54 |
55 | def _validate_tree(self):
56 | '''
57 | Validate the tree of the active document, ensuring there is a templates folder
58 | '''
59 |
60 | result = App.ActiveDocument.findObjects('App::DocumentObjectGroup', 'Templates')
61 |
62 | if not result:
63 | result = [App.ActiveDocument.addObject('App::DocumentObjectGroup', 'Templates')]
64 |
65 | return result[0]
66 |
67 | def _library_call_back(self, path):
68 | '''
69 | Library Callback
70 | Merge the selected template into the project and add it to the templates group
71 | '''
72 |
73 | #create a snapshot of the tree root where new objects will be merged
74 | snapshot = []
75 |
76 | for obj in App.ActiveDocument.RootObjects:
77 | snapshot += obj.Name
78 |
79 | #merge new objects
80 | App.ActiveDocument.mergeProject(path)
81 |
82 | #validate the template folder structure
83 | folder = self._validate_tree()
84 |
85 | #iterate the root objects, looking for objects not in the snapshot
86 | #relocate the skether objects
87 | new_objects = []
88 |
89 | for obj in App.ActiveDocument.RootObjects:
90 |
91 | if not obj.Name in snapshot:
92 | if obj.TypeId != 'Sketcher::SketchObject':
93 | continue
94 |
95 | new_objects.append(obj.Name)
96 | _o = SketchTemplate.create(obj, obj.Label)
97 | folder.addObject(_o.Object)
98 |
99 | #remove the root objects...
100 | for obj_name in new_objects:
101 | App.ActiveDocument.removeObject(obj_name)
102 |
103 | def Activated(self):
104 |
105 | TemplateLibrary.show(self._library_call_back)
106 |
107 |
108 | Gui.addCommand('ViewTemplateLibrary', ViewTemplateLibrary())
--------------------------------------------------------------------------------
/Resources/snippets/fpo_template.py:
--------------------------------------------------------------------------------
1 |
2 | # -*- coding: utf-8 -*-
3 | # **************************************************************************
4 | # * *
5 | # * Copyright (c) 20XX AUTHOR_NAME *
6 | # * *
7 | # * This program is free software; you can redistribute it and/or modify *
8 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
9 | # * as published by the Free Software Foundation; either version 2 of *
10 | # * the License, or (at your option) any later version. *
11 | # * for detail see the LICENCE text file. *
12 | # * *
13 | # * This program is distributed in the hope that it will be useful, *
14 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 | # * GNU Library General Public License for more details. *
17 | # * *
18 | # * You should have received a copy of the GNU Library General Public *
19 | # * License along with this program; if not, write to the Free Software *
20 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21 | # * USA *
22 | # * *
23 | # **************************************************************************
24 |
25 | '''
26 | DESCRIPTION
27 | '''
28 | import FreeCAD as App
29 | import Part
30 | from transportationwb import ScriptedObjectSupport as Sos
31 |
32 | _CLASS_NAME = 'CLASSNAME'
33 | _TYPE = 'Part::FeaturePython'
34 |
35 | __title__ = _CLASS_NAME + '.py'
36 | __author__ = "AUTHOR_NAME"
37 | __url__ = "https://www.freecadweb.org"
38 |
39 | def createTEMPLATE_CLASS(object_name='', parent=None):
40 | '''
41 | Class construction method
42 | object_name - Optional. Name of new object. Defaults to class name.
43 | parent - Optional. Reference to existing DocumentObjectGroup. Defaults to ActiveDocument
44 | '''
45 |
46 | _obj = None
47 | _name = _CLASS_NAME
48 |
49 | if object_name:
50 | _name = object_name
51 |
52 | if parent:
53 | _obj = parent.newObject(_TYPE, _name)
54 | else:
55 | _obj = App.ActiveDocument.addObject(_TYPE, _name)
56 |
57 | result = _CLASS_TEMPLATE(_obj)
58 | _ViewProviderCLASS_TEMPLATE(_obj.ViewObject)
59 |
60 | return result
61 |
62 | class _TEMPLATE_CLASS():
63 |
64 | def __init__(self, obj):
65 | '''
66 | Main class intialization
67 | '''
68 |
69 | self.Enabled = False
70 | self.Type = "_" + CLASS_NAME
71 | self.Object = obj
72 |
73 | obj.Proxy = self
74 |
75 | #add class properties
76 | #Sos._add_property(self, 'PROPERTY_TYPE', 'PROPERTY_NAME', 'PROPERTY_DESC', DEFUALT_VALUE, isReadOnly=False, isHidden=False)
77 |
78 | self.Enabled = True
79 |
80 | def __getstate__(self):
81 | '''
82 | State method for serialization
83 | '''
84 | return self.Type
85 |
86 | def __setstate__(self, state):
87 | '''
88 | State method for serialization
89 | '''
90 | if state:
91 | self.Type = state
92 |
93 | def execute(self, obj):
94 | '''
95 | Class execute for recompute calls
96 | '''
97 | pass
98 |
99 | class _ViewProviderTEMPLATE_CLASS(object):
100 |
101 | def __init__(self, vobj):
102 | '''
103 | View Provider initialization
104 | '''
105 | self.Object = vobj.Object
106 |
107 | def getIcon(self):
108 | '''
109 | Object icon
110 | '''
111 | return ''
112 |
113 | def attach(self, vobj):
114 | '''
115 | View Provider Scene subgraph
116 | '''
117 | pass
118 |
119 | def __getstate__(self):
120 | '''
121 | State method for serialization
122 | '''
123 | return None
124 |
125 | def __setstate__(self,state):
126 |
127 | '''
128 | State method for serialization
129 | '''
130 | return None
131 |
--------------------------------------------------------------------------------
/Resources/snippets/python_templates/fpo_template.py:
--------------------------------------------------------------------------------
1 |
2 | # -*- coding: utf-8 -*-
3 | # **************************************************************************
4 | # * *
5 | # * Copyright (c) 20XX AUTHOR_NAME *
6 | # * *
7 | # * This program is free software; you can redistribute it and/or modify *
8 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
9 | # * as published by the Free Software Foundation; either version 2 of *
10 | # * the License, or (at your option) any later version. *
11 | # * for detail see the LICENCE text file. *
12 | # * *
13 | # * This program is distributed in the hope that it will be useful, *
14 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 | # * GNU Library General Public License for more details. *
17 | # * *
18 | # * You should have received a copy of the GNU Library General Public *
19 | # * License along with this program; if not, write to the Free Software *
20 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21 | # * USA *
22 | # * *
23 | # **************************************************************************
24 |
25 | '''
26 | DESCRIPTION
27 | '''
28 | import FreeCAD as App
29 | import Part
30 | from transportationwb import ScriptedObjectSupport as Sos
31 |
32 | _CLASS_NAME = 'CLASSNAME'
33 | _TYPE = 'Part::FeaturePython'
34 |
35 | __title__ = _CLASS_NAME + '.py'
36 | __author__ = "AUTHOR_NAME"
37 | __url__ = "https://www.freecadweb.org"
38 |
39 | def createTEMPLATE_CLASS(object_name='', parent=None):
40 | '''
41 | Class construction method
42 | object_name - Optional. Name of new object. Defaults to class name.
43 | parent - Optional. Reference to existing DocumentObjectGroup. Defaults to ActiveDocument
44 | '''
45 |
46 | _obj = None
47 | _name = _CLASS_NAME
48 |
49 | if object_name:
50 | _name = object_name
51 |
52 | if parent:
53 | _obj = parent.newObject(_TYPE, _name)
54 | else:
55 | _obj = App.ActiveDocument.addObject(_TYPE, _name)
56 |
57 | result = _CLASS_TEMPLATE(_obj)
58 | _ViewProviderCLASS_TEMPLATE(_obj.ViewObject)
59 |
60 | return result
61 |
62 | class _TEMPLATE_CLASS():
63 |
64 | def __init__(self, obj):
65 | '''
66 | Main class intialization
67 | '''
68 |
69 | self.Enabled = False
70 | self.Type = "_" + CLASS_NAME
71 | self.Object = obj
72 |
73 | obj.Proxy = self
74 |
75 | #add class properties
76 | #Sos._add_property(self, 'PROPERTY_TYPE', 'PROPERTY_NAME', 'PROPERTY_DESC', DEFUALT_VALUE, isReadOnly=False, isHidden=False)
77 |
78 | self.Enabled = True
79 |
80 | def __getstate__(self):
81 | '''
82 | State method for serialization
83 | '''
84 | return self.Type
85 |
86 | def __setstate__(self, state):
87 | '''
88 | State method for serialization
89 | '''
90 | if state:
91 | self.Type = state
92 |
93 | def execute(self, obj):
94 | '''
95 | Class execute for recompute calls
96 | '''
97 | pass
98 |
99 | class _ViewProviderTEMPLATE_CLASS(object):
100 |
101 | def __init__(self, vobj):
102 | '''
103 | View Provider initialization
104 | '''
105 | self.Object = vobj.Object
106 |
107 | def getIcon(self):
108 | '''
109 | Object icon
110 | '''
111 | return ''
112 |
113 | def attach(self, vobj):
114 | '''
115 | View Provider Scene subgraph
116 | '''
117 | pass
118 |
119 | def __getstate__(self):
120 | '''
121 | State method for serialization
122 | '''
123 | return None
124 |
125 | def __setstate__(self,state):
126 |
127 | '''
128 | State method for serialization
129 | '''
130 | return None
131 |
--------------------------------------------------------------------------------
/Project/Support/DocumentProperties.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Module to manage document properties for the transportation workbench
26 | '''
27 |
28 | __title__ = "DocumentProperties.py"
29 | __author__ = "Joel Graff"
30 | __url__ = "https://www.freecadweb.org"
31 |
32 | import FreeCAD as App
33 |
34 | class DocumentProperty:
35 |
36 | Param = lambda _x: App.ParamGet('User parameter:BaseApp/Preferences/' + _x)
37 |
38 | @staticmethod
39 | def _set_string(path, key, value):
40 | DocumentProperty.Param(path).SetString(key, value)
41 |
42 | @staticmethod
43 | def _get_string(path, key, default=''):
44 | return DocumentProperty.Param(path).GetString(key, default)
45 |
46 | @staticmethod
47 | def _set_int(path, key, value):
48 | DocumentProperty.Param(path).SetInt(key, value)
49 |
50 | @staticmethod
51 | def _get_int(path, key, value=0):
52 | return DocumentProperty.Param(path).GetInt(key, value)
53 |
54 | @staticmethod
55 | def _set_float(path, key, value):
56 | DocumentProperty.Param(path).SetFloat(key, value)
57 |
58 | @staticmethod
59 | def _get_float(path, key, value=0.0):
60 | return DocumentProperty.Param(path).GetFloat(key, value)
61 |
62 | @staticmethod
63 | def _set_bool_string(value):
64 | result = '0'
65 |
66 | if value:
67 | result = '1'
68 |
69 | return result
70 |
71 | class DocumentPreferences():
72 |
73 | class SaveThumbnail():
74 |
75 | @staticmethod
76 | def set_value(value = True):
77 | DocumentProperty._set_string('Document', 'SaveThumbnail', DocumentProperty._set_bool_string(value))
78 |
79 | @staticmethod
80 | def get_value():
81 | return DocumentProperty._get_string('Document', 'SaveThmbnail')
82 |
83 | class AddThumbnailLogo():
84 |
85 | @staticmethod
86 | def set_value(value = False):
87 | DocumentProperty._set_string('Document', 'AddThumbnailLogo', DocumentProperty._set_bool_string(value))
88 |
89 | @staticmethod
90 | def get_value():
91 | return DocumentProperty._get_string('Document', 'AddThumbnailLogo')
92 |
93 |
94 | class TemplateLibrary():
95 |
96 | class Path():
97 |
98 | @staticmethod
99 | def get_value():
100 | return DocumentProperty._get_string('Mod/Transportation', 'TemplateLibPath')
101 |
102 | @staticmethod
103 | def set_value(value):
104 | DocumentProperty._set_string('Mod/Transportation', 'TemplateLibPath', value)
105 |
106 | class Policy():
107 |
108 | class MinimumTangentLength():
109 |
110 | @staticmethod
111 | def get_value():
112 | return DocumentProperty._get_float('Mod/Transportation', 'MinimumTangentLength', 500.0)
113 |
114 | @staticmethod
115 | def set_value(value):
116 | DocumentProperty._set_float('Mod/Trasnportation', 'MinimumTangentLength', value)
117 |
--------------------------------------------------------------------------------
/Project/Support/WidgetModel.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | QAbstractTableModel class for Task QTableView
26 | '''
27 |
28 | import re
29 | import operator
30 |
31 | from PySide import QtCore
32 |
33 | def create(data, headers=None, parent=None):
34 | '''
35 | Creation method for widget models.
36 |
37 | Model is a dictionary or nested list providing the data set in a tabular format
38 | '''
39 |
40 | model = WidgetModel(parent)
41 |
42 | model.data_model = data
43 | model.headers = headers
44 |
45 | return model
46 |
47 | class WidgetModel(QtCore.QAbstractTableModel):
48 |
49 | def __init__(self, parent=None):
50 |
51 | QtCore.QAbstractTableModel.__init__(self)
52 |
53 | self.data_model = None
54 | self.headers = None
55 |
56 | self.default_flags = QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
57 | self.data_roles = [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]
58 |
59 | def rowCount(self, parent=QtCore.QModelIndex()):
60 | '''
61 | Number of rows currently in the model
62 | '''
63 |
64 | if self.data_model:
65 | return len(self.data_model)
66 |
67 | return 0
68 |
69 | def columnCount(self, parent=QtCore.QModelIndex()):
70 | '''
71 | Number of columns currently in the model
72 | '''
73 | if self.data_model:
74 | if isinstance(self.data_model[0], list):
75 | return len(self.data_model[0])
76 |
77 | return 1
78 |
79 | return 0
80 |
81 | def data(self, index, role):
82 | '''
83 | Return data for valid indices and display role
84 | '''
85 |
86 | if not index.isValid():
87 | return None
88 |
89 | if not role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]:
90 | return None
91 |
92 | if not 0 <= index.row() < len(self.data_model):
93 | return None
94 |
95 | if self.columnCount(index) == 1:
96 | return self.data_model[index.row()]
97 |
98 | return self.data_model[index.row()][index.column()]
99 |
100 | def setData(self, index, value, role):
101 | '''
102 | Update existing model data
103 | '''
104 |
105 | if role != QtCore.Qt.EditRole:
106 | return False
107 |
108 | self.data_model[index.row()][index.column()] = value
109 | self.dataChanged.emit(index, index)
110 |
111 | return True
112 |
113 | def headerData(self, col, orientation, role):
114 | '''
115 | Headers to be displated
116 | '''
117 |
118 | if not self.headers:
119 | return None
120 |
121 | if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
122 | return self.headers[col]
123 |
124 | return None
125 |
126 | def flags(self, index):
127 |
128 | if index.row() > 0:
129 | return self.default_flags & ~QtCore.Qt.ItemIsEditable
130 |
131 | return self.default_flags
132 |
133 |
--------------------------------------------------------------------------------
/Project/Commands/NewProjectCmd.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2019 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import os
25 |
26 | import FreeCAD as App
27 | import FreeCADGui as Gui
28 |
29 | from PySide import QtGui, QtCore
30 |
31 | from Project.Support import DocumentProperties
32 |
33 | import Resources
34 | import Corridor
35 |
36 | class NewProject():
37 |
38 | icon_path = os.path.dirname(Resources.__file__)
39 |
40 | resources = {
41 | 'Pixmap' : icon_path + '/icons/workbench.svg',
42 | 'Accel' : "Shift+N",
43 | 'MenuText': "New Project",
44 | 'ToolTip' : "Create a new project document and make it active",
45 | 'CmdType' : "ForEdit"
46 | }
47 |
48 | def GetResources(self):
49 | return self.resources
50 |
51 | def Activated(self):
52 |
53 | if Gui.ActiveDocument == None:
54 | self._create_document()
55 |
56 | self._set_preferences()
57 | return
58 |
59 | def IsActive(self):
60 | return True
61 |
62 | def _attach_handlers(self):
63 | Gui.ActiveDocument.ActiveView.addDraggable
64 |
65 | def _set_preferences(self):
66 | App.ParamGet("User parameter:BaseApp/Preferences/Units").SetInt("UserSchema", 7)
67 | App.ParamGet('User parameter:BaseApp/Preferences/Mod/Sketcher').SetBool('AutoRecompute', False)
68 | App.ParamGet('User parameter:BaseApp/Preferences/Document').SetBool('DuplicateLabels', True)
69 |
70 | template_path = os.path.dirname(Corridor.__file__)
71 |
72 | DocumentProperties.TemplateLibrary.Path.set_value(template_path + '/Templates')
73 |
74 | def _create_document(self):
75 |
76 | '''
77 | Create a new project with default groups
78 | '''
79 |
80 | #new project dialog
81 | dlg = QtGui.QInputDialog()
82 | dlg.setWindowTitle("New Proejct")
83 | dlg.setLabelText('Enter project name:')
84 | dlg.setWindowModality(QtCore.Qt.ApplicationModal)
85 | dlg.setTextValue('New Project')
86 | dlg.exec_()
87 |
88 | if dlg.result() == False:
89 | return
90 |
91 | #assign project name, null names not accepted.
92 | project_name = dlg.textValue()
93 |
94 | if project_name =='':
95 | return
96 |
97 | App.newDocument(project_name)
98 |
99 | #substitute underscores for spaces for internal naming
100 | project_name = project_name.replace(' ', '_')
101 |
102 | #set up intial references
103 | App.setActiveDocument(project_name)
104 |
105 | App.ActiveDocument = App.getDocument(project_name)
106 | Gui.ActiveDocument = Gui.getDocument(project_name)
107 |
108 | #create default groups
109 | App.ActiveDocument.addObject('App::DocumentObjectGroup', 'Templates')
110 | App.ActiveDocument.addObject('App::DocumentObjectGroup', 'Alignments')
111 | App.ActiveDocument.addObject('App::DocumentObjectGroup', 'Element Lofts')
112 |
113 | #create observers to handle tasks when document-level events occur
114 | #Observer.create(App.ActiveDocument)
115 |
116 | Gui.addCommand('NewProject', NewProject())
117 |
--------------------------------------------------------------------------------
/Resources/data/alignment/complete_demo.csv:
--------------------------------------------------------------------------------
1 | BEARING,NORTHING,EASTING,RADIUS,DISTANCE,ID,PARENT_ID,BACK,FORWARD
2 | ,0,0,,,Mainline,,,113050
3 | ,,,,,,,148292.43,0
4 | ,,,0,0,,,,
5 | 87.64805556,,,1008.7,1791.416859,,,,
6 | 38.83861111,,,2000,613.7386026,,,,
7 | 29.91444444,,,3800,2466.731841,,,,
8 | 349.2408333,,,2300,1867.764662,,,,
9 | 359.3480556,,,4000,643.452579,,,,
10 | 6.169166667,,,2000,559.8602734,,,,
11 | 24.43222222,,,1585.53,990.2138983,,,,
12 | 355.0911111,,,3600,1320.838479,,,,
13 | 12.97499999,,,6000,2126.327426,,,,
14 | 26.87444444,,,3500,1017.510108,,,,
15 | 36.22222222,,,4000,3457.068882,,,,
16 | 41.205,,,10000,516.0634721,,,,
17 | 38.34055556,,,2000,1218.168726,,,,
18 | 58.22361111,,,3814.39,1578.688482,,,,
19 | 72.32277778,,,2257.87,1174.118968,,,,
20 | 106.8844444,,,2815,1875.903176,,,,
21 | 69.04861111,,,1520,3467.460005,,,,
22 | 36.84138889,,,2100,917.2014913,,,,
23 | 43.68,,,2500,2815.151589,,,,
24 | 83.66333333,,,3375,1726.118739,,,,
25 | 64.14111111,,,2293.84,2294.867597,,,,
26 | 80.68944444,,,6000,3999.045104,,,,
27 | 88.11611111,,,1800,776.0678555,,,,
28 | 77.9325,,,1800,718.3420265,,,,
29 | 62.48416667,,,20000,497.5683627,,,,
30 | 63.93611111,,,2883.78,1413.070865,,,,
31 | 50.4225,,,3375,1792.196827,,,,
32 | 84.83444444,,,3687.8,3056.256401,,,,
33 | 66.91583333,,,3400,2329.312532,,,,
34 | 33.68861111,,,4656.43,1811.674163,,,,
35 | 38.27138889,,,2855.9299,764.0416766,,,,
36 | 26.60138889,,,4000,1265.204375,,,,
37 | 45.32194444,,,7200,1198.102444,,,,
38 | 53.88055555,,,4149.52,1217.285038,,,,
39 | 42.37416667,,,950,916.4121979,,,,
40 | 66.64361111,,,0,425.2646071,,,,
41 | ,,,0,,Union St,IL 2,113214.23,40000
42 | ,,,,,,,,40000
43 | 357.5391667,,,0,430,,,,
44 | ,,,0,,Ogle St,IL 2,113214.23,126433.69
45 | ,,,,,,,,126433.69
46 | 177.5391667,,,0,724.3802,,,,
47 | ,,,0,,Chestnut St,IL 2,113653.6592,42000
48 | ,,,,,,,,41785.66
49 | 357.3955556,,,0,627.6679,,,,
50 | ,,,0,,Market St,IL 2,114094.9939,44000
51 | ,,,,,,,,43803.25
52 | 357.2841667,,,0,599.2619,,,,
53 | ,,,0,,Peru St,IL 2,114530.1275,46000
54 | ,,,,,,,,45792.11
55 | 356.7163889,,,0,207.8916,,,,
56 | ,,,0,,E 3rd St,IL 2,115950.62,47014.35
57 | ,,,,,,,,46549.82
58 | 86.65333333,,,0,464.5329,,,,
59 | ,,,0,,Kysor Dr,IL 2,115974.23,48014.2
60 | ,,,,,,,,48014.2
61 | 87.57722222,,,0,455.3657,,,,
62 | 88.18638889,,,0,545.2175,,,,
63 | ,,,0,,Luther Dr,IL 2,116708.83,51000
64 | ,,,,,,,,50432.84
65 | 122.2963889,,,0,567.1632,,,,
66 | ,,,0,,Old State Rd,IL 2,118014.32,52000
67 | ,,,,,,,,51472.43
68 | 89.62861111,,,0,527.5677,,,,
69 | ,,,0,,Ashelford Dr,IL 2,118841.45,53000
70 | ,,,,,,,,53000
71 | 84.21916667,,,150,113.9944609,,,,
72 | 144.3802778,,,0,804.9156609,,,,
73 | ,,,0,,River Dr S,IL 2,119786.59,54000
74 | ,,,,,,,,54000
75 | 89.07583333,,,0,402.1318,,,,
76 | ,,,0,,Mobile Home Access Road,River Dr S,54148,1000
77 | ,,,,,,,,1000
78 | 359.0758333,,,30,69,,,,
79 | 269.0758333,,,30,104.8928749,,,,
80 | 359.3480556,,,30,236.9399825,,,,
81 | 86.30416667,,,25,104.6366996,,,,
82 | 179.0758333,,,200,212.9609166,,,,
83 | 186.6686111,,,0,42.98132463,,,,
84 | ,,,0,,River Dr N Connector,IL 2,120946.6,55000
85 | ,,,,,,,,55000
86 | 111.5105556,,,0,171.92,,,,
87 | ,,,0,,River Dr N,River Dr N Connector,55171.92,4998.07
88 | ,,,,,,,,4687.89
89 | 357.8197222,,,948.97,310.1730796,,,,
90 | 347.065,,,0,242.4586796,,,,
91 | ,,,0,,Lake Entrance,IL 2,120946.6,55000
92 | ,,,,,,,,55000
93 | 291.5105556,,,0,132.9,,,,
94 | ,,,0,,Kennedy Rd,IL 2,126049.05,60003.34
95 | ,,,,,,,,60003.34
96 | 328.1911111,,,800,337.917195,,,,
97 | 4.701944444,,,0,1157.208195,,,,
98 | ,,,0,,Frontage Rd Connector,IL 2,137115.5597,60040
99 | ,,,,,,,,60040
100 | 159.0483333,,,0,144.48,,,,
101 | ,,,0,,Merdi Rd,IL 2,148292.43,62000
102 | ,,,,,,,,62000
103 | 358.0888889,,,0,1312.4904,,,,
104 | ,,,0,,Gold River Ave N,IL 2,2541.35,63000
105 | ,,,,,,,,62700
106 | 0.418333333,,,0,208.4648,,,,
107 | ,,,0,,Gold River Ave S,IL 2,2541.35,63000
108 | ,,,,,,,,62700
109 | 0.418333333,,,0,300,,,,
110 | ,,,0,,Lake Ave,IL 2,2969.26,64000
111 | ,,,,,,,,64000
112 | 359.6530556,,,0,300,,,,
113 | ,,,0,,Willow Trail,IL 2,3436.72,65000
114 | ,,,,,,,,64800
115 | 357.8552778,,,0,200,,,,
116 | ,,,0,,Antler Trail,IL 2,3700,66000
117 | ,,,,,,,,66000
118 | 22.68638889,,,0,200,,,,
119 | ,,,0,,Silver Creek Rd S,IL 2,4091.07,67000
120 | ,,,,,,,,66585.01
121 | 352.9947222,,,0,441.9881,,,,
122 | ,,,0,,Silver Creek Rd N,IL 2,6141.58,68000
123 | ,,,,,,,,67762.37
124 | 331.5819444,,,1500,142.0858944,,,,
125 | 334.8425,,,0,95.57279442,,,,
126 | ,,,0,,Prairie Rd S,IL 2,8117.55,30000
127 | ,,,,,,,,29700
128 | 341.4019444,,,4000,165.8368233,,,,
129 | 338.5352778,,,0,134.1964233,,,,
130 | ,,,0,,Prairie Rd N,IL 2,8117.55,163911.98
131 | ,,,,,,,,163911.98
132 | 353.62,,,1600,115.6538,,,,
133 | 359.085,,,0,450.347,,,,
134 | ,,,0,,Entrance,IL 2,20144.09,40000
135 | ,,,,,,,,40000
136 | 314.5891667,,,50,189.7434364,,,,
137 | 83.35722222,,,85,192.8701112,,,,
138 | 53.5825,,,35,77.27015004,,,,
139 | 344.7636111,,,0,87.80347524,,,,
140 |
--------------------------------------------------------------------------------
/Project/Tasks/alignment/ImportXmlSubtask.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Subtask to populate the XML dialog when an XML file is chosen for import
26 | '''
27 |
28 | from PySide import QtGui, QtCore
29 |
30 | import FreeCAD as App
31 | import FreeCADGui as Gui
32 |
33 | from Project.XML.AlignmentImporter import AlignmentImporter
34 | from Project.Support import WidgetModel, Units, Utils
35 | import math
36 |
37 | def create(panel, filepath):
38 |
39 | return ImportXmlSubtask(panel, filepath)
40 |
41 | class ImportXmlSubtask:
42 |
43 | def __init__(self, panel, filepath):
44 |
45 | self.panel = panel
46 |
47 | self.parser = AlignmentImporter()
48 | self.data = self.parser.import_file(filepath)
49 |
50 | if self.parser.errors:
51 | for _err in self.parser.errors:
52 | print(_err)
53 |
54 | self._setup_panel()
55 |
56 | self.errors = []
57 |
58 | def _setup_panel(self):
59 |
60 | self.panel.projectName.setText(self.data['Project']['ID'])
61 | alignment_model = list(self.data['Alignments'].keys())
62 | widget_model = WidgetModel.create(alignment_model)
63 | self.panel.alignmentsComboBox.setModel(widget_model)
64 | self.panel.alignmentsComboBox.currentTextChanged.connect(self._update_alignment)
65 |
66 | self._update_alignment(self.panel.alignmentsComboBox.currentText())
67 |
68 | def _update_alignment(self, value):
69 |
70 | subset = self.data['Alignments'][value]
71 |
72 | if subset['meta'].get('StartStation'):
73 | self.panel.startStationValueLabel.setText('{0:.2f}'.format(subset['meta']['StartStation']))
74 |
75 | if subset['meta'].get('Length'):
76 | self.panel.lengthTitleLabel.setText('Length ({0:s}):'.format(Units.get_doc_units()[0]))
77 | self.panel.lengthValueLabel.setText('{0:.2f}'.format(subset['meta']['Length']))
78 |
79 | sta_model = []
80 |
81 | if subset['station']:
82 | for st_eq in subset['station']:
83 | sta_model.append([st_eq['Back'], st_eq['Ahead']])
84 |
85 | widget_model = WidgetModel.create(sta_model, ['Back'], ['Ahead'])
86 |
87 | self.panel.staEqTableView.setModel(widget_model)
88 |
89 | curve_model = []
90 |
91 | for curve in subset['geometry']:
92 |
93 | _vals = [curve[_k] if curve.get(_k) else 0.0 for _k in [
94 | 'Direction', 'StartStation', 'BearingIn', 'BearingOut', 'Radius']
95 | ]
96 |
97 | row = '{0:s}, {1:f}, {2:.2f}, {3:.2f}, {4:.2f}, {5:.2f}'.format(
98 | curve['Type'], _vals[0], _vals[1], _vals[2], _vals[3], _vals[4]
99 | )
100 | #curve['Type'], curve['Direction'], curve['StartStation'],
101 | #curve['BearingIn'], curve['BearingOut'], curve['Radius']
102 | #)
103 | curve_model.append(row.split(','))
104 |
105 | widget_model_2 = WidgetModel.create(curve_model, ['Type', 'Dir', 'Start',
106 | 'In', 'Out', 'Radius'])
107 |
108 | self.panel.curveTableView.setModel(widget_model_2)
109 | self.panel.curveTableView.resizeColumnsToContents()
110 |
111 | def import_model(self):
112 | '''
113 | Return the model data
114 | '''
115 | return self.data
116 |
--------------------------------------------------------------------------------
/Project/Tasks/alignment/ImportAlignmentModel.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | QAbstractTableModel class for Task QTableView
26 | '''
27 |
28 | import re
29 | import operator
30 |
31 | from PySide import QtCore
32 |
33 | class ImportAlignmentModel(QtCore.QAbstractTableModel):
34 |
35 | default_flags = QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
36 |
37 | def __init__(self, nam, headers, data, parent=None):
38 |
39 | QtCore.QAbstractTableModel.__init__(self, parent)
40 |
41 | self.data_model = data
42 | self.headers = headers
43 | self.model_name = nam
44 |
45 | def rowCount(self, parent=QtCore.QModelIndex()):
46 | '''
47 | Number of rows currently in the model
48 | '''
49 |
50 | if self.data_model:
51 | return len(self.data_model)
52 |
53 | #default
54 | return 0
55 |
56 | def columnCount(self, parent=QtCore.QModelIndex()):
57 | '''
58 | Number of columns currently in the model
59 | '''
60 |
61 | if self.data_model:
62 | if isinstance(self.data_model[0], list):
63 | return len(self.data_model[0])
64 |
65 | return 1
66 |
67 | #default
68 | return 0
69 |
70 | def data(self, index, role):
71 | '''
72 | Return data for valid indices and display role
73 | '''
74 |
75 | if not index.isValid():
76 | return None
77 |
78 | if not role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]:
79 | return None
80 |
81 | if not 0 <= index.row() < len(self.data_model):
82 | return None
83 |
84 | if self.columnCount(index) == 1:
85 | return self.data_model[index.row()]
86 |
87 | return self.data_model[index.row()][index.column()]
88 |
89 | def setData(self, index, value, role):
90 | '''
91 | Update existing model data
92 | '''
93 |
94 | self.data_model[index.row()][index.column()] = value
95 | self.dataChanged.emit(index, index)
96 |
97 | return True
98 |
99 | if role != QtCore.Qt.EditRole:
100 | return False
101 |
102 | if index.isValid() and 0 <= index.row() < len(self.data_model):
103 |
104 | #test for valid data types on a per-column basis
105 | if index.column() == 0:
106 | value = self.validate_station(value)
107 |
108 | else:
109 |
110 | try:
111 | value = float(value)
112 |
113 | except:
114 | return False
115 |
116 | #set the value
117 | self.data_model[index.row()][index.column()] = value
118 |
119 | self.dataChanged.emit(index, index)
120 |
121 | return True
122 |
123 | return False
124 |
125 | def headerData(self, col, orientation, role):
126 | '''
127 | Headers to be displated
128 | '''
129 |
130 | if not self.headers:
131 | return None
132 |
133 | if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
134 | return self.headers[col]
135 |
136 | return None
137 |
138 | def flags(self, index):
139 |
140 | flags = ImportAlignmentModel.default_flags
141 |
142 | if index.row() > 0:
143 | flags = flags & ~QtCore.Qt.ItemIsEditable
144 |
145 | return flags
146 |
--------------------------------------------------------------------------------
/transportationwb/clipplane.py:
--------------------------------------------------------------------------------
1 | '''an example for use of miki for both Qt and IV'''
2 |
3 | #\cond
4 | import FreeCAD
5 | import FreeCADGui
6 | Gui = FreeCADGui
7 | App=FreeCAD
8 | #\endcond
9 |
10 | import time
11 | from pivy import coin
12 |
13 | import transportationwb
14 | from transportationwb.miki_g import createMikiGui2, MikiApp
15 | reload(transportationwb.miki_g)
16 |
17 | # reset the scene by a fresh document
18 | App.closeDocument("Unnamed")
19 | App.newDocument("Unnamed")
20 | App.setActiveDocument("Unnamed")
21 | App.ActiveDocument=App.getDocument("Unnamed")
22 | Gui.ActiveDocument=Gui.getDocument("Unnamed")
23 |
24 | # create the scene
25 |
26 |
27 | layout='''#: from pivy.coin import *
28 | SoSeparator:
29 | id: 'IVRoot'
30 | SoSeparator:
31 | SoMaterial:
32 | emissiveColor: 0.2, 0., 0.0
33 | SoBaseColor:
34 | rgb: 1, 0 ,0
35 | SoRotationXYZ:
36 | axis: 2
37 | angle:1.5708
38 | SoTranslation:
39 |
40 | id:'pos'
41 | translation: 0,-40,20
42 | SoCylinder:
43 | radius: 30
44 | height:200
45 |
46 | SoSeparator:
47 | SoMaterial:
48 | emissiveColor:0, 0, .1
49 | transparency: 0.1
50 | SoBaseColor:
51 | rgb: 0,0,1
52 | SoClipPlane:
53 | plane: coin.SbPlane(coin.SbVec3f(0.,1.,0.),0.)
54 | id:'cp_blue_a'
55 | SoClipPlane:
56 | plane: coin.SbPlane(coin.SbVec3f(-1.,0.,0.),-80.)
57 | id:'cp_blue_b'
58 | SoCube:
59 | height: 150
60 | width:200
61 | depth:150
62 |
63 | SoSeparator:
64 | SoTranslation:
65 | translation: 100,10,-50
66 | SoClipPlane:
67 | id:'cp_green'
68 | plane: coin.SbPlane(coin.SbVec3f(-1.,0.,0.),0.)
69 | SoMaterial:
70 | emissiveColor: 0, .1, 0
71 | transparency: 0.2
72 | SoBaseColor:
73 | rgb: 0, 1, 0
74 | SoCube:
75 | height: 100
76 | width:150
77 | depth:100
78 |
79 | MainWindow:
80 | id: 'QtRoot'
81 | #resize: QtCore.QSize(400,200)
82 | QtGui.QLabel:
83 | setText:"*** Clip Plane Demo Animation ***"
84 |
85 | VerticalGroup:
86 | setTitle: "actions"
87 | QtGui.QPushButton:
88 | id: "run"
89 | setText: "list all ids"
90 | clicked.connect: app.run
91 | QtGui.QPushButton:
92 | setText: "run green clipplane animation"
93 | clicked.connect: app.run_green
94 | QtGui.QPushButton:
95 | setText: "run blue clipplane animation A"
96 | clicked.connect: app.run_blue_a
97 | QtGui.QPushButton:
98 | setText: "run blue clipplane animation B"
99 | clicked.connect: app.run_blue_b
100 |
101 | QtGui.QPushButton:
102 | setText: "activate all clip planes"
103 | clicked.connect: app.activate_all
104 |
105 | QtGui.QPushButton:
106 | setText: "deactivate all clip planes"
107 | clicked.connect: app.deactivate_all
108 |
109 | QtGui.QPushButton:
110 | setText: "reset all clip planes"
111 | clicked.connect: app.reset_planes
112 |
113 | QtGui.QPushButton:
114 | setText: "close"
115 | clicked.connect: app.close
116 |
117 | '''
118 |
119 | class ComboApp(MikiApp):
120 | '''the controller for the use case some widgets start animation of SoClipPlanes'''
121 |
122 | def close(self):
123 | '''close the Gui dialog and delete the scenegraph'''
124 | Gui.ActiveDocument.ActiveView.getSceneGraph().removeChild(self.root.ids['IVRoot'])
125 | self.root.ids['QtRoot'].hide()
126 |
127 | def run(self):
128 | '''list all ids'''
129 | for mid in self.root.ids:
130 | print mid
131 |
132 | def run_green(self):
133 | '''run animation green'''
134 | ids=self.root.ids
135 | for i in range(-40,14):
136 | ids['cp_green'].plane.setValue(coin.SbPlane(coin.SbVec3f(-1.,0.,0.),i*5))
137 | Gui.updateGui()
138 | time.sleep(0.01)
139 |
140 | def run_blue_b(self):
141 | '''run animation'''
142 | ids=self.root.ids
143 | for i in range(-70,10):
144 | ids['cp_blue_b'].plane.setValue(coin.SbPlane(coin.SbVec3f(-1.,0.,0.),i*2))
145 | Gui.updateGui()
146 | time.sleep(0.01)
147 |
148 | def run_blue_a(self):
149 | '''run animation'''
150 | ids=self.root.ids
151 | for i in range(-40,20):
152 | ids['cp_blue_a'].plane.setValue(coin.SbPlane(coin.SbVec3f(0.,1.,0.),i*2))
153 | Gui.updateGui()
154 | time.sleep(0.01)
155 |
156 | def activate_all(self):
157 | '''activate all clip planes'''
158 |
159 | ids=self.root.ids
160 | ids['cp_blue_a'].on.setValue(1)
161 | ids['cp_blue_b'].on.setValue(1)
162 | ids['cp_green'].on.setValue(1)
163 |
164 | def reset_planes(self):
165 | '''put the clip planes to an initial position'''
166 | ids=self.root.ids
167 | ids['cp_green'].plane.setValue(coin.SbPlane(coin.SbVec3f(-1.,0.,0.),-200))
168 | ids['cp_blue_b'].plane.setValue(coin.SbPlane(coin.SbVec3f(-1.,0.,0.),-140))
169 | ids['cp_blue_a'].plane.setValue(coin.SbPlane(coin.SbVec3f(0.,1.,0.),-80))
170 |
171 | def deactivate_all(self):
172 | '''deactivate the clip planes - show the whole bodies'''
173 | ids=self.root.ids
174 | ids['cp_blue_a'].on.setValue(0)
175 | ids['cp_blue_b'].on.setValue(0)
176 | ids['cp_green'].on.setValue(0)
177 |
178 |
179 | def demoClipPlaneAnimation():
180 | '''starts the demo file and Gui'''
181 | app = createMikiGui2(layout, ComboApp)
182 | Gui.activeDocument().activeView().viewAxonometric()
183 | Gui.updateGui()
184 | Gui.SendMsgToActiveView("ViewFit")
185 |
186 |
--------------------------------------------------------------------------------
/Corridor/alignment/ImportVerticalCurve.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | import FreeCAD as App
25 | import FreeCADGui as Gui
26 | import os
27 | import json
28 | from PySide import QtGui
29 | from PySide import QtCore
30 | from Corridor.Alignment import VerticalCurve, Metadata
31 |
32 | class ImportVerticalCurve():
33 |
34 | def __init__(self):
35 | pass
36 |
37 | def GetResources(self):
38 | """
39 | Icon resources.
40 | """
41 |
42 | icon_path = os.path.dirname(os.path.abspath(__file__))
43 |
44 | icon_path += "../../../icons/new_alignment.svg"
45 |
46 | return {'Pixmap' : icon_path,
47 | 'Accel' : "Shift+V",
48 | 'MenuText': "Import Vertical Alignment",
49 | 'ToolTip' : "Import a Vertical Alignment from JSON",
50 | 'CmdType' : "ForEdit"}
51 |
52 | def getFile(self):
53 | '''
54 | Displays the file browser dialog to pick the JSON file
55 | '''
56 | dlg = QtGui.QFileDialog()
57 | options = dlg.Options()
58 | options |= dlg.DontUseNativeDialog
59 | dlg.setDefaultSuffix('.json')
60 | file_name, _ = dlg.getOpenFileName(dlg,"QFileDialog.getOpenFileName()", "","All Files (*);;JSON Files (*.json)", options=options)
61 |
62 | return file_name
63 |
64 | def build_alignment(self, group, data):
65 | '''
66 | Build the curve objects describing the alignemtn
67 | '''
68 |
69 | for vc_data in data['geometry']:
70 |
71 | vc_obj = VerticalCurve.createVerticalCurve(vc_data, data['meta']['units'])
72 | group.addObject(vc_obj.Object)
73 |
74 | def validate_heirarchy(self, _id, _units):
75 | '''
76 | Validates the alignment heirarchy, adding missing groups
77 | '''
78 |
79 | grand_parent = App.ActiveDocument.getObject('Alignments')
80 |
81 | if grand_parent is None:
82 | grand_parent = App.ActiveDocument.addObject('App::DocumentObjectGroup', 'Alignments')
83 |
84 | #replace non-printable characters with underscore
85 | for _x in [' ', '.', '+', '(', ')']:
86 | _id = _id.replace(_x, '_')
87 |
88 | parent = grand_parent.getObject(_id)
89 |
90 | if parent is None:
91 | parent = grand_parent.newObject('App::DocumentObjectGroup', _id)
92 |
93 | group = App.ActiveDocument.getObject('Vertical_' + _id)
94 |
95 | if group is None:
96 | group = parent.newObject("App::DocumentObjectGroup", 'Vertical_' + _id)
97 |
98 | return group
99 |
100 | def Activated(self):
101 | '''
102 | Executes the tangent construction.
103 | '''
104 |
105 | file_name = self.getFile()
106 |
107 | if file_name == '':
108 | return
109 |
110 | data = None
111 |
112 | with open(file_name, 'r') as json_data:
113 | data = json.load(json_data)
114 |
115 | for alignment in data:
116 |
117 | _id = alignment['meta']['id']
118 | _units = alignment['meta']['units']
119 |
120 | if _units.lower() in ['english', 'british']:
121 | _units = _units[0].upper() + _units[1:].lower()
122 | else:
123 | print("Invalid units specified in json")
124 | return
125 |
126 | group = self.validate_heirarchy(_id, _units)
127 |
128 | if group is None:
129 | return
130 |
131 | self.build_alignment(group, alignment)
132 |
133 | Gui.addCommand('ImportVerticalCurve', ImportVerticalCurve())
--------------------------------------------------------------------------------
/Project/XML/KeyMaps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 20XX AUTHOR_NAME *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Key maps for LandXML elements and the internal dictionary keys
26 | '''
27 | from Project.Support.Const import Const
28 |
29 | class KeyMaps(Const):
30 |
31 | XML_DEFAULT = {
32 |
33 | }
34 | #lists of tags for different units of measurements / geometry types
35 | XML_TAGS = {
36 | 'length':
37 | ['radius', 'radiusStart', 'radiusEnd', 'chord', 'external', 'midOrd', 'tangent',
38 | 'length'],
39 |
40 | 'angle':
41 | ['delta', 'dir', 'dirStart', 'dirEnd'],
42 |
43 | 'coordinate':
44 | ['Start', 'End', 'Center', 'PI']
45 |
46 | }
47 |
48 | #lists of tags for different Python data types. These are the datatypes that
49 | #they represent in XML, not in the dictionary
50 | #(e.g. 'rot' = 'ccw' / 'cw' in XML, but -1.0 / 1.0 in dictionary)
51 | XML_TYPES = {
52 | 'float':
53 | ['chord', 'constant', 'delta', 'dir', 'dirEnd', 'dirStart', 'external',
54 | 'length', 'midOrd', 'radius', 'radiusEnd', 'radiusStart', 'staBack',
55 | 'staIncrement', 'staInternal', 'staStart', 'tangent'],
56 |
57 | 'string':
58 | ['crvType', 'desc', 'name', 'note', 'manufacturer', 'manufacturerURL', 'oID',
59 | 'rot','spiType', 'state', 'timeStamp', 'version']
60 | }
61 |
62 | #map of LandXML tags to internal Python dictionary
63 | XML_MAP = {'chord': 'Chord','crvType': 'CurveType','delta': 'Delta','desc': 'Description',
64 | 'dir': 'BearingIn', 'dirEnd': 'BearingOut','dirStart': 'BearingIn',
65 | 'external': 'External', 'length': 'Length', 'midOrd': 'MiddleOrdinate',
66 | 'name': 'ID', 'note': 'Note', 'oID': 'ObjectID', 'radius': 'Radius',
67 | 'radiusStart': 'StartRadius', 'radiusEnd': 'EndRadius','rot': 'Direction',
68 | 'spiType': 'SpiralType', 'staAhead': 'Ahead', 'staBack': 'Back',
69 | 'staIncrement': 'Direction', 'staInternal': 'Position',
70 | 'staStart': 'StartStation', 'staEnd': 'EndStation', 'state': 'Status',
71 | 'tangent': 'Tangent', 'version': 'Version'}
72 |
73 | #attributes for each LandXML Tag. Attribute names are divided into two lists.
74 | #The first list is required attributes, the second is optional
75 | XML_ATTRIBS = {
76 | 'Alignment': [
77 | ['name', 'length', 'staStart'],
78 | ['desc', 'oID', 'state']
79 | ],
80 | 'Alignments': [
81 | [],
82 | ['desc', 'name', 'state']
83 | ],
84 | 'Application': [
85 | ['name'],
86 | ['desc', 'manufacturer', 'version', 'manufacturerURL', 'timeStamp']
87 | ],
88 | 'CoordGeom': [
89 | [],
90 | ['desc', 'name', 'state', 'oID']
91 | ],
92 | 'Curve': [
93 | ['rot'],
94 | ['chord', 'crvType', 'delta', 'desc', 'dirEnd', 'dirStart', 'external', 'length',
95 | 'midOrd', 'name', 'radius', 'staStart', 'state', 'tangent', 'oID', 'note']
96 | ],
97 | 'Line': [
98 | [],
99 | ['desc', 'dir', 'length', 'name', 'staStart', 'state', 'oID', 'note']
100 | ],
101 | 'Project': [
102 | ['name'],
103 | ['desc', 'state']
104 | ],
105 | 'Spiral': [
106 | ['length', 'radiusEnd', 'radiusStart', 'rot', 'spiType'],
107 | ['chord', 'constant', 'desc', 'dirEnd', 'dirStart', 'external', 'length', 'midOrd',
108 | 'name', 'note', 'oID', 'radius', 'staStart', 'state', 'tangent']
109 | ],
110 | 'StaEquation': [
111 | ['staAhead', 'staInternal'],
112 | ['desc', 'staBack', 'staIncrement']
113 | ]
114 | }
115 |
--------------------------------------------------------------------------------
/Corridor/alignment/AlignmentGroup.Py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Alignment DocumentObjectGroupPython class for highway alignments
26 | '''
27 |
28 | __title__ = "AlignmentGroup.py"
29 | __author__ = "Joel Graff"
30 | __url__ = "https://www.freecadweb.org"
31 |
32 | import FreeCAD as App
33 |
34 | from Project.Support import Properties, Units
35 | from Project.ProjectObserver import ProjectObserver
36 | from Project.XML.AlignmentExporter import AlignmentExporter
37 |
38 | def get(grp_id=''):
39 | '''
40 | Find the existing alignments object
41 | '''
42 |
43 | return App.ActiveDocument.getObject('Alignments')
44 |
45 | def create():
46 | '''
47 | Factory method for alignment group
48 | '''
49 |
50 | #return an existing instance of the same name, if found
51 | obj = App.ActiveDocument.getObject('Alignments')
52 |
53 | if obj:
54 | return obj.Proxy
55 |
56 | obj = App.ActiveDocument.addObject("App::DocumentObjectGroupPython", 'Alignments')
57 |
58 | fpo = _AlignmentGroup(obj)
59 | _ViewProviderAlignmentGroup(obj.ViewObject)
60 |
61 | return fpo
62 |
63 | class _AlignmentGroup():
64 |
65 | def __init__(self, obj):
66 |
67 | obj.Proxy = self
68 | self.Type = "AlignmentGroup"
69 | self.Object = obj
70 |
71 | Properties.add(obj, 'String', 'ID', 'Alignment group name', '',
72 | is_read_only=True)
73 |
74 | Properties.add(obj, 'String', 'Description', 'Alignment group description', '',
75 | is_read_only=True)
76 |
77 | Properties.add(obj, 'FileIncluded', 'Xml_Path', '', '', is_hidden=True)
78 |
79 | ProjectObserver.get(App.ActiveDocument).register('StartSaveDocument', self.write_xml)
80 |
81 |
82 | def onDocumentRestored(self, fp):
83 | '''
84 | Restore object references on reload
85 | '''
86 |
87 | ProjectObserver.get(App.ActiveDocument).register('StartSaveDocument', self.write_xml)
88 |
89 | def write_xml(self):
90 | '''
91 | Serialize the object data and it's children to xml files
92 | '''
93 |
94 | _list = []
95 |
96 | #iterate the list of children, acquiring their data sets
97 | #and creating a total data set for alignments.
98 | for _obj in self.Object.OutList:
99 | _list.append(_obj.Proxy.get_geometry())
100 |
101 | exporter = AlignmentExporter()
102 |
103 | template_path = App.getUserAppDataDir() + 'Mod/freecad-transportation-wb/Resources/data/'
104 | template_file = 'landXML-' + Units.get_doc_units()[1] + '.xml'
105 |
106 | xml_path = App.ActiveDocument.TransientDir + '/alignment.xml'
107 |
108 | print('writing xml...')
109 | exporter.write(_list, template_path + template_file, xml_path)
110 |
111 | self.Object.Xml_Path = xml_path
112 |
113 | def __getstate__(self):
114 | return self.Type
115 |
116 | def __setstate__(self, state):
117 | if state:
118 | self.Type = state
119 |
120 | def _get_child(self, object_type):
121 |
122 | for obj in self.Object.Group:
123 | if obj.TypeId == object_type:
124 | return obj
125 |
126 | return None
127 |
128 | def execute(self, obj):
129 | pass
130 |
131 | class _ViewProviderAlignmentGroup(object):
132 |
133 | def getIcon(self):
134 | return ''
135 |
136 | def __init__(self,vobj):
137 | self.Object = vobj.Object
138 | vobj.Proxy = self
139 |
140 | def attach(self,vobj):
141 |
142 | self.Object = vobj.Object
143 | return
144 |
145 | def claimChildren(self):
146 | return self.Object.Group
147 |
148 | def __getstate__(self):
149 | return None
150 |
151 | def __setstate__(self,state):
152 | return None
153 |
154 | def setEdit(self,vobj,mode=0):
155 | return True
156 |
157 | def unsetEdit(self,vobj,mode=0):
158 | return False
159 |
160 | def doubleClicked(self,vobj):
161 | pass
162 |
163 | def setupContextMenu(self, obj, menu):
164 | pass
165 |
166 | def edit(self):
167 | pass
--------------------------------------------------------------------------------
/transportationwb/property_creator.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 160
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 |
18 |
19 | 50
20 | 120
21 | 341
22 | 32
23 |
24 |
25 |
26 | Qt::Horizontal
27 |
28 |
29 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
30 |
31 |
32 |
33 |
34 |
35 | 20
36 | 0
37 | 371
38 | 111
39 |
40 |
41 |
42 |
43 | QLayout::SetMaximumSize
44 |
45 | -
46 |
47 |
48 | -
49 |
50 |
51 |
52 | 0
53 | 0
54 |
55 |
56 |
57 |
58 | 16777215
59 | 16777215
60 |
61 |
62 |
63 |
64 | -
65 |
66 |
67 |
68 | 0
69 | 0
70 |
71 |
72 |
73 | Name
74 |
75 |
76 | Qt::PlainText
77 |
78 |
79 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
80 |
81 |
82 |
83 | -
84 |
85 |
86 | -
87 |
88 |
89 |
90 | 0
91 | 0
92 |
93 |
94 |
95 | Category
96 |
97 |
98 | Qt::PlainText
99 |
100 |
101 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
102 |
103 |
104 |
105 | -
106 |
107 |
108 |
109 | 0
110 | 0
111 |
112 |
113 |
114 | Default Value
115 |
116 |
117 | Qt::PlainText
118 |
119 |
120 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
121 |
122 |
123 |
124 | -
125 |
126 |
127 |
128 | 0
129 | 0
130 |
131 |
132 |
133 | Type
134 |
135 |
136 | Qt::PlainText
137 |
138 |
139 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
140 |
141 |
142 |
143 | -
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 | buttonBox
153 | accepted()
154 | Dialog
155 | accept()
156 |
157 |
158 | 248
159 | 254
160 |
161 |
162 | 157
163 | 274
164 |
165 |
166 |
167 |
168 | buttonBox
169 | rejected()
170 | Dialog
171 | reject()
172 |
173 |
174 | 316
175 | 260
176 |
177 |
178 | 286
179 | 274
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/Geometry/Support.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # **************************************************************************
3 | # * *
4 | # * Copyright (c) 2018 Joel Graff *
5 | # * *
6 | # * This program is free software; you can redistribute it and/or modify *
7 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 | # * as published by the Free Software Foundation; either version 2 of *
9 | # * the License, or (at your option) any later version. *
10 | # * for detail see the LICENCE text file. *
11 | # * *
12 | # * This program is distributed in the hope that it will be useful, *
13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 | # * GNU Library General Public License for more details. *
16 | # * *
17 | # * You should have received a copy of the GNU Library General Public *
18 | # * License along with this program; if not, write to the Free Software *
19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 | # * USA *
21 | # * *
22 | # **************************************************************************
23 |
24 | '''
25 | Useful math functions and constants
26 | '''
27 | import math
28 | import FreeCAD as App
29 |
30 | from Project.Support import Utils
31 | from Project.Support.Utils import Constants as C
32 |
33 | def safe_sub(lhs, rhs, return_None=False):
34 | '''
35 | Safely subtract two vectors.
36 | Returns an empty vector or None if either vector is None
37 | '''
38 |
39 | if not lhs or not rhs:
40 |
41 | if return_None:
42 | return None
43 |
44 | return App.Vector()
45 |
46 | return lhs.sub(rhs)
47 |
48 | def safe_radians(value):
49 | '''
50 | Convert a floating point value from degrees to radians,
51 | handle None / invalid type conditions
52 | '''
53 |
54 | if value is None:
55 | return 0.0
56 |
57 | if not isinstance(value, float):
58 | return 0.0
59 |
60 | return math.radians(value)
61 |
62 | def get_rotation(in_vector, out_vector = None):
63 | '''
64 | Returns the rotation as a signed integer:
65 | 1 = cw, -1 = ccw, 0 = fail
66 |
67 | if in_vector is an instance, out_vector is ignored.
68 | '''
69 | _in = in_vector
70 | _out = out_vector
71 |
72 | if isinstance(_in, list):
73 | if not all(_in):
74 | return 0
75 |
76 | _out = in_vector[1]
77 | _in = in_vector[0]
78 |
79 | if not all([_out, _in]):
80 | return 0
81 |
82 | if not (_in.Length and _out.Length):
83 | return 0
84 |
85 | return -1 * math.copysign(1, _in.cross(_out).z)
86 |
87 | def get_ortho(vector, rot):
88 | '''
89 | Calculate the normalized orthogonal of the passed vector
90 | '''
91 |
92 | result = vector
93 |
94 | if isinstance(vector, list):
95 | result = App.Vector(vector)
96 |
97 | if not isinstance(result, App.Vector):
98 | return None
99 |
100 | return App.Vector(result.y, -result.x, 0.0).normalize().multiply(rot)
101 |
102 | def get_bearing(vector):
103 | '''
104 | Returns the absolute bearing of the passed vector.
105 | Bearing is measured clockwise from +y 'north' (0,1,0)
106 | Vector is a list of coordinates or an App.Vector
107 | '''
108 |
109 | result = vector
110 |
111 | if isinstance(vector, list):
112 | result = App.Vector(vector)
113 |
114 | if not isinstance(vector, App.Vector):
115 | return None
116 |
117 | rot = get_rotation(C.UP, result)
118 | angle = rot * C.UP.getAngle(result)
119 |
120 | if angle < 0.0:
121 | angle += C.TWO_PI
122 |
123 | return angle
124 |
125 | def within_tolerance(lhs, rhs=None):
126 | '''
127 | Determine if two values are within a pre-defined tolerance
128 |
129 | lhs / rhs - values to compare.
130 | If rhs is none, lhs mat be an array, or a single value to compare directly with tolerance
131 |
132 | Array comparisons check every value against every other, and error if any checks fail
133 | '''
134 |
135 | if lhs is None:
136 | return False
137 |
138 | if isinstance(lhs, list):
139 |
140 | for _i in range(0, len(lhs) - 1):
141 |
142 | rhs = lhs[_i:]
143 |
144 | for _val in rhs:
145 |
146 | if not abs(lhs[_i] - _val) < C.TOLERANCE:
147 | return False
148 |
149 | elif rhs is None:
150 | return abs(lhs) < C.TOLERANCE
151 |
152 | else:
153 | return abs(lhs-rhs) < C.TOLERANCE
154 |
155 | return True
156 |
157 | def vector_ortho(vector):
158 | '''
159 | Returns the orthogonal of a 2D vector as (-y, x)
160 | '''
161 |
162 | vec_list = vector
163 |
164 | if not isinstance(vector, list):
165 | vec_list = [vector]
166 |
167 | result = []
168 |
169 | for vec in vec_list:
170 | result.append(App.Vector(-vec.y, vec.x, 0.0))
171 |
172 | if len(result) == 1:
173 | return result[0]
174 |
175 | return result
176 |
177 | def vector_from_angle(angle):
178 | '''
179 | Returns a vector form a given angle in radians
180 | '''
181 |
182 | _angle = Utils.to_float(angle)
183 |
184 | if not _angle:
185 | return None
186 |
187 | return App.Vector(math.sin(_angle), math.cos(_angle), 0.0)
188 |
--------------------------------------------------------------------------------