algo
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Part
|
||||
import Draft
|
||||
from xml.etree import ElementTree as ET
|
||||
@@ -15,9 +16,7 @@ scale = 1000.0
|
||||
class OSMImporter:
|
||||
|
||||
def __init__(self, origin):
|
||||
self.Origin = origin
|
||||
if origin is None:
|
||||
self.Origin = FreeCAD.Vector(0, 0, 0)
|
||||
self.Origin = origin if origin else FreeCAD.Vector(0, 0, 0)
|
||||
self.overpass_url = "https://overpass-api.de/api/interpreter"
|
||||
self.nodes = {}
|
||||
self.ways_data = defaultdict(dict)
|
||||
@@ -40,10 +39,11 @@ class OSMImporter:
|
||||
'vegetation': (0.4, 0.8, 0.4),
|
||||
'water': (0.4, 0.6, 1.0)
|
||||
}
|
||||
self.ssl_context = ssl.create_default_context(cafile=certifi.where())
|
||||
|
||||
def transformFromLatLon(self, lat, lon):
|
||||
def transform_from_latlon(self, lat, lon):
|
||||
x, y, _, _ = utm.from_latlon(lat, lon)
|
||||
return (x, y, 0) * 1000
|
||||
return FreeCAD.Vector(x, y, .0) * scale - self.Origin
|
||||
|
||||
def get_osm_data(self, bbox):
|
||||
query = f"""
|
||||
@@ -61,43 +61,36 @@ class OSMImporter:
|
||||
(._;>;);
|
||||
out body;
|
||||
"""
|
||||
# Configurar contexto SSL seguro
|
||||
ssl_context = ssl.create_default_context(cafile=certifi.where())
|
||||
|
||||
# Modificar tu código de descarga
|
||||
response = urllib.request.urlopen(
|
||||
req = urllib.request.Request(
|
||||
self.overpass_url,
|
||||
data=query.encode('utf-8'),
|
||||
context=ssl_context,
|
||||
timeout=30
|
||||
headers={'User-Agent': 'FreeCAD-OSM-Importer/1.0'},
|
||||
method='POST'
|
||||
)
|
||||
return response.read()
|
||||
return urllib.request.urlopen(req, context=self.ssl_context, timeout=30).read()
|
||||
|
||||
def create_layer(self, name):
|
||||
if not FreeCAD.ActiveDocument.getObject(name):
|
||||
layer = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", name)
|
||||
return layer
|
||||
return FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", name)
|
||||
return FreeCAD.ActiveDocument.getObject(name)
|
||||
|
||||
def process_osm_data(self, osm_data):
|
||||
root = ET.fromstring(osm_data)
|
||||
|
||||
# Primera pasada: almacenar todos los nodos
|
||||
# Almacenar nodos transformados
|
||||
for node in root.findall('node'):
|
||||
'''self.nodes[node.attrib['id']] = (
|
||||
float(node.attrib['lon']),
|
||||
float(node.attrib['lat']),
|
||||
0)'''
|
||||
self.nodes[node.attrib['id']] = self.transformFromLatLon(
|
||||
self.nodes[node.attrib['id']] = self.transform_from_latlon(
|
||||
float(node.attrib['lat']),
|
||||
float(node.attrib['lon'])
|
||||
)
|
||||
|
||||
# Segunda pasada: procesar ways y relaciones
|
||||
# Procesar ways
|
||||
for way in root.findall('way'):
|
||||
tags = {tag.attrib['k']: tag.attrib['v'] for tag in way.findall('tag')}
|
||||
nodes = [nd.attrib['ref'] for nd in way.findall('nd')]
|
||||
self.ways_data[way.attrib['id']] = {'tags': tags, 'nodes': nodes}
|
||||
way_id = way.attrib['id']
|
||||
self.ways_data[way_id] = {
|
||||
'tags': {tag.attrib['k']: tag.attrib['v'] for tag in way.findall('tag')},
|
||||
'nodes': [nd.attrib['ref'] for nd in way.findall('nd')]
|
||||
}
|
||||
|
||||
self.create_transportation()
|
||||
self.create_buildings()
|
||||
@@ -133,7 +126,7 @@ class OSMImporter:
|
||||
self.create_railway(nodes, transport_layer)
|
||||
|
||||
def create_road(self, nodes, width, road_type, layer):
|
||||
points = [FreeCAD.Vector(n[0], n[1], .0) * scale - self.Origin for n in nodes]
|
||||
points = [n for n in nodes]
|
||||
polyline = Draft.make_wire(points, closed=False, face=False)
|
||||
polyline.Label = f"Road_{road_type}"
|
||||
polyline.ViewObject.LineWidth = 2.0
|
||||
@@ -143,7 +136,7 @@ class OSMImporter:
|
||||
layer.addObject(polyline)
|
||||
|
||||
def create_railway(self, nodes, layer):
|
||||
points = [FreeCAD.Vector(n[0], n[1], .0) * scale - self.Origin for n in nodes]
|
||||
points = [n for n in nodes]
|
||||
rail_line = Draft.make_wire(points, closed=False, face=False)
|
||||
rail_line.Label = "Railway"
|
||||
rail_line.ViewObject.LineWidth = 1.5
|
||||
@@ -152,7 +145,6 @@ class OSMImporter:
|
||||
|
||||
def create_buildings(self):
|
||||
building_layer = self.create_layer("Buildings")
|
||||
|
||||
for way_id, data in self.ways_data.items():
|
||||
if 'building' not in data['tags']:
|
||||
continue
|
||||
@@ -167,14 +159,14 @@ class OSMImporter:
|
||||
height = self.get_building_height(tags)
|
||||
|
||||
# Crear polígono base
|
||||
polygon_points = [FreeCAD.Vector(n[0], n[1], .0) * scale - self.Origin for n in nodes]
|
||||
polygon_points = [n for n in nodes]
|
||||
if polygon_points[0] != polygon_points[-1]:
|
||||
polygon_points.append(polygon_points[0])
|
||||
|
||||
try:
|
||||
polygon = Part.makePolygon(polygon_points)
|
||||
face = Part.Face(polygon)
|
||||
extruded = face.extrude(FreeCAD.Vector(0, 0, height) * scale - self.Origin )
|
||||
extruded = face.extrude(FreeCAD.Vector(0, 0, height))# * scale - self.Origin )
|
||||
|
||||
building = building_layer.addObject("Part::Feature", f"Building_{way_id}")
|
||||
building.Shape = extruded
|
||||
@@ -190,7 +182,8 @@ class OSMImporter:
|
||||
except Exception as e:
|
||||
print(f"Error en edificio {way_id}: {str(e)}")
|
||||
|
||||
def get_building_height(self, tags):
|
||||
@staticmethod
|
||||
def get_building_height(tags):
|
||||
# Lógica de cálculo de altura
|
||||
if 'height' in tags:
|
||||
try:
|
||||
@@ -205,44 +198,355 @@ class OSMImporter:
|
||||
return 5.0 # Altura por defecto
|
||||
|
||||
def create_power_infrastructure(self):
|
||||
power_layer = self.create_layer("Power")
|
||||
power_layer = self.create_layer("Power_Infrastructure")
|
||||
|
||||
for way_id, data in self.ways_data.items():
|
||||
tags = data['tags']
|
||||
nodes = [self.nodes[ref] for ref in data['nodes'] if ref in self.nodes]
|
||||
|
||||
if 'power' in tags:
|
||||
if tags['power'] == 'line':
|
||||
self.create_power_line(nodes, power_layer)
|
||||
elif tags['power'] == 'substation':
|
||||
self.create_substation(nodes, power_layer)
|
||||
feature_type = tags['power']
|
||||
|
||||
def create_power_line(self, nodes, layer):
|
||||
if feature_type == 'line':
|
||||
self.create_power_line(
|
||||
nodes=nodes,
|
||||
tags=tags,
|
||||
layer=power_layer
|
||||
)
|
||||
|
||||
elif feature_type == 'substation':
|
||||
self.create_substation(
|
||||
way_id=way_id,
|
||||
tags=tags,
|
||||
nodes=nodes,
|
||||
layer=power_layer
|
||||
)
|
||||
|
||||
elif feature_type == 'tower':
|
||||
self.create_power_tower(
|
||||
position=nodes[0] if nodes else None,
|
||||
tags=tags,
|
||||
layer=power_layer
|
||||
)
|
||||
|
||||
def create_power_line(self, nodes, tags, layer):
|
||||
"""Crea líneas de transmisión eléctrica con propiedades técnicas"""
|
||||
try:
|
||||
# Configuración basada en tags
|
||||
line_type = tags.get('line', 'overhead')
|
||||
voltage = self.parse_voltage(tags.get('voltage', '0'))
|
||||
cables = int(tags.get('cables', '3'))
|
||||
material = tags.get('material', 'aluminum')
|
||||
|
||||
# Crear geometría
|
||||
points = [FreeCAD.Vector(*n) for n in nodes]
|
||||
if len(points) < 2:
|
||||
return
|
||||
|
||||
wire = Draft.make_wire(points, closed=False, face=False)
|
||||
wire.Label = f"Power_Line_{voltage}V"
|
||||
|
||||
# Propiedades visuales
|
||||
wire.ViewObject.LineWidth = 1 + (voltage / 100000)
|
||||
color = self.feature_colors['power']['line']
|
||||
wire.ViewObject.ShapeColor = color
|
||||
|
||||
# Propiedades técnicas
|
||||
wire.addProperty("App::PropertyFloat", "Voltage", "PowerLine", "Voltage in volts").Voltage = voltage
|
||||
wire.addProperty("App::PropertyInteger", "Cables", "PowerLine", "Number of conductors").Cables = cables
|
||||
wire.addProperty("App::PropertyString", "Material", "PowerLine", "Conductor material").Material = material
|
||||
wire.addProperty("App::PropertyString", "Type", "PowerLine", "Line type").Type = line_type
|
||||
|
||||
layer.addObject(wire)
|
||||
|
||||
# Añadir torres si es overhead
|
||||
if line_type == 'overhead':
|
||||
distance_between_towers = 150 # metros por defecto
|
||||
if 'distance_between_towers' in tags:
|
||||
try:
|
||||
distance_between_towers = float(tags['distance_between_towers'])
|
||||
except:
|
||||
pass
|
||||
|
||||
self.create_power_towers_along_line(
|
||||
points=points,
|
||||
voltage=voltage,
|
||||
distance=distance_between_towers,
|
||||
layer=layer
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintError(f"Error creating power line: {str(e)}\n")
|
||||
|
||||
def create_power_towers_along_line(self, points, voltage, distance, layer):
|
||||
"""Crea torres de transmisión a lo largo de la línea"""
|
||||
total_length = 0
|
||||
previous_point = None
|
||||
|
||||
for point in points:
|
||||
if previous_point is not None:
|
||||
segment_length = (point - previous_point).Length
|
||||
num_towers = int(segment_length / distance)
|
||||
|
||||
if num_towers > 0:
|
||||
step = segment_length / num_towers
|
||||
direction = (point - previous_point).normalize()
|
||||
|
||||
for i in range(num_towers):
|
||||
tower_pos = previous_point + (direction * (i * step))
|
||||
self.create_power_tower(
|
||||
position=tower_pos,
|
||||
tags={'voltage': str(voltage)},
|
||||
layer=layer
|
||||
)
|
||||
|
||||
previous_point = point
|
||||
|
||||
def create_power_tower(self, position, tags, layer):
|
||||
"""Crea una torre de transmisión individual"""
|
||||
try:
|
||||
voltage = self.parse_voltage(tags.get('voltage', '0'))
|
||||
|
||||
# Dimensiones basadas en voltaje
|
||||
base_size = 2.0 + (voltage / 100000)
|
||||
height = 25.0 + (voltage / 10000)
|
||||
|
||||
# Geometría de la torre
|
||||
base = Part.makeBox(base_size, base_size, 3.0,
|
||||
FreeCAD.Vector(position.x - base_size / 2, position.y - base_size / 2, 0))
|
||||
mast = Part.makeCylinder(0.5, height, FreeCAD.Vector(position.x, position.y, 3.0))
|
||||
|
||||
# Unir componentes
|
||||
tower = base.fuse(mast)
|
||||
tower_obj = layer.addObject("Part::Feature", "Power_Tower")
|
||||
tower_obj.Shape = tower
|
||||
tower_obj.ViewObject.ShapeColor = self.feature_colors['power']['tower']
|
||||
|
||||
# Añadir propiedades
|
||||
tower_obj.addProperty("App::PropertyFloat", "Voltage", "Technical", "Design voltage").Voltage = voltage
|
||||
tower_obj.addProperty("App::PropertyFloat", "Height", "Technical", "Tower height").Height = height
|
||||
|
||||
# Añadir crossarms (crucetas)
|
||||
for i in range(3):
|
||||
crossarm_height = 3.0 + (i * 5.0)
|
||||
crossarm = Part.makeBox(
|
||||
4.0, 0.2, 0.2,
|
||||
FreeCAD.Vector(position.x - 2.0, position.y - 0.1, crossarm_height)
|
||||
)
|
||||
tower_obj.Shape = tower_obj.Shape.fuse(crossarm)
|
||||
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintError(f"Error creating power tower: {str(e)}\n")
|
||||
|
||||
def create_power_line_simple(self, nodes, layer):
|
||||
# Torres de alta tensión
|
||||
for node in nodes:
|
||||
cylinder = Part.makeCylinder(1.0, 20.0, FreeCAD.Vector(node[0], node[1], 0) * scale - self.Origin )
|
||||
cylinder = Part.makeCylinder(1.0, 20.0, FreeCAD.Vector(node[0], node[1], 0))# * scale - self.Origin )
|
||||
pole = FreeCAD.ActiveDocument.addObject("Part::Feature", "PowerPole")
|
||||
layer.addObject(pole)
|
||||
pole.Shape = cylinder
|
||||
pole.ViewObject.ShapeColor = self.feature_colors['power']['tower']
|
||||
|
||||
# Líneas eléctricas
|
||||
points = [FreeCAD.Vector(n[0], n[1], .0) * scale - self.Origin for n in nodes]
|
||||
points = [n for n in nodes]
|
||||
cable = Draft.make_wire(points, closed=False, face=False)
|
||||
cable.ViewObject.LineWidth = 3.0
|
||||
cable.ViewObject.ShapeColor = self.feature_colors['power']['line']
|
||||
layer.addObject(cable)
|
||||
|
||||
def create_substation(self, nodes, layer):
|
||||
# Crear área de subestación
|
||||
polygon_points = [FreeCAD.Vector(n[0], n[1], 0) * scale - self.Origin for n in nodes]
|
||||
if len(polygon_points) > 2:
|
||||
polygon = Part.makePolygon(polygon_points)
|
||||
face = Part.Face(polygon)
|
||||
substation = FreeCAD.ActiveDocument.addObject("Part::Feature", "Substation")
|
||||
layer.addObject(substation)
|
||||
substation.Shape = face.extrude(FreeCAD.Vector(0, 0, 0.5) * scale - self.Origin )
|
||||
substation.ViewObject.ShapeColor = self.feature_colors['power']['substation']
|
||||
def create_substation(self, way_id, tags, nodes, layer):
|
||||
"""Crea subestaciones con todos los componentes detallados"""
|
||||
try:
|
||||
# 1. Parámetros base
|
||||
voltage = self.parse_voltage(tags.get('voltage', '0'))
|
||||
substation_type = tags.get('substation', 'distribution')
|
||||
name = tags.get('name', f"Substation_{way_id}")
|
||||
|
||||
if len(nodes) < 3:
|
||||
FreeCAD.Console.PrintWarning(f"Subestación {way_id} ignorada: polígono inválido\n")
|
||||
return
|
||||
|
||||
# 2. Geometría base
|
||||
polygon_points = [n for n in nodes if isinstance(n, FreeCAD.Vector)]
|
||||
if polygon_points[0] != polygon_points[-1]:
|
||||
polygon_points.append(polygon_points[0])
|
||||
|
||||
# 3. Base del terreno
|
||||
base_height = 0.3
|
||||
try:
|
||||
base_shape = Part.makePolygon(polygon_points)
|
||||
base_face = Part.Face(base_shape)
|
||||
base_extrude = base_face.extrude(FreeCAD.Vector(0, 0, base_height))
|
||||
base_obj = layer.addObject("Part::Feature", f"{name}_Base")
|
||||
base_obj.Shape = base_extrude
|
||||
base_obj.ViewObject.ShapeColor = (0.2, 0.2, 0.2)
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintError(f"Error base {way_id}: {str(e)}\n")
|
||||
|
||||
# 4. Cercado perimetral
|
||||
if tags.get('fence', 'no') == 'yes':
|
||||
try:
|
||||
fence_offset = -0.8 # metros hacia adentro
|
||||
fence_points = self.offset_polygon(polygon_points, fence_offset)
|
||||
if len(fence_points) > 2:
|
||||
fence_shape = Part.makePolygon(fence_points)
|
||||
fence_face = Part.Face(fence_shape)
|
||||
fence_extrude = fence_face.extrude(FreeCAD.Vector(0, 0, 2.8))
|
||||
fence_obj = layer.addObject("Part::Feature", f"{name}_Fence")
|
||||
fence_obj.Shape = fence_extrude
|
||||
fence_obj.ViewObject.ShapeColor = (0.4, 0.4, 0.4)
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintWarning(f"Error cerca {way_id}: {str(e)}\n")
|
||||
|
||||
# 5. Edificio principal
|
||||
if tags.get('building', 'no') == 'yes':
|
||||
try:
|
||||
building_offset = -2.0 # metros hacia adentro
|
||||
building_height = 4.5 + (voltage / 100000)
|
||||
building_points = self.offset_polygon(polygon_points, building_offset)
|
||||
if len(building_points) > 2:
|
||||
building_shape = Part.makePolygon(building_points)
|
||||
building_face = Part.Face(building_shape)
|
||||
building_extrude = building_face.extrude(FreeCAD.Vector(0, 0, building_height))
|
||||
building_obj = layer.addObject("Part::Feature", f"{name}_Building")
|
||||
building_obj.Shape = building_extrude
|
||||
building_obj.ViewObject.ShapeColor = (0.7, 0.7, 0.7)
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintWarning(f"Error edificio {way_id}: {str(e)}\n")
|
||||
|
||||
# 6. Transformadores
|
||||
try:
|
||||
num_transformers = int(tags.get('transformers', 1))
|
||||
for i in range(num_transformers):
|
||||
transformer_pos = self.calculate_equipment_position(
|
||||
polygon_points,
|
||||
index=i,
|
||||
total=num_transformers,
|
||||
offset=3.0
|
||||
)
|
||||
transformer = self.create_transformer(
|
||||
position=transformer_pos,
|
||||
voltage=voltage,
|
||||
tech_type=tags.get('substation:type', 'outdoor')
|
||||
)
|
||||
layer.addObject(transformer)
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintWarning(f"Error transformadores {way_id}: {str(e)}\n")
|
||||
|
||||
# 7. Torre de seccionamiento para alta tensión
|
||||
if substation_type == 'transmission' and voltage >= 110000:
|
||||
try:
|
||||
tower_pos = self.calculate_tower_position(polygon_points)
|
||||
tower = self.create_circuit_breaker_tower(
|
||||
position=tower_pos,
|
||||
voltage=voltage
|
||||
)
|
||||
layer.addObject(tower)
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintWarning(f"Error torre {way_id}: {str(e)}\n")
|
||||
|
||||
# 8. Propiedades técnicas
|
||||
substation_data = layer.addObject("App::FeaturePython", f"{name}_Data")
|
||||
props = {
|
||||
"Voltage": voltage,
|
||||
"Type": substation_type,
|
||||
"Components": ['Base'] + (['Fence'] if 'fence' in tags else []) +
|
||||
(['Building'] if 'building' in tags else []) +
|
||||
[f'Transformer_{n + 1}' for n in range(num_transformers)]
|
||||
}
|
||||
for prop, value in props.items():
|
||||
if isinstance(value, list):
|
||||
substation_data.addProperty("App::PropertyStringList", prop, "Technical").Components = value
|
||||
else:
|
||||
substation_data.addProperty(
|
||||
"App::PropertyFloat" if isinstance(value, float) else "App::PropertyString",
|
||||
prop, "Technical").setValue(value)
|
||||
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintError(f"Error crítico en subestación {way_id}: {str(e)}\n")
|
||||
|
||||
def add_substation_fence(self, parent_obj, polygon_points):
|
||||
"""Añade cerca perimetral"""
|
||||
try:
|
||||
offset_points = self.offset_polygon(polygon_points, -0.5)
|
||||
fence = Part.makePolygon(offset_points).extrude(FreeCAD.Vector(0, 0, 2.5))
|
||||
fence_obj = parent_obj.Document.addObject("Part::Feature", "Fence")
|
||||
fence_obj.Shape = fence
|
||||
fence_obj.ViewObject.ShapeColor = (0.4, 0.4, 0.4)
|
||||
fence_obj.Placement.Base = parent_obj.Placement.Base
|
||||
except Exception as e:
|
||||
FreeCAD.Console.PrintWarning(f"Error en cerca: {str(e)}\n")
|
||||
|
||||
def parse_voltage(self, voltage_str):
|
||||
# Convertir valores comunes de voltaje a numéricos
|
||||
voltage_map = {
|
||||
'low': 400,
|
||||
'medium': 20000,
|
||||
'high': 110000,
|
||||
'extra high': 380000,
|
||||
'ultra high': 765000
|
||||
}
|
||||
try:
|
||||
return float(''.join(filter(str.isdigit, voltage_str.split()[0]))) * 1000
|
||||
except:
|
||||
return 20000 # Valor por defecto
|
||||
|
||||
def offset_polygon(self, points, offset):
|
||||
"""Versión corregida sin error de sintaxis"""
|
||||
if not points:
|
||||
return []
|
||||
|
||||
sum_x = sum(p.x for p in points)
|
||||
sum_y = sum(p.y for p in points)
|
||||
centroid = FreeCAD.Vector(sum_x / len(points), sum_y / len(points), 0)
|
||||
|
||||
return [p + (centroid - p).normalize() * offset for p in points]
|
||||
|
||||
def create_transformer(self, position, voltage, technology):
|
||||
# Crear transformador básico según características
|
||||
height = 2.0 + (voltage / 100000)
|
||||
radius = 0.5 + (voltage / 500000)
|
||||
|
||||
transformer = Part.makeCylinder(radius, height, FreeCAD.Vector(position))
|
||||
transformer_obj = FreeCAD.ActiveDocument.addObject("Part::Feature", "Transformer")
|
||||
transformer_obj.Shape = transformer
|
||||
transformer_obj.ViewObject.ShapeColor = (0.1, 0.1, 0.5) if 'oil' in technology.lower() else (0.5, 0.5, 0.5)
|
||||
return transformer_obj
|
||||
|
||||
def calculate_equipment_position(self, polygon_points, index, total, offset=0.0):
|
||||
"""Calcula posición equidistante alrededor del perímetro con offset"""
|
||||
perimeter = sum((p2 - p1).Length for p1, p2 in zip(polygon_points, polygon_points[1:]))
|
||||
target_dist = (perimeter / total) * index
|
||||
|
||||
accumulated = 0.0
|
||||
for i in range(len(polygon_points) - 1):
|
||||
p1 = polygon_points[i]
|
||||
p2 = polygon_points[i + 1]
|
||||
segment_length = (p2 - p1).Length
|
||||
if accumulated + segment_length >= target_dist:
|
||||
direction = (p2 - p1).normalize()
|
||||
return p1 + direction * (target_dist - accumulated) + direction.cross(FreeCAD.Vector(0, 0, 1)) * offset
|
||||
accumulated += segment_length
|
||||
return polygon_points[0]
|
||||
|
||||
def create_circuit_breaker_tower(self, position, voltage):
|
||||
"""Crea torre de seccionamiento especializada"""
|
||||
tower = Part.makeCompound([
|
||||
Part.makeCylinder(0.8, 12, position), # Poste principal
|
||||
Part.makeBox(3, 0.3, 0.3, position + FreeCAD.Vector(-1.5, -0.15, 12)), # Cruceta superior
|
||||
Part.makeBox(2.5, 0.3, 0.3, position + FreeCAD.Vector(-1.25, -0.15, 9)) # Cruceta media
|
||||
])
|
||||
tower_obj = FreeCAD.ActiveDocument.addObject("Part::Feature", "CircuitBreakerTower")
|
||||
tower_obj.Shape = tower
|
||||
tower_obj.ViewObject.ShapeColor = (0.1, 0.1, 0.1)
|
||||
tower_obj.addProperty("App::PropertyFloat", "Voltage", "Technical").Voltage = voltage
|
||||
return tower_obj
|
||||
|
||||
def calculate_tower_position(self, polygon_points):
|
||||
# Colocar torre en el punto medio del lado más largo
|
||||
# (Implementación compleja que requeriría cálculo geométrico)
|
||||
return FreeCAD.Vector(polygon_points[0].x, polygon_points[0].y, 0)
|
||||
|
||||
|
||||
def create_vegetation(self):
|
||||
vegetation_layer = self.create_layer("Vegetation")
|
||||
@@ -251,7 +555,7 @@ class OSMImporter:
|
||||
for node_id, coords in self.nodes.items():
|
||||
# Verificar si es un árbol
|
||||
# (Necesitarías procesar los tags de los nodos, implementación simplificada)
|
||||
cylinder = Part.makeCylinder(0.5, 5.0, FreeCAD.Vector(coords[0], coords[1], 0) * scale - self.Origin )
|
||||
cylinder = Part.makeCylinder(0.5, 5.0, FreeCAD.Vector(coords[0], coords[1], 0))# * scale - self.Origin )
|
||||
tree = FreeCAD.ActiveDocument.addObject("Part::Feature", "Tree")
|
||||
vegetation_layer.addObject(tree)
|
||||
tree.Shape = cylinder
|
||||
@@ -262,7 +566,7 @@ class OSMImporter:
|
||||
if 'natural' in data['tags'] or 'landuse' in data['tags']:
|
||||
nodes = [self.nodes[ref] for ref in data['nodes'] if ref in self.nodes]
|
||||
if len(nodes) > 2:
|
||||
polygon_points = [FreeCAD.Vector(n[0], n[1], 0) * scale - self.Origin for n in nodes]
|
||||
polygon_points = [n for n in nodes]
|
||||
polygon = Part.makePolygon(polygon_points)
|
||||
face = Part.Face(polygon)
|
||||
area = vegetation_layer.addObject("Part::Feature", "GreenArea")
|
||||
@@ -276,9 +580,10 @@ class OSMImporter:
|
||||
if 'natural' in data['tags'] and data['tags']['natural'] == 'water':
|
||||
nodes = [self.nodes[ref] for ref in data['nodes'] if ref in self.nodes]
|
||||
if len(nodes) > 2:
|
||||
polygon_points = [FreeCAD.Vector(n[0], n[1], 0) * scale - self.Origin for n in nodes]
|
||||
polygon_points = [n for n in nodes]
|
||||
polygon = Part.makePolygon(polygon_points)
|
||||
face = Part.Face(polygon)
|
||||
water = water_layer.addObject("Part::Feature", "WaterBody")
|
||||
water.Shape = face.extrude(FreeCAD.Vector(0, 0, 0.1) * scale - self.Origin )
|
||||
water.Shape = face.extrude(FreeCAD.Vector(0, 0, 0.1))# * scale - self.Origin )
|
||||
water.ViewObject.ShapeColor = self.feature_colors['water']
|
||||
|
||||
|
||||
111
Importer/module_inserter.py
Normal file
111
Importer/module_inserter.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import os
|
||||
import csv
|
||||
from PySide import QtGui, QtCore
|
||||
|
||||
|
||||
class SelectorDialog(QtGui.QDialog):
|
||||
def __init__(self, csv_path, title, parent=None):
|
||||
super(SelectorDialog, self).__init__(parent)
|
||||
self.setWindowTitle(title)
|
||||
self.csv_path = csv_path
|
||||
self.data = []
|
||||
self.brand_filter = ""
|
||||
self.model_filter = ""
|
||||
|
||||
# Cargar datos del CSV
|
||||
self.load_csv_data()
|
||||
|
||||
# Crear widgets
|
||||
self.create_widgets()
|
||||
self.create_layout()
|
||||
self.create_connections()
|
||||
|
||||
def load_csv_data(self):
|
||||
"""Carga los datos desde el archivo CSV"""
|
||||
if os.path.exists(self.csv_path):
|
||||
with open(self.csv_path, 'r') as f:
|
||||
reader = csv.DictReader(f, delimiter=';')
|
||||
self.data = [row for row in reader]
|
||||
|
||||
def get_unique_brands(self):
|
||||
"""Obtiene marcas únicas"""
|
||||
return list(set(row['Marca'] for row in self.data))
|
||||
|
||||
def get_models_by_brand(self, brand):
|
||||
"""Filtra modelos por marca"""
|
||||
return [row['Modelo'] for row in self.data if row['Marca'] == brand]
|
||||
|
||||
def create_widgets(self):
|
||||
self.lbl_brand = QtGui.QLabel("Marca:")
|
||||
self.cb_brand = QtGui.QComboBox()
|
||||
self.cb_brand.addItems(self.get_unique_brands())
|
||||
|
||||
self.lbl_model = QtGui.QLabel("Modelo:")
|
||||
self.cb_model = QtGui.QComboBox()
|
||||
self.update_model_combo()
|
||||
|
||||
self.btn_accept = QtGui.QPushButton("Aceptar")
|
||||
self.btn_cancel = QtGui.QPushButton("Cancelar")
|
||||
|
||||
def create_layout(self):
|
||||
layout = QtGui.QVBoxLayout()
|
||||
form_layout = QtGui.QFormLayout()
|
||||
form_layout.addRow(self.lbl_brand, self.cb_brand)
|
||||
form_layout.addRow(self.lbl_model, self.cb_model)
|
||||
|
||||
button_layout = QtGui.QHBoxLayout()
|
||||
button_layout.addWidget(self.btn_accept)
|
||||
button_layout.addWidget(self.btn_cancel)
|
||||
|
||||
layout.addLayout(form_layout)
|
||||
layout.addLayout(button_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
def create_connections(self):
|
||||
self.cb_brand.currentIndexChanged.connect(self.update_model_combo)
|
||||
self.btn_accept.clicked.connect(self.accept)
|
||||
self.btn_cancel.clicked.connect(self.reject)
|
||||
|
||||
def update_model_combo(self):
|
||||
brand = self.cb_brand.currentText()
|
||||
models = self.get_models_by_brand(brand)
|
||||
self.cb_model.clear()
|
||||
self.cb_model.addItems(models)
|
||||
|
||||
def get_selected_item(self):
|
||||
brand = self.cb_brand.currentText()
|
||||
model = self.cb_model.currentText()
|
||||
for row in self.data:
|
||||
if row['Marca'] == brand and row['Modelo'] == model:
|
||||
return row
|
||||
return None
|
||||
|
||||
|
||||
def select_modulo():
|
||||
csv_path = "/ruta/a/tu/databases/modulos.csv" # Ajusta esta ruta
|
||||
dialog = SelectorDialog(csv_path, "Seleccionar Módulo")
|
||||
if dialog.exec_():
|
||||
selected = dialog.get_selected_item()
|
||||
print("Módulo seleccionado:", selected) # Aquí puedes agregar la lógica de importación
|
||||
|
||||
|
||||
def select_inversor():
|
||||
csv_path = "/ruta/a/tu/databases/inversores.csv" # Ajusta esta ruta
|
||||
dialog = SelectorDialog(csv_path, "Seleccionar Inversor")
|
||||
if dialog.exec_():
|
||||
selected = dialog.get_selected_item()
|
||||
print("Inversor seleccionado:", selected) # Aquí puedes agregar la lógica de importación
|
||||
|
||||
|
||||
# Crear una barra de herramientas para acceder fácilmente
|
||||
toolbar = QtGui.QToolBar()
|
||||
select_modulo_action = QtGui.QAction("Seleccionar Módulo", toolbar)
|
||||
select_modulo_action.triggered.connect(select_modulo)
|
||||
toolbar.addAction(select_modulo_action)
|
||||
|
||||
select_inversor_action = QtGui.QAction("Seleccionar Inversor", toolbar)
|
||||
select_inversor_action.triggered.connect(select_inversor)
|
||||
toolbar.addAction(select_inversor_action)
|
||||
|
||||
# Agregar la barra de herramientas a FreeCAD
|
||||
Gui.addToolBar(toolbar)
|
||||
Reference in New Issue
Block a user