new code
This commit is contained in:
@@ -29,6 +29,15 @@ import Part
|
||||
import numpy
|
||||
import os
|
||||
|
||||
from xml.etree.ElementTree import Element, SubElement
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
import datetime
|
||||
from xml.dom import minidom
|
||||
|
||||
from numpy.matrixlib.defmatrix import matrix
|
||||
|
||||
from Utils import PVPlantUtils as utils
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
@@ -63,6 +72,11 @@ def check_collada():
|
||||
FreeCAD.Console.PrintError(translate("PVPlant", "pycollada no encontrado, soporte Collada desactivado.") + "\n")
|
||||
return COLLADA_AVAILABLE
|
||||
|
||||
# Asegurar que el texto es Unicode válido
|
||||
def safe_text(text):
|
||||
if isinstance(text, bytes):
|
||||
return text.decode('utf-8', errors='replace')
|
||||
return text
|
||||
|
||||
# from ARCH:
|
||||
def triangulate(shape):
|
||||
@@ -249,7 +263,306 @@ def export(exportList, filename, tessellation=1, colors=None):
|
||||
FreeCAD.Console.PrintMessage(translate("Arch", "file %s successfully created.") % filename)
|
||||
|
||||
|
||||
def exportToPVC(path, exportTerrain = False):
|
||||
def exportToPVC(path, exportTerrain=False):
|
||||
filename = f"{path}.pvc"
|
||||
|
||||
# 1. Validación inicial de objetos esenciales
|
||||
site = None
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
if obj.Name.startswith("Site") and hasattr(obj, 'Terrain'):
|
||||
site = obj
|
||||
break
|
||||
|
||||
if not site:
|
||||
FreeCAD.Console.PrintError("No se encontró objeto 'Site' válido\n")
|
||||
return False
|
||||
|
||||
# 2. Configuración de metadatos y autor
|
||||
generated_on = str(datetime.datetime.now())
|
||||
|
||||
try:
|
||||
author = FreeCAD.ActiveDocument.CreatedBy
|
||||
except (AttributeError, UnicodeEncodeError):
|
||||
author = "Unknown"
|
||||
|
||||
author = author.replace("<", "").replace(">", "")
|
||||
ver = FreeCAD.Version()
|
||||
appli = f"PVPlant for FreeCAD {ver[0]}.{ver[1]} build{ver[2]}"
|
||||
|
||||
# 3. Creación estructura XML base
|
||||
root = Element('COLLADA')
|
||||
root.set('xmlns', 'http://www.collada.org/2005/11/COLLADASchema')
|
||||
root.set('version', '1.4.1')
|
||||
|
||||
# 4. Sección <asset>
|
||||
asset = SubElement(root, 'asset')
|
||||
contrib = SubElement(asset, 'contributor')
|
||||
SubElement(contrib, 'author').text = safe_text(author)
|
||||
SubElement(contrib, 'authoring_tool').text = safe_text(appli)
|
||||
SubElement(asset, 'created').text = generated_on
|
||||
SubElement(asset, 'modified').text = generated_on
|
||||
SubElement(asset, 'title').text = safe_text(FreeCAD.ActiveDocument.Name)
|
||||
unit = SubElement(asset, 'unit')
|
||||
unit.set('name', 'meter')
|
||||
unit.set('meter', '1')
|
||||
|
||||
# 5. Materiales y efectos
|
||||
materials = ["Frames", "Tree_trunk", "Tree_crown", "Topography_mesh"]
|
||||
|
||||
# Library materials
|
||||
lib_materials = SubElement(root, 'library_materials')
|
||||
for i, name in enumerate(materials):
|
||||
mat = SubElement(lib_materials, 'material')
|
||||
mat.set('id', f'Material{i}')
|
||||
mat.set('name', name)
|
||||
SubElement(mat, 'instance_effect').set('url', f'#Material{i}-fx')
|
||||
|
||||
# Library effects
|
||||
lib_effects = SubElement(root, 'library_effects')
|
||||
for i, _ in enumerate(materials):
|
||||
effect = SubElement(lib_effects, 'effect')
|
||||
effect.set('id', f'Material{i}-fx')
|
||||
effect.set('name', f'Material{i}')
|
||||
profile = SubElement(effect, 'profile_COMMON')
|
||||
technique = SubElement(profile, 'technique')
|
||||
technique.set('sid', 'standard')
|
||||
lambert = SubElement(technique, 'lambert')
|
||||
|
||||
# Componentes del material
|
||||
color = SubElement(SubElement(lambert, 'emission'), 'color')
|
||||
color.set('sid', 'emission')
|
||||
color.text = '0.000000 0.000000 0.000000 1.000000'
|
||||
color = SubElement(SubElement(lambert, 'ambient'), 'color')
|
||||
color.set('sid', 'ambient')
|
||||
color.text = '0.200000 0.200000 0.200000 1.000000'
|
||||
color = SubElement(SubElement(lambert, 'diffuse'), 'color')
|
||||
color.set('sid', 'diffuse')
|
||||
color.text = '0.250000 0.500000 0.000000 1.000000'
|
||||
transparent = SubElement(lambert, 'transparent')
|
||||
transparent.set('opaque', 'RGB_ZERO')
|
||||
color = SubElement(transparent, 'color')
|
||||
color.set('sid', 'transparent')
|
||||
color.text = '0.000000 0.000000 0.000000 1.000000'
|
||||
value = SubElement(SubElement(lambert, 'transparency'), 'float')
|
||||
value.set('sid', 'transparency')
|
||||
value.text = '0.000000'
|
||||
|
||||
# 6. Geometrías
|
||||
lib_geometries = SubElement(root, 'library_geometries')
|
||||
|
||||
# 7. Escena visual
|
||||
lib_visual = SubElement(root, 'library_visual_scenes')
|
||||
visual_scene = SubElement(lib_visual, 'visual_scene')
|
||||
visual_scene.set('id', 'Scene') # cambiar a visual_scene_0
|
||||
visual_scene.set('name', 'Scene') # cambiar a Default visual scene
|
||||
|
||||
scene_node = SubElement(visual_scene, 'node')
|
||||
scene_node.set('id', 'node_0_id')
|
||||
scene_node.set('name', 'node_0_name')
|
||||
scene_node.set('sid', 'node_0_sid')
|
||||
|
||||
scene_matrix = SubElement(scene_node, 'matrix')
|
||||
scene_matrix.set('sid', 'matrix_0')
|
||||
scene_matrix.text = '1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000'
|
||||
|
||||
root_node = SubElement(scene_node, 'node')
|
||||
root_node.set('id', 'node_1_id')
|
||||
root_node.set('name', 'node_1_name')
|
||||
root_node.set('sid', 'node_1_sid')
|
||||
|
||||
# 8. Función para procesar geometrías
|
||||
def create_geometry(name, vindex, findex, material_id, objind=0, frame_data=None, isTracker = False, axis_line=None):
|
||||
"""Crea elementos COLLADA para una geometría"""
|
||||
# Source (vertices)
|
||||
source_mesh = SubElement(geom, 'mesh')
|
||||
source = SubElement(source_mesh, 'source')
|
||||
source.set('id', f'{name}-mesh_source')
|
||||
float_array = SubElement(source, 'float_array')
|
||||
float_array.set('id', f'{name}-float_array')
|
||||
float_array.set('count', str(len(vindex)))
|
||||
float_array.text = ' '.join(f'{v:.6f}' for v in vindex)
|
||||
|
||||
technique = SubElement(source, 'technique_common')
|
||||
accessor = SubElement(technique, 'accessor')
|
||||
accessor.set('count', str(len(vindex)))
|
||||
accessor.set('source', f'#{name}-float_array')
|
||||
accessor.set('stride', '3')
|
||||
for ax in ['X', 'Y', 'Z']:
|
||||
param = SubElement(accessor, 'param')
|
||||
param.set('name', ax)
|
||||
param.set('type', 'float')
|
||||
|
||||
# Vertices
|
||||
vertices = SubElement(source_mesh, 'vertices')
|
||||
vertices.set('id', f'{name}-vertices_source')
|
||||
vertices = SubElement(vertices, 'input')
|
||||
vertices.set('semantic', 'POSITION')
|
||||
vertices.set('source', f'#{name}-mesh_source')
|
||||
|
||||
# Triangles
|
||||
triangles = SubElement(source_mesh, 'triangles')
|
||||
triangles.set('count', '0')
|
||||
triangles.set('material', f'Material{material_id}')
|
||||
triangles_input = SubElement(triangles, 'input')
|
||||
triangles_input.set('offset', '0')
|
||||
triangles_input.set('semantic', 'VERTEX')
|
||||
triangles_input.set('source', f'#{name}-vertices_source')
|
||||
|
||||
p = SubElement(triangles, 'p')
|
||||
p.text = ' '.join(map(str, findex))
|
||||
|
||||
# Parámetros especiales para estructuras
|
||||
|
||||
frame_params = SubElement(source_mesh, 'tracker_parameters')
|
||||
if frame_data:
|
||||
for key, val in frame_data.items():
|
||||
elem = SubElement(frame_params, key)
|
||||
elem.text = str(val)
|
||||
|
||||
if isTracker:
|
||||
axis_parameter = SubElement(frame_params, 'axis_vertices')
|
||||
if axis_line:
|
||||
for idx, vert in enumerate(axis_line):
|
||||
array = SubElement(axis_parameter, 'float_array')
|
||||
array.set('id', f'{name}-axis_float_array{idx}')
|
||||
array.set('count', '3')
|
||||
array.text = ' '.join(f'{v:.6f}' for v in vert)
|
||||
|
||||
# 9. Procesar estructuras (frames/trackers)
|
||||
center = FreeCAD.Vector()
|
||||
if site.Terrain:
|
||||
center = site.Terrain.Mesh.BoundBox.Center
|
||||
|
||||
objind = 0
|
||||
for frame_type in site.Frames:
|
||||
is_tracker = "tracker" in frame_type.Proxy.Type.lower()
|
||||
|
||||
modules = frame_type.Shape.SubShapes[0].SubShapes[0]
|
||||
pts = []
|
||||
for i in range(4):
|
||||
pts.append(modules.BoundBox.getPoint(i))
|
||||
|
||||
new_shape = Part.Face(Part.makePolygon(pts))
|
||||
mesh = Mesh.Mesh(triangulate(new_shape))
|
||||
axis = Part.makeLine(FreeCAD.Vector(modules.BoundBox.XMin, 0, modules.BoundBox.ZMax),
|
||||
FreeCAD.Vector(modules.BoundBox.XMax, 0, modules.BoundBox.ZMax))
|
||||
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
if hasattr(obj, "Setup") and obj.Setup == frame_type:
|
||||
# Procesar geometría
|
||||
mesh.Placement = obj.getGlobalPlacement()
|
||||
axis.Placement = obj.getGlobalPlacement()
|
||||
|
||||
# Transformar vértices
|
||||
vindex = []
|
||||
for point in mesh.Points:
|
||||
adjusted = (point.Vector - center) * scale
|
||||
vindex.extend([
|
||||
-adjusted.x,
|
||||
adjusted.z,
|
||||
adjusted.y
|
||||
])
|
||||
|
||||
# Índices de caras
|
||||
findex = []
|
||||
for facet in mesh.Facets:
|
||||
findex.extend(facet.PointIndices)
|
||||
|
||||
# AXIS
|
||||
# TODO: revisar si es así:
|
||||
vaxis = []
|
||||
for vert in axis.Vertexes:
|
||||
adjusted = (vert.Point - center) * scale
|
||||
vaxis.append([
|
||||
-adjusted.x,
|
||||
adjusted.z,
|
||||
adjusted.y
|
||||
])
|
||||
|
||||
# Crear geometría COLLADA
|
||||
geom = SubElement(lib_geometries, 'geometry')
|
||||
geom.set('id', f'Frame_{objind}')
|
||||
|
||||
# Parámetros específicos de estructura
|
||||
frame_data = {
|
||||
'module_width': obj.Setup.ModuleWidth.Value,
|
||||
'module_height': obj.Setup.ModuleHeight.Value,
|
||||
'module_x_spacing': obj.Setup.ModuleColGap.Value,
|
||||
'module_y_spacing': obj.Setup.ModuleRowGap.Value,
|
||||
'module_name': 'Generic'
|
||||
}
|
||||
|
||||
if is_tracker:
|
||||
frame_data.update({
|
||||
'tracker_type': 'single_axis_trackers',
|
||||
'min_phi': obj.Setup.MinPhi.Value,
|
||||
'max_phi': obj.Setup.MaxPhi.Value,
|
||||
'min_theta': 0,
|
||||
'max_theta': 0
|
||||
})
|
||||
|
||||
create_geometry(
|
||||
name=f'Frame_{objind}',
|
||||
vindex=vindex,
|
||||
findex=findex,
|
||||
material_id=0,
|
||||
objind=objind,
|
||||
frame_data=frame_data,
|
||||
isTracker = is_tracker,
|
||||
axis_line=vaxis
|
||||
)
|
||||
|
||||
# Instancia en escena
|
||||
instance = SubElement(root_node, 'instance_geometry')
|
||||
instance.set('url', f'#Frame_{objind}')
|
||||
|
||||
bind_material = SubElement(instance, 'bind_material')
|
||||
technique_common = SubElement(bind_material, 'technique_common')
|
||||
instance_material = SubElement(technique_common, 'instance_material')
|
||||
instance_material.set('symbol', 'Material0')
|
||||
instance_material.set('target', '#Material0')
|
||||
|
||||
objind += 1
|
||||
|
||||
# 10. Procesar terreno si está habilitado
|
||||
if exportTerrain and site.Terrain:
|
||||
mesh = site.Terrain.Mesh
|
||||
vindex = []
|
||||
for point in mesh.Points:
|
||||
point = point.Vector
|
||||
vindex.extend([
|
||||
-point.x * SCALE,
|
||||
point.z * SCALE,
|
||||
point.y * SCALE
|
||||
])
|
||||
|
||||
findex = []
|
||||
for facet in mesh.Facets:
|
||||
findex.extend(facet.PointIndices)
|
||||
|
||||
geom = SubElement(lib_geometries, 'geometry')
|
||||
geom.set('id', 'Terrain')
|
||||
create_geometry('Terrain', vindex, findex, material_id=3)
|
||||
|
||||
instance = SubElement(root_node, 'instance_geometry')
|
||||
instance.set('url', '#Terrain')
|
||||
|
||||
# 11. Escena principal
|
||||
scene = SubElement(root, 'scene')
|
||||
SubElement(scene, 'instance_visual_scene').set('url', '#Scene')
|
||||
|
||||
# 12. Exportar a archivo
|
||||
xml_str = minidom.parseString(
|
||||
ElementTree.tostring(root, encoding='utf-8')
|
||||
).toprettyxml(indent=" ")
|
||||
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
f.write(xml_str)
|
||||
|
||||
FreeCAD.Console.PrintMessage(f"Archivo PVC generado: {filename}\n")
|
||||
return True
|
||||
|
||||
def exportToPVC_old(path, exportTerrain = False):
|
||||
filename = f"{path}.pvc"
|
||||
|
||||
from xml.etree.ElementTree import Element, SubElement
|
||||
@@ -291,17 +604,18 @@ def exportToPVC(path, exportTerrain = False):
|
||||
|
||||
# xml: 1. Asset:
|
||||
asset = SubElement(root, 'asset')
|
||||
|
||||
asset_contributor = SubElement(asset, 'contributor')
|
||||
asset_contributor_autor = SubElement(asset_contributor, 'autor')
|
||||
#asset_contributor_autor.text = author
|
||||
asset_contributor_autor = SubElement(asset_contributor, 'author')
|
||||
asset_contributor_autor.text = author
|
||||
asset_contributor_authoring_tool = SubElement(asset_contributor, 'authoring_tool')
|
||||
#asset_contributor_authoring_tool.text = appli
|
||||
asset_contributor_authoring_tool.text = appli
|
||||
asset_contributor_comments = SubElement(asset_contributor, 'comments')
|
||||
asset_keywords = SubElement(asset, 'keywords')
|
||||
asset_revision = SubElement(asset, 'revision')
|
||||
asset_subject = SubElement(asset, 'subject')
|
||||
asset_tittle = SubElement(asset, 'title')
|
||||
#asset_tittle.text = FreeCAD.ActiveDocument.Name
|
||||
asset_tittle.text = FreeCAD.ActiveDocument.Name
|
||||
asset_unit = SubElement(asset, 'unit')
|
||||
asset_unit.set('meter', '0.001')
|
||||
asset_unit.set('name', 'millimeter')
|
||||
@@ -359,7 +673,6 @@ def exportToPVC(path, exportTerrain = False):
|
||||
# xml: 4. library_geometries:
|
||||
library_geometries = SubElement(root, 'library_geometries')
|
||||
def add_geometry(objtype, vindex, findex, objind = 0, centers = None):
|
||||
|
||||
isFrame = False
|
||||
if objtype == 0:
|
||||
geometryName = 'Frame'
|
||||
@@ -505,36 +818,20 @@ def exportToPVC(path, exportTerrain = False):
|
||||
end_time.text = '1.000000'
|
||||
|
||||
# xml: 6. scene:
|
||||
scene = SubElement(root, 'scene')
|
||||
'''scene = SubElement(root, 'scene')
|
||||
instance = SubElement(scene, 'instance_visual_scene')
|
||||
instance.set('url', '#')
|
||||
|
||||
full_list_of_objects = FreeCAD.ActiveDocument.Objects
|
||||
instance.set('url', '#')'''
|
||||
|
||||
# CASO 1 - FRAMES:
|
||||
frameType = site.Frames
|
||||
frame_setup = {"type": [],
|
||||
"footprint": []}
|
||||
for obj in frameType:
|
||||
frame_setup["type"] = obj
|
||||
frame_setup["footprint"] = ""
|
||||
|
||||
objind = 0
|
||||
|
||||
# TODO: revisar
|
||||
for typ in frameType:
|
||||
isTracker = "tracker" in typ.Proxy.Type.lower()
|
||||
isTracker = False
|
||||
|
||||
objectlist = FreeCAD.ActiveDocument.findObjects(Name="Tracker")
|
||||
tmp = []
|
||||
for obj in objectlist:
|
||||
if obj.Name.startswith("TrackerSetup"):
|
||||
continue
|
||||
else:
|
||||
tmp.append(obj)
|
||||
objectlist = tmp.copy()
|
||||
#isTracker = False
|
||||
|
||||
objectlist = utils.findObjects("Tracker")
|
||||
for obj in objectlist:
|
||||
if obj.Setup == typ:
|
||||
findex = numpy.array([])
|
||||
@@ -580,7 +877,6 @@ def exportToPVC(path, exportTerrain = False):
|
||||
v = Topology[0][i]
|
||||
vindex[list(range(i * 3, i * 3 + 3))] = (-(v.x - center.x) * scale, (v.z - center.z) * scale,
|
||||
(v.y - center.y) * scale)
|
||||
|
||||
# 2. face indices
|
||||
findex = numpy.empty(len(Topology[1]) * 3, numpy.int64)
|
||||
for i in range(len(Topology[1])):
|
||||
|
||||
Reference in New Issue
Block a user