primera subida
This commit is contained in:
321
Utils/PVPlantUtils.py
Normal file
321
Utils/PVPlantUtils.py
Normal file
@@ -0,0 +1,321 @@
|
||||
import math
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
from PySide import QtCore
|
||||
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
|
||||
|
||||
|
||||
|
||||
def VectorToPoint(vector):
|
||||
from shapely.geometry import Point
|
||||
if True:
|
||||
return Point(vector.x, vector.y)
|
||||
else:
|
||||
return Point(vector.x, vector.y, vector.z)
|
||||
|
||||
# buscar el camino más corto:
|
||||
from collections import defaultdict
|
||||
class Graph():
|
||||
def __init__(self):
|
||||
"""
|
||||
self.edges is a dict of all possible next nodes
|
||||
e.g. {'X': ['A', 'B', 'C', 'E'], ...}
|
||||
self.weights has all the weights between two nodes,
|
||||
with the two nodes as a tuple as the key
|
||||
e.g. {('X', 'A'): 7, ('X', 'B'): 2, ...}
|
||||
"""
|
||||
self.edges = defaultdict(list)
|
||||
self.weights = {}
|
||||
|
||||
def add_edge(self, from_node, to_node, weight):
|
||||
# Note: assumes edges are bi-directional
|
||||
self.edges[from_node].append(to_node)
|
||||
self.edges[to_node].append(from_node)
|
||||
self.weights[(from_node, to_node)] = weight
|
||||
self.weights[(to_node, from_node)] = weight
|
||||
|
||||
|
||||
|
||||
def dijsktra(graph, initial, end):
|
||||
# shortest paths is a dict of nodes
|
||||
# whose value is a tuple of (previous node, weight)
|
||||
shortest_paths = {initial: (None, 0)}
|
||||
current_node = initial
|
||||
visited = set()
|
||||
|
||||
while current_node != end:
|
||||
visited.add(current_node)
|
||||
destinations = graph.edges[current_node]
|
||||
weight_to_current_node = shortest_paths[current_node][1]
|
||||
|
||||
for next_node in destinations:
|
||||
weight = graph.weights[(current_node, next_node)] + weight_to_current_node
|
||||
if next_node not in shortest_paths:
|
||||
shortest_paths[next_node] = (current_node, weight)
|
||||
else:
|
||||
current_shortest_weight = shortest_paths[next_node][1]
|
||||
if current_shortest_weight > weight:
|
||||
shortest_paths[next_node] = (current_node, weight)
|
||||
|
||||
next_destinations = {node: shortest_paths[node] for node in shortest_paths if node not in visited}
|
||||
if not next_destinations:
|
||||
return "Route Not Possible"
|
||||
# next node is the destination with the lowest weight
|
||||
current_node = min(next_destinations, key=lambda k: next_destinations[k][1])
|
||||
|
||||
# Work back through destinations in shortest path
|
||||
path = []
|
||||
while current_node is not None:
|
||||
path.append(current_node)
|
||||
next_node = shortest_paths[current_node][0]
|
||||
current_node = next_node
|
||||
# Reverse path
|
||||
path = path[::-1]
|
||||
return path
|
||||
|
||||
|
||||
'''
|
||||
Flatten a wire to 2 axis: X - Y
|
||||
'''
|
||||
def FlattenWire(wire):
|
||||
pts = []
|
||||
xx = 0
|
||||
for i, ver in enumerate(wire.Vertexes):
|
||||
if i == 0:
|
||||
pts.append(FreeCAD.Vector(xx, ver.Point.z, 0))
|
||||
else:
|
||||
xx += (ver.Point - wire.Vertexes[i - 1].Point).Length
|
||||
pts.append(FreeCAD.Vector(xx, ver.Point.z, 0))
|
||||
return Part.makePolygon(pts)
|
||||
|
||||
def flattenWire(wire):
|
||||
pts = []
|
||||
for i, ver in enumerate(wire.Vertexes):
|
||||
point = FreeCAD.Vector(ver.Point)
|
||||
point.z = 0
|
||||
pts.append(point)
|
||||
return Part.makePolygon(pts)
|
||||
|
||||
def simplifyWire(wire):
|
||||
if not wire.isDerivedFrom("Part::Part2DObject"):
|
||||
wire = flattenWire(wire)
|
||||
pts = [ver.Point for ver in wire.Vertexes]
|
||||
for i in range(len(pts)-2):
|
||||
'''
|
||||
'''
|
||||
|
||||
'''for i in range(len(wire.Edges) - 1):
|
||||
ed1 = wire.Edges[i]
|
||||
ed2 = wire.Edges[i + 1]
|
||||
vec1 = ed1.Vertexes[1].Point.sub(ed1.Vertexes[0].Point)
|
||||
vec2 = ed2.Vertexes[1].Point.sub(ed2.Vertexes[0].Point)
|
||||
angle = vec1.getAngle(vec2)
|
||||
if angle == 0:'''
|
||||
|
||||
|
||||
|
||||
def getPointsFromVertexes(Vertexes):
|
||||
return [ver.Point for ver in Vertexes]
|
||||
|
||||
def makeProfileFromTerrain(path):
|
||||
import PVPlantSite
|
||||
terrain = PVPlantSite.get().Terrain
|
||||
if terrain:
|
||||
return terrain.Shape.makeParallelProjection(path.Shape.Wires[0], FreeCAD.Vector(0, 0, 1))
|
||||
|
||||
def angleToPercent(deg):
|
||||
''' ángulo en porcentaje = tan(ángulo en grados) * 100% '''
|
||||
|
||||
return math.tan(math.radians(deg)) * 100
|
||||
|
||||
def PercentToAngle(percent):
|
||||
''' ángulo en grados = arctan(ángulo en porcentaje / 100%) '''
|
||||
|
||||
return math.degrees(math.atan(percent / 100))
|
||||
|
||||
def getEWAngle(frame1, frame2):
|
||||
vec = frame2.Placement.Base.sub(frame1.Placement.Base)
|
||||
rad = vec.getAngle(FreeCAD.Vector(1, 0, 0))
|
||||
deg = math.degrees(rad)
|
||||
if deg > 90:
|
||||
deg = 180 - deg
|
||||
return deg
|
||||
|
||||
def simplifyWire(wire):
|
||||
import math
|
||||
|
||||
closed = False
|
||||
points = [ver.Point for ver in wire.Vertexes]
|
||||
if points[0] == points[-1]:
|
||||
points.pop(-1)
|
||||
closed = True
|
||||
|
||||
if len(points) < 3:
|
||||
return wire
|
||||
|
||||
'''cnt = 0
|
||||
while cnt < (len(points) - 2):
|
||||
p1 = cnt + 1
|
||||
if p1 == len(points)-2:
|
||||
p1 = 0
|
||||
elif p1 == len(points)-1:
|
||||
p1 = 1
|
||||
|
||||
p2 = p1 + 1
|
||||
vec1 = points[p1].sub(points[cnt])
|
||||
vec2 = points[p2].sub(points[p1])
|
||||
angle = vec2.getAngle(vec1)
|
||||
# Edges have same direction
|
||||
if (round(angle, 2) == 0) or (round(angle - math.pi, 2) == 0):
|
||||
points.pop(cnt + 1)
|
||||
else:
|
||||
cnt += 1'''
|
||||
|
||||
i = 0
|
||||
while i < len(points) - 2:
|
||||
p1 = points[(i + 1) % len(points)]
|
||||
p2 = points[(i + 2) % len(points)]
|
||||
vec1 = p1 - points[i]
|
||||
vec2 = p2 - p1
|
||||
angle = vec2.getAngle(vec1)
|
||||
# Agregar tolerancia para el ángulo
|
||||
if round(angle, 2) == 0 or round(angle - math.pi, 2) == 0:
|
||||
points.pop(i + 1)
|
||||
else:
|
||||
i += 1
|
||||
|
||||
if closed:
|
||||
points.append(FreeCAD.Vector(points[0]))
|
||||
|
||||
pol = Part.makePolygon(points)
|
||||
return pol
|
||||
|
||||
def getProjected(shape, direction=FreeCAD.Vector(0, 0, 1)): # Based on Draft / shape2dview
|
||||
""" returns projected edges from a shape and a direction """
|
||||
|
||||
import Part, TechDraw
|
||||
edges = []
|
||||
groups = TechDraw.projectEx(shape, direction)
|
||||
for g in groups[0:5]:
|
||||
if g:
|
||||
if len(g.Edges) > 0:
|
||||
edges.extend(g.Edges)
|
||||
if len(edges) > 1:
|
||||
ow = TechDraw.findOuterWire(edges)
|
||||
else:
|
||||
ow = Part.Wire(edges[0])
|
||||
return ow
|
||||
|
||||
|
||||
def findObjects(classtype):
|
||||
objects = FreeCAD.ActiveDocument.Objects
|
||||
objlist = list()
|
||||
for object in objects:
|
||||
if hasattr(object, "Proxy"):
|
||||
if object.Proxy.Type == classtype:
|
||||
objlist.append(object)
|
||||
return objlist
|
||||
|
||||
def getClosePoints(sh1, angle):
|
||||
'''
|
||||
sh1= reference
|
||||
tag angle = height / offset
|
||||
- dato conocido: angle
|
||||
- si conocemos offset (= 1 mm) => height = offset * tag angle
|
||||
'''
|
||||
|
||||
import Draft, math, Part
|
||||
import MeshPart as mp
|
||||
|
||||
pts = []
|
||||
for ver in sh1.Vertexes:
|
||||
point = FreeCAD.Vector(ver.Point)
|
||||
point.z = 0
|
||||
pts.append([point, ver])
|
||||
minsh1 = min(pts, key=lambda x: x[1].Z)[1]
|
||||
|
||||
projected = getProjected(max(sh1.Wires, key=lambda x: x.Length))
|
||||
sh2 = projected.makeOffset2D(1, 0, False, False, True)
|
||||
height = math.tan(math.radians(angle))
|
||||
sh2.Placement.Base.z = - height
|
||||
sh2pts = []
|
||||
for edge in sh2.Edges:
|
||||
count = 0
|
||||
if issubclass(type(edge.Curve), Part.Circle):
|
||||
v1 = edge.Vertexes[0].Point.sub(edge.Curve.Center)
|
||||
v2 = edge.Curve.Center.sub(edge.Vertexes[0].Point)
|
||||
count = int(v1.getAngle(v2) / math.radians(5))
|
||||
|
||||
if count > 0:
|
||||
sh2pts.extend(edge.discretize(Number=count))
|
||||
else:
|
||||
sh2pts.append(edge.Vertexes[0].Point)
|
||||
|
||||
def getline(real, pro):
|
||||
land = FreeCAD.ActiveDocument.Mesh002.Mesh
|
||||
vec = FreeCAD.Vector(real.Point)
|
||||
vec.z = 0
|
||||
vec = vec.sub(pro)
|
||||
vec.normalize()
|
||||
vec.Length = 10000
|
||||
vec = real.Point.sub(vec)
|
||||
line = Part.LineSegment(real.Point, vec)
|
||||
plane = Part.Plane(minsh1, FreeCAD.Vector(0, 0, 1))
|
||||
|
||||
tmp = mp.projectPointsOnMesh([real.Point,], land, vec)
|
||||
if len(tmp) > 0:
|
||||
return tmp[0]
|
||||
|
||||
#Draft.makeLine(real.Point, vec)
|
||||
#return vec
|
||||
|
||||
lines = []
|
||||
if len(sh1.Vertexes) >= len(sh2pts):
|
||||
for ver in sh1.Vertexes:
|
||||
point = FreeCAD.Vector(ver.Point)
|
||||
point.z = 0
|
||||
mn = min(sh2.Vertexes, key=lambda x: x.Point.sub(point).Length)
|
||||
getpoints(ver, mn)
|
||||
else:
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
for point in sh2pts:
|
||||
mn = min(pts, key=lambda x: x[0].sub(point).Length)
|
||||
lines.append(getline(mn[1], point))
|
||||
total_time = datetime.now() - starttime
|
||||
print(" -- Tiempo tardado en ajustar al terreno:", total_time)
|
||||
|
||||
ret = [ver.Point for ver in sh1.Vertexes]
|
||||
ret.extend(lines)
|
||||
Draft.makeWire(lines, closed=True)
|
||||
import Mesh
|
||||
from MeshTools.Triangulation import Triangulate
|
||||
m = Triangulate(ret, MaxlengthLE=4000)
|
||||
Mesh.show(m)
|
||||
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
def offset_wire(wire, distance):
|
||||
# Crear un tubo alrededor de la wire original
|
||||
tube = Part.makeTube(wire, distance)
|
||||
# Offsetear el tubo
|
||||
offset_wire = tube.makeOffsetShape(distance)
|
||||
return offset_wire
|
||||
Reference in New Issue
Block a user