This commit is contained in:
2025-11-20 00:57:15 +01:00
parent 049898c939
commit d61260fdd3
10 changed files with 1704 additions and 520 deletions

View File

@@ -26,6 +26,9 @@ import PVPlantSite
import Utils.PVPlantUtils as utils
import MeshPart as mp
import pivy
from pivy import coin
if FreeCAD.GuiUp:
import FreeCADGui
from DraftTools import translate
@@ -361,12 +364,12 @@ class OffsetArea(_Area):
wire = utils.getProjected(base, vec)
wire = wire.makeOffset2D(obj.OffsetDistance.Value, 2, False, False, True)
sections = mp.projectShapeOnMesh(wire, land, vec)
print(" javi ", sections)
pts = []
for section in sections:
pts.extend(section)
# Crear forma solo si hay resultados
if sections:
if len(pts)>0:
obj.Shape = Part.makePolygon(pts)
else:
obj.Shape = Part.Shape() # Forma vacía si falla
@@ -412,35 +415,9 @@ class ProhibitedArea(OffsetArea):
self.Type = obj.Type = "ProhibitedArea"
obj.Proxy = self
'''# Propiedades de color
if not hasattr(obj, "OriginalColor"):
obj.addProperty("App::PropertyColor",
"OriginalColor",
"Display",
"Color for original wire")
obj.OriginalColor = (1.0, 0.0, 0.0) # Rojo
if not hasattr(obj, "OffsetColor"):
obj.addProperty("App::PropertyColor",
"OffsetColor",
"Display",
"Color for offset wire")
obj.OffsetColor = (1.0, 0.5, 0.0) # Naranja
# Propiedades de grosor
if not hasattr(obj, "OriginalWidth"):
obj.addProperty("App::PropertyFloat",
"OriginalWidth",
"Display",
"Line width for original wire")
obj.OriginalWidth = 4.0
if not hasattr(obj, "OffsetWidth"):
obj.addProperty("App::PropertyFloat",
"OffsetWidth",
"Display",
"Line width for offset wire")
obj.OffsetWidth = 4.0'''
def onDocumentRestored(self, obj):
"""Method run when the document is restored."""
self.setProperties(obj)
def execute(self, obj):
# Comprobar dependencias
@@ -482,121 +459,402 @@ class ProhibitedArea(OffsetArea):
obj.Shape = Part.Shape()
# Actualizar colores en la vista
if FreeCAD.GuiUp and obj.ViewObject:
obj.ViewObject.Proxy.updateVisual()
"""if FreeCAD.GuiUp and obj.ViewObject:
obj.ViewObject.Proxy.updateVisual()"""
class ViewProviderForbiddenArea(_ViewProviderArea):
class ViewProviderForbiddenArea_old:
def __init__(self, vobj):
super().__init__(vobj)
# Valores por defecto
self.original_color = (1.0, 0.0, 0.0) # Rojo
self.offset_color = (1.0, 0.5, 0.0) # Naranja
self.original_width = 4.0
self.offset_width = 4.0
self.line_widths = [] # Almacenará los grosores por arista
vobj.Proxy = self
self.setProperties(vobj)
vobj.LineColor = (1.0, 0.0, 0.0)
vobj.LineWidth = 4
vobj.PointColor = (1.0, 0.0, 0.0)
vobj.PointSize = 4
def setProperties(self, vobj):
# Propiedades de color
if not hasattr(vobj, "OriginalColor"):
vobj.addProperty("App::PropertyColor",
"OriginalColor",
"ObjectStyle",
"Color for original wire")
vobj.OriginalColor = (1.0, 0.0, 0.0) # Rojo
def getIcon(self):
''' Return object treeview icon. '''
return str(os.path.join(DirIcons, "area_forbidden.svg"))
if not hasattr(vobj, "OffsetColor"):
vobj.addProperty("App::PropertyColor",
"OffsetColor",
"ObjectStyle",
"Color for offset wire")
vobj.OffsetColor = (1.0, 0.0, 0.0) # Rojo
def claimChildren(self):
""" Provides object grouping """
children = []
if self.ViewObject and self.ViewObject.Object.Base:
children.append(self.ViewObject.Object.Base)
return children
# Propiedades de grosor
if not hasattr(vobj, "OriginalWidth"):
vobj.addProperty("App::PropertyFloat",
"OriginalWidth",
"ObjectStyle",
"Line width for original wire")
vobj.OriginalWidth = 4.0
if not hasattr(vobj, "OffsetWidth"):
vobj.addProperty("App::PropertyFloat",
"OffsetWidth",
"ObjectStyle",
"Line width for offset wire")
vobj.OffsetWidth = 4.0
# Deshabilitar el color por defecto
vobj.setPropertyStatus("LineColor", "Hidden")
vobj.setPropertyStatus("PointColor", "Hidden")
vobj.setPropertyStatus("ShapeAppearance", "Hidden")
def attach(self, vobj):
super().attach(vobj)
# Inicializar visualización
self.updateVisual()
self.ViewObject = vobj
self.Object = vobj.Object
def updateVisual(self):
"""Actualiza colores y grosores de línea"""
if not hasattr(self, 'ViewObject') or not self.ViewObject or not self.ViewObject.Object:
return
# Crear la estructura de escena Coin3D
self.root = coin.SoGroup()
obj = self.ViewObject.Object
# Switch para habilitar/deshabilitar la selección
self.switch = coin.SoSwitch()
self.switch.whichChild = coin.SO_SWITCH_ALL
# Obtener propiedades de color y grosor
try:
self.original_color = obj.OriginalColor
self.offset_color = obj.OffsetColor
self.original_width = obj.OriginalWidth
self.offset_width = obj.OffsetWidth
except:
pass
# Separador para el wire original
self.original_sep = coin.SoSeparator()
self.original_color = coin.SoBaseColor()
self.original_coords = coin.SoCoordinate3()
self.original_line_set = coin.SoLineSet()
self.original_draw_style = coin.SoDrawStyle()
# Actualizar colores si hay forma
if hasattr(obj, 'Shape') and obj.Shape and not obj.Shape.isNull():
if len(obj.Shape.SubShapes) >= 2:
# Asignar colores
colors = []
colors.append(self.original_color) # Primer wire (original)
colors.append(self.offset_color) # Segundo wire (offset)
self.ViewObject.DiffuseColor = colors
# Separador para el wire offset
self.offset_sep = coin.SoSeparator()
self.offset_color = coin.SoBaseColor()
self.offset_coords = coin.SoCoordinate3()
self.offset_line_set = coin.SoLineSet()
self.offset_draw_style = coin.SoDrawStyle()
# Preparar grosores por arista
#self.prepareLineWidths()
# Construir la jerarquía de escena
self.original_sep.addChild(self.original_color)
self.original_sep.addChild(self.original_draw_style)
self.original_sep.addChild(self.original_coords)
self.original_sep.addChild(self.original_line_set)
# Asignar grosores usando LineWidthArray
'''if self.line_widths:
self.ViewObject.LineWidthArray = self.line_widths'''
self.offset_sep.addChild(self.offset_color)
self.offset_sep.addChild(self.offset_draw_style)
self.offset_sep.addChild(self.offset_coords)
self.offset_sep.addChild(self.offset_line_set)
# Establecer grosor global como respaldo
#self.ViewObject.LineWidth = max(self.original_width, self.offset_width)
self.switch.addChild(self.original_sep)
self.switch.addChild(self.offset_sep)
self.root.addChild(self.switch)
def prepareLineWidths(self):
"""Prepara la lista de grosores para cada arista"""
self.line_widths = []
obj = self.ViewObject.Object
vobj.addDisplayMode(self.root, "Wireframe")
if hasattr(obj, 'Shape') and obj.Shape and not obj.Shape.isNull():
# Contar aristas en cada subforma
for i, subshape in enumerate(obj.Shape.SubShapes):
edge_count = len(subshape.Edges) if hasattr(subshape, 'Edges') else 1
# Inicializar estilos de dibujo
self.original_draw_style.style = coin.SoDrawStyle.LINES
self.offset_draw_style.style = coin.SoDrawStyle.LINES
# Determinar grosor según tipo de wire
width = self.original_width if i == 0 else self.offset_width
# Asignar el mismo grosor a todas las aristas de este wire
self.line_widths.extend([width] * edge_count)
def onChanged(self, vobj, prop):
"""Maneja cambios en propiedades de visualización"""
if prop in ["LineColor", "PointColor", "ShapeColor", "LineWidth"]:
# Actualizar visualización inicial
if hasattr(self.Object, 'Shape'):
self.updateData(self.Object, "Shape")
self.updateVisual()
def updateData(self, obj, prop):
"""Actualiza cuando cambian los datos del objeto"""
if prop == "Shape":
if prop == "Shape" and obj.Shape and not obj.Shape.isNull():
self.updateGeometry()
def updateGeometry(self):
"""Actualiza la geometría en la escena 3D"""
if not hasattr(self, 'Object') or not self.Object.Shape or self.Object.Shape.isNull():
return
# Limpiar coordenadas existentes
self.original_coords.point.deleteValues(0)
self.offset_coords.point.deleteValues(0)
# Obtener los sub-shapes
subshapes = []
if hasattr(self.Object.Shape, 'SubShapes') and self.Object.Shape.SubShapes:
subshapes = self.Object.Shape.SubShapes
elif hasattr(self.Object.Shape, 'ChildShapes') and self.Object.Shape.ChildShapes:
subshapes = self.Object.Shape.ChildShapes
# Procesar wire original (primer sub-shape)
if len(subshapes) > 0:
self.processShape(subshapes[0], self.original_coords, self.original_line_set)
# Procesar wire offset (segundo sub-shape)
if len(subshapes) > 1:
self.processShape(subshapes[1], self.offset_coords, self.offset_line_set)
# Actualizar colores y grosores
self.updateVisual()
def processShape(self, shape, coords_node, lineset_node):
"""Procesa una forma y la añade al nodo de coordenadas"""
if not shape or shape.isNull():
return
points = []
line_indices = []
current_index = 0
# Obtener todos los edges de la forma
edges = []
if hasattr(shape, 'Edges'):
edges = shape.Edges
elif hasattr(shape, 'ChildShapes'):
for child in shape.ChildShapes:
if hasattr(child, 'Edges'):
edges.extend(child.Edges)
for edge in edges:
try:
# Discretizar la curva para obtener puntos
vertices = edge.discretize(Number=50)
for i, vertex in enumerate(vertices):
points.append([vertex.x, vertex.y, vertex.z])
line_indices.append(current_index)
current_index += 1
# Añadir -1 para indicar fin de línea
line_indices.append(-1)
except Exception as e:
print(f"Error processing edge: {e}")
continue
# Configurar coordenadas y líneas
if points:
coords_node.point.setValues(0, len(points), points)
lineset_node.numVertices.deleteValues(0)
lineset_node.numVertices.setValues(0, len(line_indices), line_indices)
def updateVisual(self):
"""Actualiza colores y grosores según las propiedades"""
if not hasattr(self, 'ViewObject') or not self.ViewObject:
return
vobj = self.ViewObject
try:
# Configurar wire original
if hasattr(vobj, "OriginalColor"):
original_color = vobj.OriginalColor
self.original_color.rgb.setValue(original_color[0], original_color[1], original_color[2])
if hasattr(vobj, "OriginalWidth"):
self.original_draw_style.lineWidth = vobj.OriginalWidth
# Configurar wire offset
if hasattr(vobj, "OffsetColor"):
offset_color = vobj.OffsetColor
self.offset_color.rgb.setValue(offset_color[0], offset_color[1], offset_color[2])
if hasattr(vobj, "OffsetWidth"):
self.offset_draw_style.lineWidth = vobj.OffsetWidth
except Exception as e:
print(f"Error updating visual: {e}")
def onChanged(self, vobj, prop):
"""Maneja cambios en propiedades"""
if prop in ["OriginalColor", "OffsetColor", "OriginalWidth", "OffsetWidth"]:
self.updateVisual()
'''def __getstate__(self):
return {
"original_color": self.original_color,
"offset_color": self.offset_color,
"original_width": self.original_width,
"offset_width": self.offset_width
}
def getDisplayModes(self, obj):
return ["Wireframe"]
def getDefaultDisplayMode(self):
return "Wireframe"
def setDisplayMode(self, mode):
return mode
def claimChildren(self):
"""Proporciona agrupamiento de objetos"""
children = []
if hasattr(self, 'Object') and self.Object and hasattr(self.Object, "Base"):
children.append(self.Object.Base)
return children
def getIcon(self):
'''Return object treeview icon'''
return str(os.path.join(DirIcons, "area_forbidden.svg"))
def onDocumentRestored(self, vobj):
"""Método ejecutado cuando el documento es restaurado"""
self.ViewObject = vobj
self.Object = vobj.Object
self.setProperties(vobj)
self.attach(vobj)
def __getstate__(self):
return None
def __setstate__(self, state):
if "original_color" in state:
self.original_color = state["original_color"]
if "offset_color" in state:
self.offset_color = state["offset_color"]
if "original_width" in state:
self.original_width = state.get("original_width", 4.0)
if "offset_width" in state:
self.offset_width = state.get("offset_width", 4.0)'''
return None
class ViewProviderForbiddenArea:
def __init__(self, vobj):
vobj.Proxy = self
self.ViewObject = vobj
# Inicializar propiedades PRIMERO
self.setProperties(vobj)
# Configurar colores iniciales
self.updateColors(vobj)
def setProperties(self, vobj):
if not hasattr(vobj, "OriginalColor"):
vobj.addProperty("App::PropertyColor",
"OriginalColor",
"Display",
"Color for original wire")
vobj.OriginalColor = (1.0, 0.0, 0.0) # Rojo
if not hasattr(vobj, "OffsetColor"):
vobj.addProperty("App::PropertyColor",
"OffsetColor",
"Display",
"Color for offset wire")
vobj.OffsetColor = (1.0, 0.5, 0.0) # Naranja
def updateColors(self, vobj):
"""Actualiza los colores desde las propiedades"""
try:
if hasattr(vobj, "OriginalColor"):
self.original_color.rgb.setValue(*vobj.OriginalColor)
else:
self.original_color.rgb.setValue(1.0, 0.0, 0.0)
if hasattr(vobj, "OffsetColor"):
self.offset_color.rgb.setValue(*vobj.OffsetColor)
else:
self.offset_color.rgb.setValue(1.0, 0.5, 0.0)
except Exception as e:
print(f"Error en updateColors: {e}")
def onDocumentRestored(self, vobj):
self.setProperties(vobj)
# No llamar a __init__ de nuevo, solo actualizar propiedades
self.updateColors(vobj)
def getIcon(self):
return str(os.path.join(DirIcons, "area_forbidden.svg"))
def attach(self, vobj):
self.ViewObject = vobj
# Inicializar nodos Coin3D
self.root = coin.SoGroup()
self.original_coords = coin.SoCoordinate3()
self.offset_coords = coin.SoCoordinate3()
self.original_color = coin.SoBaseColor()
self.offset_color = coin.SoBaseColor()
self.original_lineset = coin.SoLineSet()
self.offset_lineset = coin.SoLineSet()
# Añadir un nodo de dibujo para establecer el estilo de línea
self.draw_style = coin.SoDrawStyle()
self.draw_style.style = coin.SoDrawStyle.LINES
self.draw_style.lineWidth = 3.0
# Construir la escena
self.root.addChild(self.draw_style)
# Grupo para el polígono original
original_group = coin.SoGroup()
original_group.addChild(self.original_color)
original_group.addChild(self.original_coords)
original_group.addChild(self.original_lineset)
# Grupo para el polígono offset
offset_group = coin.SoGroup()
offset_group.addChild(self.offset_color)
offset_group.addChild(self.offset_coords)
offset_group.addChild(self.offset_lineset)
self.root.addChild(original_group)
self.root.addChild(offset_group)
vobj.addDisplayMode(self.root, "Standard")
# Asegurar que la visibilidad esté activada
vobj.Visibility = True
def updateData(self, obj, prop):
if prop == "Shape":
self.updateVisual(obj)
def updateVisual(self, obj):
"""Actualiza la representación visual basada en la forma del objeto"""
if not hasattr(obj, 'Shape') or not obj.Shape or obj.Shape.isNull():
return
try:
# Obtener todos los bordes de la forma compuesta
all_edges = obj.Shape.Edges
# Separar bordes por polígono (asumimos que el primer polígono es el original)
# Esto es una simplificación - podrías necesitar una lógica más sofisticada
if len(all_edges) >= 2:
# Polígono original - primer conjunto de bordes
original_edges = [all_edges[0]]
original_points = []
for edge in original_edges:
for vertex in edge.Vertexes:
original_points.append((vertex.Point.x, vertex.Point.y, vertex.Point.z))
# Polígono offset - segundo conjunto de bordes
offset_edges = [all_edges[1]]
offset_points = []
for edge in offset_edges:
for vertex in edge.Vertexes:
offset_points.append((vertex.Point.x, vertex.Point.y, vertex.Point.z))
# Asignar puntos a los nodos Coordinate3
if original_points:
self.original_coords.point.setValues(0, len(original_points), original_points)
self.original_lineset.numVertices.setValue(len(original_points))
if offset_points:
self.offset_coords.point.setValues(0, len(offset_points), offset_points)
self.offset_lineset.numVertices.setValue(len(offset_points))
# Actualizar colores
if hasattr(obj, 'ViewObject') and obj.ViewObject:
self.updateColors(obj.ViewObject)
except Exception as e:
print(f"Error en updateVisual: {e}")
def onChanged(self, vobj, prop):
if prop in ["OriginalColor", "OffsetColor"]:
self.updateColors(vobj)
elif prop == "Visibility" and vobj.Visibility:
# Cuando la visibilidad cambia a True, actualizar visual
self.updateVisual(vobj.Object)
def getDisplayModes(self, obj):
return ["Standard"]
def getDefaultDisplayMode(self):
return "Standard"
def setDisplayMode(self, mode):
return mode
def claimChildren(self):
children = []
if hasattr(self, 'ViewObject') and self.ViewObject and hasattr(self.ViewObject.Object, 'Base'):
children.append(self.ViewObject.Object.Base)
return children
def dumps(self):
return None
def loads(self, state):
return None
''' PV Area: '''
def makePVSubplant():
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "PVSubplant")