# /********************************************************************** # * * # * Copyright (c) 2021 Javier BraƱa * # * * # * 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())