primera subida
This commit is contained in:
464
Utils/PVPlantTrace.py
Normal file
464
Utils/PVPlantTrace.py
Normal file
@@ -0,0 +1,464 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify*
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307*
|
||||
# * USA *
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
import os
|
||||
from copy import deepcopy
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
from pivy import coin
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
'''
|
||||
import threading
|
||||
import datetime
|
||||
|
||||
class ThreadClass(threading.Thread):
|
||||
def __init__(self, land, Trace):
|
||||
self.land = land
|
||||
self.trace = Trace
|
||||
|
||||
def run(self):
|
||||
tmp = self.land.makeParallelProjection(self.trace, FreeCAD.Vector(0, 0, 1))
|
||||
pts = [ver.Point for ver in tmp.Vertexes]
|
||||
return pts
|
||||
|
||||
|
||||
for i in range(2):
|
||||
t = ThreadClass()
|
||||
t.start()
|
||||
'''
|
||||
|
||||
|
||||
def makeTrace(points = None, label = "Trace"):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Trace")
|
||||
obj.Label = label
|
||||
Trace(obj)
|
||||
ViewProviderTrace(obj.ViewObject)
|
||||
if points:
|
||||
obj.Points = points
|
||||
return obj
|
||||
|
||||
|
||||
class Trace:
|
||||
def __init__(self, obj):
|
||||
self.setCommonProperties(obj)
|
||||
|
||||
def setCommonProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
if not ("Points" in pl):
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"Points",
|
||||
"PlacementLine",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
)
|
||||
|
||||
if not ("ProjectionPoints" in pl):
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"ProjectionPoints",
|
||||
"PlacementLine",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
)
|
||||
|
||||
if not ("ShowTrend" in pl):
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"ShowTrend",
|
||||
"PlacementLine",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).ShowTrend = True
|
||||
|
||||
if not ("Edit" in pl):
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"Edit",
|
||||
"PlacementLine",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).Edit = False
|
||||
|
||||
self.Type = "TraceLine"
|
||||
obj.Proxy = self
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
''' Do something when a property has changed '''
|
||||
if prop == "Edit":
|
||||
if obj.Edit:
|
||||
subobj = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]
|
||||
if subobj.__class__ == Part.Circle:
|
||||
print ("Circle")
|
||||
|
||||
def execute(self, obj):
|
||||
shape = None
|
||||
base = None
|
||||
if len(obj.Points) > 1:
|
||||
base = Part.makePolygon(obj.Points)
|
||||
import DraftGeomUtils
|
||||
|
||||
w = DraftGeomUtils.filletWire(base, 8000)
|
||||
if w:
|
||||
shape = w
|
||||
if shape:
|
||||
obj.Shape = shape
|
||||
|
||||
'''
|
||||
if len(obj.ProjectionPoints) > 1 and obj.ShowTrend:
|
||||
# TODO: check:
|
||||
from scipy import stats
|
||||
xx = list()
|
||||
yy = list()
|
||||
zz = list()
|
||||
|
||||
for pts in obj.ProjectionPoints:
|
||||
xx.append(pts.x)
|
||||
yy.append(pts.y)
|
||||
zz.append(pts.z)
|
||||
|
||||
slope, intercept, r, p, std_err = stats.linregress(yy, zz)
|
||||
|
||||
def myfunc(x):
|
||||
return slope * x + intercept
|
||||
|
||||
x = list()
|
||||
x.append(yy[0])
|
||||
x.append(yy[-1])
|
||||
newzz = list(map(myfunc, x))
|
||||
|
||||
for p in range(len(obj.Points) - 1):
|
||||
#found = [i for i in map(lambda n: float(n.replace(',', '.')), values) if 1.50 < i < 2.50]
|
||||
r = []
|
||||
|
||||
#if obj.Points[p]
|
||||
mi = obj.Points[p + 1]
|
||||
ma = obj.Points[p]
|
||||
for p3d in obj.ProjectionPoints:
|
||||
if mi.x <= p3d.x <= ma.x and mi.y <= p3d.y <= ma.y:
|
||||
r.append(p3d)
|
||||
|
||||
tmp = Part.makePolygon([FreeCAD.Vector(xx[0], yy[0], newzz[0]),
|
||||
FreeCAD.Vector(xx[-1], yy[-1], newzz[-1])])
|
||||
#obj.Shape = obj.Shape.fuse([tmp,])
|
||||
'''
|
||||
|
||||
class ViewFunctions:
|
||||
def get_stations(self, obj):
|
||||
""" Retrieve the coordinates of the start and end points of the station
|
||||
tick mark orthogonal to the alignment """
|
||||
|
||||
start = obj.Proxy.model.data['meta']['StartStation']
|
||||
length = obj.Proxy.model.data['meta']['Length']
|
||||
end = start + length/1000
|
||||
|
||||
stations = {}
|
||||
|
||||
for sta in range(int(start), int(end)):
|
||||
if sta % 10 == 0:
|
||||
tuple_coord, tuple_vec =\
|
||||
obj.Proxy.model.get_orthogonal( sta, "Left", True)
|
||||
|
||||
coord = FreeCAD.Vector(tuple_coord)
|
||||
vec = FreeCAD.Vector(tuple_vec)
|
||||
|
||||
left_vec = deepcopy(vec)
|
||||
right_vec = deepcopy(vec)
|
||||
|
||||
left_side = coord.add(left_vec.multiply(1500))
|
||||
right_side = coord.add(right_vec.negative().multiply(1500))
|
||||
|
||||
stations[sta] = [left_side, right_side]
|
||||
|
||||
return stations
|
||||
|
||||
class ViewProviderTrace(ViewFunctions):
|
||||
def __init__(self, vobj):
|
||||
''' Set view properties '''
|
||||
self.Object = None
|
||||
self.editor = None
|
||||
self.select_state = True
|
||||
self.active = False
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon '''
|
||||
|
||||
return str(os.path.join(DirIcons, "Trace.svg"))
|
||||
|
||||
def attach(self, vobj):
|
||||
''' Create Object visuals in 3D view '''
|
||||
|
||||
self.Object = vobj.Object
|
||||
|
||||
# Line style.
|
||||
line_style = coin.SoDrawStyle()
|
||||
line_style.style = coin.SoDrawStyle.LINES
|
||||
line_style.lineWidth = 2
|
||||
|
||||
# Line geometry keepers.
|
||||
line_color = coin.SoBaseColor()
|
||||
line_color.rgb = (1.0, 0.0, 0.0)
|
||||
self.lines = coin.SoSeparator()
|
||||
self.lines.addChild(line_style)
|
||||
self.lines.addChild(line_color)
|
||||
|
||||
# Curve geometry keepers.
|
||||
curve_color = coin.SoBaseColor()
|
||||
curve_color.rgb = (0.0, 0.5, 0.0)
|
||||
self.curves = coin.SoSeparator()
|
||||
self.curves.addChild(line_style)
|
||||
self.curves.addChild(curve_color)
|
||||
|
||||
# Spiral geometry keepers.
|
||||
spiral_color = coin.SoBaseColor()
|
||||
spiral_color.rgb = (0.0, 0.33, 1.0)
|
||||
self.spirals = coin.SoSeparator()
|
||||
self.spirals.addChild(line_style)
|
||||
self.spirals.addChild(spiral_color)
|
||||
|
||||
# Labels root.
|
||||
ticks = coin.SoSeparator()
|
||||
self.tick_coords = coin.SoGeoCoordinate()
|
||||
self.tick_lines = coin.SoLineSet()
|
||||
ticks.addChild(self.tick_coords)
|
||||
ticks.addChild(self.tick_lines)
|
||||
self.labels = coin.SoSeparator()
|
||||
|
||||
# Alignment root.
|
||||
lines_root = coin.SoSeparator()
|
||||
lines_root.addChild(self.lines)
|
||||
lines_root.addChild(self.curves)
|
||||
lines_root.addChild(self.spirals)
|
||||
lines_root.addChild(ticks)
|
||||
lines_root.addChild(self.labels)
|
||||
vobj.addDisplayMode(lines_root, "Wireframe")
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
'''
|
||||
Update Object visuals when a data property changed.
|
||||
'''
|
||||
if prop == "Shape":
|
||||
shape = obj.getPropertyByName(prop)
|
||||
if not shape.SubShapes: return
|
||||
|
||||
# Set System.
|
||||
#origin = geo_origin.get()
|
||||
#geo_system = ["UTM", origin.UtmZone, "FLAT"]
|
||||
|
||||
copy_shape = shape.copy()
|
||||
copy_shape.Placement.move(shape.Placement.Base)
|
||||
#copy_shape.Placement.move(origin.Origin)
|
||||
|
||||
lines = copy_shape.SubShapes[0]
|
||||
for wire in lines.Wires:
|
||||
points = []
|
||||
for vertex in wire.OrderedVertexes:
|
||||
points.append(vertex.Point)
|
||||
|
||||
line = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
line.style = 'EMISSIVE_DIFFUSE'
|
||||
|
||||
line_coords = coin.SoGeoCoordinate()
|
||||
#line_coords.geoSystem.setValues(geo_system)
|
||||
line_coords.point.values = points
|
||||
line_set = coin.SoLineSet()
|
||||
|
||||
line.addChild(line_coords)
|
||||
line.addChild(line_set)
|
||||
self.lines.addChild(line)
|
||||
|
||||
del points
|
||||
|
||||
curves = copy_shape.SubShapes[1]
|
||||
for wire in curves.Wires:
|
||||
points = []
|
||||
for vertex in wire.OrderedVertexes:
|
||||
points.append(vertex.Point)
|
||||
|
||||
curve = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
curve.style = 'EMISSIVE_DIFFUSE'
|
||||
|
||||
curve_coords = coin.SoGeoCoordinate()
|
||||
#curve_coords.geoSystem.setValues(geo_system)
|
||||
curve_coords.point.values = points
|
||||
curve_set = coin.SoLineSet()
|
||||
|
||||
curve.addChild(curve_coords)
|
||||
curve.addChild(curve_set)
|
||||
self.curves.addChild(curve)
|
||||
|
||||
del points
|
||||
|
||||
spirals = copy_shape.SubShapes[2]
|
||||
for wire in spirals.Wires:
|
||||
points = []
|
||||
for vertex in wire.OrderedVertexes:
|
||||
points.append(vertex.Point)
|
||||
|
||||
spiral = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
spiral.style = 'EMISSIVE_DIFFUSE'
|
||||
|
||||
spiral_coords = coin.SoGeoCoordinate()
|
||||
#spiral_coords.geoSystem.setValues(geo_system)
|
||||
spiral_coords.point.values = points
|
||||
spiral_set = coin.SoLineSet()
|
||||
|
||||
spiral.addChild(spiral_coords)
|
||||
spiral.addChild(spiral_set)
|
||||
self.spirals.addChild(spiral)
|
||||
|
||||
del points
|
||||
del copy_shape
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
"""Method called when the document requests the object to enter edit mode.
|
||||
|
||||
Edit mode is entered when a user double clicks on an object in the tree
|
||||
view, or when they use the menu option [Edit -> Toggle Edit Mode].
|
||||
|
||||
Just display the standard Point Edit task panel.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mode: int or str
|
||||
The edit mode the document has requested. Set to 0 when requested via
|
||||
a double click or [Edit -> Toggle Edit Mode].
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
If edit mode was entered.
|
||||
"""
|
||||
|
||||
if (mode == 0) and hasattr(self, "Object"):
|
||||
import Utils.profile_editor as editor
|
||||
if vobj.Selectable:
|
||||
self.select_state = True
|
||||
vobj.Selectable = False
|
||||
|
||||
pts = list()
|
||||
for i in range(len(self.Object.Points)):
|
||||
p = self.Object.Points[i]
|
||||
#pts.append(editor.MarkerOnShape([p]))
|
||||
self.editor = editor.Edit(self.Object) #(pts, self.Object)
|
||||
'''for i in range(min(len(self.Object.Shape.Edges), len(self.editor.lines))):
|
||||
self.editor.lines[i].updateLine()'''
|
||||
self.active = True
|
||||
return True
|
||||
return False
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Disable edit
|
||||
"""
|
||||
import Utils.profile_editor as editor
|
||||
if isinstance(self.editor, editor.Edit):# and check_pivy():
|
||||
pts = list()
|
||||
for p in self.editor.points:
|
||||
if isinstance(p, editor.MarkerOnShape):
|
||||
pt = p.points[0]
|
||||
pts.append(FreeCAD.Vector(pt[0], pt[1], pt[2]))
|
||||
self.Object.Points = pts
|
||||
vobj.Selectable = self.select_state
|
||||
self.editor.quit()
|
||||
del self.editor
|
||||
self.editor = None
|
||||
self.active = False
|
||||
self.Object.Document.recompute()
|
||||
return True
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
if not hasattr(self, 'active'):
|
||||
self.active = False
|
||||
if not self.active:
|
||||
self.active = True
|
||||
# self.setEdit(vobj)
|
||||
vobj.Document.setEdit(vobj)
|
||||
else:
|
||||
vobj.Document.resetEdit()
|
||||
self.active = False
|
||||
return True
|
||||
|
||||
def setupContextMenu(self, obj, menu):
|
||||
"""
|
||||
Context menu construction
|
||||
"""
|
||||
pass
|
||||
|
||||
def edit(self):
|
||||
"""
|
||||
Edit callback
|
||||
"""
|
||||
pass
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Save variables to file.
|
||||
"""
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Get variables from file.
|
||||
"""
|
||||
return None
|
||||
|
||||
class CommandTrace:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "Trace.svg")),
|
||||
'Accel': "T, R",
|
||||
'MenuText': "Trace",
|
||||
'ToolTip': "Trace"}
|
||||
|
||||
def Activated(self):
|
||||
points = None
|
||||
'''
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if sel:
|
||||
points = sel[0].Points
|
||||
'''
|
||||
obj = makeTrace(points)
|
||||
#obj.ViewObject.Document.setEdit(obj.ViewObject)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Trace', CommandTrace())
|
||||
Reference in New Issue
Block a user