primera subida
This commit is contained in:
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
8
.idea/PVPlant.iml
generated
Normal file
8
.idea/PVPlant.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N802" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.10" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/PVPlant.iml" filepath="$PROJECT_DIR$/.idea/PVPlant.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
201
Civil/Trench/TrenchOperators.py
Normal file
201
Civil/Trench/TrenchOperators.py
Normal file
@@ -0,0 +1,201 @@
|
||||
|
||||
def getcenter(lEdges, r):
|
||||
import math
|
||||
rndEdges = lEdges[0:2]
|
||||
rndEdges = Part.__sortEdges__(rndEdges)
|
||||
|
||||
lVertexes = rndEdges[0].Vertexes + [rndEdges[1].Vertexes[-1]]
|
||||
U1 = lVertexes[0].Point.sub(lVertexes[1].Point)
|
||||
U1.normalize()
|
||||
U2 = lVertexes[2].Point.sub(lVertexes[1].Point)
|
||||
U2.normalize()
|
||||
|
||||
alpha = U1.getAngle(U2)
|
||||
# Edges have same direction
|
||||
'''if (round(alpha, 0) == 0) or (round(alpha - math.pi, 0) == 0):
|
||||
pt1 = FreeCAD.Vector(U1)
|
||||
x = pt1.x
|
||||
pt1.x = pt1.y
|
||||
pt1.y = -x
|
||||
return rndEdges
|
||||
pointsDirection = lineSelected.discretize(Number=500) # discretize the path line first selection
|
||||
v = pointsDirection[0].sub(pointsDirection[1]) # avec vecteurs 1 et 2 (direction debut ligne)
|
||||
r = App.Rotation(App.Vector(0, 0, 1), v)'''
|
||||
|
||||
dToCenter = r / math.sin(alpha / 2.0)
|
||||
# dToTangent = (dToCenter ** 2 - r ** 2) ** 0.5
|
||||
dirVect = U2.add(U1)
|
||||
dirVect.normalize()
|
||||
dirVect.scale(dToCenter, dToCenter, dToCenter)
|
||||
pt1 = lVertexes[1].Point.add(dirVect)
|
||||
pt2 = -1 * pt1
|
||||
pt2.z = pt1.z
|
||||
print(pt1, " - ", pt2)
|
||||
return [pt1, pt2]
|
||||
|
||||
# from DRAFT
|
||||
def split_wire(wire, newPoint, edgeIndex):
|
||||
import Draft
|
||||
wire1Points = []
|
||||
wire2Points = []
|
||||
print("New Point: ", newPoint)
|
||||
print("edgeIndex: ", edgeIndex)
|
||||
for index, point in enumerate(wire.Points):
|
||||
print("index: ", index, " - point: ", point)
|
||||
if index == edgeIndex:
|
||||
wire1Points.append(point)
|
||||
wire1Points.append(wire.Placement.inverse().multVec(newPoint))
|
||||
wire2Points.append(newPoint)
|
||||
# wire2Points.append(wire.Placement.multVec(point))
|
||||
elif index < edgeIndex:
|
||||
wire1Points.append(point)
|
||||
elif index > edgeIndex:
|
||||
wire2Points.append(wire.Placement.multVec(point))
|
||||
if len(wire1Points) == 1:
|
||||
wire1Points.insert(0, wire.Points[0])
|
||||
if len(wire2Points) == 1:
|
||||
wire2Points.appen(wire.Points[-1])
|
||||
wire.Points = wire1Points
|
||||
wire2 = Draft.makeWire(wire2Points, placement=wire.Placement)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
wires = [wire, wire2]
|
||||
return sorted(wires, key=lambda obj: obj.Length, reverse=True)
|
||||
|
||||
|
||||
def SplitTrench(trench, point):
|
||||
if not trench or not point:
|
||||
return None
|
||||
|
||||
import Part
|
||||
wire = trench.Base
|
||||
vertex = Part.Vertex(point)
|
||||
|
||||
'''Find the minimum distance to another shape:
|
||||
|
||||
- distToShape(shape) -> (dist, vectors, infos) dist is the minimum distance, in mm (float value).
|
||||
vectors is a list of pairs of App.Vector. Each pair corresponds to solution.
|
||||
|
||||
Example:
|
||||
[(Vector (2.0, -1.0, 2.0), Vector (2.0, 0.0, 2.0)), (Vector (2.0,-1.0, 2.0), Vector (2.0, -1.0, 3.0))]
|
||||
- First vector is a point on self, second vector is a point on s.
|
||||
infos contains additional info on the solutions. It is a list of tuples: (topo1, index1, params1, topo2, index2, params2)
|
||||
- topo1, topo2 are strings identifying type of BREP element: 'Vertex', 'Edge', or 'Face'.
|
||||
- index1, index2 are indexes of the elements (zero-based).
|
||||
- params1, params2 are parameters of internal space of the elements. For vertices, params is None.
|
||||
For edges, params is one float, u. For faces, params is a tuple (u,v).
|
||||
(719762.0578530617,
|
||||
[(Vector (225057.375, 783988.625, 715062.875), Vector (306961.4605149741, 778138.3688035253, 0.0))],
|
||||
[('Vertex', 0, None, 'Edge', 0, 79697.52668425611)])
|
||||
'''
|
||||
|
||||
(dist, vectors, infos) = vertex.distToShape(wire.Shape)
|
||||
if not dist:
|
||||
return None
|
||||
|
||||
Location = FreeCAD.Vector(vectors[0][1])
|
||||
if not Location:
|
||||
return None
|
||||
|
||||
Normal = None
|
||||
edind = 0
|
||||
if infos[0][3] == 'Vertex':
|
||||
vec = Location.sub(point)
|
||||
Normal = FreeCAD.Vector(vec[1], -vec[0], vec[2])
|
||||
edind = int(infos[0][4]) - 1
|
||||
elif infos[0][3] == 'Edge':
|
||||
ed = wire.Shape.Edges[int(dist[2][0][4])]
|
||||
Normal = ed.Vertexes[1].Point.sub(ed.Vertexes[0].Point)
|
||||
edind = int(infos[0][4])
|
||||
|
||||
wires = split_wire(wire, Location, edind)
|
||||
trench.Base = wires[0]
|
||||
trench1 = makeTrench(wire[1])
|
||||
return Location, [trench, trench1], node
|
||||
|
||||
def JoinTrench(trench1, trench2):
|
||||
if not trench1 or not trench2:
|
||||
return None
|
||||
|
||||
|
||||
class CommandSplitTrench: # V1:
|
||||
"""Gui command for the Line tool."""
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "trench.svg")),
|
||||
'MenuText': "Trench",
|
||||
'Accel': "C, T",
|
||||
'ToolTip': "Creates a Trench object from setup dialog."}
|
||||
|
||||
def IsActive(self):
|
||||
return (not (FreeCAD.ActiveDocument is None) and
|
||||
not (FreeCAD.ActiveDocument.getObject("Trench") is None))
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
done = False
|
||||
|
||||
if len(sel) > 0:
|
||||
import Draft
|
||||
for obj in sel:
|
||||
if Draft.getType(obj) == "Wire":
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Trench")
|
||||
makeTrench(obj)
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
done = True
|
||||
break
|
||||
|
||||
if not done:
|
||||
taskd = TrenchTaskPanel()
|
||||
if taskd:
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
else:
|
||||
print(" No ha sido posible crear el formulario")
|
||||
|
||||
|
||||
class CommandJoinTrench: # V1:
|
||||
"""Gui command for the Line tool."""
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "trenchsplit.svg")),
|
||||
'MenuText': "Semi-Automatic Trench Generator",
|
||||
'Accel': "T, S",
|
||||
'ToolTip': "Creates a Trench object from setup dialog."}
|
||||
|
||||
def IsActive(self):
|
||||
return (not (FreeCAD.ActiveDocument is None) and
|
||||
not (FreeCAD.ActiveDocument.getObject("Trench") is None))
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
semi = semiAutomaticTrench()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandTrenchGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['PVPlantSplitTrench',
|
||||
'PVPlantJoinTrench',
|
||||
])
|
||||
|
||||
def GetResources(self):
|
||||
return {'MenuText': 'Trench operations',
|
||||
'ToolTip': 'Trench operations'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
active = not (FreeCAD.ActiveDocument is None)
|
||||
terrain = not (FreeCAD.ActiveDocument.getObject("Terrain") is None)
|
||||
active = active and terrain
|
||||
if terrain:
|
||||
active = active and not (FreeCAD.ActiveDocument.getObject("Terrain").Mesh is None)
|
||||
return active
|
||||
|
||||
FreeCADGui.addCommand('PVPlantTrench', CommandTrench())
|
||||
FreeCADGui.addCommand('PVPlantSemiAutomaticTrench', CommandSemiAutomaticTrench())
|
||||
FreeCADGui.addCommand('Trenches', CommandTrenchGroup())
|
||||
23
CompositeListWidgetExample/CompositeListWidgetExample.pro
Normal file
23
CompositeListWidgetExample/CompositeListWidgetExample.pro
Normal file
@@ -0,0 +1,23 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2016-04-12T20:54:56
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = CompositeListWidgetExample
|
||||
TEMPLATE = app
|
||||
|
||||
|
||||
SOURCES += main.cpp\
|
||||
qmainwidget.cpp \
|
||||
thewidgetitem.cpp
|
||||
|
||||
HEADERS += qmainwidget.h \
|
||||
thewidgetitem.h
|
||||
|
||||
FORMS += qmainwidget.ui \
|
||||
thewidgetitem.ui
|
||||
5
CompositeListWidgetExample/README.md
Normal file
5
CompositeListWidgetExample/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Composite List Widget Example [Quick Qt 3]
|
||||
|
||||

|
||||
|
||||
|
||||
10
CompositeListWidgetExample/main.cpp
Normal file
10
CompositeListWidgetExample/main.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "qmainwidget.h"
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
QMainWidget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
38
CompositeListWidgetExample/qmainwidget.cpp
Normal file
38
CompositeListWidgetExample/qmainwidget.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "qmainwidget.h"
|
||||
#include "ui_qmainwidget.h"
|
||||
|
||||
QMainWidget::QMainWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::QMainWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
QMainWidget::~QMainWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void QMainWidget::on_addBtn_clicked()
|
||||
{
|
||||
//Creating a new list widget item whose parent is the listwidget itself
|
||||
QListWidgetItem *listWidgetItem = new QListWidgetItem(ui->listWidget);
|
||||
|
||||
//Adding the item to the listwidget
|
||||
ui->listWidget->addItem (listWidgetItem);
|
||||
|
||||
//Creating an object of the designed widget which is to be added to the listwidget
|
||||
TheWidgetItem *theWidgetItem = new TheWidgetItem;
|
||||
|
||||
//Making sure that the listWidgetItem has the same size as the TheWidgetItem
|
||||
listWidgetItem->setSizeHint (theWidgetItem->sizeHint ());
|
||||
|
||||
//Finally adding the itemWidget to the list
|
||||
ui->listWidget->setItemWidget (listWidgetItem, theWidgetItem);
|
||||
}
|
||||
|
||||
void QMainWidget::on_delBtn_clicked()
|
||||
{
|
||||
//Delete selected item from the listWidget
|
||||
delete ui->listWidget->currentItem ();
|
||||
}
|
||||
34
CompositeListWidgetExample/qmainwidget.h
Normal file
34
CompositeListWidgetExample/qmainwidget.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef QMAINWIDGET_H
|
||||
#define QMAINWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QListWidget>
|
||||
#include <QListWidgetItem>
|
||||
#include "thewidgetitem.h"
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
|
||||
namespace Ui {
|
||||
class QMainWidget;
|
||||
}
|
||||
|
||||
class QMainWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QMainWidget(QWidget *parent = 0);
|
||||
~QMainWidget();
|
||||
|
||||
QVector <TheWidgetItem*> itemVec;
|
||||
|
||||
private slots:
|
||||
void on_addBtn_clicked();
|
||||
|
||||
void on_delBtn_clicked();
|
||||
|
||||
private:
|
||||
Ui::QMainWidget *ui;
|
||||
};
|
||||
|
||||
#endif // QMAINWIDGET_H
|
||||
47
CompositeListWidgetExample/qmainwidget.ui
Normal file
47
CompositeListWidgetExample/qmainwidget.ui
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QMainWidget</class>
|
||||
<widget class="QWidget" name="QMainWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>459</width>
|
||||
<height>329</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QMainWidget</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addBtn">
|
||||
<property name="text">
|
||||
<string>Add Widget Item</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="delBtn">
|
||||
<property name="text">
|
||||
<string>Delete Selected Item</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
26
CompositeListWidgetExample/thewidgetitem.cpp
Normal file
26
CompositeListWidgetExample/thewidgetitem.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "thewidgetitem.h"
|
||||
#include "ui_thewidgetitem.h"
|
||||
|
||||
TheWidgetItem::TheWidgetItem(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::TheWidgetItem)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
TheWidgetItem::~TheWidgetItem()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TheWidgetItem::on_pressThisBtn_clicked()
|
||||
{
|
||||
//Getting text from lineEdit and setting it to the label
|
||||
ui->label->setText (ui->lineEdit->text ());
|
||||
}
|
||||
|
||||
void TheWidgetItem::on_horizontalSlider_valueChanged(int value)
|
||||
{
|
||||
//Connecting slider with the progressbar
|
||||
ui->progressBar->setValue (value);
|
||||
}
|
||||
32
CompositeListWidgetExample/thewidgetitem.h
Normal file
32
CompositeListWidgetExample/thewidgetitem.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef THEWIDGETITEM_H
|
||||
#define THEWIDGETITEM_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSlider>
|
||||
#include <QProgressBar>
|
||||
#include <QLabel>
|
||||
|
||||
namespace Ui {
|
||||
class TheWidgetItem;
|
||||
}
|
||||
|
||||
class TheWidgetItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TheWidgetItem(QWidget *parent = 0);
|
||||
~TheWidgetItem();
|
||||
|
||||
private slots:
|
||||
void on_pressThisBtn_clicked();
|
||||
|
||||
void on_horizontalSlider_valueChanged(int value);
|
||||
|
||||
private:
|
||||
Ui::TheWidgetItem *ui;
|
||||
};
|
||||
|
||||
#endif // THEWIDGETITEM_H
|
||||
71
CompositeListWidgetExample/thewidgetitem.ui
Normal file
71
CompositeListWidgetExample/thewidgetitem.ui
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TheWidgetItem</class>
|
||||
<widget class="QWidget" name="TheWidgetItem">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>363</width>
|
||||
<height>83</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Write something</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pressThisBtn">
|
||||
<property name="text">
|
||||
<string>Press this</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Text from lineEdit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="horizontalSlider">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
6
DEM/importLidar.py
Normal file
6
DEM/importLidar.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import numpy as np
|
||||
import laspy as lpinput_path="gdrive/My Drive/10-MEDIUM/DATA/Point Cloud Sample/"
|
||||
dataname="NZ19_Wellington.las"point_cloud=lp.file.File(input_path+dataname+".las", mode="r")
|
||||
|
||||
points = np.vstack((point_cloud.x, point_cloud.y, point_cloud.z)).transpose()
|
||||
colors = np.vstack((point_cloud.red, point_cloud.green, point_cloud.blue)).transpose()
|
||||
103
DataImport.ui
Normal file
103
DataImport.ui
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formDataImport</class>
|
||||
<widget class="QWidget" name="formDataImport">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>497</width>
|
||||
<height>396</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Importar datos desde:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioInternet">
|
||||
<property name="text">
|
||||
<string>Importar nube desde Google</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioFile">
|
||||
<property name="text">
|
||||
<string>Nube de puntos desde archivo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_3">
|
||||
<property name="text">
|
||||
<string>RadioButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Archivo:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Archivo:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_4"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonSel">
|
||||
<property name="text">
|
||||
<string>Sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
333
Electrical/Cable/PVPlantCable.py
Normal file
333
Electrical/Cable/PVPlantCable.py
Normal file
@@ -0,0 +1,333 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 ArchComponent
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
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
|
||||
|
||||
import PVPlantResources
|
||||
|
||||
|
||||
def makeCable(base = None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Cable")
|
||||
Cable(obj)
|
||||
ViewProviderCable(obj.ViewObject)
|
||||
if base:
|
||||
obj.Base = base
|
||||
return obj
|
||||
|
||||
class Cable(ArchComponent.Component):
|
||||
"A Base Frame Obcject - Class"
|
||||
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
# General:
|
||||
if not ("Manufacturer" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Manufacturer",
|
||||
"General",
|
||||
"Connection")
|
||||
|
||||
if not ("Factory" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Factory",
|
||||
"General",
|
||||
"Connection ")
|
||||
|
||||
if not ("DesignStandard" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"DesignStandard",
|
||||
"General",
|
||||
"Connection ")
|
||||
|
||||
if not ("CableDesignation" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"CableDesignation",
|
||||
"General",
|
||||
"Connection ").CableDesignation="RH5Z1-OL"
|
||||
|
||||
if not ("MaximumVoltage" in pl):
|
||||
obj.addProperty("App::PropertyElectricPotential",
|
||||
"MaximumVoltage",
|
||||
"General",
|
||||
"Connection ").MaximumVoltage="30kV"
|
||||
|
||||
if not ("MaxTemperatureForContinuousOperation" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"MaxTemperatureForContinuousOperation",
|
||||
"General",
|
||||
"Connection ").MaxTemperatureForContinuousOperation=95
|
||||
|
||||
if not ("MaxTemperatureDuringEmergencyConditions" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"MaxTemperatureDuringEmergencyConditions",
|
||||
"General",
|
||||
"Connection ").MaxTemperatureDuringEmergencyConditions=105
|
||||
|
||||
if not ("MaxTemperatureDuringShortCircuit" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"MaxTemperatureDuringShortCircuit",
|
||||
"General",
|
||||
"Connection ").MaxTemperatureDuringShortCircuit=250
|
||||
|
||||
|
||||
# Conductor:
|
||||
if not ("Material" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"Material",
|
||||
"Conductor",
|
||||
"Connection ").Material=["Copper", "Aluminium"]
|
||||
|
||||
if not ("Standard" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Standard",
|
||||
"Conductor",
|
||||
"Connection ").Standard = "IEC 60228"
|
||||
|
||||
if not ("CrossSection" in pl):
|
||||
obj.addProperty("App::PropertyArea",
|
||||
"CrossSection",
|
||||
"Conductor",
|
||||
"Connection ").CrossSection = 95
|
||||
|
||||
if not ("MaximumConductorDiameter" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"MaximumConductorDiameter",
|
||||
"Conductor",
|
||||
"Connection ")
|
||||
|
||||
if not ("MinimumConductorDiameter" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"MinimumConductorDiameter",
|
||||
"Conductor",
|
||||
"Connection ")
|
||||
|
||||
if not ("MaximumResistance" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"MaximumResistance",
|
||||
"Conductor",
|
||||
"Connection ")
|
||||
|
||||
# Insulation:
|
||||
if not ("InsulationMaterial" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"InsulationMaterial",
|
||||
"Insulation",
|
||||
"Connection ").InsulationMaterial=["HEPR", "XLPE"]
|
||||
|
||||
if not ("InsulationStandard" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"InsulationStandard",
|
||||
"Insulation",
|
||||
"Connection ").InsulationStandard = "IEC 60502-2"
|
||||
|
||||
if not ("InsulationNominalThickness" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"InsulationNominalThickness",
|
||||
"Insulation",
|
||||
"Sección").InsulationNominalThickness = 7.25
|
||||
|
||||
if not ("InsulationMinimumThickness" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"InsulationMinimumThickness",
|
||||
"Insulation",
|
||||
"Sección").InsulationMinimumThickness = 6.43
|
||||
|
||||
if not ("InsulationResistance" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"InsulationResistance",
|
||||
"Insulation",
|
||||
"Sección").InsulationResistance = 3670000
|
||||
|
||||
# Outer semi-conductive layer:
|
||||
if not ("OuterMaterial" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"OuterMaterial",
|
||||
"OuterLayer",
|
||||
"Connection ").OuterMaterial = "Semicon. compound"
|
||||
|
||||
if not ("OuterNominalThickness" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"OuterNominalThickness",
|
||||
"OuterLayer",
|
||||
"Sección").OuterNominalThickness = 0.5
|
||||
|
||||
if not ("OuterMinimumThickness" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"OuterMinimumThickness",
|
||||
"OuterLayer",
|
||||
"Sección").OuterMinimumThickness = 0.5
|
||||
|
||||
# algo
|
||||
if not ("ExternalDiameter" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"ExternalDiameter",
|
||||
"Cable",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Diameter")).ExternalDiameter = 6.6
|
||||
|
||||
if not ("Section" in pl):
|
||||
obj.addProperty("App::PropertyArea",
|
||||
"Section",
|
||||
"Cable",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Sección"))
|
||||
|
||||
if not ("Core" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"Core",
|
||||
"Cable",
|
||||
"Core").Core = ["1", "2", "3", ]
|
||||
|
||||
if not ("RadiusOfCurvature" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"RadiusOfCurvature",
|
||||
"Cable",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Diameter")).RadiusOfCurvature = 100
|
||||
|
||||
self.Type = "Cable"
|
||||
|
||||
obj.Proxy = self
|
||||
obj.IfcType = "Cable Segment"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and object properties."""
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
obj.Proxy = self
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
''' Do something when a property has changed '''
|
||||
|
||||
def getPoint(self, val):
|
||||
if val.Proxy.Type == 'String':
|
||||
return val.StringPoles[0]
|
||||
elif val.Proxy.Type == 'StringBox':
|
||||
input = val.Shape.SubShapes[2].SubShapes[0]
|
||||
return input.CenterOfMass
|
||||
else:
|
||||
return val.Placement.Base
|
||||
|
||||
def execute(self, obj):
|
||||
import Part, DraftGeomUtils
|
||||
import Draft
|
||||
|
||||
if obj.Base:
|
||||
w = obj.Base.Shape.SubShapes[1].SubShapes[0]
|
||||
w = DraftGeomUtils.filletWire(w, 150)
|
||||
else:
|
||||
return
|
||||
|
||||
"""if obj.Base:
|
||||
# Si tiene ruta, dibujar ruteado
|
||||
import PVPlantTrench as trench
|
||||
if isinstance(obj.Base, trench.Trench):
|
||||
w = obj.Base.Shape.SubShapes[0]
|
||||
else:
|
||||
w = obj.Base.Shape
|
||||
elif obj.From and obj.Name:
|
||||
'''line = Part.LineSegment()
|
||||
line.StartPoint = getPoint(obj.From)
|
||||
line.EndPoint = getPoint(obj.To)
|
||||
w = Part.Wire(line.toShape())'''
|
||||
w = Part.makePolygon([self.getPoint(obj.From), self.getPoint(obj.To)])
|
||||
else:
|
||||
return"""
|
||||
|
||||
r = obj.ExternalDiameter.Value / 2
|
||||
p = Part.Wire([Part.Circle(FreeCAD.Vector(0, 0, 0),
|
||||
FreeCAD.Vector(0, 1, 0),
|
||||
r).toShape()])
|
||||
c = obj.Offset
|
||||
c.x -= r
|
||||
c.z += r
|
||||
v1 = w.Vertexes[1].Point - w.Vertexes[0].Point
|
||||
v2 = DraftGeomUtils.getNormal(p)
|
||||
p.Placement.Base = w.Vertexes[0].Point + c
|
||||
p.Placement.Rotation = FreeCAD.Rotation(v2, v1)
|
||||
|
||||
obj.Shape = w.makePipeShell([p], True, False, 0)
|
||||
obj.Distance = w.Length
|
||||
|
||||
|
||||
class ViewProviderCable(ArchComponent.ViewProviderComponent):
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(PVPlantResources.DirIcons, "cable.svg"))
|
||||
|
||||
|
||||
class CommandCable:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "cable.svg")),
|
||||
'Accel': "E, C",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "Cable"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Calcular el BOQ de la")}
|
||||
|
||||
def Activated(self):
|
||||
import Draft
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
wire = None
|
||||
for obj in sel:
|
||||
if Draft.getType(obj) == "Wire":
|
||||
wire = obj
|
||||
break
|
||||
|
||||
makeCable(wire)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantCable', CommandCable())
|
||||
308
Electrical/Cable/PVPlantElectricalLine.py
Normal file
308
Electrical/Cable/PVPlantElectricalLine.py
Normal file
@@ -0,0 +1,308 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 ArchComponent
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
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
|
||||
|
||||
import PVPlantResources
|
||||
__dir__ = os.path.join(PVPlantResources.__dir__, "Electrical", "Cable")
|
||||
|
||||
|
||||
def makeElectricalLine(base = None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "ElectricalLine")
|
||||
ElectricalLine(obj)
|
||||
ViewProviderElectricalLine(obj.ViewObject)
|
||||
if base:
|
||||
obj.Base = base
|
||||
|
||||
'''try:
|
||||
folder = FreeCAD.ActiveDocument.Trenches
|
||||
except:
|
||||
folder = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Trenches')
|
||||
folder.Label = "Trenches"
|
||||
folder.addObject(obj)'''
|
||||
return obj
|
||||
|
||||
|
||||
class ElectricalLine(ArchComponent.Component):
|
||||
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("Paths" in pl):
|
||||
obj.addProperty("App::PropertyLinkSubList",
|
||||
"Paths",
|
||||
"General",
|
||||
"Connection")
|
||||
|
||||
if not ("offset" in pl):
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"offset",
|
||||
"General",
|
||||
"Connection")
|
||||
|
||||
if not ("From" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"From",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection "))
|
||||
|
||||
if not ("To" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"To",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection "))
|
||||
|
||||
if not ("Cable" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Cable",
|
||||
"Line",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection "))
|
||||
|
||||
if not ("Phases" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"Phases",
|
||||
"Line",
|
||||
"Connection").Phases = ["2", "3"]
|
||||
obj.Phases = "3"
|
||||
|
||||
if not ("LineType" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"LineType",
|
||||
"Line",
|
||||
"Connection").LineType = ["AC", "DC"]
|
||||
|
||||
if not ("Setup" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"Setup",
|
||||
"Line",
|
||||
"Connection").Setup = ["Trifoil", "Parallel"]
|
||||
|
||||
obj.Proxy = self
|
||||
obj.IfcType = "Cable Segment"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and object properties."""
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def updateOutputProperties(self, obj):
|
||||
''' '''
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
if prop == "Cable":
|
||||
''' '''
|
||||
if hasattr(obj.Cable, "Proxy") and (obj.Cable.Proxy.Type == "Cable"):
|
||||
''' '''
|
||||
else:
|
||||
obj.Cable = None
|
||||
|
||||
if prop == "LineType":
|
||||
obj.Phases = "2" if obj.LineType == "DC" else "3"
|
||||
obj.setEditorMode("Phases", obj.LineType == "DC")
|
||||
self.updateOutputProperties(self, obj)
|
||||
|
||||
def execute(self, obj):
|
||||
import Part, DraftGeomUtils
|
||||
|
||||
w = self.generatePath(obj)
|
||||
if (not w) and (not obj.Cable):
|
||||
return
|
||||
|
||||
r = obj.Cable.ExternalDiameter.Value / 2
|
||||
sh = Part.makeCompound([])
|
||||
cnt = int(obj.Phases)
|
||||
if obj.Phases == "3" and obj.Setup == "Parallel":
|
||||
offsets = [FreeCAD.Vector(-2 * r, 0, r),
|
||||
FreeCAD.Vector(2 * r, 0, r),
|
||||
FreeCAD.Vector(0, 0, r)]
|
||||
else:
|
||||
offsets = [FreeCAD.Vector(-r, 0, r),
|
||||
FreeCAD.Vector(r, 0, r),
|
||||
FreeCAD.Vector(0, 0, r * (1 + 3 ** 0.5))]
|
||||
|
||||
for i in range(cnt):
|
||||
ph = Part.Wire([Part.Circle(offsets[i] + obj.offset,
|
||||
FreeCAD.Vector(0, 1, 0),
|
||||
r).toShape()])
|
||||
v1 = w.Vertexes[1].Point - w.Vertexes[0].Point
|
||||
if v1.y < 0:
|
||||
v1 = -v1
|
||||
v2 = DraftGeomUtils.getNormal(ph)
|
||||
ph.Placement.Base = w.Vertexes[0].Point
|
||||
ph.Placement.Rotation = FreeCAD.Rotation(v2, v1)
|
||||
sh.add(w.makePipeShell([ph, ], True, False, 0))
|
||||
|
||||
obj.Shape = sh
|
||||
|
||||
def generatePath(self, obj):
|
||||
import Utils.PVPlantFillets as fillets
|
||||
|
||||
result = None
|
||||
# 1. sort
|
||||
if not obj.Base:
|
||||
return None
|
||||
|
||||
print(obj.Paths)
|
||||
|
||||
w = obj.Base.Shape.SubShapes[1].SubShapes[0]
|
||||
w = fillets.filletWire(w, obj.Cable.RadiusOfCurvature)
|
||||
return w
|
||||
|
||||
|
||||
class ViewProviderElectricalLine(ArchComponent.ViewProviderComponent):
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
self.Object = None
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
''' Create Object visuals in 3D view. '''
|
||||
self.Object = vobj.Object
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(PVPlantResources.DirIcons, "electricalline.png"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Cable:
|
||||
children.append(self.Object.Cable)
|
||||
return children
|
||||
|
||||
|
||||
class ElectricalLineTaskPanel:
|
||||
def __init__(self, obj=None):
|
||||
self.new = False
|
||||
self.selection = None
|
||||
self.selectionViewObject = None
|
||||
self.obj = obj
|
||||
|
||||
if obj is None:
|
||||
self.new = True
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(__dir__, "PVPlantElectricalLine.ui"))
|
||||
'''self.form.buttonAddLayer.clicked.connect(self.addLayer)
|
||||
self.form.buttonDeleteLayer.clicked.connect(self.removeLayer)
|
||||
self.form.buttonUp.clicked.connect(self.moveUp)
|
||||
self.form.buttonDown.clicked.connect(self.moveDown)'''
|
||||
|
||||
|
||||
#self.observer = SelectionObserver.SelObserver()
|
||||
FreeCADGui.Selection.addObserver(self)
|
||||
|
||||
def addSelection(self, document, object, element, position): # Selection
|
||||
''' '''
|
||||
obj = FreeCAD.getDocument(document).getObject(object)
|
||||
if hasattr(obj, "Proxy"):
|
||||
if obj.Proxy.Type == "Trench":
|
||||
self.selection = obj
|
||||
self.selectionViewObject = obj.ViewObject.DisplayMode
|
||||
obj.ViewObject.DisplayMode = "Wireframe"
|
||||
self.TrechDialog = FreeCADGui.PySideUic.loadUi(os.path.join(__dir__, "PVPlantElectricalLineDialog.ui"))
|
||||
self.TrechDialog.labelTitle.setText(obj.Name)
|
||||
self.TrechDialog.spinBox.setMaximum(obj.Cables)
|
||||
self.TrechDialog.buttonAccept.clicked.connect(self.addTrenchRoute)
|
||||
self.TrechDialog.show()
|
||||
|
||||
def clearSelection(self, doc):
|
||||
''' '''
|
||||
if self.selectionViewObject:
|
||||
self.selection.ViewObject.DisplayMode = self.selectionViewObject
|
||||
self.selectionViewObject = None
|
||||
pass
|
||||
|
||||
def addTrenchRoute(self):
|
||||
val = self.TrechDialog.spinBox.value
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
self.TrechDialog.close()
|
||||
|
||||
def accept(self):
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Electrical Line")
|
||||
makeElectricalLine()
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
self.closeForm()
|
||||
return False
|
||||
|
||||
def closeForm(self):
|
||||
FreeCADGui.Selection.removeObserver(self)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
|
||||
class CommandElectricalLine:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "electricalline.png")),
|
||||
'Accel': "E, L",
|
||||
'MenuText': "Línea eléctrica",
|
||||
'ToolTip': "Crea una línea electríca en AC o DC.\n Selecciona la configuración de cable."}
|
||||
|
||||
def Activated(self):
|
||||
TaskPanel = ElectricalLineTaskPanel()
|
||||
FreeCADGui.Control.showDialog(TaskPanel)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
active = not (FreeCAD.ActiveDocument is None)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlanElectricalLine', CommandElectricalLine())
|
||||
|
||||
218
Electrical/Cable/PVPlantElectricalLine.ui
Normal file
218
Electrical/Cable/PVPlantElectricalLine.ui
Normal file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>332</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Dimensions</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Heigth (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Largura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
71
Electrical/Cable/PVPlantElectricalLineDialog.ui
Normal file
71
Electrical/Cable/PVPlantElectricalLineDialog.ui
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formTrechPathSelector</class>
|
||||
<widget class="QDialog" name="formTrechPathSelector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>178</width>
|
||||
<height>79</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Seleccionar ruta</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="labelTitle">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(180, 180, 180);
|
||||
border-color: rgb(129, 129, 129);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spinBox">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="buttonAccept">
|
||||
<property name="text">
|
||||
<string>Aceptar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
373
Electrical/CombinerBox/PVPlantStringBox.py
Normal file
373
Electrical/CombinerBox/PVPlantStringBox.py
Normal file
@@ -0,0 +1,373 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 ArchComponent
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
from PySide import QtCore
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
from pivy import coin
|
||||
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
|
||||
|
||||
import PVPlantResources
|
||||
|
||||
def makeStringbox():
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "StringBox")
|
||||
_StringBox(obj)
|
||||
_ViewProviderStringBox(obj.ViewObject)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
#FreeCADGui.ActiveDocument.ActiveView.fitAll()
|
||||
return obj
|
||||
|
||||
class _StringBox(ArchComponent.Component):
|
||||
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.obj = obj
|
||||
self.setProperties(obj)
|
||||
self.Type = "StringBox"
|
||||
|
||||
# Does a IfcType exist?
|
||||
obj.IfcType = "Electric Distribution Board"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
# obj.MoveWithHost = False
|
||||
|
||||
def setProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
'''[
|
||||
'App::PropertyBool',
|
||||
'App::PropertyBoolList',
|
||||
'App::PropertyFloat',
|
||||
'App::PropertyFloatList',
|
||||
'App::PropertyFloatConstraint',
|
||||
'App::PropertyPrecision',
|
||||
'App::PropertyQuantity',
|
||||
'App::PropertyQuantityConstraint',
|
||||
'App::PropertyAngle',
|
||||
'App::PropertyDistance',
|
||||
'App::PropertyLength',
|
||||
'App::PropertyArea',
|
||||
'App::PropertyVolume',
|
||||
'App::PropertyFrequency',
|
||||
'App::PropertySpeed',
|
||||
'App::PropertyAcceleration',
|
||||
'App::PropertyForce',
|
||||
'App::PropertyPressure',
|
||||
'App::PropertyVacuumPermittivity',
|
||||
'App::PropertyInteger',
|
||||
'App::PropertyIntegerConstraint',
|
||||
'App::PropertyPercent',
|
||||
'App::PropertyEnumeration',
|
||||
'App::PropertyIntegerList',
|
||||
'App::PropertyIntegerSet',
|
||||
'App::PropertyMap',
|
||||
'App::PropertyString',
|
||||
'App::PropertyPersistentObject',
|
||||
'App::PropertyUUID',
|
||||
'App::PropertyFont',
|
||||
'App::PropertyStringList',
|
||||
'App::PropertyLink',
|
||||
'App::PropertyLinkChild',
|
||||
'App::PropertyLinkGlobal',
|
||||
'App::PropertyLinkHidden',
|
||||
'App::PropertyLinkSub',
|
||||
'App::PropertyLinkSubChild',
|
||||
'App::PropertyLinkSubGlobal',
|
||||
'App::PropertyLinkSubHidden',
|
||||
'App::PropertyLinkList',
|
||||
'App::PropertyLinkListChild',
|
||||
'App::PropertyLinkListGlobal',
|
||||
'App::PropertyLinkListHidden',
|
||||
'App::PropertyLinkSubList',
|
||||
'App::PropertyLinkSubListChild',
|
||||
'App::PropertyLinkSubListGlobal',
|
||||
'App::PropertyLinkSubListHidden',
|
||||
'App::PropertyXLink',
|
||||
'App::PropertyXLinkSub',
|
||||
'App::PropertyXLinkSubList',
|
||||
'App::PropertyXLinkList',
|
||||
'App::PropertyMatrix',
|
||||
'App::PropertyVector',
|
||||
'App::PropertyVectorDistance',
|
||||
'App::PropertyPosition',
|
||||
'App::PropertyDirection',
|
||||
'App::PropertyVectorList',
|
||||
'App::PropertyPlacement',
|
||||
'App::PropertyPlacementList',
|
||||
'App::PropertyPlacementLink',
|
||||
'App::PropertyColor',
|
||||
'App::PropertyColorList',
|
||||
'App::PropertyMaterial',
|
||||
'App::PropertyMaterialList',
|
||||
'App::PropertyPath',
|
||||
'App::PropertyFile',
|
||||
'App::PropertyFileIncluded',
|
||||
'App::PropertyPythonObject',
|
||||
'App::PropertyExpressionEngine',
|
||||
'Part::PropertyPartShape',
|
||||
'Part::PropertyGeometryList',
|
||||
'Part::PropertyShapeHistory',
|
||||
'Part::PropertyFilletEdges',
|
||||
'Mesh::PropertyNormalList',
|
||||
'Mesh::PropertyCurvatureList',
|
||||
'Mesh::PropertyMeshKernel',
|
||||
'Sketcher::PropertyConstraintList'
|
||||
]'''
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "InputsFromStrings" in pl:
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"InputsFromStrings",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection ")).InputsFromStrings = 12
|
||||
|
||||
if not ("PositiveInputs" in pl):
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"PositiveInputs",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).PositiveInputs = []
|
||||
obj.setEditorMode("PositiveInputs", 1)
|
||||
|
||||
if not ("NegativeInputs" in pl):
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"NegativeInputs",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).NegativeInputs = []
|
||||
obj.setEditorMode("NegativeInputs", 1)
|
||||
|
||||
if not "InputCables" in pl:
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"InputCables",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "InputCables"))
|
||||
|
||||
# Outputs
|
||||
'''
|
||||
if not "Outputs" in pl:
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"Outputs",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Outputs = 1
|
||||
'''
|
||||
|
||||
if not ("PositiveOut" in pl):
|
||||
obj.addProperty("Part::PropertyPartShape",
|
||||
"PositiveOut",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
)
|
||||
obj.setEditorMode("PositiveOut", 1)
|
||||
|
||||
if not ("NegativeOut" in pl):
|
||||
obj.addProperty("Part::PropertyPartShape",
|
||||
"NegativeOut",
|
||||
"Connections",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
)
|
||||
obj.setEditorMode("NegativeOut", 1)
|
||||
|
||||
# Size:
|
||||
if not "Width" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Width",
|
||||
"Box",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Width = 330
|
||||
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Box",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Length = 848
|
||||
|
||||
if not "Height" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Height",
|
||||
"Box",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Height = 615
|
||||
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and Arch wall properties."""
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
obj.Proxy = self
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
if prop == "InputsFromStrings":
|
||||
for i in range(int(obj.getPropertyByName(prop).Value)):
|
||||
obj.removeProperty("PositiveInput" + str(i+1))
|
||||
obj.removeProperty("NegativeInput" + str(i + 1))
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
# obj.Shape: compound
|
||||
# |- body: compound
|
||||
# |-- body: solid
|
||||
# |-- door: solid
|
||||
# |-- inputs: solids
|
||||
# |-- outputs: solids
|
||||
# |- inputs references: compound
|
||||
# |-- positives: compound
|
||||
# |--- positive: point of vertex
|
||||
|
||||
solids = []
|
||||
pts = []
|
||||
|
||||
def getdownFace(object):
|
||||
downface = object.Faces[0]
|
||||
for face in object.Faces:
|
||||
if face.CenterOfMass.z < downface.CenterOfMass.z:
|
||||
downface = face
|
||||
return downface
|
||||
|
||||
def drawInputs(numrows, offsetx, type, cpd):
|
||||
numInputs = int(obj.InputsFromStrings.Value)
|
||||
nperrow = int(round(numInputs / numrows, 0))
|
||||
gap = 45
|
||||
diameter = 20
|
||||
points = []
|
||||
cnt = 0
|
||||
for r in range(numrows):
|
||||
xx = -obj.Length.Value / 2 + offsetx + gap / 2 * (r % 2)
|
||||
yy = -diameter + gap * r
|
||||
for i in range(min(numInputs, nperrow)):
|
||||
cyl = Part.makeCylinder(10, 20, FreeCAD.Vector(xx + gap * i, yy, -20))
|
||||
solids.append(cyl)
|
||||
points.append(getdownFace(cyl).CenterOfMass)
|
||||
cnt += 1
|
||||
inname = ("PositiveIn" if type == 0 else "NegativeIn") + str(cnt)
|
||||
obj.addProperty("Part::PropertyPartShape",
|
||||
inname,
|
||||
"Inputs",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
)
|
||||
obj.setEditorMode(inname, 1)
|
||||
setattr(obj, inname, getdownFace(cyl))
|
||||
cpd.add(cyl)
|
||||
numInputs -= nperrow
|
||||
return points
|
||||
|
||||
box = Part.makeBox(obj.Length.Value, obj.Width.Value, obj.Height.Value)
|
||||
box.Placement.Base.x -= obj.Length.Value / 2
|
||||
box.Placement.Base.y -= obj.Width.Value / 2
|
||||
|
||||
# Output:
|
||||
cpd_out = Part.makeCompound([])
|
||||
outp = Part.makeCylinder(65/2, 20, FreeCAD.Vector(0, 0, -20))
|
||||
#out.Placement.Base.x += 50
|
||||
#out.Placement.Base.y += 65/2
|
||||
solids.append(outp)
|
||||
cpd_out.add(outp)
|
||||
obj.PositiveOut = getdownFace(outp)
|
||||
|
||||
outn = outp.copy()
|
||||
outn.Placement.Base.x += 65 + 10
|
||||
solids.append(outn)
|
||||
cpd_out.add(outn)
|
||||
obj.NegativeOut = getdownFace(outn)
|
||||
|
||||
# Inputs:
|
||||
cpd_Pos_Inputs = Part.makeCompound([])
|
||||
cpd_Neg_Inputs = Part.makeCompound([])
|
||||
obj.PositiveInputs = drawInputs(2, 80, 0, cpd_Pos_Inputs).copy()
|
||||
obj.NegativeInputs = drawInputs(4, 650, 1, cpd_Neg_Inputs).copy()
|
||||
|
||||
pts.append(getdownFace(box).CenterOfMass)
|
||||
pts.append(getdownFace(outn).CenterOfMass)
|
||||
pts.append(getdownFace(outp).CenterOfMass)
|
||||
|
||||
obj.Shape = Part.makeCompound([box, cpd_out, cpd_Pos_Inputs, cpd_Neg_Inputs])
|
||||
|
||||
class _ViewProviderStringBox(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(PVPlantResources.DirIcons, "StringBox.svg"))
|
||||
|
||||
def attach(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
sep = coin.SoSeparator()
|
||||
self.coords = coin.SoCoordinate3()
|
||||
sep.addChild(self.coords)
|
||||
self.coords.point.deleteValues(0)
|
||||
symbol = coin.SoMarkerSet()
|
||||
symbol.markerIndex = FreeCADGui.getMarkerIndex("", 5)
|
||||
sep.addChild(symbol)
|
||||
rn = vobj.RootNode
|
||||
rn.addChild(sep)
|
||||
ArchComponent.ViewProviderComponent.attach(self, vobj)
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
|
||||
if prop == "PositiveInputs":
|
||||
if obj.PositiveInputs:
|
||||
self.coords.point.setNum(len(obj.PositiveInputs))
|
||||
self.coords.point.setValues([[p.x, p.y, p.z] for p in obj.PositiveInputs])
|
||||
else:
|
||||
self.coords.point.deleteValues(0)
|
||||
|
||||
|
||||
class _CommandBoxEnclosure:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "StringBox.svg")),
|
||||
'Accel': "C, E",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "Movimiento de tierras"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Calcular el movimiento de tierras")}
|
||||
|
||||
def Activated(self):
|
||||
makeStringbox()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantStringBox', _CommandBoxEnclosure())
|
||||
550
Electrical/Conduit.py
Normal file
550
Electrical/Conduit.py
Normal file
@@ -0,0 +1,550 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2016 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* 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 ArchComponent
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from draftutils.translate import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
## @package ArchPipe
|
||||
# \ingroup ARCH
|
||||
# \brief The Pipe object and tools
|
||||
#
|
||||
# This module provides tools to build Pipe and Pipe connector objects.
|
||||
# Pipes are tubular objects extruded along a base line.
|
||||
|
||||
__title__ = "Arch Pipe tools"
|
||||
__author__ = "Yorik van Havre"
|
||||
__url__ = "https://www.freecadweb.org"
|
||||
|
||||
|
||||
def makePipe(baseobj=None, diameter=0, length=0, placement=None, name="Pipe"):
|
||||
|
||||
"makePipe([baseobj,diamerter,length,placement,name]): creates an pipe object from the given base object"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
obj= FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
|
||||
obj.Label = name
|
||||
Pipe(obj)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
ViewProviderPipe(obj.ViewObject)
|
||||
if baseobj:
|
||||
baseobj.ViewObject.hide()
|
||||
|
||||
if baseobj:
|
||||
obj.Base = baseobj
|
||||
else:
|
||||
if length:
|
||||
obj.Length = length
|
||||
|
||||
if diameter:
|
||||
obj.Diameter = diameter
|
||||
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
|
||||
return obj
|
||||
|
||||
def makePipeConnector(pipes,radius=0,name="Connector"):
|
||||
|
||||
"makePipeConnector(pipes,[radius,name]): creates a connector between the given pipes"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
obj= FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
|
||||
obj.Label = name
|
||||
_ArchPipeConnector(obj)
|
||||
obj.Pipes = pipes
|
||||
if not radius:
|
||||
radius = pipes[0].Diameter
|
||||
obj.Radius = radius
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderPipe(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
class Pipe(ArchComponent.Component):
|
||||
"the Arch Pipe object"
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self,obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Diameter" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Diameter",
|
||||
"Conduit",
|
||||
QT_TRANSLATE_NOOP("App::Property","The diameter of this pipe, if not based on a profile")).Diameter = 60
|
||||
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Conduit",
|
||||
QT_TRANSLATE_NOOP("App::Property","The length of this pipe, if not based on an edge"))
|
||||
|
||||
if not "Profile" in pl:
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Profile",
|
||||
"Conduit",
|
||||
QT_TRANSLATE_NOOP("App::Property","An optional closed profile to base this pipe on"))
|
||||
|
||||
if not "Start" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Start",
|
||||
"Conduit",
|
||||
QT_TRANSLATE_NOOP("App::Property","Offset from the start point"))
|
||||
|
||||
|
||||
if not "Offset" in pl:
|
||||
obj.addProperty("App::PropertyVector",
|
||||
"Offset",
|
||||
"Conduit",
|
||||
QT_TRANSLATE_NOOP("App::Property","Offset from the start point xy"))
|
||||
|
||||
|
||||
if not "WallThickness" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"WallThickness",
|
||||
"Conduit",
|
||||
QT_TRANSLATE_NOOP("App::Property","The wall thickness of this pipe, if not based on a profile")).WallThickness = 2
|
||||
|
||||
self.Type = "Conduit"
|
||||
# IfcPipeSegment is new in IFC4
|
||||
from ArchIFC import IfcTypes
|
||||
if "Cable Carrier Segment" in IfcTypes:
|
||||
obj.IfcType = "Cable Carrier Segment"
|
||||
obj.PredefinedType = "CONDUITSEGMENT"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
obj.setEditorMode("PredefinedType", 1)
|
||||
else:
|
||||
# IFC2x3 does not know a Pipe Segment
|
||||
obj.IfcType = "Undefined"
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
ArchComponent.Component.onDocumentRestored(self,obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self,obj):
|
||||
import Part, DraftGeomUtils, math
|
||||
pl = obj.Placement
|
||||
|
||||
w = self.getWire(obj)
|
||||
if not w:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Unable to build the base path")+"\n")
|
||||
return
|
||||
|
||||
if obj.Start.Value:
|
||||
# new:
|
||||
d = obj.Start.Value
|
||||
for i, e in enumerate(w.Edges):
|
||||
if e.Length < d:
|
||||
d -= e.Length
|
||||
else:
|
||||
v = e.Vertexes[-1].Point.sub(e.Vertexes[0].Point).normalize()
|
||||
v.multiply(d)
|
||||
p = e.Vertexes[0].Point.add(v)
|
||||
pts = [ver.Point for ver in w.Vertexes]
|
||||
pts = [p] + pts[i + 1:]
|
||||
w = Part.makePolygon(pts)
|
||||
break
|
||||
|
||||
if obj.Length.Value == 0:
|
||||
obj.Length.Value = w.Length
|
||||
elif obj.Length.Value > 0:
|
||||
d = obj.Length.Value
|
||||
for i, e in enumerate(w.Edges):
|
||||
if e.Length < d:
|
||||
d -= e.Length
|
||||
else:
|
||||
v = e.Vertexes[-1].Point.sub(e.Vertexes[0].Point).normalize()
|
||||
v.multiply(d)
|
||||
p = e.Vertexes[0].Point.add(v)
|
||||
pts = [ver.Point for ver in w.Vertexes]
|
||||
pts = pts[:i + 1] + [p]
|
||||
w = Part.makePolygon(pts)
|
||||
break
|
||||
pla = FreeCAD.Vector(w.Vertexes[int(len(w.Vertexes)/2)].Point)
|
||||
w.Placement.Base -= pla
|
||||
p = self.getProfile(obj)
|
||||
if not p:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Unable to build the profile") + "\n")
|
||||
return
|
||||
|
||||
# move and rotate the profile to the first point
|
||||
if hasattr(p,"CenterOfMass"):
|
||||
c = p.CenterOfMass
|
||||
else:
|
||||
c = p.BoundBox.Center
|
||||
|
||||
delta = w.Vertexes[0].Point - c + FreeCAD.Vector(obj.Offset.y, obj.Offset.x, 0)
|
||||
p.translate(delta)
|
||||
import Draft
|
||||
if Draft.getType(obj.Base) == "BezCurve":
|
||||
v1 = obj.Base.Placement.multVec(obj.Base.Points[1])-w.Vertexes[0].Point
|
||||
else:
|
||||
v1 = w.Vertexes[1].Point-w.Vertexes[0].Point
|
||||
v2 = DraftGeomUtils.getNormal(p)
|
||||
rot = FreeCAD.Rotation(v2,v1)
|
||||
p.rotate(w.Vertexes[0].Point,rot.Axis,math.degrees(rot.Angle))
|
||||
shapes = []
|
||||
try:
|
||||
if p.Faces:
|
||||
for f in p.Faces:
|
||||
sh = w.makePipeShell([f.OuterWire],True,False,2)
|
||||
for shw in f.Wires:
|
||||
if shw.hashCode() != f.OuterWire.hashCode():
|
||||
sh2 = w.makePipeShell([shw],True,False,2)
|
||||
sh = sh.cut(sh2)
|
||||
sh.Placement.Base += pla
|
||||
shapes.append(sh)
|
||||
elif p.Wires:
|
||||
for pw in p.Wires:
|
||||
sh = w.makePipeShell([pw],True,False,2)
|
||||
sh.Placement.Base += pla
|
||||
shapes.append(sh)
|
||||
except Exception:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Unable to build the pipe")+"\n")
|
||||
else:
|
||||
if len(shapes) == 0:
|
||||
return
|
||||
elif len(shapes) == 1:
|
||||
sh = shapes[0]
|
||||
else:
|
||||
sh = Part.makeCompound(shapes)
|
||||
obj.Shape = sh
|
||||
if not obj.Base:
|
||||
obj.Placement = pl
|
||||
|
||||
def getWire(self,obj):
|
||||
import Part
|
||||
if obj.Base:
|
||||
if not hasattr(obj.Base,'Shape'):
|
||||
FreeCAD.Console.PrintError(translate("Arch","The base object is not a Part")+"\n")
|
||||
return
|
||||
if len(obj.Base.Shape.Wires) != 1:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Too many wires in the base shape")+"\n")
|
||||
return
|
||||
if obj.Base.Shape.Wires[0].isClosed():
|
||||
FreeCAD.Console.PrintError(translate("Arch","The base wire is closed")+"\n")
|
||||
return
|
||||
w = obj.Base.Shape.Wires[0]
|
||||
else:
|
||||
if obj.Length.Value == 0:
|
||||
return
|
||||
w = Part.Wire([Part.LineSegment(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,obj.Length.Value)).toShape()])
|
||||
return w
|
||||
|
||||
def getProfile(self,obj):
|
||||
|
||||
import Part
|
||||
if obj.Profile:
|
||||
if not obj.Profile.getLinkedObject().isDerivedFrom("Part::Part2DObject"):
|
||||
FreeCAD.Console.PrintError(translate("Arch","The profile is not a 2D Part")+"\n")
|
||||
return
|
||||
if not obj.Profile.Shape.Wires[0].isClosed():
|
||||
FreeCAD.Console.PrintError(translate("Arch","The profile is not closed")+"\n")
|
||||
return
|
||||
p = obj.Profile.Shape.Wires[0]
|
||||
else:
|
||||
if obj.Diameter.Value == 0:
|
||||
return
|
||||
p = Part.Wire([Part.Circle(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),obj.Diameter.Value/2).toShape()])
|
||||
if obj.WallThickness.Value and (obj.WallThickness.Value < obj.Diameter.Value/2):
|
||||
p2 = Part.Wire([Part.Circle(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),(obj.Diameter.Value/2-obj.WallThickness.Value)).toShape()])
|
||||
p = Part.Face(p)
|
||||
p2 = Part.Face(p2)
|
||||
p = p.cut(p2)
|
||||
return p
|
||||
|
||||
class ViewProviderPipe(ArchComponent.ViewProviderComponent):
|
||||
|
||||
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self,vobj):
|
||||
|
||||
ArchComponent.ViewProviderComponent.__init__(self,vobj)
|
||||
vobj.ShapeColor = (255, 50, 50)
|
||||
|
||||
def getIcon(self):
|
||||
|
||||
return ":/icons/Arch_Pipe_Tree.svg"
|
||||
|
||||
class CommandConduit:
|
||||
"the Arch Pipe command definition"
|
||||
|
||||
def GetResources(self):
|
||||
|
||||
return {'Pixmap' : 'Arch_Pipe',
|
||||
'MenuText': QT_TRANSLATE_NOOP("Arch_Pipe","Pipe"),
|
||||
'Accel': "P, I",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_Pipe","Creates a pipe object from a given Wire or Line")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
s = FreeCADGui.Selection.getSelection()
|
||||
if s:
|
||||
for obj in s:
|
||||
if hasattr(obj,'Shape'):
|
||||
if len(obj.Shape.Wires) == 1:
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Conduit")
|
||||
makePipe(obj, name="Conduit")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
else:
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Conduit")
|
||||
makePipe(name="Conduit")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
class _CommandPipeConnector:
|
||||
"the Arch Pipe command definition"
|
||||
|
||||
def GetResources(self):
|
||||
|
||||
return {'Pixmap' : 'Arch_PipeConnector',
|
||||
'MenuText': QT_TRANSLATE_NOOP("Arch_PipeConnector","Connector"),
|
||||
'Accel': "P, C",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_PipeConnector","Creates a connector between 2 or 3 selected pipes")}
|
||||
|
||||
def IsActive(self):
|
||||
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
|
||||
import Draft
|
||||
s = FreeCADGui.Selection.getSelection()
|
||||
if not (len(s) in [2,3]):
|
||||
FreeCAD.Console.PrintError(translate("Arch","Please select exactly 2 or 3 Pipe objects")+"\n")
|
||||
return
|
||||
o = "["
|
||||
for obj in s:
|
||||
if Draft.getType(obj) != "Pipe":
|
||||
FreeCAD.Console.PrintError(translate("Arch","Please select only Pipe objects")+"\n")
|
||||
return
|
||||
o += "FreeCAD.ActiveDocument."+obj.Name+","
|
||||
o += "]"
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Connector"))
|
||||
FreeCADGui.addModule("Arch")
|
||||
FreeCADGui.doCommand("obj = Arch.makePipeConnector("+o+")")
|
||||
FreeCADGui.addModule("Draft")
|
||||
FreeCADGui.doCommand("Draft.autogroup(obj)")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
class _ArchPipeConnector(ArchComponent.Component):
|
||||
|
||||
|
||||
"the Arch Pipe Connector object"
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
self.setProperties(obj)
|
||||
obj.IfcType = "Pipe Fitting"
|
||||
|
||||
def setProperties(self,obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Radius" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Radius", "PipeConnector", QT_TRANSLATE_NOOP("App::Property","The curvature radius of this connector"))
|
||||
if not "Pipes" in pl:
|
||||
obj.addProperty("App::PropertyLinkList", "Pipes", "PipeConnector", QT_TRANSLATE_NOOP("App::Property","The pipes linked by this connector"))
|
||||
if not "ConnectorType" in pl:
|
||||
obj.addProperty("App::PropertyEnumeration", "ConnectorType", "PipeConnector", QT_TRANSLATE_NOOP("App::Property","The type of this connector"))
|
||||
obj.ConnectorType = ["Corner","Tee"]
|
||||
obj.setEditorMode("ConnectorType",1)
|
||||
self.Type = "PipeConnector"
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self,obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
tol = 1 # tolerance for alignment. This is only visual, we can keep it low...
|
||||
ptol = 0.001 # tolerance for coincident points
|
||||
|
||||
import math,Part,DraftGeomUtils,ArchCommands
|
||||
if len(obj.Pipes) < 2:
|
||||
return
|
||||
if len(obj.Pipes) > 3:
|
||||
FreeCAD.Console.PrintWarning(translate("Arch","Only the 3 first wires will be connected")+"\n")
|
||||
if obj.Radius.Value == 0:
|
||||
return
|
||||
wires = []
|
||||
order = []
|
||||
for o in obj.Pipes:
|
||||
wires.append(o.Proxy.getWire(o))
|
||||
if wires[0].Vertexes[0].Point.sub(wires[1].Vertexes[0].Point).Length <= ptol:
|
||||
order = ["start","start"]
|
||||
point = wires[0].Vertexes[0].Point
|
||||
elif wires[0].Vertexes[0].Point.sub(wires[1].Vertexes[-1].Point).Length <= ptol:
|
||||
order = ["start","end"]
|
||||
point = wires[0].Vertexes[0].Point
|
||||
elif wires[0].Vertexes[-1].Point.sub(wires[1].Vertexes[-1].Point).Length <= ptol:
|
||||
order = ["end","end"]
|
||||
point = wires[0].Vertexes[-1].Point
|
||||
elif wires[0].Vertexes[-1].Point.sub(wires[1].Vertexes[0].Point).Length <= ptol:
|
||||
order = ["end","start"]
|
||||
point = wires[0].Vertexes[-1].Point
|
||||
else:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Common vertex not found")+"\n")
|
||||
return
|
||||
if order[0] == "start":
|
||||
v1 = wires[0].Vertexes[1].Point.sub(wires[0].Vertexes[0].Point).normalize()
|
||||
else:
|
||||
v1 = wires[0].Vertexes[-2].Point.sub(wires[0].Vertexes[-1].Point).normalize()
|
||||
if order[1] == "start":
|
||||
v2 = wires[1].Vertexes[1].Point.sub(wires[1].Vertexes[0].Point).normalize()
|
||||
else:
|
||||
v2 = wires[1].Vertexes[-2].Point.sub(wires[1].Vertexes[-1].Point).normalize()
|
||||
p = obj.Pipes[0].Proxy.getProfile(obj.Pipes[0])
|
||||
# If the pipe has a non-zero WallThickness p is a shape instead of a wire:
|
||||
if p.ShapeType != "Wire":
|
||||
p = p.Wires
|
||||
p = Part.Face(p)
|
||||
if len(obj.Pipes) == 2:
|
||||
if obj.ConnectorType != "Corner":
|
||||
obj.ConnectorType = "Corner"
|
||||
if round(v1.getAngle(v2),tol) in [0,round(math.pi,tol)]:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Pipes are already aligned")+"\n")
|
||||
return
|
||||
normal = v2.cross(v1)
|
||||
offset = math.tan(math.pi/2-v1.getAngle(v2)/2)*obj.Radius.Value
|
||||
v1.multiply(offset)
|
||||
v2.multiply(offset)
|
||||
self.setOffset(obj.Pipes[0],order[0],offset)
|
||||
self.setOffset(obj.Pipes[1],order[1],offset)
|
||||
# find center
|
||||
perp = v1.cross(normal).normalize()
|
||||
perp.multiply(obj.Radius.Value)
|
||||
center = point.add(v1).add(perp)
|
||||
# move and rotate the profile to the first point
|
||||
delta = point.add(v1)-p.CenterOfMass
|
||||
p.translate(delta)
|
||||
vp = DraftGeomUtils.getNormal(p)
|
||||
rot = FreeCAD.Rotation(vp,v1)
|
||||
p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle))
|
||||
sh = p.revolve(center,normal,math.degrees(math.pi-v1.getAngle(v2)))
|
||||
#sh = Part.makeCompound([sh]+[Part.Vertex(point),Part.Vertex(point.add(v1)),Part.Vertex(center),Part.Vertex(point.add(v2))])
|
||||
else:
|
||||
if obj.ConnectorType != "Tee":
|
||||
obj.ConnectorType = "Tee"
|
||||
if wires[2].Vertexes[0].Point == point:
|
||||
order.append("start")
|
||||
elif wires[0].Vertexes[-1].Point == point:
|
||||
order.append("end")
|
||||
else:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Common vertex not found")+"\n")
|
||||
if order[2] == "start":
|
||||
v3 = wires[2].Vertexes[1].Point.sub(wires[2].Vertexes[0].Point).normalize()
|
||||
else:
|
||||
v3 = wires[2].Vertexes[-2].Point.sub(wires[2].Vertexes[-1].Point).normalize()
|
||||
if round(v1.getAngle(v2),tol) in [0,round(math.pi,tol)]:
|
||||
pair = [v1,v2,v3]
|
||||
elif round(v1.getAngle(v3),tol) in [0,round(math.pi,tol)]:
|
||||
pair = [v1,v3,v2]
|
||||
elif round(v2.getAngle(v3),tol) in [0,round(math.pi,tol)]:
|
||||
pair = [v2,v3,v1]
|
||||
else:
|
||||
FreeCAD.Console.PrintError(translate("Arch","At least 2 pipes must align")+"\n")
|
||||
return
|
||||
offset = obj.Radius.Value
|
||||
v1.multiply(offset)
|
||||
v2.multiply(offset)
|
||||
v3.multiply(offset)
|
||||
self.setOffset(obj.Pipes[0],order[0],offset)
|
||||
self.setOffset(obj.Pipes[1],order[1],offset)
|
||||
self.setOffset(obj.Pipes[2],order[2],offset)
|
||||
normal = pair[0].cross(pair[2])
|
||||
# move and rotate the profile to the first point
|
||||
delta = point.add(pair[0])-p.CenterOfMass
|
||||
p.translate(delta)
|
||||
vp = DraftGeomUtils.getNormal(p)
|
||||
rot = FreeCAD.Rotation(vp,pair[0])
|
||||
p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle))
|
||||
t1 = p.extrude(pair[1].multiply(2))
|
||||
# move and rotate the profile to the second point
|
||||
delta = point.add(pair[2])-p.CenterOfMass
|
||||
p.translate(delta)
|
||||
vp = DraftGeomUtils.getNormal(p)
|
||||
rot = FreeCAD.Rotation(vp,pair[2])
|
||||
p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle))
|
||||
t2 = p.extrude(pair[2].negative().multiply(2))
|
||||
# create a cut plane
|
||||
cp = Part.makePolygon([point,point.add(pair[0]),point.add(normal),point])
|
||||
cp = Part.Face(cp)
|
||||
if cp.normalAt(0,0).getAngle(pair[2]) < math.pi/2:
|
||||
cp.reverse()
|
||||
cf, cv, invcv = ArchCommands.getCutVolume(cp,t2)
|
||||
t2 = t2.cut(cv)
|
||||
sh = t1.fuse(t2)
|
||||
obj.Shape = sh
|
||||
|
||||
def setOffset(self,pipe,pos,offset):
|
||||
|
||||
if pos == "start":
|
||||
if pipe.OffsetStart != offset:
|
||||
pipe.OffsetStart = offset
|
||||
pipe.Proxy.execute(pipe)
|
||||
else:
|
||||
if pipe.OffsetEnd != offset:
|
||||
pipe.OffsetEnd = offset
|
||||
pipe.Proxy.execute(pipe)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Conduit', CommandConduit())
|
||||
FreeCADGui.addCommand('Arch_PipeConnector',_CommandPipeConnector())
|
||||
|
||||
class _ArchPipeGroupCommand:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['Arch_Pipe','Arch_PipeConnector'])
|
||||
def GetResources(self):
|
||||
return { 'MenuText': QT_TRANSLATE_NOOP("Arch_PipeTools",'Pipe tools'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_PipeTools",'Pipe tools')
|
||||
}
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand('Arch_PipeTools', _ArchPipeGroupCommand())
|
||||
398
Electrical/Inverter/PVPlantInverter.py
Normal file
398
Electrical/Inverter/PVPlantInverter.py
Normal file
@@ -0,0 +1,398 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
import ArchComponent
|
||||
import os
|
||||
import zipfile
|
||||
import re
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from DraftTools import translate
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
__title__ = "PVPlant Areas"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
Dir3dObjects = os.path.join(PVPlantResources.DirResources, "3dObjects")
|
||||
|
||||
|
||||
def makeStringInverter():
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "StringInverter")
|
||||
InverterBase(obj)
|
||||
ViewProviderStringInverter(obj.ViewObject)
|
||||
|
||||
try:
|
||||
folder = FreeCAD.ActiveDocument.StringInverters
|
||||
except:
|
||||
folder = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'StringInverters')
|
||||
folder.Label = "StringInverters"
|
||||
folder.addObject(obj)
|
||||
return obj
|
||||
|
||||
|
||||
class InverterBase(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
''' Initialize the Area object '''
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
|
||||
self.oldMPPTs = 0
|
||||
|
||||
self.Type = None
|
||||
self.obj = None
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not "File" in pl:
|
||||
obj.addProperty("App::PropertyFile",
|
||||
"File",
|
||||
"Inverter",
|
||||
"The base file this component is built upon")
|
||||
|
||||
if not ("MPPTs" in pl):
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"MPPTs",
|
||||
"Inverter",
|
||||
"Points that define the area"
|
||||
).MPPTs = 0
|
||||
|
||||
if not ("Generator" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"Generator",
|
||||
"Inverter",
|
||||
"Points that define the area"
|
||||
).Generator = ["Generic", "Library"]
|
||||
obj.Generator = "Generic"
|
||||
|
||||
if not ("Type" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Type",
|
||||
"Base",
|
||||
"Points that define the area"
|
||||
).Type = "InverterBase"
|
||||
obj.setEditorMode("Type", 1)
|
||||
|
||||
self.Type = obj.Type
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
""" Method run when the document is restored """
|
||||
self.setProperties(obj)
|
||||
|
||||
def onBeforeChange(self, obj, prop):
|
||||
|
||||
if prop == "MPPTs":
|
||||
self.oldMPPTs = int(obj.MPPTs)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
''' '''
|
||||
|
||||
if prop == "Generator":
|
||||
if obj.Generator == "Generic":
|
||||
obj.setEditorMode("MPPTs", 0)
|
||||
else:
|
||||
obj.setEditorMode("MPPTs", 1)
|
||||
|
||||
if prop == "MPPTs":
|
||||
''' '''
|
||||
if self.oldMPPTs > obj.MPPTs:
|
||||
''' borrar sobrantes '''
|
||||
obj.removeProperty()
|
||||
|
||||
elif self.oldMPPTs < obj.MPPTs:
|
||||
''' crear los faltantes '''
|
||||
for i in range(self.oldMPPTs, int(obj.MPPTs)):
|
||||
''' '''
|
||||
print(i)
|
||||
else:
|
||||
pass
|
||||
|
||||
if (prop == "File") and obj.File:
|
||||
''' '''
|
||||
|
||||
def execute(self, obj):
|
||||
''' '''
|
||||
# obj.Shape: compound
|
||||
# |- body: compound
|
||||
# |-- inverter: solid
|
||||
# |-- door: solid
|
||||
# |-- holder: solid
|
||||
|
||||
# |- connectors: compound
|
||||
# |-- DC: compound
|
||||
# |--- MPPT 1..x: compound
|
||||
# |---- positive: compound
|
||||
# |----- connector 1..y: ??
|
||||
# |---- negative 1..y: compound
|
||||
# |----- connector 1..y: ??
|
||||
# |-- AC: compound
|
||||
# |--- R,S,T,: ??
|
||||
# |-- Communication
|
||||
|
||||
pl = obj.Placement
|
||||
filename = self.getFile(obj)
|
||||
if filename:
|
||||
parts = self.getPartsList(obj)
|
||||
if parts:
|
||||
zdoc = zipfile.ZipFile(filename)
|
||||
if zdoc:
|
||||
f = zdoc.open(parts[list(parts.keys())[-1]][1])
|
||||
shapedata = f.read()
|
||||
f.close()
|
||||
shapedata = shapedata.decode("utf8")
|
||||
shape = self.cleanShape(shapedata, obj, parts[list(parts.keys())[-1]][2])
|
||||
obj.Shape = shape
|
||||
if not pl.isIdentity():
|
||||
obj.Placement = pl
|
||||
obj.MPPTs = len(shape.SubShapes[1].SubShapes[0].SubShapes)
|
||||
|
||||
def cleanShape(self, shapedata, obj, materials):
|
||||
"cleans the imported shape"
|
||||
|
||||
import Part
|
||||
shape = Part.Shape()
|
||||
shape.importBrepFromString(shapedata)
|
||||
'''if obj.FuseArch and materials:
|
||||
# separate lone edges
|
||||
shapes = []
|
||||
for edge in shape.Edges:
|
||||
found = False
|
||||
for solid in shape.Solids:
|
||||
for soledge in solid.Edges:
|
||||
if edge.hashCode() == soledge.hashCode():
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
if found:
|
||||
break
|
||||
else:
|
||||
shapes.append(edge)
|
||||
print("solids:",len(shape.Solids),"mattable:",materials)
|
||||
for key,solindexes in materials.items():
|
||||
if key == "Undefined":
|
||||
# do not join objects with no defined material
|
||||
for solindex in [int(i) for i in solindexes.split(",")]:
|
||||
shapes.append(shape.Solids[solindex])
|
||||
else:
|
||||
fusion = None
|
||||
for solindex in [int(i) for i in solindexes.split(",")]:
|
||||
if not fusion:
|
||||
fusion = shape.Solids[solindex]
|
||||
else:
|
||||
fusion = fusion.fuse(shape.Solids[solindex])
|
||||
if fusion:
|
||||
shapes.append(fusion)
|
||||
shape = Part.makeCompound(shapes)
|
||||
try:
|
||||
shape = shape.removeSplitter()
|
||||
except Exception:
|
||||
print(obj.Label,": error removing splitter")'''
|
||||
return shape
|
||||
|
||||
def getFile(self, obj, filename=None):
|
||||
"gets a valid file, if possible"
|
||||
|
||||
if not filename:
|
||||
filename = obj.File
|
||||
if not filename:
|
||||
return None
|
||||
if not filename.lower().endswith(".fcstd"):
|
||||
return None
|
||||
if not os.path.exists(filename):
|
||||
# search for the file in the current directory if not found
|
||||
basename = os.path.basename(filename)
|
||||
currentdir = os.path.dirname(obj.Document.FileName)
|
||||
altfile = os.path.join(currentdir,basename)
|
||||
if altfile == obj.Document.FileName:
|
||||
return None
|
||||
elif os.path.exists(altfile):
|
||||
return altfile
|
||||
else:
|
||||
# search for subpaths in current folder
|
||||
altfile = None
|
||||
subdirs = self.splitall(os.path.dirname(filename))
|
||||
for i in range(len(subdirs)):
|
||||
subpath = [currentdir]+subdirs[-i:]+[basename]
|
||||
altfile = os.path.join(*subpath)
|
||||
if os.path.exists(altfile):
|
||||
return altfile
|
||||
return None
|
||||
return filename
|
||||
|
||||
def getPartsList(self, obj, filename=None):
|
||||
|
||||
"returns a list of Part-based objects in a FCStd file"
|
||||
|
||||
parts = {}
|
||||
materials = {}
|
||||
filename = self.getFile(obj,filename)
|
||||
if not filename:
|
||||
return parts
|
||||
zdoc = zipfile.ZipFile(filename)
|
||||
with zdoc.open("Document.xml") as docf:
|
||||
name = None
|
||||
label = None
|
||||
part = None
|
||||
materials = {}
|
||||
writemode = False
|
||||
for line in docf:
|
||||
line = line.decode("utf8")
|
||||
if "<Object name=" in line:
|
||||
n = re.findall('name=\"(.*?)\"',line)
|
||||
if n:
|
||||
name = n[0]
|
||||
elif "<Property name=\"Label\"" in line:
|
||||
writemode = True
|
||||
elif writemode and "<String value=" in line:
|
||||
n = re.findall('value=\"(.*?)\"',line)
|
||||
if n:
|
||||
label = n[0]
|
||||
writemode = False
|
||||
elif "<Property name=\"Shape\" type=\"Part::PropertyPartShape\"" in line:
|
||||
writemode = True
|
||||
elif writemode and "<Part file=" in line:
|
||||
n = re.findall('file=\"(.*?)\"',line)
|
||||
if n:
|
||||
part = n[0]
|
||||
writemode = False
|
||||
elif "<Property name=\"MaterialsTable\" type=\"App::PropertyMap\"" in line:
|
||||
writemode = True
|
||||
elif writemode and "<Item key=" in line:
|
||||
n = re.findall('key=\"(.*?)\"',line)
|
||||
v = re.findall('value=\"(.*?)\"',line)
|
||||
if n and v:
|
||||
materials[n[0]] = v[0]
|
||||
elif writemode and "</Map>" in line:
|
||||
writemode = False
|
||||
elif "</Object>" in line:
|
||||
if name and label and part:
|
||||
parts[name] = [label,part,materials]
|
||||
name = None
|
||||
label = None
|
||||
part = None
|
||||
materials = {}
|
||||
writemode = False
|
||||
return parts
|
||||
|
||||
def getColors(self,obj):
|
||||
|
||||
"returns the DiffuseColor of the referenced object"
|
||||
|
||||
filename = self.getFile(obj)
|
||||
if not filename:
|
||||
return None
|
||||
part = obj.Part
|
||||
if not obj.Part:
|
||||
return None
|
||||
zdoc = zipfile.ZipFile(filename)
|
||||
if not "GuiDocument.xml" in zdoc.namelist():
|
||||
return None
|
||||
colorfile = None
|
||||
with zdoc.open("GuiDocument.xml") as docf:
|
||||
writemode1 = False
|
||||
writemode2 = False
|
||||
for line in docf:
|
||||
line = line.decode("utf8")
|
||||
if ("<ViewProvider name=" in line) and (part in line):
|
||||
writemode1 = True
|
||||
elif writemode1 and ("<Property name=\"DiffuseColor\"" in line):
|
||||
writemode1 = False
|
||||
writemode2 = True
|
||||
elif writemode2 and ("<ColorList file=" in line):
|
||||
n = re.findall('file=\"(.*?)\"',line)
|
||||
if n:
|
||||
colorfile = n[0]
|
||||
break
|
||||
if not colorfile:
|
||||
return None
|
||||
if not colorfile in zdoc.namelist():
|
||||
return None
|
||||
colors = []
|
||||
cf = zdoc.open(colorfile)
|
||||
buf = cf.read()
|
||||
cf.close()
|
||||
for i in range(1,int(len(buf)/4)):
|
||||
colors.append((buf[i*4+3]/255.0,buf[i*4+2]/255.0,buf[i*4+1]/255.0,buf[i*4]/255.0))
|
||||
if colors:
|
||||
return colors
|
||||
return None
|
||||
|
||||
def splitall(self,path):
|
||||
|
||||
"splits a path between its components"
|
||||
|
||||
allparts = []
|
||||
while 1:
|
||||
parts = os.path.split(path)
|
||||
if parts[0] == path: # sentinel for absolute paths
|
||||
allparts.insert(0, parts[0])
|
||||
break
|
||||
elif parts[1] == path: # sentinel for relative paths
|
||||
allparts.insert(0, parts[1])
|
||||
break
|
||||
else:
|
||||
path = parts[0]
|
||||
allparts.insert(0, parts[1])
|
||||
return allparts
|
||||
|
||||
class ViewProviderStringInverter(ArchComponent.ViewProviderComponent):
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(PVPlantResources.DirIcons, "Inverter.svg"))
|
||||
|
||||
|
||||
class CommandStringInverter:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "Inverter.svg")),
|
||||
'Accel': "E, I",
|
||||
'MenuText': "String Inverter",
|
||||
'ToolTip': "String Placement",}
|
||||
|
||||
def Activated(self):
|
||||
sinverter = makeStringInverter()
|
||||
|
||||
def IsActive(self):
|
||||
active = not (FreeCAD.ActiveDocument is None)
|
||||
return active
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('StringInverter', CommandStringInverter())
|
||||
|
||||
0
Electrical/Wiring.py
Normal file
0
Electrical/Wiring.py
Normal file
80
Export/PVPlantBOQCivil.py
Normal file
80
Export/PVPlantBOQCivil.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD, Draft
|
||||
import PVPlantSite
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
|
||||
import Part
|
||||
import pivy
|
||||
from pivy import coin
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Trench"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
from PVPlantResources import DirDocuments as DirDocuments
|
||||
import openpyxl
|
||||
|
||||
|
||||
def makeBOQCivil():
|
||||
''' create a excel '''
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class _CommandBOQCivil:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "boqc.svg")),
|
||||
'Accel': "R, C",
|
||||
'MenuText': "BOQ Civil",
|
||||
'ToolTip': ""}
|
||||
|
||||
def Activated(self):
|
||||
makeBOQCivil()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('BOQCivil', _CommandBOQCivil())
|
||||
104
Export/PVPlantBOQElectrical.py
Normal file
104
Export/PVPlantBOQElectrical.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD, Draft
|
||||
import copy
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
|
||||
import Part
|
||||
import pivy
|
||||
from pivy import coin
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Trench"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
def makeBOQElectrical():
|
||||
''' create a excel '''
|
||||
print("makeBOQElectrical")
|
||||
import sys
|
||||
sys.path.append(r"/")
|
||||
funct = 0
|
||||
if funct == 0:
|
||||
print(" ------- Prueba generar layout en excel: ")
|
||||
# export layout to Excel:
|
||||
from Export import layoutToExcel
|
||||
layoutToExcel.generateLayout()
|
||||
return
|
||||
else:
|
||||
print(" ------- Prueba dibujar contorno de los objetos seleccionados: ")
|
||||
import numpy as np
|
||||
import MeshTools.MeshGetBoundary as mgb
|
||||
# contorno:
|
||||
maxdist = 6000
|
||||
if FreeCADGui.Selection.hasSelection():
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
pts = []
|
||||
for obj in sel:
|
||||
for panel in obj.Shape.SubShapes[0].SubShapes[0].SubShapes:
|
||||
zm = panel.BoundBox.ZMax
|
||||
for i in range(8):
|
||||
pt = panel.BoundBox.getPoint(i)
|
||||
if pt.z == zm:
|
||||
pts.append(pt)
|
||||
import PVPlantCreateTerrainMesh
|
||||
m = PVPlantCreateTerrainMesh.Triangulate(np.array(pts), MaxlengthLE=maxdist, use3d=False)
|
||||
b = mgb.get_boundary(m)
|
||||
Part.show(b)
|
||||
|
||||
class _CommandBOQElectrical:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "boqe.svg")),
|
||||
'Accel': "R, E",
|
||||
'MenuText': "BOQ Electrical",
|
||||
'ToolTip': ""}
|
||||
|
||||
def Activated(self):
|
||||
makeBOQElectrical()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('BOQElectrical', _CommandBOQElectrical())
|
||||
344
Export/PVPlantBOQMechanical.py
Normal file
344
Export/PVPlantBOQMechanical.py
Normal file
@@ -0,0 +1,344 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
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
|
||||
|
||||
import openpyxl
|
||||
from openpyxl.styles import Alignment, Border, Side, PatternFill, Font
|
||||
import PVPlantResources
|
||||
import PVPlantSite
|
||||
|
||||
# Estilos:
|
||||
thin = Side(border_style="thin", color="7DA4B8")
|
||||
double = Side(border_style="double", color="ff0000")
|
||||
border_thin = Border(top=thin, left=thin, right=thin, bottom=thin)
|
||||
border_fat = Border(top=thin, left=thin, right=thin, bottom=thin)
|
||||
# fill = PatternFill("solid", fgColor="DDDDDD")
|
||||
# fill = GradientFill(stop=("000000", "FFFFFF"))
|
||||
|
||||
scale = 0.001 # milimeters to meter
|
||||
|
||||
def style_range(ws, cell_range, border=Border(), fill=None, font=None, alignment=None):
|
||||
"""
|
||||
Apply styles to a range of cells as if they were a single cell.
|
||||
|
||||
:param ws: Excel worksheet instance
|
||||
:param range: An excel range to style (e.g. A1:F20)
|
||||
:param border: An openpyxl Border
|
||||
:param fill: An openpyxl PatternFill or GradientFill
|
||||
:param font: An openpyxl Font object
|
||||
"""
|
||||
|
||||
top = Border(top=border.top)
|
||||
left = Border(left=border.left)
|
||||
right = Border(right=border.right)
|
||||
bottom = Border(bottom=border.bottom)
|
||||
|
||||
first_cell = ws[cell_range.split(":")[0]]
|
||||
if alignment:
|
||||
first_cell.alignment = alignment
|
||||
|
||||
rows = ws[cell_range]
|
||||
if font:
|
||||
first_cell.font = font
|
||||
|
||||
for cell in rows[0]:
|
||||
cell.border = cell.border + top
|
||||
for cell in rows[-1]:
|
||||
cell.border = cell.border + bottom
|
||||
|
||||
for row in rows:
|
||||
l = row[0]
|
||||
r = row[-1]
|
||||
l.border = l.border + left
|
||||
r.border = r.border + right
|
||||
if fill:
|
||||
for c in row:
|
||||
c.fill = fill
|
||||
|
||||
def spreadsheetBOQFrames(sheet, sel):
|
||||
sheet['A1'] = 'Index'
|
||||
sheet['B1'] = 'Frame'
|
||||
sheet['C1'] = 'Frame Type'
|
||||
sheet['D1'] = 'X'
|
||||
sheet['E1'] = 'Y'
|
||||
sheet['F1'] = 'Z'
|
||||
sheet['G1'] = 'Angle N-S'
|
||||
sheet['H1'] = 'Angle L-W'
|
||||
sheet['I1'] = 'Nº Poles'
|
||||
|
||||
sheet.column_dimensions['A'].width = 8
|
||||
sheet.column_dimensions['B'].width = 30
|
||||
sheet.column_dimensions['C'].width = 20
|
||||
sheet.column_dimensions['D'].width = 20
|
||||
sheet.column_dimensions['E'].width = 20
|
||||
sheet.column_dimensions['F'].width = 20
|
||||
sheet.column_dimensions['G'].width = 15
|
||||
sheet.column_dimensions['H'].width = 15
|
||||
sheet.column_dimensions['I'].width = 15
|
||||
sheet.row_dimensions[1].height = 40
|
||||
|
||||
style_range(sheet, 'A1:I1',
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
fill=PatternFill("solid", fgColor="7DA4B8"),
|
||||
font=Font(name='Quicksand', size=10, b=True, color="FFFFFF"),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
|
||||
for ind in range(0, len(sel)):
|
||||
row = ind + 2
|
||||
sheet['A{0}'.format(row)] = ind + 1
|
||||
sheet['B{0}'.format(row)] = sel[ind].Label
|
||||
sheet['C{0}'.format(row)] = sel[ind].Setup.Label
|
||||
sheet['D{0}'.format(row)] = sel[ind].Placement.Base.x * scale
|
||||
sheet['E{0}'.format(row)] = sel[ind].Placement.Base.y * scale
|
||||
sheet['R{0}'.format(row)] = sel[ind].Placement.Base.z * scale
|
||||
sheet['G{0}'.format(row)] = sel[ind].Placement.Rotation.toEuler()[0]
|
||||
sheet['H{0}'.format(row)] = sel[ind].Placement.Rotation.toEuler()[1]
|
||||
sheet['I{0}'.format(row)] = sel[ind].Setup.NumberPole.Value
|
||||
style_range(sheet, 'A' + str(row) + ':I' + str(row),
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
font=Font(name='Quicksand', size=10),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
|
||||
def spreadsheetBOQPoles(sheet, sel):
|
||||
import MeshPart as mp
|
||||
from Mechanical.Frame import PVPlantFrame
|
||||
|
||||
# Data:
|
||||
terrain = PVPlantSite.get().Terrain.Mesh # Shape
|
||||
|
||||
# Headers:
|
||||
sheet['A1'] = 'Frame'
|
||||
sheet['B1'] = 'Pole'
|
||||
sheet['C1'] = 'Pole Type'
|
||||
sheet['D1'] = 'X'
|
||||
sheet['E1'] = 'Y'
|
||||
sheet['F1'] = 'Z frame attach'
|
||||
sheet['G1'] = 'Z aerial head'
|
||||
sheet['H1'] = 'Pole length'
|
||||
sheet['I1'] = 'Pole aerial length'
|
||||
sheet['J1'] = 'Pole terrain enter length'
|
||||
|
||||
sheet.column_dimensions['A'].width = 30
|
||||
sheet.column_dimensions['B'].width = 8
|
||||
sheet.column_dimensions['C'].width = 20
|
||||
sheet.column_dimensions['D'].width = 20
|
||||
sheet.column_dimensions['E'].width = 20
|
||||
sheet.column_dimensions['F'].width = 20
|
||||
sheet.column_dimensions['G'].width = 20
|
||||
sheet.column_dimensions['H'].width = 20
|
||||
sheet.column_dimensions['I'].width = 20
|
||||
sheet.column_dimensions['J'].width = 20
|
||||
sheet.row_dimensions[1].height = 40
|
||||
style_range(sheet, 'A1:J1',
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
fill=PatternFill("solid", fgColor="7DA4B8"),
|
||||
font=Font(name='Quicksand', size=11, b=True, color="FFFFFF"),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
sheet['A2'] = ""
|
||||
sheet.row_dimensions[2].height = 5
|
||||
|
||||
data = {"Frame": [],
|
||||
#"FrameType": [],
|
||||
"Pole": [],
|
||||
"PoleType": [],
|
||||
"PoleLength": [],
|
||||
"Center": [],
|
||||
"Head": []}
|
||||
|
||||
cnt = 0
|
||||
for frame_ind, frame in enumerate(sel):
|
||||
poles = frame.Shape.SubShapes[1].SubShapes[0].SubShapes
|
||||
numpoles = int(frame.Setup.NumberPole.Value)
|
||||
seq = frame.Setup.PoleSequence
|
||||
if len(seq) < numpoles:
|
||||
seq = PVPlantFrame.getarray(frame.Setup.PoleSequence, numpoles)
|
||||
for pole_ind in range(numpoles):
|
||||
pole = poles[pole_ind]
|
||||
poletype = frame.Setup.PoleType[seq[pole_ind]]
|
||||
data["Frame"].append(frame.Label)
|
||||
#data["FrameType"].append(frame.Setup.Label)
|
||||
data["Pole"].append(pole_ind + 1)
|
||||
data["PoleType"].append(poletype.Label)
|
||||
data["PoleLength"].append(int(poletype.Height))
|
||||
data["Center"].append(pole.BoundBox.Center)
|
||||
data["Head"].append(pole.BoundBox.ZMax)
|
||||
cnt += 1
|
||||
|
||||
pts = mp.projectPointsOnMesh(data["Center"], terrain, FreeCAD.Vector(0, 0, 1))
|
||||
#if cnt == len(pts):
|
||||
data["Soil"] = pts
|
||||
|
||||
row = 3
|
||||
group_from = row
|
||||
f = data["Frame"][0]
|
||||
for i in range(0, len(data["Frame"])):
|
||||
if f != data["Frame"][i]:
|
||||
style_range(sheet, 'A' + str(group_from) + ':F' + str(row - 1),
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
font=Font(name='Quicksand', size=11, ),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
sheet.merge_cells('A' + str(group_from) + ':A' + str(row - 1))
|
||||
style_range(sheet, 'A' + str(group_from) + ':A' + str(row - 1),
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
font=Font(name='Quicksand', size=11, ),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
#sheet['A{0}'.format(row)] = ""
|
||||
sheet.row_dimensions[row].height = 5
|
||||
row += 1
|
||||
f = data["Frame"][i]
|
||||
group_from = row
|
||||
|
||||
sheet['A{0}'.format(row)] = data['Frame'][i]
|
||||
sheet['B{0}'.format(row)] = data['Pole'][i]
|
||||
sheet['C{0}'.format(row)] = data['PoleType'][i]
|
||||
sheet['D{0}'.format(row)] = round(data['Center'][i].x, 0) * scale
|
||||
sheet['D{0}'.format(row)].number_format = "0.000"
|
||||
sheet['E{0}'.format(row)] = round(data['Center'][i].y, 0) * scale
|
||||
sheet['E{0}'.format(row)].number_format = "0.000"
|
||||
try:
|
||||
sheet['F{0}'.format(row)] = round(data['Soil'][i].z, 0) * scale
|
||||
sheet['F{0}'.format(row)].number_format = "0.000"
|
||||
except:
|
||||
pass
|
||||
sheet['G{0}'.format(row)] = round(data['Head'][i]) * scale
|
||||
sheet['G{0}'.format(row)].number_format = "0.000"
|
||||
sheet['H{0}'.format(row)] = data["PoleLength"][i] * scale
|
||||
sheet['H{0}'.format(row)].number_format = "0.000"
|
||||
sheet['I{0}'.format(row)] = '=G{0}-F{0}'.format(row)
|
||||
sheet['I{0}'.format(row)].number_format = "0.000"
|
||||
sheet['J{0}'.format(row)] = '=H{0}-I{0}'.format(row)
|
||||
sheet['J{0}'.format(row)].number_format = "0.000"
|
||||
|
||||
style_range(sheet, 'A' + str(row) + ':J' + str(row),
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
font=Font(name='Quicksand', size=11,),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
row += 1
|
||||
|
||||
def spreadsheetBOQPanelCollision(sheet, sel):
|
||||
# Headers:
|
||||
sheet['A1'] = 'Frame'
|
||||
sheet['B1'] = 'Nombre'
|
||||
sheet['C1'] = 'X'
|
||||
sheet['D1'] = 'Y'
|
||||
sheet['E1'] = 'Z'
|
||||
sheet['G1'] = 'Ángulo E-O'
|
||||
sheet['H1'] = 'Nº Hincas'
|
||||
|
||||
sheet.column_dimensions['A'].width = 30
|
||||
sheet.column_dimensions['B'].width = 8
|
||||
sheet.column_dimensions['C'].width = 20
|
||||
sheet.column_dimensions['D'].width = 20
|
||||
sheet.column_dimensions['E'].width = 20
|
||||
sheet.column_dimensions['F'].width = 20
|
||||
sheet.column_dimensions['G'].width = 20
|
||||
sheet.column_dimensions['H'].width = 20
|
||||
sheet.column_dimensions['I'].width = 20
|
||||
sheet.row_dimensions[1].height = 40
|
||||
style_range(sheet, 'A1:I1',
|
||||
border=Border(top=thin, left=thin, right=thin, bottom=thin),
|
||||
fill=PatternFill("solid", fgColor="7DA4B8"),
|
||||
font=Font(name='Quicksand', size=11, b=True, color="FFFFFF"),
|
||||
alignment=Alignment(horizontal="center", vertical="center"))
|
||||
sheet['A2'] = ""
|
||||
sheet.row_dimensions[2].height = 5
|
||||
|
||||
# Data:
|
||||
for frame_ind in range(0, len(sel)):
|
||||
frame = sel[frame_ind]
|
||||
sheet['A{0}'.format(ind + 2)] = ind
|
||||
sheet['B{0}'.format(ind + 2)] = sel[ind].Label
|
||||
sheet['C{0}'.format(ind + 2)] = sel[ind].Placement.Base.x * scale
|
||||
sheet['D{0}'.format(ind + 2)] = sel[ind].Placement.Base.y * scale
|
||||
sheet['E{0}'.format(ind + 2)] = sel[ind].Placement.Base.z * scale
|
||||
sheet['F{0}'.format(ind + 2)] = sel[ind].Placement.Rotation.toEuler()[0]
|
||||
sheet['G{0}'.format(ind + 2)] = sel[ind].Placement.Rotation.toEuler()[1]
|
||||
sheet['H{0}'.format(ind + 2)] = sel[ind].NumberPole.Value
|
||||
|
||||
class _CommandBOQMechanical:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "boqm.svg")),
|
||||
'Accel': "R, M",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "BOQ Mecánico"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Calcular el BOQ de la")}
|
||||
|
||||
def Activated(self):
|
||||
# make file global:
|
||||
#sel = FreeCAD.ActiveDocument.findObjects(Name="Tracker")
|
||||
sel = []
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
'''if not hasattr(obj, "Proxy"):
|
||||
continue
|
||||
if issubclass(obj.Proxy.__class__, PVPlantRack.Frame):
|
||||
objects.append(obj)'''
|
||||
if obj.Name.startswith("Tracker") and not obj.Name.startswith("TrackerSetup"):
|
||||
sel.append(obj)
|
||||
sel = sorted(sel, key=lambda x: x.Label)
|
||||
if len(sel) > 0:
|
||||
path = os.path.dirname(FreeCAD.ActiveDocument.FileName)
|
||||
filename = os.path.join(path, "BOQMechanical.xlsx")
|
||||
mywb = openpyxl.Workbook()
|
||||
sheet = mywb.active
|
||||
sheet.title = 'Frames information'
|
||||
spreadsheetBOQFrames(sheet, sel)
|
||||
|
||||
sheet = mywb.create_sheet("Poles information")
|
||||
spreadsheetBOQPoles(sheet, sel)
|
||||
mywb.save(filename)
|
||||
|
||||
print("Se ha generado el BOQMechanical: ")
|
||||
print(filename)
|
||||
'''import sys
|
||||
path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
|
||||
sys.path.append(path)'''
|
||||
|
||||
import subprocess
|
||||
subprocess.Popen('explorer ' + path)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('BOQMechanical', _CommandBOQMechanical())
|
||||
466
Export/exportDXF.py
Normal file
466
Export/exportDXF.py
Normal file
@@ -0,0 +1,466 @@
|
||||
import math
|
||||
import FreeCAD
|
||||
from Utils.PVPlantUtils import findObjects
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Export to DXF"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
field = {"name": "", "width": 0, "heigth": 0}
|
||||
|
||||
|
||||
class exportDXF:
|
||||
|
||||
def __init__(self, filename):
|
||||
''' '''
|
||||
self.doc = None
|
||||
self.msp = None
|
||||
self.filename = filename
|
||||
|
||||
'''
|
||||
doc.linetypes.add("GRENZE2",
|
||||
# linetype definition in acad.lin:
|
||||
# A,.25,-.1,[BOX,ltypeshp.shx,x=-.1,s=.1],-.1,1
|
||||
# replacing BOX by shape index 132 (got index from an AutoCAD file),
|
||||
# ezdxf can't get shape index from ltypeshp.shx
|
||||
pattern="A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1",
|
||||
description="Grenze eckig ----[]-----[]----[]-----[]----[]--",
|
||||
length=1.45, # required for complex line types
|
||||
})
|
||||
|
||||
doc.linetypes.add("GRENZE2",
|
||||
# linetype definition in acad.lin:
|
||||
# A,.25,-.1,[BOX,ltypeshp.shx,x=-.1,s=.1],-.1,1
|
||||
# replacing BOX by shape index 132 (got index from an AutoCAD file),
|
||||
# ezdxf can't get shape index from ltypeshp.shx
|
||||
pattern = "A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1",
|
||||
description = "Límite1 ----0-----0----0-----0----0-----0--",
|
||||
length = 1.45, # required for complex line types
|
||||
})
|
||||
'''
|
||||
|
||||
def createFile(self, version='R2018'):
|
||||
import ezdxf
|
||||
from ezdxf.tools.standards import linetypes
|
||||
|
||||
# 1. Create a new document
|
||||
self.doc = ezdxf.new(version)
|
||||
# 2. Setup document:
|
||||
self.doc.header["$INSUNITS"] = 6
|
||||
self.doc.header['$MEASUREMENT'] = 1
|
||||
self.doc.header['$LUNITS'] = 2
|
||||
self.doc.header['$AUNITS'] = 0
|
||||
|
||||
# 3. Add new entities to the modelspace:
|
||||
self.msp = self.doc.modelspace()
|
||||
|
||||
print("linetypes: ", self.doc.linetypes)
|
||||
for name, desc, pattern in linetypes():
|
||||
if name not in self.doc.linetypes:
|
||||
self.doc.linetypes.add(name=name,
|
||||
pattern=pattern,
|
||||
description=desc,
|
||||
)
|
||||
|
||||
|
||||
self.doc.linetypes.add(name="FENCELINE1",
|
||||
pattern="A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1",
|
||||
description="Límite1 ----0-----0----0-----0----0-----0--",
|
||||
length=1.45) # required for complex line types
|
||||
|
||||
def save(self):
|
||||
from os.path import exists
|
||||
file_exists = exists(self.filename)
|
||||
self.doc.saveas(self.filename)
|
||||
self.doc.save()
|
||||
|
||||
def createLayer(self, layerName="newLayer", layerColor=(0,0,0), layerLineType='CONTINUOUS'):
|
||||
layer = self.doc.layers.add(name=layerName, linetype=layerLineType)
|
||||
layer.rgb = layerColor
|
||||
return layer
|
||||
|
||||
def createBlock(self, blockName='newBlock'):
|
||||
# Create a block
|
||||
block = self.doc.blocks.new(name=blockName)
|
||||
return block
|
||||
|
||||
def insertBlock(self, name, point=(0.0, 0.0), rotation=0.0, xscale=0.0, yscale=0.0):
|
||||
if name == "":
|
||||
return None
|
||||
|
||||
return self.msp.add_blockref(name, point, dxfattribs={
|
||||
'xscale': xscale,
|
||||
'yscale': yscale,
|
||||
'rotation': rotation
|
||||
})
|
||||
|
||||
def createPolyline(self, wire):
|
||||
data = getWire(wire.Shape)
|
||||
lwp = self.msp.add_lwpolyline(data)
|
||||
return lwp
|
||||
|
||||
|
||||
def getWire(wire, nospline=False, width=.0):
|
||||
"""Return a list of DXF ready points and bulges from a wire.
|
||||
|
||||
It builds a list of points from the edges of a `wire`.
|
||||
If the edges are circular arcs, the "bulge" of that edge is calculated,
|
||||
for other cases, the bulge is considered zero.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
wire : Part::TopoShape ('Wire')
|
||||
A shape representing a wire.
|
||||
|
||||
nospline : bool, optional
|
||||
It defaults to `False`.
|
||||
If it is `True`, the edges of the wire are not considered as
|
||||
being one of `'BSplineCurve'`, `'BezierCurve'`, or `'Ellipse'`,
|
||||
and a simple point is added to the list.
|
||||
Otherwise, `getSplineSegs(edge)` is used to extract
|
||||
the points and add them to the list.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of tuples
|
||||
It returns a list of tuples ``[(...), (...), ...]``
|
||||
where each tuple indicates a point with additional information
|
||||
besides the coordinates.
|
||||
Two types of tuples may be returned.
|
||||
|
||||
[(float, float, float, None, None, float), ...]
|
||||
When `lw` is `True` (`'lwpolyline'`)
|
||||
the first three values represent the coordinates of the point,
|
||||
the next two are `None`, and the last value is the bulge.
|
||||
|
||||
[((float, float, float), None, [None, None], float), ...]
|
||||
When `lw` is `False` (`'polyline'`)
|
||||
the first element is a tuple of three values that indicate
|
||||
the coordinates of the point, the next element is `None`,
|
||||
the next element is a list of two `None` values,
|
||||
and the last element is the value of the bulge.
|
||||
|
||||
See also
|
||||
--------
|
||||
calcBulge
|
||||
"""
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
import math
|
||||
|
||||
def fmt(vec, b=0.0):
|
||||
return (vec.x * 0.001, vec.y * 0.001, width, width, b)
|
||||
|
||||
points = []
|
||||
edges = Part.__sortEdges__(wire.Edges)
|
||||
for edge in edges:
|
||||
v1 = edge.Vertexes[0].Point
|
||||
if DraftGeomUtils.geomType(edge) == "Circle":
|
||||
# polyline bulge -> negative makes the arc go clockwise
|
||||
angle = edge.LastParameter - edge.FirstParameter
|
||||
bul = math.tan(angle / 4)
|
||||
if edge.Curve.Axis.dot(FreeCAD.Vector(0, 0, 1)) < 0:
|
||||
bul = -bul
|
||||
points.append(fmt(v1, bul))
|
||||
elif (DraftGeomUtils.geomType(edge) in ["BSplineCurve",
|
||||
"BezierCurve",
|
||||
"Ellipse"]) and (not nospline):
|
||||
spline = getSplineSegs(edge)
|
||||
spline.pop()
|
||||
for p in spline:
|
||||
points.append(fmt(p))
|
||||
else:
|
||||
points.append(fmt(v1))
|
||||
|
||||
v = edges[-1].Vertexes[-1].Point
|
||||
points.append(fmt(v))
|
||||
|
||||
return points
|
||||
|
||||
|
||||
def getArcData(edge):
|
||||
"""Return center, radius, start, and end angles of a circle-based edge.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
edge : Part::TopoShape ('Edge')
|
||||
An edge representing a circular arc, either open or closed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
(tuple, float, float, float)
|
||||
It returns a tuple of four values; the first value is a tuple
|
||||
with the coordinates of the center `(x, y, z)`;
|
||||
the other three represent the magnitude of the radius,
|
||||
and the start and end angles in degrees that define the arc.
|
||||
|
||||
(tuple, float, 0, 0)
|
||||
If the number of vertices in the `edge` is only one, only the center
|
||||
point exists, so it's a full circumference; in this case, both
|
||||
angles are zero.
|
||||
"""
|
||||
ce = edge.Curve.Center
|
||||
radius = edge.Curve.Radius
|
||||
if len(edge.Vertexes) == 1:
|
||||
# closed circle
|
||||
return DraftVecUtils.tup(ce), radius, 0, 0
|
||||
else:
|
||||
# new method: recalculate ourselves as we cannot trust edge.Curve.Axis
|
||||
# or XAxis
|
||||
p1 = edge.Vertexes[0].Point
|
||||
p2 = edge.Vertexes[-1].Point
|
||||
v1 = p1.sub(ce)
|
||||
v2 = p2.sub(ce)
|
||||
# print(v1.cross(v2))
|
||||
# print(edge.Curve.Axis)
|
||||
# print(p1)
|
||||
# print(p2)
|
||||
# we can use Z check since arcs getting here will ALWAYS be in XY plane
|
||||
# Z can be 0 if the arc is 180 deg
|
||||
# if (v1.cross(v2).z >= 0) or (edge.Curve.Axis.z > 0):
|
||||
# Calculates the angles of the first and last points
|
||||
# in the circular arc, with respect to the global X axis.
|
||||
if edge.Curve.Axis.z > 0:
|
||||
# clockwise
|
||||
ang1 = -DraftVecUtils.angle(v1)
|
||||
ang2 = -DraftVecUtils.angle(v2)
|
||||
else:
|
||||
# counterclockwise
|
||||
ang2 = -DraftVecUtils.angle(v1)
|
||||
ang1 = -DraftVecUtils.angle(v2)
|
||||
|
||||
# obsolete method - fails a lot
|
||||
# if round(edge.Curve.Axis.dot(Vector(0, 0, 1))) == 1:
|
||||
# ang1, ang2 = edge.ParameterRange
|
||||
# else:
|
||||
# ang2, ang1 = edge.ParameterRange
|
||||
# if edge.Curve.XAxis != Vector(1, 0, 0):
|
||||
# ang1 -= DraftVecUtils.angle(edge.Curve.XAxis)
|
||||
# ang2 -= DraftVecUtils.angle(edge.Curve.XAxis)
|
||||
|
||||
return (DraftVecUtils.tup(ce), radius,
|
||||
math.degrees(ang1), math.degrees(ang2))
|
||||
|
||||
|
||||
class _PVPlantExportDXF(QtGui.QWidget):
|
||||
'''The editmode TaskPanel to select what you want to export'''
|
||||
|
||||
def __init__(self):
|
||||
# super(_PVPlantExportDXF, self).__init__()
|
||||
QtGui.QWidget.__init__(self)
|
||||
|
||||
import os
|
||||
# self.form:
|
||||
self.form = FreeCADGui.PySideUic.loadUi(
|
||||
os.path.join(os.path.dirname(os.path.realpath(__file__)), "exportDXF.ui"))
|
||||
# setWindowIcon(QtGui.QIcon(os.path.join(PVPlantResources.DirIcons, "convert.svg")))
|
||||
# self.form.buttonTo.clicked.connect(self.addTo)
|
||||
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||
self.layout.addWidget(self.form)
|
||||
|
||||
self.form.buttonAcept.clicked.connect(self.onAceptClick)
|
||||
|
||||
path = os.path.join(os.path.dirname(FreeCAD.ActiveDocument.FileName), "outputs", "autocad")
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
self.filename = os.path.join(path, FreeCAD.ActiveDocument.Name) + ".dxf"
|
||||
|
||||
def createLayers(self):
|
||||
''' '''
|
||||
self.exporter.createLayer("Areas_Boundary", layerColor=(0, 125, 125), layerLineType="FENCELINE1")
|
||||
self.exporter.createLayer("Areas_Exclusion", layerColor=(255, 0, 0))
|
||||
self.exporter.createLayer("Areas_Offsets", layerColor=(128, 128, 255))
|
||||
|
||||
self.exporter.createLayer("Internal_Roads", layerColor=(128, 128, 128))
|
||||
self.exporter.createLayer("Internal_Roads_Axis", layerColor=(255, 255, 255), layerLineType="DASHEDX2")
|
||||
|
||||
|
||||
def writeArea(self):
|
||||
for area in FreeCAD.ActiveDocument.Boundary.Group:
|
||||
pol = self.exporter.createPolyline(area)
|
||||
pol.dxf.layer = "Areas_Boundary"
|
||||
|
||||
for area in FreeCAD.ActiveDocument.Exclusion.Group:
|
||||
pol = self.exporter.createPolyline(area)
|
||||
pol.dxf.layer = "Areas_Exclusion"
|
||||
|
||||
for area in FreeCAD.ActiveDocument.Offsets.Group:
|
||||
self.exporter.createPolyline(area)
|
||||
pol.dxf.layer = "Areas_Offsets"
|
||||
|
||||
def writeFrameSetups(self):
|
||||
import Part
|
||||
# 1. Profiles:
|
||||
profilelist = list()
|
||||
for ts in FreeCAD.ActiveDocument.Site.Frames:
|
||||
for poletype in ts.PoleType:
|
||||
if not (poletype in profilelist):
|
||||
profilelist.append(poletype)
|
||||
block = self.exporter.createBlock(poletype.Label)
|
||||
w = poletype.Base.Shape.Wires[0]
|
||||
w.Placement.Base = FreeCAD.Vector(w.Placement.Base).sub(w.BoundBox.Center)
|
||||
block.add_lwpolyline(getWire(w))
|
||||
|
||||
block.add_circle((0, 0), 0.2, dxfattribs={'color': 2})
|
||||
p = math.sin(math.radians(45)) * 0.2
|
||||
|
||||
block.add_line((-p, -p), (p, p), dxfattribs={"layer": "MyLines"})
|
||||
block.add_line((-p, p), (p, -p), dxfattribs={"layer": "MyLines"})
|
||||
|
||||
# 2. Frames
|
||||
for ts in FreeCAD.ActiveDocument.Site.Frames:
|
||||
w = max(ts.Shape.SubShapes[0].SubShapes[0].SubShapes[0].Faces, key=lambda x: x.Area)
|
||||
pts = [w.BoundBox.getPoint(i) for i in range(4)]
|
||||
pts.append(FreeCAD.Vector(pts[0]))
|
||||
w = Part.makePolygon(pts)
|
||||
w.Placement.Base = w.Placement.Base.sub(w.BoundBox.Center)
|
||||
mblockname = "Trina_TSM-DEG21C-20-6XXWp Vertex"
|
||||
mblock = self.exporter.createBlock(mblockname)
|
||||
mblock.add_lwpolyline(getWire(w))
|
||||
|
||||
rblock = self.exporter.createBlock(ts.Label)
|
||||
w = max(ts.Shape.SubShapes[0].SubShapes[1].SubShapes[0].Faces, key=lambda x: x.Placement.Base.z).Wires[0]
|
||||
w.Placement.Base = w.Placement.Base.sub(w.BoundBox.Center)
|
||||
rblock.add_lwpolyline(getWire(w))
|
||||
for module in ts.Shape.SubShapes[0].SubShapes[0].SubShapes:
|
||||
point = FreeCAD.Vector(module.BoundBox.Center) * 0.001
|
||||
point = point[:2]
|
||||
rblock.add_blockref(mblockname, point, dxfattribs={
|
||||
'xscale': .0,
|
||||
'yscale': .0,
|
||||
'rotation': 0})
|
||||
for ind in range(int(ts.NumberPole.Value)):
|
||||
point = ts.Shape.SubShapes[1].SubShapes[0].SubShapes[ind].Placement.Base * 0.001
|
||||
point = point[:2]
|
||||
name = ts.PoleType[ts.PoleSequence[ind]].Label
|
||||
rblock.add_blockref(name, point, dxfattribs={
|
||||
'xscale': .0,
|
||||
'yscale': .0,
|
||||
'rotation': 0})
|
||||
|
||||
def writeFrames(self):
|
||||
objects = findObjects('Tracker')
|
||||
for frame in objects:
|
||||
if hasattr(frame, "Setup"):
|
||||
point = frame.Placement.Base * 0.001
|
||||
point = point[:2]
|
||||
self.exporter.insertBlock(frame.Setup.Label, point=point, rotation=frame.AngleZ)
|
||||
|
||||
def writeRoads(self):
|
||||
objects = findObjects("Road")
|
||||
#rblock = self.exporter.createBlock("Internal_roads")
|
||||
for road in objects:
|
||||
base = self.exporter.createPolyline(road.Base)
|
||||
base.dxf.const_width = road.Width.Value * 0.001
|
||||
base.dxf.layer = "Internal_Roads"
|
||||
|
||||
axis = self.exporter.createPolyline(road.Base)
|
||||
axis.dxf.const_width = .2
|
||||
axis.dxf.layer = "Internal_Roads_Axis"
|
||||
#my_lines = doc.layers.get('MyLines')
|
||||
|
||||
def writeTrenches(self):
|
||||
objects = findObjects("Trench")
|
||||
# rblock = self.exporter.createBlock("Internal_roads")
|
||||
for obj in objects:
|
||||
base = self.exporter.createPolyline(obj.Base)
|
||||
base.dxf.const_width = obj.Width.Value * 0.001
|
||||
base.dxf.layer = "Trench"
|
||||
|
||||
def setup_layout4(self, doc):
|
||||
layout2 = doc.layouts.new("scale 1-1")
|
||||
# The default paperspace scale is 1:1
|
||||
# 1 mm printed is 1 drawing unit in paperspace
|
||||
# For most use cases this is the preferred scaling and important fact:
|
||||
# the paperspace scaling has no influence on the VIEWPORT scaling - this is
|
||||
# a total different topic, see example "viewports_in_paperspace.py"
|
||||
|
||||
layout2.page_setup(size=(297, 210),
|
||||
margins=(10, 10, 10, 10),
|
||||
units="mm",
|
||||
scale=(1, 1),
|
||||
#offset=(50, 50),
|
||||
)
|
||||
layout2.add_viewport(
|
||||
# center of viewport in paperspace units
|
||||
center=(100, 100),
|
||||
# viewport size in paperspace units
|
||||
size=(50, 50),
|
||||
# modelspace point to show in center of viewport in WCS
|
||||
view_center_point=(60, 40),
|
||||
# how much modelspace area to show in viewport in drawing units
|
||||
view_height=20,
|
||||
#status=2,
|
||||
)
|
||||
lower_left, upper_right = layout2.get_paper_limits()
|
||||
x1, y1 = lower_left
|
||||
x2, y2 = upper_right
|
||||
center = lower_left.lerp(upper_right)
|
||||
|
||||
# Add DXF entities to the "Layout1" in paperspace coordinates:
|
||||
layout2.add_line((x1, center.y), (x2, center.y)) # horizontal center line
|
||||
layout2.add_line((center.x, y1), (center.x, y2)) # vertical center line
|
||||
layout2.add_circle((0, 0), radius=5) # plot origin
|
||||
|
||||
def onAceptClick(self):
|
||||
self.exporter = exportDXF(self.filename)
|
||||
if self.exporter:
|
||||
self.exporter.createFile()
|
||||
self.createLayers()
|
||||
self.writeArea()
|
||||
self.writeFrameSetups()
|
||||
self.writeFrames()
|
||||
self.writeRoads()
|
||||
self.writeTrenches()
|
||||
self.setup_layout4(self.exporter.doc)
|
||||
|
||||
self.exporter.save()
|
||||
print(self.filename)
|
||||
|
||||
self.close()
|
||||
|
||||
|
||||
class _CommandExportDXF:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "dxf.svg")),
|
||||
'Accel': "E, A",
|
||||
'MenuText': "Export to DXF",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Export choosed layers to dxf")}
|
||||
|
||||
def Activated(self):
|
||||
taskd = _PVPlantExportDXF()
|
||||
taskd.setParent(FreeCADGui.getMainWindow())
|
||||
taskd.setWindowFlags(QtCore.Qt.Dialog or QtCore.Qt.Dialog)
|
||||
taskd.setWindowModality(QtCore.Qt.WindowModal)
|
||||
taskd.show()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('exportDXF', _CommandExportDXF())
|
||||
77
Export/exportDXF.ui
Normal file
77
Export/exportDXF.ui
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formPVSyst</class>
|
||||
<widget class="QDialog" name="formPVSyst">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>715</width>
|
||||
<height>520</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export to PVSyst</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Tab 1</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Tab 2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAcept">
|
||||
<property name="text">
|
||||
<string>Aceptar</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Accept">
|
||||
<normaloff>../../../../../.designer/backup</normaloff>../../../../../.designer/backup</iconset>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonCancel">
|
||||
<property name="text">
|
||||
<string>Cancelar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
15
Export/exportGeoJson.py
Normal file
15
Export/exportGeoJson.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import geojson
|
||||
from geojson import Point, Feature, FeatureCollection, dump
|
||||
|
||||
point = Point((-115.81, 37.24))
|
||||
|
||||
features = []
|
||||
features.append(Feature(geometry=point, properties={"country": "Spain"}))
|
||||
|
||||
# add more features...
|
||||
# features.append(...)
|
||||
|
||||
feature_collection = FeatureCollection(features)
|
||||
|
||||
with open('myfile.geojson', 'w') as f:
|
||||
dump(feature_collection, f)
|
||||
470
Export/exportPF.py
Normal file
470
Export/exportPF.py
Normal file
@@ -0,0 +1,470 @@
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
path_PF = r"C:\Program Files\DIgSILENT\PowerFactory 2021 SP2\Python\3.10"
|
||||
os.environ['PATH'] = path_PF + ";" + os.environ['PATH']
|
||||
os.add_dll_directory(path_PF)
|
||||
sys.path.append(path_PF)
|
||||
|
||||
import powerfactory as pf
|
||||
|
||||
app = pf.GetApplication()
|
||||
|
||||
print(app)
|
||||
|
||||
user = app.GetCurrentuser()
|
||||
project = app.ActivateProject('Nine-bus System') # Nombre del proyecto
|
||||
prj = app.GetActiveProject()
|
||||
|
||||
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
path = r'C:\Program Files\DIgSILENT\PowerFactory 2021 SP2\Python\3.10'
|
||||
os.environ['PATH'] += (";" + path)
|
||||
sys.path.append(path)
|
||||
|
||||
import powerfactory as pf
|
||||
|
||||
app = pf.GetApplication()
|
||||
if app is None:
|
||||
raise Exception('getting Powerfactory application failed')
|
||||
|
||||
# app.Show()
|
||||
|
||||
user = app.GetCurrentUser()
|
||||
projects = user.GetContents('*.IntPrj', 0)
|
||||
names = [pro.GetAttribute("loc_name") for pro in projects]
|
||||
|
||||
res = app.ActivateProject("ProyectoPrueba")
|
||||
if res == 1: # no existe y hay crearlo
|
||||
proj = app.CreateProject("ProyectoPrueba", "GridNueva")
|
||||
else:
|
||||
proj = app.GetActiveProject()
|
||||
|
||||
#########
|
||||
# MODEL #
|
||||
#########
|
||||
# Network model
|
||||
netmod = app.GetProjectFolder('netmod')
|
||||
# Network data
|
||||
netdata = app.GetProjectFolder('netdat')
|
||||
# Diagrams
|
||||
diag_fold = app.GetProjectFolder('dia')
|
||||
# Variations
|
||||
var_fold = app.GetProjectFolder('scheme')
|
||||
|
||||
###########
|
||||
# LIBRARY #
|
||||
###########
|
||||
# Equipment library
|
||||
equip = app.GetProjectFolder('equip')
|
||||
# lines_fold = equip.GetContents('Lines')[0][0]
|
||||
# User defined models
|
||||
main_lib = equip.GetParent()
|
||||
# udm = main_lib.GetContents('User Defined Models*')[0][0]
|
||||
# Script library
|
||||
script_lib = app.GetProjectFolder('script')
|
||||
# Template library
|
||||
templ_lib = app.GetProjectFolder('templ')
|
||||
# Operational library
|
||||
oplib = app.GetProjectFolder('oplib')
|
||||
# Characteristics
|
||||
# opchar = oplib.GetContents('Characteristics')[0][0]
|
||||
# Thermal ratings
|
||||
therm_fold = app.GetProjectFolder('therm')
|
||||
# MVAr limit curves
|
||||
mvar_fold = app.GetProjectFolder('mvar')
|
||||
|
||||
##############
|
||||
# STUDY CASE #
|
||||
##############
|
||||
# Study cases
|
||||
op_scen = app.GetProjectFolder('scen')
|
||||
# Operational scenarios
|
||||
sc_fold = app.GetProjectFolder('study')
|
||||
|
||||
# Diagramas:
|
||||
schemas = diag_fold.GetContents('*.IntGrfnet', 0)
|
||||
sch = None
|
||||
for obj in schemas:
|
||||
if obj.loc_name == "miEsquema":
|
||||
sch = obj
|
||||
break
|
||||
|
||||
if sch is None:
|
||||
sch = diag_fold.CreateObject("IntGrfnet", "miEsquema")
|
||||
|
||||
# redes:
|
||||
print(netdata)
|
||||
grids = netdata.GetContents('*.ElmNet', 0)
|
||||
grid = grids[0]
|
||||
ln = grid.GetContents('*.ElmLne', 0)[0]
|
||||
print(ln)
|
||||
# print(ln.type_id)
|
||||
print(f"Terminal 1 de la línea {ln.loc_name}: {ln.bus1}")
|
||||
print(f"Terminal 2 de la línea {ln.loc_name}: {ln.bus2}")
|
||||
|
||||
|
||||
def createCable(name):
|
||||
''''''
|
||||
cable = equip.CreateObject("TypCab", name)
|
||||
cable.uline
|
||||
cable.typCon = "cmp" # Forma (cmp: Macizo, hol: orificio, seg: sermento)
|
||||
cable.diaCon = 5.0 # diámetro externo (double) (mm)
|
||||
|
||||
# Capas condutoras: conductor, funda, blindaje
|
||||
cable.cHasEl = [1, 1, 1] # Existe
|
||||
cable.materialCond = [] # Material ()
|
||||
cable.crho = [] # Resistividad 20ºC (double) (uOhm*cm)
|
||||
cable.my = [] # Premeabilidad relativa (double)
|
||||
cable.cThEl = [] # Espesor (dobule) (mm)
|
||||
cable.Cf = [] # Factor de Relleno (double) (%)
|
||||
cable.rpha = [] # Resistenca DC 20ºC Ohm/km
|
||||
|
||||
# Capas de aislamiento: Aislamiento, Funda Exterior, Cubierta
|
||||
cable.cHasIns = [0, 0, 0] # Existe
|
||||
cable.materialIns = [] # Material
|
||||
cable.ctand = [] # Factor de Pérdidas Dieléctricas
|
||||
cable.cepsr = [] # Permeavilidad relativa
|
||||
cable.thlns = [] # Espesor (mm)
|
||||
|
||||
# Capas semicoductoras: Nucleo, Aislamiento
|
||||
cable.cHasSc = [] # Existe
|
||||
cable.thSc = [] # Espesor (mm)
|
||||
cable.cAdvSc = [] # Avanzado
|
||||
cable.rhoSc = [] # Resistividad uOhm*cm
|
||||
cable.mySc = [] # Permeabilidad relativa
|
||||
cable.epsrSC = [] # Premitividad relativa
|
||||
|
||||
cable.manuf = "" # fabricante
|
||||
|
||||
# 1 Flujo de carga
|
||||
cable.tmax = 90.0 # Máx. temperatura (ºC)
|
||||
|
||||
# 2. Cortocircuito VDE/IEC
|
||||
cable.rtemp = 80.0 # temperatura final máxima (ºC)
|
||||
cable.Ithr = 0.0 # Corriente de corta duración 1s (kA)
|
||||
|
||||
# 3. Análisis de Cables
|
||||
cable.tmax_screen = 70.0 # max. temparatura operación (ºC)
|
||||
cable.eps_emiss = 0.9 # coeficiente de emisión en la superficie
|
||||
cable.iopt_treated = True # Secado e impregnado
|
||||
cable.tshc = 1.0 # Cálculo de cortocircuito adiabático - Duración de la falla (s)
|
||||
|
||||
return cable
|
||||
|
||||
|
||||
def createLine(name):
|
||||
elmlne = p.CreateObject("ElmPvsys", name)
|
||||
elmlne.type_id = "" # Tipo
|
||||
elmlne.bus1 = "" # terminal i
|
||||
elmlne.bus2 = "" # terminal j
|
||||
elmlne.nlnum = 1 # líneas en paralelo
|
||||
elmlne.dline = 0.8 # longitud de la línea (double) (km)
|
||||
elmlne.fline = 1.0 # factor de reduccion (double)
|
||||
elmlne.inAir = 0 # Medio (0: Tierra, 1: Aérea)
|
||||
elmlne.i_dist = 0 # Modelo de la línea (0: Parámetros Concentrados, 1: Parámetros Distribuidos)
|
||||
|
||||
return elmlne
|
||||
|
||||
|
||||
def createPVPanel(name):
|
||||
typpvpanel = equip.CreateObject("TypPvPanel", name)
|
||||
typpvpanel.Ppk = 500.0 # Potencia Pico MPP (double) (W)
|
||||
typpvpanel.Umpp = 80.0 # Tensión nominal MPP (double) (V)
|
||||
typpvpanel.Impp = 6.0 # Corriente nominal MPP (double) (A)
|
||||
typpvpanel.Uoc = 90.0 # Tensión de Circuito Abierto (double) (V)
|
||||
typpvpanel.Isc = 7.0 # Corriente de cortocircuito (double) (A)
|
||||
typpvpanel.material = 0 # Material: 0:mono-SI, 1:poli-Si, 2:samor-SI, 3: CIS, 4:CdTe, 5: otro
|
||||
typpvpanel.usetval = 1 # Usar valores típicos
|
||||
typpvpanel.cT = -0.4 # Coeficiente de tenperatura P (double) (%/Cº)
|
||||
typpvpanel.noct = 45.0 # SINTC (double) (Cº)
|
||||
|
||||
typpvpanel.manuf = "" # Fabricante
|
||||
typpypanel.chr_name = "" # Nombre característico
|
||||
typpypanel.appr_status = 1 # Estado: 0: No aprobado, 1: aprobado
|
||||
|
||||
return typpvpanel
|
||||
|
||||
|
||||
def createPV(name):
|
||||
elmpvsys = grid.CreateObject("ElmPvsys", name)
|
||||
elmpvsys.typ_id = None
|
||||
elmpvsys.bus1 = None # terminal ()
|
||||
elmpvsys.mode_pgi = 0 # modelo (0:Entrada de potencia Activa, 1: Cálculo solar)
|
||||
elmpvsys.phtech = 0 # tecnología (0: 3F, 1: 3F-T, 2:1F F-T, 3:1F F-N)
|
||||
elmpvsys.ngnum = 1 # Inversores en paralelo (int)
|
||||
elmpvsys.npnum = 1 # Paneles por incersro (int)
|
||||
elmpvsys.sgn = 1.0 # Potencia aparente (double) (kVA)
|
||||
elmpvsys.cosn = 0.8 # Factor de Potencia nominal (double)
|
||||
# elmpvsys.
|
||||
return elmpvsys
|
||||
|
||||
|
||||
def createBarra(name, uknom=33.0):
|
||||
typbar = equip.CreateObject("TypBar", name)
|
||||
typbar.uknow = uknom
|
||||
|
||||
# 1. Cortocircuito VDE/IEC
|
||||
typbar.Ithlim = 0 # Corriente Nominal de Corto tiempo (kA)
|
||||
typbar.Tkr = 1 # tiempo Corriente Nominal de Corto tiempo (s)
|
||||
typbar.Iplim = 0 # Corriente Pico de cortocircuito (kA)
|
||||
|
||||
return typbar
|
||||
|
||||
|
||||
def createTerminal(name):
|
||||
elmterm = grid.CreateObject("ElmTerm", name)
|
||||
elmterm.systype = 0 # Tipo de sistema (0: AC, 1: DC, 2: AC/BI)
|
||||
elmterm.iUsage = 0 # Uso (0:Busbar, 1:Junction, Node 2: Internal node)
|
||||
elmterm.phtech = "ABC" # Tecnología de Fases: ABC, ABC-N, BI, BI-N, 2F, 2F-N, 1F, 1F-N, N
|
||||
elmterm.uknom = 33.0 # Tensión Nominal Línea-Línea (double)
|
||||
elmterm.iEarth = False # Aterrizado (bool)
|
||||
# Load Flow:
|
||||
# 1. Control de tensión:
|
||||
elmterm.vtarget = 1.0 # Tensión destino (double) (p.u.)
|
||||
elmterm.Vtarget = 0.0 # Tensión destino (double) (kV)
|
||||
elmterm.dvmax = 0.0 # Max delta V (double) (%)
|
||||
elmterm.dvmin = 0.0 # Min delta V (double) (%)
|
||||
elmterm.ivpriority = -1 # prioriddad
|
||||
# 2. Límite de tensión del estado estable
|
||||
elmterm.vmax = 1.05 # Límite superior de tensión (p.u.)
|
||||
elmterm.vmin = 0.0 # Límite inferior de tensión (p.u.)
|
||||
# 3. Límites del cambio del paso de tensión
|
||||
elmterm.vstep_change = True # Límites del cambio del paso de tensión (bool)
|
||||
elmterm.vstep_n1 = 6.0 # n-1 (%)
|
||||
elmterm.vstep_n2 = 12.0 # n-2 (%)
|
||||
elmterm.vstep_bus = 12.0 # falla de barra (%)
|
||||
# Análisis de Arco Eléctrico:
|
||||
elmterm.iAccessLoc = False # Ubicación Accesible (bool)
|
||||
elmterm.isSoftConstr = False # Restrinción blanda (bool)
|
||||
|
||||
crearCelda()
|
||||
|
||||
return elmterm
|
||||
|
||||
|
||||
def createCubic(parent, name):
|
||||
stacubic = parent.CreateObject("StaCubic", name)
|
||||
stacubic.cterm = parent
|
||||
# stacubic.obj_id =
|
||||
# stacubic.plntObjs =
|
||||
return stacubic
|
||||
|
||||
|
||||
def createSwitch(name):
|
||||
staswitch = ""
|
||||
|
||||
|
||||
def createTransformer(name):
|
||||
|
||||
|
||||
#
|
||||
|
||||
def createTransformerType(name):
|
||||
typTr3 = equip.CreateObject("TypTr3", name)
|
||||
typTr3.nt3ph = 3 # Tecnología (2: Monofásico, 3: trifásico)
|
||||
|
||||
# Potencia Nominal:
|
||||
typTr3.strn3_h = 1.0 # Lado AT (double) (MVA)
|
||||
typTr3.strn3_m = 1.0 # Lado MT (double) (MVA)
|
||||
typTr3.strn3_l = 1.0 # Lado BT (double) (MVA)
|
||||
|
||||
# Tensión nominal:
|
||||
typTr3.utrn3_h = 0.0 # Lado AT (double) (kV)
|
||||
typTr3.utrn3_m = 0.0 # Lado MT (double) (kV)
|
||||
typTr3.utrn3_l = 0.0 # Lado BT (double) (kV)
|
||||
|
||||
# Grupo Vectorial:
|
||||
typTr3.tr3cn_h = "YN" # Lado AT (Y, YN, Z, ZN, D)
|
||||
typTr3.nt3ag_h = 0.0 # Lado AT - Ángulo de desfase (double) (*30deg)
|
||||
typTr3.tr3cn_m = "YN" # Lado MT (Y, YN, Z, ZN, D)
|
||||
typTr3.nt3ag_m = 0.0 # Lado MT - Ángulo de desfase (double) (*30deg)
|
||||
typTr3.tr3cn_l = "YN" # Lado BT (Y, YN, Z, ZN, D)
|
||||
typTr3.nt3ag_l = 0.0 # Lado BT - Ángulo de desfase (double) (*30deg)
|
||||
|
||||
# Impedancia de secuencia positiva
|
||||
# Tensión de Cortocircuito uk:
|
||||
typTr3.uktr3_h = 3.0 # AT-MT (double) (%)
|
||||
typTr3.uktr3_m = 3.0 # MT-BT (double) (%)
|
||||
typTr3.uktr3_l = 3.0 # BT-AT (double) (%)
|
||||
|
||||
# Pérdidas en el Cobre
|
||||
typTr3.pcut3_h = 0.0 # AT-MT (double) (kW)
|
||||
typTr3.pcut3_m = 0.0 # MT-BT (double) (kW)
|
||||
typTr3.pcut3_l = 0.0 # BT-AT (double) (kW)
|
||||
|
||||
# Impedancia de secuencia cero
|
||||
# Tensión de Cortocircuito uk0:
|
||||
typTr3.uk0hm = 3.0 # AT-MT (double) (%)
|
||||
typTr3.uk0ml = 3.0 # MT-BT (double) (%)
|
||||
typTr3.uk0hl = 3.0 # BT-AT (double) (%)
|
||||
|
||||
# Pérdidas en el Cobre
|
||||
typTr3.ur0hm = 0.0 # AT-MT (double) (kW)
|
||||
typTr3.ur0ml = 0.0 # MT-BT (double) (kW)
|
||||
typTr3.ur0hl = 0.0 # BT-AT (double) (kW)
|
||||
|
||||
|
||||
# print(dir(app))
|
||||
# print(dir(app.CreateProject))
|
||||
|
||||
|
||||
cable = equip.GetContents('*.TypCab', 0)[0]
|
||||
print(dir(cable))
|
||||
print(cable.cHasEl)
|
||||
print(cable.materialCond)
|
||||
print(cable.tab_con)
|
||||
|
||||
'''
|
||||
Run a load flow
|
||||
|
||||
#define project name and study case
|
||||
projName = '_TSI_Nine-bus System'
|
||||
study_case = '01_Study_Case.IntCase'
|
||||
|
||||
#activate project
|
||||
project = app.ActivateProject(projName)
|
||||
proj = app.GetActiveProject()
|
||||
|
||||
#get the study case folder and activate project
|
||||
oFolder_studycase = app.GetProjectFolder('study')
|
||||
oCase = oFolder_studycase.GetContents(study_case)[0]
|
||||
oCase.Activate()
|
||||
|
||||
#get load flow object and execute
|
||||
oLoadflow=app.GetFromStudyCase('ComLdf') #get load flow object
|
||||
oLoadflow.Execute() #execute load flow
|
||||
'''
|
||||
|
||||
'''
|
||||
Print the results for generators, lines, and buses
|
||||
|
||||
|
||||
#get the generators and their active/reactive power and loading
|
||||
Generators = app.GetCalcRelevantObjects('*.ElmSym')
|
||||
for gen in Generators: #loop through list
|
||||
name = getattr(gen, 'loc_name') # get name of the generator
|
||||
actPower = getattr(gen,'c:p') #get active power
|
||||
reacPower = getattr(gen,'c:q') #get reactive power
|
||||
genloading = getattr(gen,'c:loading') #get loading
|
||||
#print results
|
||||
print('%s: P = %.2f MW, Q = %.2f MVAr, loading = %.0f percent' %(name,actPower,reacPower,genloading))
|
||||
|
||||
print('-----------------------------------------')
|
||||
|
||||
#get the lines and print their loading
|
||||
Lines=app.GetCalcRelevantObjects('*.ElmLne')
|
||||
for line in Lines: #loop through list
|
||||
name = getattr(line, 'loc_name') # get name of the line
|
||||
value = getattr(line, 'c:loading') #get value for the loading
|
||||
#print results
|
||||
print('Loading of the line: %s = %.2f percent' %(name,value))
|
||||
|
||||
print('-----------------------------------------')
|
||||
|
||||
#get the buses and print their voltage
|
||||
Buses=app.GetCalcRelevantObjects('*.ElmTerm')
|
||||
for bus in Buses: #loop through list
|
||||
name = getattr(bus, 'loc_name') # get name of the bus
|
||||
amp = getattr(bus, 'm:u1') #get voltage magnitude
|
||||
phase = getattr(bus, 'm:phiu') #get voltage angle
|
||||
#print results
|
||||
print('Voltage at %s = %.2f pu %.2f deg' %(name,amp,phase))
|
||||
'''
|
||||
|
||||
'''
|
||||
Run an RMS simulation
|
||||
|
||||
#define project name and study case
|
||||
projName = '_TSI_nine_bus_system'
|
||||
study_case = '01_Study_Case.IntCase'
|
||||
|
||||
#activate project
|
||||
project = app.ActivateProject(projName)
|
||||
proj = app.GetActiveProject()
|
||||
|
||||
#get the study case folder and activate project
|
||||
oFolder_studycase = app.GetProjectFolder('study')
|
||||
oCase = oFolder_studycase.GetContents(study_case)[0]
|
||||
oCase.Activate()
|
||||
|
||||
# calculate initial conditions
|
||||
oInit = app.GetFromStudyCase('ComInc') #get initial condition calculation object
|
||||
oInit.Execute()
|
||||
|
||||
#run RMS-simulation
|
||||
oRms = app.GetFromStudyCase('ComSim') #get RMS-simulation object
|
||||
oRms.Execute()
|
||||
'''
|
||||
|
||||
'''
|
||||
Retrieve RMS results from PowerFactory in Python
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
def getResults():
|
||||
#get result file
|
||||
elmRes = app.GetFromStudyCase('*.ElmRes')
|
||||
app.ResLoadData(elmRes)
|
||||
|
||||
#Get number of rows and columns
|
||||
NrRow = app.ResGetValueCount(elmRes,0)
|
||||
|
||||
#get objects of interest
|
||||
oSG1 = app.GetCalcRelevantObjects('G1.ElmSym')[0]
|
||||
oBus1 = app.GetCalcRelevantObjects('Bus 1.ElmTerm')[0]
|
||||
oLine4_5 = app.GetCalcRelevantObjects('Line 4-5.ElmLne')[0]
|
||||
|
||||
#Get index of variable of interest
|
||||
ColIndex_time = app.ResGetIndex(elmRes,elmRes,'b:tnow')
|
||||
ColIndex_ut = app.ResGetIndex(elmRes,oSG1,'s:ut')
|
||||
ColIndex_P = app.ResGetIndex(elmRes,oSG1,'s:P1')
|
||||
ColIndex_Q = app.ResGetIndex(elmRes,oSG1,'s:Q1')
|
||||
ColIndex_speed = app.ResGetIndex(elmRes,oSG1,'s:xspeed')
|
||||
ColIndex_u_bus1 = app.ResGetIndex(elmRes,oBus1,'m:u')
|
||||
ColIndex_loading_line_4_5 = app.ResGetIndex(elmRes,oLine4_5,'c:loading')
|
||||
|
||||
#pre-allocate result variables
|
||||
result_time = np.zeros((NrRow,))
|
||||
result_ut = np.zeros((NrRow))
|
||||
result_P = np.zeros((NrRow))
|
||||
result_Q = np.zeros((NrRow))
|
||||
result_speed = np.zeros((NrRow))
|
||||
result_u_bus1 = np.zeros((NrRow))
|
||||
result_loading_line_4_5 = np.zeros((NrRow))
|
||||
|
||||
#get results for each time step
|
||||
for i in range(NrRow):
|
||||
result_time[i] = app.ResGetData(elmRes,i,ColIndex_time)[1]
|
||||
result_ut[i] = app.ResGetData(elmRes,i,ColIndex_ut)[1]
|
||||
result_P[i] = app.ResGetData(elmRes,i,ColIndex_P)[1]
|
||||
result_Q[i] = app.ResGetData(elmRes,i,ColIndex_Q)[1]
|
||||
result_speed[i] = app.ResGetData(elmRes,i,ColIndex_speed)[1]
|
||||
result_u_bus1[i] = app.ResGetData(elmRes,i,ColIndex_u_bus1)[1]
|
||||
result_loading_line_4_5[i] = app.ResGetData(elmRes,i,ColIndex_loading_line_4_5)[1]
|
||||
|
||||
results = pd.DataFrame()
|
||||
results['time'] = result_time
|
||||
results['P'] = result_P
|
||||
results['Q'] = result_Q
|
||||
results['ut'] = result_ut
|
||||
results['speed'] = result_speed
|
||||
results['u_bus1'] = result_u_bus1
|
||||
results['loading_line_4_5'] = result_loading_line_4_5
|
||||
return results
|
||||
|
||||
#query results
|
||||
RES = getResults()
|
||||
'''
|
||||
|
||||
## Graphical objects:
|
||||
|
||||
|
||||
|
||||
864
Export/exportPVSyst.py
Normal file
864
Export/exportPVSyst.py
Normal file
@@ -0,0 +1,864 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 Arch
|
||||
import Draft
|
||||
import FreeCAD
|
||||
import Mesh
|
||||
import MeshPart
|
||||
import Part
|
||||
import numpy
|
||||
import os
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
from DraftTools import translate
|
||||
else:
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
## @package importDAE
|
||||
# \ingroup ARCH
|
||||
# \brief DAE (Collada) file format importer and exporter
|
||||
#
|
||||
# This module provides tools to import and export Collada (.dae) files.
|
||||
|
||||
__title__ = "FreeCAD Collada importer"
|
||||
__author__ = "Yorik van Havre"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
try:
|
||||
# Python 2 forward compatibility
|
||||
range = xrange
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
|
||||
def checkCollada():
|
||||
"checks if collada if available"
|
||||
|
||||
global collada
|
||||
COLLADA = None
|
||||
try:
|
||||
import collada
|
||||
except ImportError:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "pycollada not found, collada support is disabled.") + "\n")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
# from ARCH:
|
||||
def triangulate(shape):
|
||||
"triangulates the given face"
|
||||
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
|
||||
mesher = p.GetInt("ColladaMesher", 0)
|
||||
tessellation = p.GetFloat("ColladaTessellation", 1.0)
|
||||
grading = p.GetFloat("ColladaGrading", 0.3)
|
||||
segsperedge = p.GetInt("ColladaSegsPerEdge", 1)
|
||||
segsperradius = p.GetInt("ColladaSegsPerRadius", 2)
|
||||
secondorder = p.GetBool("ColladaSecondOrder", False)
|
||||
optimize = p.GetBool("ColladaOptimize", True)
|
||||
allowquads = p.GetBool("ColladaAllowQuads", False)
|
||||
|
||||
if mesher == 0:
|
||||
return shape.tessellate(tessellation)
|
||||
elif mesher == 1:
|
||||
return MeshPart.meshFromShape(Shape=shape, MaxLength=tessellation).Topology
|
||||
else:
|
||||
return MeshPart.meshFromShape(Shape=shape, GrowthRate=grading, SegPerEdge=segsperedge,
|
||||
SegPerRadius=segsperradius, SecondOrder=secondorder, Optimize=optimize,
|
||||
AllowQuad=allowquads).Topology
|
||||
|
||||
def export(exportList, filename, tessellation=1, colors=None):
|
||||
"""export(exportList,filename,tessellation=1,colors=None) -- exports FreeCAD contents to a DAE file.
|
||||
colors is an optional dictionary of objName:shapeColorTuple or objName:diffuseColorList elements
|
||||
to be used in non-GUI mode if you want to be able to export colors. Tessellation is used when breaking
|
||||
curved surfaces into triangles."""
|
||||
|
||||
if not checkCollada(): return
|
||||
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
|
||||
scale = p.GetFloat("ColladaScalingFactor", 1.0)
|
||||
scale = scale * 0.001 # from millimeters (FreeCAD) to meters (Collada)
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
|
||||
c = p.GetUnsigned("DefaultShapeColor", 4294967295)
|
||||
defaultcolor = (float((c >> 24) & 0xFF) / 255.0, float((c >> 16) & 0xFF) / 255.0, float((c >> 8) & 0xFF) / 255.0)
|
||||
colmesh = collada.Collada()
|
||||
colmesh.assetInfo.upaxis = collada.asset.UP_AXIS.Z_UP
|
||||
|
||||
# authoring info
|
||||
cont = collada.asset.Contributor()
|
||||
try:
|
||||
author = FreeCAD.ActiveDocument.CreatedBy
|
||||
except UnicodeEncodeError:
|
||||
author = FreeCAD.ActiveDocument.CreatedBy.encode("utf8")
|
||||
author = author.replace("<", "")
|
||||
author = author.replace(">", "")
|
||||
cont.author = author
|
||||
ver = FreeCAD.Version()
|
||||
appli = "PVPlant for FreeCAD" + ver[0] + "." + ver[1] + " build" + ver[2] + "\n"
|
||||
cont.authoring_tool = appli
|
||||
|
||||
colmesh.assetInfo.contributors.append(cont)
|
||||
colmesh.assetInfo.unitname = "meter"
|
||||
colmesh.assetInfo.unitmeter = 1.0
|
||||
|
||||
defaultmat = None
|
||||
objind = 0
|
||||
scenenodes = []
|
||||
|
||||
# TODO: cambiar lo de objeclist. Buscar los elementos que se necesitan exportar
|
||||
objectlist = Draft.get_group_contents(exportList, walls=True, addgroups=True)
|
||||
objectlist = Arch.pruneIncluded(objectlist)
|
||||
for obj in objectlist:
|
||||
findex = numpy.array([])
|
||||
m = None
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
print("exporting object ", obj.Name, obj.Shape)
|
||||
new_shape = obj.Shape.copy()
|
||||
new_shape.Placement = obj.getGlobalPlacement()
|
||||
m = Mesh.Mesh(triangulate(new_shape))
|
||||
elif obj.isDerivedFrom("Mesh::Feature"):
|
||||
print("exporting object ", obj.Name, obj.Mesh)
|
||||
m = obj.Mesh
|
||||
elif obj.isDerivedFrom("App::Part"):
|
||||
for child in obj.OutList:
|
||||
objectlist.append(child)
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
if m:
|
||||
Topology = m.Topology
|
||||
Facets = m.Facets
|
||||
|
||||
# vertex indices
|
||||
vindex = numpy.empty(len(Topology[0]) * 3)
|
||||
for i in range(len(Topology[0])):
|
||||
v = Topology[0][i]
|
||||
vindex[list(range(i * 3, i * 3 + 3))] = (v.x * scale, v.y * scale, v.z * scale)
|
||||
|
||||
# normals
|
||||
nindex = numpy.empty(len(Facets) * 3)
|
||||
for i in range(len(Facets)):
|
||||
n = Facets[i].Normal
|
||||
nindex[list(range(i * 3, i * 3 + 3))] = (n.x, n.y, n.z)
|
||||
|
||||
# face indices
|
||||
findex = numpy.empty(len(Topology[1]) * 6, numpy.int64)
|
||||
for i in range(len(Topology[1])):
|
||||
f = Topology[1][i]
|
||||
findex[list(range(i * 6, i * 6 + 6))] = (f[0], i, f[1], i, f[2], i)
|
||||
|
||||
print(len(vindex), " vert indices, ", len(nindex), " norm indices, ", len(findex), " face indices.")
|
||||
vert_src = collada.source.FloatSource("cubeverts-array" + str(objind), vindex, ('X', 'Y', 'Z'))
|
||||
normal_src = collada.source.FloatSource("cubenormals-array" + str(objind), nindex, ('X', 'Y', 'Z'))
|
||||
geom = collada.geometry.Geometry(colmesh, "geometry" + str(objind), obj.Name, [vert_src, normal_src])
|
||||
input_list = collada.source.InputList()
|
||||
input_list.addInput(0, 'VERTEX', "#cubeverts-array" + str(objind))
|
||||
input_list.addInput(1, 'NORMAL', "#cubenormals-array" + str(objind))
|
||||
matnode = None
|
||||
matref = "materialref"
|
||||
if hasattr(obj, "Material"):
|
||||
if obj.Material:
|
||||
if hasattr(obj.Material, "Material"):
|
||||
if "DiffuseColor" in obj.Material.Material:
|
||||
kd = tuple([float(k) for k in obj.Material.Material["DiffuseColor"].strip("()").split(",")])
|
||||
effect = collada.material.Effect("effect_" + obj.Material.Name, [], "phong", diffuse=kd,
|
||||
specular=(1, 1, 1))
|
||||
mat = collada.material.Material("mat_" + obj.Material.Name, obj.Material.Name, effect)
|
||||
colmesh.effects.append(effect)
|
||||
colmesh.materials.append(mat)
|
||||
matref = "ref_" + obj.Material.Name
|
||||
matnode = collada.scene.MaterialNode(matref, mat, inputs=[])
|
||||
|
||||
if not matnode:
|
||||
if colors:
|
||||
if obj.Name in colors:
|
||||
color = colors[obj.Name]
|
||||
if color:
|
||||
if isinstance(color[0], tuple):
|
||||
# this is a diffusecolor. For now, use the first color - #TODO: Support per-face colors
|
||||
color = color[0]
|
||||
# print("found color for obj",obj.Name,":",color)
|
||||
kd = color[:3]
|
||||
effect = collada.material.Effect("effect_" + obj.Name, [], "phong", diffuse=kd,
|
||||
specular=(1, 1, 1))
|
||||
mat = collada.material.Material("mat_" + obj.Name, obj.Name, effect)
|
||||
colmesh.effects.append(effect)
|
||||
colmesh.materials.append(mat)
|
||||
matref = "ref_" + obj.Name
|
||||
matnode = collada.scene.MaterialNode(matref, mat, inputs=[])
|
||||
elif FreeCAD.GuiUp:
|
||||
if hasattr(obj.ViewObject, "ShapeColor"):
|
||||
kd = obj.ViewObject.ShapeColor[:3]
|
||||
effect = collada.material.Effect("effect_" + obj.Name, [], "phong", diffuse=kd, specular=(1, 1, 1))
|
||||
mat = collada.material.Material("mat_" + obj.Name, obj.Name, effect)
|
||||
colmesh.effects.append(effect)
|
||||
colmesh.materials.append(mat)
|
||||
matref = "ref_" + obj.Name
|
||||
matnode = collada.scene.MaterialNode(matref, mat, inputs=[])
|
||||
|
||||
if not matnode:
|
||||
if not defaultmat:
|
||||
effect = collada.material.Effect("effect_default", [], "phong", diffuse=defaultcolor,
|
||||
specular=(1, 1, 1))
|
||||
defaultmat = collada.material.Material("mat_default", "default_material", effect)
|
||||
colmesh.effects.append(effect)
|
||||
colmesh.materials.append(defaultmat)
|
||||
matnode = collada.scene.MaterialNode(matref, defaultmat, inputs=[])
|
||||
|
||||
triset = geom.createTriangleSet(findex, input_list, matref)
|
||||
geom.primitives.append(triset)
|
||||
colmesh.geometries.append(geom)
|
||||
geomnode = collada.scene.GeometryNode(geom, [matnode])
|
||||
node = collada.scene.Node("node" + str(objind), children=[geomnode])
|
||||
scenenodes.append(node)
|
||||
objind += 1
|
||||
|
||||
myscene = collada.scene.Scene("PVScene", scenenodes)
|
||||
colmesh.scenes.append(myscene)
|
||||
colmesh.scene = myscene
|
||||
colmesh.write(filename)
|
||||
|
||||
FreeCAD.Console.PrintMessage(translate("Arch", "file %s successfully created.") % filename)
|
||||
|
||||
def exportToDAE(path):
|
||||
filename = path + ".dae"
|
||||
|
||||
def exportToPVC(path, exportTerrain = False):
|
||||
filename = path + ".pvc"
|
||||
scale = 0.001 # from millimeters (FreeCAD) to meters (Collada)
|
||||
|
||||
from xml.etree.ElementTree import Element, SubElement
|
||||
import datetime
|
||||
|
||||
generated_on = str(datetime.datetime.now())
|
||||
|
||||
site = None
|
||||
tmp = FreeCAD.ActiveDocument.getObjectsByLabel('Site')
|
||||
for obj in tmp:
|
||||
if obj.Name.startswith("Site"):
|
||||
site = obj
|
||||
break
|
||||
terrain = None
|
||||
center = None
|
||||
if not(site.Terrain is None):
|
||||
terrain = site.Terrain.Mesh
|
||||
center = terrain.BoundBox.Center
|
||||
else:
|
||||
center = FreeCAD.Vector()
|
||||
|
||||
try:
|
||||
author = FreeCAD.ActiveDocument.CreatedBy
|
||||
except UnicodeEncodeError:
|
||||
author = FreeCAD.ActiveDocument.CreatedBy.encode("utf8")
|
||||
|
||||
author = author.replace("<", "")
|
||||
author = author.replace(">", "")
|
||||
ver = FreeCAD.Version()
|
||||
appli = "PVPlant for FreeCAD" + ver[0] + "." + ver[1] + " build" + ver[2] + "\n"
|
||||
|
||||
# xml: Configure one attribute with set()
|
||||
root = Element('COLLADA')
|
||||
root.set('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
|
||||
root.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
|
||||
root.set('version', '1.4.1')
|
||||
root.set('xmlns', 'http://www.collada.org/2005/11/COLLADASchema')
|
||||
#root.append(Comment('Generated by ElementTree_csv_to_xml.py for PyMOTW'))
|
||||
|
||||
# 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_authoring_tool = SubElement(asset_contributor, 'authoring_tool')
|
||||
#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_unit = SubElement(asset, 'unit')
|
||||
asset_unit.set('meter', '0.001')
|
||||
asset_unit.set('name', 'millimeter')
|
||||
|
||||
# xml: 2. library_materials:
|
||||
library_materials = SubElement(root, 'library_materials')
|
||||
buf = ['Frames', 'Tree_trunk', 'Tree_crown', 'Topography_mesh']
|
||||
|
||||
for i in range(0, len(buf)):
|
||||
material = SubElement(library_materials, 'material')
|
||||
material.set('id', 'Material{0}'.format(i))
|
||||
material.set('name', buf[i])
|
||||
material_effect = SubElement(material, 'instance_effect')
|
||||
material_effect.set('url', '#Material{0}-fx'.format(i))
|
||||
|
||||
# xml: 3. library_effects:
|
||||
library_effects = SubElement(root, 'library_effects')
|
||||
buf = ['0.250000 0.500000 0.000000 1.000000',
|
||||
'0.500000 0.375000 0.250000 1.000000',
|
||||
'0.250000 1.000000 0.000000 1.000000',
|
||||
'0.250000 1.000000 0.000000 1.000000']
|
||||
|
||||
for i in range(0, len(buf)):
|
||||
effect = SubElement(library_effects, 'effect')
|
||||
effect.set('id', 'Material{0}-fx'.format(i))
|
||||
effect.set('name', 'Material{0}'.format(i))
|
||||
profile_COMMON = SubElement(effect, 'profile_COMMON')
|
||||
library_effects_effect_technique = SubElement(profile_COMMON, 'technique')
|
||||
library_effects_effect_technique.set('sid', 'standard')
|
||||
library_effects_effect_technique_lambert = SubElement(library_effects_effect_technique, 'lambert')
|
||||
library_effects_effect_technique_lambert_emission = SubElement(library_effects_effect_technique_lambert,
|
||||
'emission')
|
||||
library_effects_effect_technique_lambert_emission_color = SubElement(
|
||||
library_effects_effect_technique_lambert_emission, 'color')
|
||||
library_effects_effect_technique_lambert_emission_color.set('sid', 'emission')
|
||||
library_effects_effect_technique_lambert_emission_color.text = '0.000000 0.000000 0.000000 1.000000'
|
||||
ambient = SubElement(library_effects_effect_technique_lambert, 'ambient')
|
||||
ambient_color = SubElement(ambient, 'color')
|
||||
ambient_color.set('sid', 'ambient')
|
||||
ambient_color.text = '0.200000 0.200000 0.200000 1.000000'
|
||||
diffuse = SubElement(library_effects_effect_technique_lambert, 'diffuse')
|
||||
diffuse_color = SubElement(diffuse, 'color')
|
||||
diffuse_color.set('sid', 'diffuse')
|
||||
diffuse_color.text = buf[i]
|
||||
transparent = SubElement(library_effects_effect_technique_lambert, 'transparent')
|
||||
transparent.set('opaque', 'RGB_ZERO')
|
||||
transparent_color = SubElement(transparent, 'color')
|
||||
transparent_color.set('sid', 'transparent')
|
||||
transparent_color.text = '0.000000 0.000000 0.000000 1.000000'
|
||||
transparency = SubElement(library_effects_effect_technique_lambert, 'transparency')
|
||||
transparency_value = SubElement(transparency, 'float')
|
||||
transparency_value.set('sid', 'transparency')
|
||||
transparency_value.text = '0'
|
||||
|
||||
# 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'
|
||||
referenceSTR = 'frame'
|
||||
isFrame = True
|
||||
elif objtype == 1:
|
||||
geometryName = 'ShadowMesh' ## --> ???
|
||||
referenceSTR = 'ShadowMesh' ## --> ???
|
||||
elif objtype == 2:
|
||||
geometryName = 'TerrainMesh'
|
||||
referenceSTR = 'TerrainMesh'
|
||||
|
||||
geometry = SubElement(library_geometries, 'geometry')
|
||||
geometry.set('id', geometryName + '{0}'.format(objind))
|
||||
mesh = SubElement(geometry, 'mesh')
|
||||
|
||||
source = SubElement(mesh, 'source')
|
||||
source.set('id', referenceSTR + '{0}MeshSource'.format(objind))
|
||||
float_array = SubElement(source, 'float_array')
|
||||
float_array.set('id', referenceSTR + '{0}FloatArray'.format(objind))
|
||||
float_array.set('count', '{0}'.format(len(vindex)))
|
||||
float_array.text = "" # vindex
|
||||
for ver in vindex:
|
||||
if len(float_array.text) > 0:
|
||||
float_array.text += ' '
|
||||
float_array.text += '{0:.6f}'.format(ver)
|
||||
|
||||
technique_common = SubElement(source, 'technique_common')
|
||||
accessor = SubElement(technique_common, 'accessor')
|
||||
accessor.set('count', '{0}'.format(len(vindex)))
|
||||
accessor.set('source', '#' + referenceSTR + '{0}FloatArray'.format(objind))
|
||||
accessor.set('stride', '3')
|
||||
param = SubElement(accessor, 'param')
|
||||
param.set('name', 'X')
|
||||
param.set('type', 'float')
|
||||
param = SubElement(accessor, 'param')
|
||||
param.set('name', 'Y')
|
||||
param.set('type', 'float')
|
||||
param = SubElement(accessor, 'param')
|
||||
param.set('name', 'Z')
|
||||
param.set('type', 'float')
|
||||
|
||||
vertices = SubElement(mesh, 'vertices')
|
||||
vertices.set('id', referenceSTR + '{0}VerticesSource'.format(objind))
|
||||
input = SubElement(vertices, "input")
|
||||
input.set('semantic', 'POSITION')
|
||||
input.set('source', '#' + referenceSTR + '{0}MeshSource'.format(objind))
|
||||
|
||||
triangles = SubElement(mesh, 'triangles')
|
||||
triangles.set('count', '0')
|
||||
triangles.set('material', 'Material0')
|
||||
input = SubElement(triangles, "input")
|
||||
input.set('offset', '0')
|
||||
input.set('semantic', 'VERTEX')
|
||||
input.set('source', '#' + referenceSTR + '{0}VerticesSource'.format(objind))
|
||||
p = SubElement(triangles, "p")
|
||||
p.text = ''
|
||||
for f in findex:
|
||||
if len(p.text) > 0:
|
||||
p.text += ' '
|
||||
p.text += '{0}'.format(f)
|
||||
|
||||
if isFrame:
|
||||
frame = SubElement(mesh, 'tracker_parameters' if isTracker else 'frame_parameters')
|
||||
module_width = SubElement(frame, "module_width")
|
||||
module_width.text = '{0}'.format(int(obj.Setup.ModuleWidth.Value))
|
||||
module_height = SubElement(frame, "module_height")
|
||||
module_height.text = '{0}'.format(int(obj.Setup.ModuleHeight.Value))
|
||||
module_x_spacing = SubElement(frame, "module_x_spacing")
|
||||
module_x_spacing.text = '{0}'.format(int(obj.Setup.ModuleColGap.Value))
|
||||
module_y_spacing = SubElement(frame, "module_y_spacing")
|
||||
module_y_spacing.text = '{0}'.format(int(obj.Setup.ModuleRowGap.Value))
|
||||
module_manufacturer = SubElement(frame, "module_manufacturer")
|
||||
module_manufacturer.text = 'generic'
|
||||
module_name = SubElement(frame, "module_name")
|
||||
module_name.text = 'generic'
|
||||
if isTracker:
|
||||
tracker_type = SubElement(frame, 'tracker_type')
|
||||
tracker_type.text = 'single_axis_trackers'
|
||||
axis = SubElement(frame, 'axis_vertices')
|
||||
for ind in range(0, len(centers)):
|
||||
array = SubElement(axis, 'float_array')
|
||||
array.set('id', 'tracker{0}AxisFloatArray1'.format(ind))
|
||||
array.set('count', '3')
|
||||
array.text = '{0:.6f} {1:.6f} {2:.6f}'.format(centers[i].x, centers[i].y, centers[i].z)
|
||||
|
||||
min_phi = SubElement(frame, 'min_phi')
|
||||
min_phi.text = '{0}'.format(int(obj.Setup.MinPhi.Value))
|
||||
max_phi = SubElement(frame, 'max_phi')
|
||||
max_phi.text = '{0}'.format(int(obj.Setup.MaxPhi.Value))
|
||||
min_theta = SubElement(frame, 'min_theta')
|
||||
min_theta.text = '{0}'.format(0)
|
||||
max_theta = SubElement(frame, 'max_theta')
|
||||
max_theta.text = '{0}'.format(0)
|
||||
|
||||
# xml: 5. library_visual_scenes:
|
||||
instance_geometry = SubElement(node, 'instance_geometry')
|
||||
instance_geometry.set('url', geometryName + '{0}'.format(objind))
|
||||
|
||||
bind_material = SubElement(instance_geometry, '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')
|
||||
instance_material = SubElement(technique_common, 'instance_material')
|
||||
instance_material.set('symbol', 'Material1')
|
||||
instance_material.set('target', '#Material1')
|
||||
instance_material = SubElement(technique_common, 'instance_material')
|
||||
instance_material.set('symbol', 'Material2')
|
||||
instance_material.set('target', '#Material2')
|
||||
|
||||
# xml: 5. library_visual_scenes:
|
||||
library_visual_scenes = SubElement(root, 'library_visual_scenes')
|
||||
visual_scene = SubElement(library_visual_scenes, 'visual_scene')
|
||||
visual_scene.set('id', '')
|
||||
visual_scene.set('name', '')
|
||||
|
||||
node = SubElement(visual_scene, 'node')
|
||||
node.set('id', 'Fbx_Root')
|
||||
node.set('name', 'Fbx_Root')
|
||||
node.set('sid', 'Fbx_Root')
|
||||
matrix = SubElement(node, 'matrix')
|
||||
matrix.set('sid', 'matrix')
|
||||
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'
|
||||
node = SubElement(node, 'node')
|
||||
node.set('id', 'PVcase52')
|
||||
node.set('name', 'PVcase52')
|
||||
node.set('sid', 'PVcase52')
|
||||
matrix = SubElement(node, 'matrix')
|
||||
matrix.set('sid', 'matrix')
|
||||
matrix.text = '1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000'
|
||||
|
||||
extra = SubElement(visual_scene, 'extra')
|
||||
technique = SubElement(extra, 'technique')
|
||||
technique.set('profile', 'MAX3D')
|
||||
frame_rate = SubElement(technique, 'frame_rate')
|
||||
frame_rate.text = '30.000000'
|
||||
technique = SubElement(extra, 'technique')
|
||||
technique.set('profile', 'FCOLLADA')
|
||||
start_time = SubElement(technique, 'start_time')
|
||||
start_time.text = '0.000000'
|
||||
end_time = SubElement(technique, 'end_time')
|
||||
end_time.text = '1.000000'
|
||||
|
||||
# xml: 6. scene:
|
||||
scene = SubElement(root, 'scene')
|
||||
instance = SubElement(scene, 'instance_visual_scene')
|
||||
instance.set('url', '#')
|
||||
|
||||
full_list_of_objects = FreeCAD.ActiveDocument.Objects
|
||||
|
||||
# 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 type in frameType:
|
||||
isTracker = "tracker" in type.Proxy.Type.lower()
|
||||
#TODO: Sólo para los proyectos de NAcho. Borrar
|
||||
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()
|
||||
|
||||
for obj in objectlist:
|
||||
if obj.Setup == type:
|
||||
findex = numpy.array([])
|
||||
|
||||
modules = obj.Setup.Shape.SubShapes[0].SubShapes[0]
|
||||
pts = []
|
||||
for i in range(4):
|
||||
pts.append(modules.BoundBox.getPoint(i))
|
||||
|
||||
# temp -----
|
||||
if obj.Tilt.Value != 0:
|
||||
zz = int(pts[0].z) - (obj.Setup.MainBeamHeight.Value / 2 + obj.Setup.BeamHeight.Value)
|
||||
for p in pts:
|
||||
p.z -= zz
|
||||
new_shape = Part.Face(Part.makePolygon(pts))
|
||||
new_shape.Placement.Rotation.setEulerAngles("XYZ", obj.Tilt.Value, 0, 0)
|
||||
pts = []
|
||||
for ver in new_shape.Vertexes:
|
||||
p = ver.Point
|
||||
p.z += zz
|
||||
pts.append(p)
|
||||
# end temp -----
|
||||
|
||||
new_shape = Part.Face(Part.makePolygon(pts))
|
||||
new_shape.Placement = obj.Placement.copy()
|
||||
m = Mesh.Mesh(triangulate(new_shape))
|
||||
centers = []
|
||||
|
||||
if isTracker:
|
||||
minLengths = []
|
||||
for ed in new_shape.Edges:
|
||||
minLengths.append(ed.Length)
|
||||
minLength = min(minLengths)
|
||||
for ed in new_shape.Edges:
|
||||
if ed.Length == minLength:
|
||||
centers.append(ed.CenterOfMass)
|
||||
if m:
|
||||
Topology = m.Topology
|
||||
|
||||
# 1. vertex indices
|
||||
vindex = numpy.empty(len(Topology[0]) * 3)
|
||||
for i in range(len(Topology[0])):
|
||||
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])):
|
||||
f = Topology[1][i]
|
||||
findex[list(range(i * 3, i * 3 + 3))] = (f[0], f[1], f[2])
|
||||
|
||||
add_geometry(0, vindex, findex, objind, centers if isTracker else None)
|
||||
objind += 1
|
||||
|
||||
# CASE 2: Shadow objects
|
||||
#objectlist = FreeCAD.ActiveDocument.findObjects(Label = "Tree") # TODO: Cambiar label por name
|
||||
objectlist=[]
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
if obj.Name.startswith("Tracker"):
|
||||
continue
|
||||
else:
|
||||
objectlist.append(obj)
|
||||
objind = 0
|
||||
|
||||
for obj in objectlist:
|
||||
findex = numpy.array([])
|
||||
m = None
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
new_shape = obj.Shape.copy()
|
||||
new_shape.Placement = obj.getGlobalPlacement()
|
||||
m = Mesh.Mesh(triangulate(new_shape))
|
||||
elif obj.isDerivedFrom("Mesh::Feature"):
|
||||
m = obj.Mesh
|
||||
elif obj.isDerivedFrom("App::Part"):
|
||||
for child in obj.OutList:
|
||||
objectlist.append(child)
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
if m:
|
||||
Topology = m.Topology
|
||||
# vertex indices
|
||||
vindex = numpy.empty(len(Topology[0]) * 3)
|
||||
for i in range(len(Topology[0])):
|
||||
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)
|
||||
|
||||
# face indices
|
||||
findex = numpy.empty(len(Topology[1]) * 3, numpy.int64)
|
||||
for i in range(len(Topology[1])):
|
||||
f = Topology[1][i]
|
||||
findex[list(range(i * 3, i * 3 + 3))] = (f[0], f[1], f[2])
|
||||
|
||||
add_geometry(1, vindex, findex, objind)
|
||||
objind += 1
|
||||
|
||||
|
||||
# CASE 3: Terrain
|
||||
# TODO: ver si se puede partir en varias mesh para que trabaje más rápido
|
||||
if exportTerrain:
|
||||
m = terrain
|
||||
if m:
|
||||
Topology = m.Topology
|
||||
# Facets = m.Facets
|
||||
|
||||
# vertex indices
|
||||
vindex = numpy.empty(len(Topology[0]) * 3)
|
||||
for i in range(len(Topology[0])):
|
||||
v = Topology[0][i]
|
||||
vindex[list(range(i * 3, i * 3 + 3))] = (-v.x * scale, v.z * scale, v.y * scale)
|
||||
|
||||
# face indices
|
||||
findex = numpy.empty(len(Topology[1]) * 3, numpy.int64)
|
||||
for i in range(len(Topology[1])):
|
||||
f = Topology[1][i]
|
||||
findex[list(range(i * 3, i * 3 + 3))] = (f[0], f[1], f[2])
|
||||
|
||||
add_geometry(2, vindex, findex)
|
||||
|
||||
# xml: 5. library_visual_scenes: ¿¿¿¿¿???????
|
||||
'''
|
||||
instance_geometry = SubElement(node, 'instance_geometry')
|
||||
instance_geometry.set('url', 'TerrainMesh{0}'.format(0))
|
||||
|
||||
bind_material = SubElement(instance_geometry, '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')
|
||||
instance_material = SubElement(technique_common, 'instance_material')
|
||||
instance_material.set('symbol', 'Material1')
|
||||
instance_material.set('target', '#Material1')
|
||||
instance_material = SubElement(technique_common, 'instance_material')
|
||||
instance_material.set('symbol', 'Material2')
|
||||
instance_material.set('target', '#Material2')
|
||||
'''
|
||||
|
||||
extra = SubElement(node, 'extra')
|
||||
technique = SubElement(extra, 'technique')
|
||||
technique.set('profile', 'FCOLLADA')
|
||||
visibility = SubElement(technique, 'visibility')
|
||||
visibility.text = '1.000000'
|
||||
|
||||
|
||||
# save the file:
|
||||
st = prettify(root)
|
||||
#print(st)
|
||||
f = open(filename, "w")
|
||||
f.write(st)
|
||||
f.close()
|
||||
FreeCAD.Console.PrintMessage("Se ha generado correctamente el archivo PVC: ", filename)
|
||||
return True
|
||||
|
||||
def prettify(elem):
|
||||
""" Return a pretty-printed XML string for the Element. """
|
||||
|
||||
from xml.etree import ElementTree
|
||||
from xml.dom import minidom
|
||||
|
||||
rough_string = ElementTree.tostring(elem, 'utf-8')
|
||||
reparsed = minidom.parseString(rough_string)
|
||||
return reparsed.toprettyxml(indent=" ")
|
||||
|
||||
def exportToH2P(path): # sólo válido para mesas
|
||||
filename = path + ".h2p"
|
||||
f2 = '{:.2f}'
|
||||
f3 = '{:.3f}'
|
||||
|
||||
st = 'START\n'
|
||||
# TODO: hacer un bucle para cada tipo-tamaño de estructura.
|
||||
# posible solucción: un primer bucle para identificar los tipos-tamaños de estructura
|
||||
#FreeCAD.ActiveDocument.findObjects
|
||||
#FreeCAD.ActiveDocument.Objects
|
||||
|
||||
objects = FreeCAD.ActiveDocument.findObjects(Name="Tracker")
|
||||
grouptype = []
|
||||
#for obj in objects:
|
||||
grouptype.append(objects[0])
|
||||
|
||||
for type in grouptype:
|
||||
st += 'TABLE\n' \
|
||||
'10\n'
|
||||
st += f3.format(type.Width.Value) + ',' + f3.format(type.Length.Value) + ',' + \
|
||||
f3.format(0) + ',' + f3.format(0) + ',' + f3.format(0) + ',' + f3.format(0) + "\n"
|
||||
#'#{ f3 %pvsyst.ilb.to_mm },#{f3 %pvsyst.irb.to_mm},#{f3 %pvsyst.itb.to_mm},' \
|
||||
#'#{f3 %pvsyst.ibb.to_mm}\n'
|
||||
st += '20\n'
|
||||
st += str(int(type.ModulesCols.Value)) + ',' + str(int(type.ModulesRows.Value)) + ',' + \
|
||||
str(type.ModuleColGap.Value) + ',' + str(type.ModuleRowGap.Value) + ',' + '30\n'
|
||||
st += '30\n'
|
||||
st += '1,' + f3.format(type.ModuleWidth.Value) + ',' + f3.format(type.ModuleHeight.Value) + ',' + \
|
||||
f3.format(type.ModuleThick.Value) + ',' + f2.format(450) + '\n' #f2.format(type.ModulePower.Value) + '\n'
|
||||
|
||||
# cornerdown = find_component_sizes(group.cdef)[1]
|
||||
# pvorigin = Geom::Point3d.new(cornerdown.x, cornerdown.y, 0)
|
||||
# group.instances.each{ | ins | str += pvsyst_insert(ins, pvorigin)}
|
||||
|
||||
for obj in objects:
|
||||
if obj.CloneOf == type:
|
||||
st += H2PInsert(obj)
|
||||
|
||||
## TODO: Bucle para buscar objetos que den sombra y el terreno. Todos llaman a H2PMesh
|
||||
mesh = FreeCAD.ActiveDocument.getObjectsByLabel('Surface')[0].Mesh
|
||||
st += H2PMesh(mesh, False)
|
||||
st += "END\n"
|
||||
|
||||
# save the file:
|
||||
f = open(filename, "w")
|
||||
f.write(st)
|
||||
f.close()
|
||||
FreeCAD.Console.PrintMessage("Se ha generado el archivo PVC: ", filename)
|
||||
return True
|
||||
|
||||
def H2PInsert(obj):
|
||||
f3 = '{:.3f}'
|
||||
f2 = '{:.2f}'
|
||||
scale = 0.001 ## ver como se puede hacer para que sea general. Pasar de mm a m
|
||||
|
||||
st = 'INSERT\n' \
|
||||
'10\n'
|
||||
st += f3.format(obj.Placement.Base.x * scale) + ',' + f3.format(obj.Placement.Base.y * scale) + ',' + \
|
||||
f3.format((obj.Placement.Base.z + obj.PoleLength.Value - obj.RammingDeep.Value + 1000) * scale) + '\n'
|
||||
st += '50\n'
|
||||
st += f2.format(-obj.Placement.Rotation.toEuler()[0]) + '\n'
|
||||
st += '55\n'
|
||||
st += f2.format(obj.Placement.Rotation.toEuler()[1]) + '\n'
|
||||
st += '56\n'
|
||||
st += f2.format(obj.Placement.Rotation.toEuler()[2]) + '\n'
|
||||
|
||||
return st
|
||||
|
||||
def H2PMesh(mesh, type):
|
||||
scale = 0.001 ## ver como se puede hacer para que sea general. Pasar de mm a m
|
||||
|
||||
f3 = '{:.3f}'
|
||||
st = ''
|
||||
if type:
|
||||
st = 'ShadowObject\nFence\n'
|
||||
else:
|
||||
st = 'DGM\n'
|
||||
|
||||
for face in mesh.Facets:
|
||||
p1 = face.Points[0]
|
||||
p2 = face.Points[1]
|
||||
p3 = face.Points[2]
|
||||
|
||||
st += f3.format(p1[0] * scale) + "," + f3.format(p1[1] * scale) + "," + f3.format(p1[2] * scale) + ";"
|
||||
st += f3.format(p2[0] * scale) + "," + f3.format(p2[1] * scale) + "," + f3.format(p2[2] * scale) + ";"
|
||||
st += f3.format(p3[0] * scale) + "," + f3.format(p3[1] * scale) + "," + f3.format(p3[2] * scale) + "\n"
|
||||
|
||||
return st
|
||||
|
||||
class _PVSystTaskPanel:
|
||||
|
||||
def __init__(self):
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/exportPVSyst.ui")
|
||||
self.form = self.form
|
||||
|
||||
def show(self):
|
||||
# self.form.setWindowModality(Qt.WindowModal)
|
||||
self.form.show()
|
||||
|
||||
def accept(self):
|
||||
import datetime
|
||||
x = datetime.datetime.now()
|
||||
date = x.strftime("%y%m%d%H%M%S")
|
||||
overwrite = True
|
||||
|
||||
path = os.path.join(os.path.dirname(FreeCAD.ActiveDocument.FileName), "outputs", "PVSyst")
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
name = FreeCAD.ActiveDocument.Label
|
||||
if not overwrite:
|
||||
name = date + "-" + name
|
||||
filename = os.path.join(path, name)
|
||||
|
||||
#if self.form.cbDAE.isChecked():
|
||||
# exportToDAE(filename)
|
||||
|
||||
if self.form.cbPVC.isChecked():
|
||||
exportToPVC(filename, self.form.cbTerrain.isChecked())
|
||||
|
||||
if self.form.cbH2P.isChecked():
|
||||
exportToH2P(filename)
|
||||
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
class _CommandExportToPVSyst:
|
||||
"Export to PVSyst"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "PVsyst.png")),
|
||||
'Accel': "E, P",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Outputs", "Export to PVSyst"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Outputs", "Exportar a PVSyst")}
|
||||
|
||||
def Activated(self):
|
||||
taskd = _PVSystTaskPanel()
|
||||
# taskd.show()
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('ExportToPVSyst', _CommandExportToPVSyst())
|
||||
84
Export/exportPVSyst.ui
Normal file
84
Export/exportPVSyst.ui
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formPVSyst</class>
|
||||
<widget class="QDialog" name="formPVSyst">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>301</width>
|
||||
<height>123</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export to PVSyst</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Export format:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbH2P">
|
||||
<property name="text">
|
||||
<string>Helios 3D (H2P) - PVSyst 6.0 or higher</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbPVC">
|
||||
<property name="text">
|
||||
<string>PVCase (PVC) - PVSyst 7.0 or higher</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbTerrain">
|
||||
<property name="text">
|
||||
<string>Exportar terreno</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
159
Export/layoutToExcel.py
Normal file
159
Export/layoutToExcel.py
Normal file
@@ -0,0 +1,159 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD, Draft
|
||||
import PVPlantSite
|
||||
import copy
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import Part
|
||||
import pivy
|
||||
from pivy import coin
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Trench"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
from PVPlantResources import DirDocuments as DirDocuments
|
||||
|
||||
|
||||
'''import os
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
def open_file(path):
|
||||
if platform.system() == "Windows":
|
||||
os.startfile(path)
|
||||
elif platform.system() == "Darwin":
|
||||
subprocess.Popen(["open", path])
|
||||
else:
|
||||
subprocess.Popen(["xdg-open", path])'''
|
||||
|
||||
|
||||
from PVPlantPlacement import getCols
|
||||
|
||||
def generateLayout(numcells = 3, gapc = 3):
|
||||
# TODO: hacerlo por zonas
|
||||
|
||||
objects = []
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
if not hasattr(obj, "Proxy"):
|
||||
continue
|
||||
'''if issubclass(obj.Proxy.__class__, PVPlantRack.Frame):
|
||||
objects.append(obj)'''
|
||||
if obj.Name.startswith("Tracker") and not obj.Name.startswith("TrackerSetup"):
|
||||
objects.append(obj)
|
||||
|
||||
if len(objects) == 0:
|
||||
FreeCAD.Console.PrintError("No hay trackes" + "\n")
|
||||
return False
|
||||
|
||||
columns = getCols(objects.copy())
|
||||
|
||||
MaxY = max(objects, key=lambda obj: obj.Placement.Base.y).Placement.Base.y
|
||||
long_max = max(objects, key=lambda obj: obj.Setup.Length.Value).Setup.Length.Value
|
||||
num_pole_max = max(objects, key=lambda obj: obj.Setup.NumberPole.Value).Setup.NumberPole.Value
|
||||
num_module_max = max(objects, key=lambda obj: obj.Setup.ModuleColumns.Value).Setup.ModuleColumns.Value
|
||||
# TODO: calcular la serparación entre trackers.
|
||||
gapy = 500
|
||||
|
||||
import openpyxl
|
||||
path = os.path.dirname(FreeCAD.ActiveDocument.FileName)
|
||||
filename = os.path.join(path, "layout.xlsx")
|
||||
mywb = openpyxl.Workbook()
|
||||
|
||||
# 1. Hincas
|
||||
sheet = mywb.active
|
||||
sheet.title = 'Poles'
|
||||
m = -(numcells * num_pole_max + gapc) / (long_max + gapy)
|
||||
line = lambda x: int(m * (x - MaxY))
|
||||
drawLayout(sheet, columns, line, 0)
|
||||
|
||||
# 2. Paneles
|
||||
sheet = mywb.create_sheet("Modules")
|
||||
m = -(numcells * num_module_max + gapc) / (long_max + gapy)
|
||||
line = lambda x: int(m * (x - MaxY) + 1)
|
||||
#drawLayout(sheet, columns, line, 1)
|
||||
|
||||
mywb.save(filename)
|
||||
print("Se ha generado el lyout en excel satisfactoriamente en: ")
|
||||
print(filename)
|
||||
os.startfile(path)
|
||||
|
||||
#from os import startfile
|
||||
#startfile("archivo.txt")
|
||||
|
||||
return True
|
||||
|
||||
def drawLayout(sheet, cols, line, cnt = 0, numcell = 3, gap = 3):
|
||||
from openpyxl.styles import Alignment, Border, Side, PatternFill, GradientFill, Font
|
||||
thin = Side(border_style="thin", color="000000")
|
||||
|
||||
for i, col in enumerate(cols):
|
||||
colnum = i * 3 + 1
|
||||
for g, group in enumerate(col):
|
||||
rownum = int(line(group[0].Placement.Base.y)) + 1
|
||||
if rownum < 1:
|
||||
continue
|
||||
for frame in group:
|
||||
num = int(frame.Setup.NumberPole.Value if cnt == 0 else frame.Setup.ModuleColumns.Value)
|
||||
sheet.merge_cells(start_row=rownum, start_column=colnum,
|
||||
end_row=rownum, end_column=colnum + 1)
|
||||
titlecell = sheet.cell(row=rownum, column=colnum)
|
||||
titlecell.value = frame.Label
|
||||
titlecell.border = Border(top=thin, left=thin, right=thin, bottom=thin)
|
||||
titlecell.font = Font(b=True, color="FF0000")
|
||||
titlecell.alignment = Alignment(horizontal="center", vertical="center")
|
||||
rownum += 1
|
||||
for ind in range(num):
|
||||
sheet.merge_cells(start_row=rownum, start_column=colnum,
|
||||
end_row=rownum + numcell - 1, end_column=colnum)
|
||||
polecell = sheet.cell(row=rownum, column=colnum)
|
||||
polecell.value = ind + 1
|
||||
polecell.alignment = Alignment(horizontal="center", vertical="center")
|
||||
|
||||
sheet.merge_cells(start_row=rownum, start_column=colnum + 1,
|
||||
end_row=rownum + numcell - 1, end_column=colnum + 1)
|
||||
polecell = sheet.cell(row=rownum, column=colnum + 1)
|
||||
polecell.value = "Celda-" + str(ind + 1)
|
||||
polecell.value = frame.Label
|
||||
polecell.border = Border(top=thin, left=thin, right=thin, bottom=thin)
|
||||
polecell.font = Font(b=True, color="FF0000")
|
||||
polecell.alignment = Alignment(horizontal="center", vertical="center")
|
||||
|
||||
rownum += numcell
|
||||
rownum += 1
|
||||
|
||||
264
GraphProfile.py
Normal file
264
GraphProfile.py
Normal file
@@ -0,0 +1,264 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
import Part
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
|
||||
import pivy
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "Graph Terrain Profile"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
|
||||
def makeGraphProfile(path = None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "GraphProfile")
|
||||
_GraphProfile(obj)
|
||||
_ViewProviderGraphProfile(obj.ViewObject)
|
||||
|
||||
if path:
|
||||
obj.Path = path
|
||||
|
||||
return obj
|
||||
|
||||
class _GraphProfile:
|
||||
def __init__(self, obj):
|
||||
self.setCommonProperties(obj)
|
||||
|
||||
def setCommonProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("Path" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Path",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "")
|
||||
)
|
||||
#obj.setEditorMode("NumberOfStrings", 1)
|
||||
|
||||
if not ("AdjustToContent" in pl):
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"AdjustToContent",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "")
|
||||
).AdjustToContent = True
|
||||
|
||||
if not ("PKMinorDistance" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"PKMinorDistance",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "")
|
||||
).PKMinorDistance = 20000
|
||||
|
||||
if not ("YAxisStep" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"YAxisStep",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "")
|
||||
).YAxisStep = 5000
|
||||
|
||||
if not ("Points" in pl):
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"Points",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "")
|
||||
)
|
||||
obj.setEditorMode("Points", 1)
|
||||
|
||||
self.Type = "GraphProfile"
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
|
||||
if prop == "Path":
|
||||
if obj.getPropertyByName(prop):
|
||||
from Utils import PVPlantUtils
|
||||
profile = PVPlantUtils.FlattenWire(PVPlantUtils.makeProfileFromTerrain(obj.Path))
|
||||
obj.Points = PVPlantUtils.getPointsFromVertexes(profile.Vertexes)
|
||||
else:
|
||||
obj.Points.clear()
|
||||
print("Graph: onChanged")
|
||||
|
||||
def execute(self, obj):
|
||||
if (obj.Path is None) or (obj.Points is None):
|
||||
return
|
||||
|
||||
profile = Part.makePolygon(obj.Points)
|
||||
xx_max = profile.BoundBox.XMax
|
||||
yy_min = profile.BoundBox.YMin
|
||||
yy_max = profile.BoundBox.YMax
|
||||
yy_length = yy_max
|
||||
yy_axis_minus = int(yy_min / 10) * 10 - obj.YAxisStep.Value
|
||||
|
||||
# 1. Make Axis:
|
||||
x_axis = Part.makePolygon([FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(xx_max, 0, 0)])
|
||||
y_axis = None
|
||||
if obj.AdjustToContent:
|
||||
yy_length -= yy_min
|
||||
y_axis = Part.makePolygon([FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, (yy_max - yy_min) * 1.1, 0)])
|
||||
profile.Placement.Base.y = profile.Placement.Base.y - yy_min + obj.YAxisStep.Value
|
||||
else:
|
||||
y_axis = Part.makePolygon([FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, yy_max, 0)])
|
||||
|
||||
shapes = []
|
||||
|
||||
# 2. grid
|
||||
cnt = 0
|
||||
while cnt <= xx_max:
|
||||
line = y_axis.copy()
|
||||
line.Placement.Base = y_axis.Placement.Base + FreeCAD.Vector(cnt, 0, 0)
|
||||
shapes.append(line)
|
||||
cnt += obj.PKMinorDistance.Value
|
||||
|
||||
cnt = 0
|
||||
while cnt <= yy_length:
|
||||
line = x_axis.copy()
|
||||
line.Placement.Base = x_axis.Placement.Base + FreeCAD.Vector(0, cnt, 0)
|
||||
shapes.append(line)
|
||||
cnt += obj.YAxisStep.Value
|
||||
|
||||
shapes.append(profile)
|
||||
|
||||
# Shape:
|
||||
obj.Shape = Part.makeCompound(shapes)
|
||||
|
||||
|
||||
|
||||
class _ViewProviderGraphProfile:
|
||||
def __init__(self, vobj):
|
||||
'''
|
||||
Set view properties.
|
||||
'''
|
||||
self.Object = vobj.Object
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
'''
|
||||
Create Object visuals in 3D view.
|
||||
'''
|
||||
self.Object = vobj.Object
|
||||
return
|
||||
|
||||
def getIcon(self):
|
||||
'''
|
||||
Return object treeview icon.
|
||||
'''
|
||||
|
||||
return str(os.path.join(DirIcons, "stringsetup.svg"))
|
||||
'''
|
||||
def claimChildren(self):
|
||||
"""
|
||||
Provides object grouping
|
||||
"""
|
||||
return self.Object.Group
|
||||
'''
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Enable edit
|
||||
"""
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Disable edit
|
||||
"""
|
||||
return False
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
"""
|
||||
Detect double click
|
||||
"""
|
||||
pass
|
||||
|
||||
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 _CommandGraphProfile:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "Profile.svg")),
|
||||
'Accel': "C, P",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "Terrain Profile Graph"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "")}
|
||||
|
||||
def Activated(self):
|
||||
path = None
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel)>0:
|
||||
path = sel[0]
|
||||
obj = makeGraphProfile(path)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('GraphTerrainProfile', _CommandGraphProfile())
|
||||
|
||||
143
Importer/importDXF.py
Normal file
143
Importer/importDXF.py
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Export to DXF"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
def importDXF(filename):
|
||||
print("---------- import to dxf ----------")
|
||||
|
||||
if filename == "":
|
||||
return
|
||||
|
||||
import sys
|
||||
import ezdxf
|
||||
|
||||
doc = None
|
||||
try:
|
||||
doc = ezdxf.readfile(filename)
|
||||
except IOError:
|
||||
print(f"Not a DXF file or a generic I/O error.")
|
||||
sys.exit(1)
|
||||
except ezdxf.DXFStructureError:
|
||||
print(f"Invalid or corrupted DXF file.")
|
||||
sys.exit(2)
|
||||
|
||||
# iteration
|
||||
for layer in doc.layers:
|
||||
print(layer.dxf.name)
|
||||
|
||||
#if layer.dxf.name != "0":
|
||||
# layer.off() # switch all layers off except layer "0"
|
||||
|
||||
# check for existing layer definition
|
||||
if "MyLines" in doc.layers:
|
||||
layer = doc.layers.get("MyLines")
|
||||
|
||||
layer_count = len(doc.layers) # total count of layer definitions
|
||||
|
||||
|
||||
class _PVPlantImportDXF:
|
||||
'''The editmode TaskPanel to select what you want to export'''
|
||||
|
||||
def __init__(self):
|
||||
self.doc = None
|
||||
|
||||
# self.form:
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(PVPlantResources.__dir__, "importDXF.ui"))
|
||||
self.form.setWindowIcon(QtGui.QIcon(os.path.join(PVPlantResources.DirIcons, "dxf.svg")))
|
||||
self.form.buttonOpen.clicked.connect(self.openFile)
|
||||
self.form.listLayer.currentItemChanged.connect(self.onLayerSelect)
|
||||
|
||||
def openFile(self):
|
||||
''' '''
|
||||
"getOpenFileName(parent: typing.Union[PySide2.QtWidgets.QWidget, NoneType] = None," \
|
||||
"caption: str = ''," \
|
||||
"dir: str = ''," \
|
||||
"filter: str = ''," \
|
||||
"options: PySide2.QtWidgets.QFileDialog.Options = Default(QFileDialog.Options)) -> typing.Tuple[str, str]"
|
||||
filename, trash = QtGui.QFileDialog().getOpenFileName(None, 'Select File', os.getcwd(), 'Autocad dxf (*.dxf)')
|
||||
if filename == "":
|
||||
return
|
||||
|
||||
import sys
|
||||
import ezdxf
|
||||
|
||||
try:
|
||||
self.doc = ezdxf.readfile(filename)
|
||||
except IOError:
|
||||
print(f"Not a DXF file or a generic I/O error.")
|
||||
sys.exit(1)
|
||||
except ezdxf.DXFStructureError:
|
||||
print(f"Invalid or corrupted DXF file.")
|
||||
sys.exit(2)
|
||||
|
||||
# iteration
|
||||
self.form.listLayer.clear()
|
||||
for layer in self.doc.layers:
|
||||
self.form.listLayer.addItem(layer.dxf.name)
|
||||
|
||||
msp = self.doc.modelspace()
|
||||
for e in msp:
|
||||
print(e.dxftype())
|
||||
#self.form.listObjects.addItem(e.dxftype())
|
||||
|
||||
def onLayerSelect(self, item):
|
||||
''' '''
|
||||
print(item.text())
|
||||
self.form.listLayer.clear()
|
||||
if self.doc:
|
||||
msp = self.doc.modelspace()
|
||||
'''
|
||||
layer = self.doc.layers.get(item.text())
|
||||
for obj in layer.entities_in_redraw_order(reverse=False):
|
||||
self.form.listObjects.addItem(obj)
|
||||
'''
|
||||
for obj in msp.query('*[layer=="'+item.text()+'"]'):
|
||||
#self.form.listObjects.addItem(obj)
|
||||
print(obj)
|
||||
|
||||
def accept(self):
|
||||
''' '''
|
||||
|
||||
class CommandImportDXF:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "dxf.svg")),
|
||||
'Accel': "E, X",
|
||||
'MenuText': "Importer to DXF",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Importer choosed layers to dxf")}
|
||||
|
||||
def Activated(self):
|
||||
taskd = _PVPlantImportDXF()
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('importDXF', CommandImportDXF())
|
||||
75
Importer/importDXF.ui
Normal file
75
Importer/importDXF.ui
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formPVSyst</class>
|
||||
<widget class="QDialog" name="formPVSyst">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>421</width>
|
||||
<height>471</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export to PVSyst</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonOpen">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listLayer"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listObjects"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushOpenFile">
|
||||
<property name="text">
|
||||
<string>Aceptar</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Accept">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
92
Init.py
Normal file
92
Init.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#****************************************************************************
|
||||
#* *
|
||||
#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
|
||||
#* 3D exporter for FreeCAD *
|
||||
#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
|
||||
#* Copyright (c) 2015 *
|
||||
#* Maurice easyw@katamail.com *
|
||||
#* *
|
||||
#* Kicad STEPUP (TM) is a TradeMark and cannot be freely useable *
|
||||
#* *
|
||||
|
||||
#FreeCAD.addImportType("Kicad pcb board/mod File Type (*.kicad_pcb *.kicad_mod)","kicadStepUptools")
|
||||
|
||||
|
||||
FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC")
|
||||
FreeCAD.addExportType("Industry Foundation Classes (*.ifc)","importIFC")
|
||||
FreeCAD.addImportType("Wavefront OBJ - Arch module (*.obj)","importOBJ")
|
||||
FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ")
|
||||
FreeCAD.addExportType("WebGL file (*.html)","importWebGL")
|
||||
FreeCAD.addExportType("JavaScript Object Notation (*.json)","importJSON")
|
||||
FreeCAD.addImportType("Collada (*.dae)","importDAE")
|
||||
FreeCAD.addExportType("Collada (*.dae)","importDAE")
|
||||
FreeCAD.addImportType("3D Studio mesh (*.3ds)","import3DS")
|
||||
FreeCAD.addImportType("SweetHome3D XML export (*.zip)","importSH3D")
|
||||
|
||||
import os
|
||||
|
||||
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
|
||||
|
||||
ICONPATH = os.path.join(os.path.dirname(__file__), "resources")
|
||||
|
||||
zone_list = ["Z1", "Z2", "Z3", "Z4", "Z5", "Z6", "Z7", "Z8", "Z9", "Z10", "Z11", "Z12",
|
||||
"Z13", "Z14", "Z15", "Z16", "Z17", "Z18", "Z19", "Z20", "Z21", "Z22", "Z23", "Z24",
|
||||
"Z25", "Z26", "Z27", "Z28", "Z29", "Z30", "Z31", "Z32", "Z33", "Z34", "Z35", "Z36",
|
||||
"Z37", "Z38", "Z39", "Z40", "Z41", "Z42", "Z43", "Z44", "Z45", "Z46", "Z47", "Z48",
|
||||
"Z49", "Z50", "Z51", "Z52", "Z53", "Z54", "Z55", "Z56", "Z57", "Z58", "Z59", "Z60"]
|
||||
|
||||
marker_dict = {
|
||||
'NONE': -1, 'BACKSLASH_5_5': 4, 'BACKSLASH_7_7': 34,
|
||||
'BACKSLASH_9_9': 64, 'BAR_5_5': 5, 'BAR_7_7': 35, 'BAR_9_9': 65,
|
||||
'CAUTION_FILLED_5_5': 28, 'CAUTION_FILLED_7_7': 58, 'CAUTION_FILLED_9_9': 88,
|
||||
'CAUTION_LINE_5_5': 18, 'CAUTION_LINE_7_7': 48, 'CAUTION_LINE_9_9': 78,
|
||||
'CIRCLE_FILLED_5_5': 20, 'CIRCLE_FILLED_7_7': 50, 'CIRCLE_FILLED_9_9': 80,
|
||||
'CIRCLE_LINE_5_5': 10, 'CIRCLE_LINE_7_7': 40, 'CIRCLE_LINE_9_9': 70,
|
||||
'CROSS_5_5': 0, 'CROSS_7_7': 30, 'CROSS_9_9': 60, 'DIAMOND_FILLED_5_5': 22,
|
||||
'DIAMOND_FILLED_7_7': 52, 'DIAMOND_FILLED_9_9': 82, 'DIAMOND_LINE_5_5': 12,
|
||||
'DIAMOND_LINE_7_7': 42, 'DIAMOND_LINE_9_9': 72, 'EXTENSION': 512,
|
||||
'FIRST_INSTANCE': 0, 'HOURGLASS_FILLED_5_5': 25, 'HOURGLASS_FILLED_7_7': 55,
|
||||
'HOURGLASS_FILLED_9_9': 85, 'HOURGLASS_LINE_5_5': 15, 'HOURGLASS_LINE_7_7': 45,
|
||||
'HOURGLASS_LINE_9_9': 75, 'LIGHTNING_5_5': 8, 'LIGHTNING_7_7': 38,
|
||||
'LIGHTNING_9_9': 68, 'LINES': 7, 'LINE_STRIP': 8, 'MINUS_5_5': 2,
|
||||
'MINUS_7_7': 32, 'MINUS_9_9': 62, 'NUM_MARKERS': 90, 'OTHER_INSTANCE': 2,
|
||||
'PINE_TREE_FILLED_5_5': 27, 'PINE_TREE_FILLED_7_7': 57, 'PINE_TREE_FILLED_9_9': 87,
|
||||
'PINE_TREE_LINE_5_5': 17, 'PINE_TREE_LINE_7_7': 47, 'PINE_TREE_LINE_9_9': 77,
|
||||
'PLUS_5_5': 1, 'PLUS_7_7': 31, 'PLUS_9_9': 61, 'POINTS': 6, 'POLYGON': 3,
|
||||
'PROTO_INSTANCE': 1, 'QUADS': 4, 'QUAD_STRIP': 5, 'RHOMBUS_FILLED_5_5': 24,
|
||||
'RHOMBUS_FILLED_7_7': 54, 'RHOMBUS_FILLED_9_9': 84, 'RHOMBUS_LINE_5_5': 14,
|
||||
'RHOMBUS_LINE_7_7': 44, 'RHOMBUS_LINE_9_9': 74, 'SATELLITE_FILLED_5_5': 26,
|
||||
'SATELLITE_FILLED_7_7': 56, 'SATELLITE_FILLED_9_9': 86, 'SATELLITE_LINE_5_5': 16,
|
||||
'SATELLITE_LINE_7_7': 46, 'SATELLITE_LINE_9_9': 76, 'SHIP_FILLED_5_5': 29,
|
||||
'SHIP_FILLED_7_7': 59, 'SHIP_FILLED_9_9': 89, 'SHIP_LINE_5_5': 19,
|
||||
'SHIP_LINE_7_7': 49, 'SHIP_LINE_9_9': 79, 'SLASH_5_5': 3, 'SLASH_7_7': 33,
|
||||
'SLASH_9_9': 63, 'SQUARE_FILLED_5_5': 21, 'SQUARE_FILLED_7_7': 51,
|
||||
'SQUARE_FILLED_9_9': 81, 'SQUARE_LINE_5_5': 11, 'SQUARE_LINE_7_7': 41,
|
||||
'SQUARE_LINE_9_9': 71, 'STAR_5_5': 6, 'STAR_7_7': 36, 'STAR_9_9': 66,
|
||||
'TRIANGLES': 2, 'TRIANGLE_FAN': 1, 'TRIANGLE_FILLED_5_5': 23,
|
||||
'TRIANGLE_FILLED_7_7': 53, 'TRIANGLE_FILLED_9_9': 83, 'TRIANGLE_LINE_5_5': 13,
|
||||
'TRIANGLE_LINE_7_7': 43, 'TRIANGLE_LINE_9_9': 73, 'TRIANGLE_STRIP': 0,
|
||||
'VRML1': 1, 'VRML2': 2, 'WELL_5_5': 9, 'WELL_7_7': 39, 'WELL_9_9': 69,
|
||||
'Y_5_5': 7, 'Y_7_7': 37, 'Y_9_9': 67}
|
||||
|
||||
line_patterns = {
|
||||
"Continues _______________________________": 0xFFFF,
|
||||
"Border __ . __ __ . __ __ . __ __ . __": 0x3CF2,
|
||||
"Border (.5x) __.__.__.__.__.__.__.__.__.__._": 0x3939,
|
||||
"Border (2x) ____ ____ . ____ ____ . _": 0xFDFA,
|
||||
"Center ____ _ ____ _ ____ _ ____ _ ___": 0xFF3C,
|
||||
"Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ _": 0xFC78,
|
||||
"Center (2x) ________ __ ________ __ ___": 0xFFDE,
|
||||
"Dash dot __ . __ . __ . __ . __ . __ . _": 0xE4E4,
|
||||
"Dash dot (.5x) _._._._._._._._._._._._._._._._": 0xEBAE,
|
||||
"Dash dot (2x) ____ . ____ . ____ . ____": 0xFF08,
|
||||
"Dashed __ __ __ __ __ __ __ __ __ __ _": 0x739C,
|
||||
"Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _": 0xDB6E,
|
||||
"Dashed (2x) ____ ____ ____ ____ ____ _": 0xFFE0,
|
||||
"Divide ____ . . ____ . . ____ . . ____": 0xFF24,
|
||||
"Divide (.5x) __..__..__..__..__..__..__..__.": 0xEAEA,
|
||||
"Divide (2x) ________ . . ________ . . ": 0xFFEA,
|
||||
"Dot . . . . . . . . . . . . . . . .": 0x4924,
|
||||
"Dot (.5x) ...............................": 0x5555,
|
||||
"Dot (2x) . . . . . . . . . . .": 0x8888}
|
||||
247
InitGui.py
Normal file
247
InitGui.py
Normal file
@@ -0,0 +1,247 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
__title__="FreeCAD Fotovoltaic Power Plant Toolkit"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "sn"
|
||||
|
||||
|
||||
|
||||
class PVPlantWorkbench (Workbench):
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
MenuText = "PVPlant"
|
||||
ToolTip = "Workbench for PV design"
|
||||
Icon = str(os.path.join(DirIcons, "icon.svg"))
|
||||
|
||||
def Initialize(self):
|
||||
import sys
|
||||
sys.path.append(r"C:\Users\javie\AppData\Roaming\FreeCAD\Mod")
|
||||
|
||||
# Mias
|
||||
import PVPlantGeoreferencing, PVPlantPlacement, \
|
||||
PVPlantTerrainAnalisys, PVPlantSite, PVPlantImportGrid, PVPlantFence,\
|
||||
PVPlantFoundation, PVPlantCreateTerrainMesh, \
|
||||
PVPlantTreeGenerator, PVPlantBuilding, PVPlantTrench, PVPlantEarthWorks, \
|
||||
PVPlantStringing, \
|
||||
PVPlantPad, PVPlantRoad, PVPlantTerrain, PVPlantManhole, \
|
||||
GraphProfile, Utils.PVPlantTrace,\
|
||||
reload
|
||||
import PVPlantRackChecking
|
||||
|
||||
from Project.Area import PVPlantArea, PVPlantAreaUtils
|
||||
from Project import ProjectSetup
|
||||
from Export import exportPVSyst, PVPlantBOQMechanical, PVPlantBOQElectrical, PVPlantBOQCivil,\
|
||||
exportDXF
|
||||
from Importer import importDXF
|
||||
|
||||
from Mechanical.Frame import PVPlantFrame
|
||||
|
||||
from Electrical.Cable import PVPlantCable, PVPlantElectricalLine
|
||||
from Electrical.CombinerBox import PVPlantStringBox
|
||||
from Electrical.Inverter import PVPlantInverter
|
||||
|
||||
# A list of command names created in the line above
|
||||
self.projectlist = ["Reload",
|
||||
"PVPlantSite",
|
||||
"PVPlantGeoreferencing",
|
||||
"ProjectSetup",
|
||||
#"ImportGrid",
|
||||
"Terrain",
|
||||
"PointsGroup",
|
||||
"PVPlantCreateTerrainMesh",
|
||||
"PVPlantAreas",
|
||||
"SplitArea",
|
||||
"TerrainAnalisys",
|
||||
"Trenches",
|
||||
"PVPlantEarthworks",
|
||||
"PVPlantPad",
|
||||
"PVPlantRoad",
|
||||
"PVPlantManhole",
|
||||
#"PVPlantFoundation"
|
||||
"GraphTerrainProfile",
|
||||
"Trace",
|
||||
]
|
||||
self.framelist = [
|
||||
"RackType",
|
||||
"PVPlantRackCheck",
|
||||
"Separator",
|
||||
"PVPlantPlacement",
|
||||
"PVPlantAdjustToTerrain",
|
||||
"PVPlantConvertTo",
|
||||
"PVArea"
|
||||
]
|
||||
|
||||
self.objectlist = [
|
||||
"PVPlantTree",
|
||||
"PVPlantBuilding",
|
||||
"PVPlantFenceGroup",
|
||||
]
|
||||
|
||||
self.inportExportlist = ["BOQCivil",
|
||||
"BOQMechanical",
|
||||
"BOQElectrical",
|
||||
"Separator",
|
||||
"exportDXF",
|
||||
#"importDXF",
|
||||
"ExportToPVSyst",
|
||||
]
|
||||
|
||||
self.electricalList = ["PVPlantStringBox",
|
||||
"PVPlantCable",
|
||||
"PVPlanElectricalLine",
|
||||
"Conduit",
|
||||
"Stringing",
|
||||
"Separator",
|
||||
"StringInverter",
|
||||
]
|
||||
|
||||
self.roads = ["PVPlantRoad",
|
||||
|
||||
]
|
||||
|
||||
self.pads = ["PVPlantPad",
|
||||
"Separator"
|
||||
]
|
||||
|
||||
# Toolbar
|
||||
self.appendToolbar("Civil", self.projectlist) # creates a new toolbar with your commands
|
||||
self.appendToolbar("PVPlant", self.framelist) # creates a new toolbar with your commands
|
||||
self.appendToolbar("Shadow", self.objectlist) # creates a new toolbar with your commands
|
||||
self.appendToolbar("Outputs", self.inportExportlist) # creates a new toolbar with your commands
|
||||
self.appendToolbar("Electrical", self.electricalList) # creates a new toolbar with your commands
|
||||
|
||||
# Menu
|
||||
self.appendMenu("&Civil", self.projectlist) # creates a new menu
|
||||
self.appendMenu("&PVPlant", self.framelist) # creates a new menu
|
||||
self.appendMenu("&Shadow", self.objectlist) # creates a new menu
|
||||
self.appendMenu("&Outputs", self.inportExportlist) # creates a new menu
|
||||
self.appendMenu("&Electrical", self.electricalList) # creates a new menu
|
||||
|
||||
# Draft tools
|
||||
from DraftTools import translate
|
||||
self.drafttools = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse",
|
||||
"Draft_Polygon","Draft_Rectangle", "Draft_Text",
|
||||
"Draft_Dimension", "Draft_BSpline","Draft_Point",
|
||||
"Draft_Facebinder","Draft_BezCurve","Draft_Label"]
|
||||
self.draftmodtools = ["Draft_Move","Draft_Rotate","Draft_Offset",
|
||||
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
|
||||
"Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array",
|
||||
"Draft_Clone"]
|
||||
self.draftextratools = ["Draft_WireToBSpline","Draft_ShapeString",
|
||||
"Draft_PathArray","Draft_Mirror","Draft_Stretch"]
|
||||
self.draftcontexttools = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup","Draft_AutoGroup",
|
||||
"Draft_SelectGroup","Draft_SelectPlane",
|
||||
"Draft_ShowSnapBar","Draft_ToggleGrid",]
|
||||
self.draftutils = ["Draft_Heal","Draft_FlipDimension",
|
||||
"Draft_ToggleConstructionMode","Draft_ToggleContinueMode","Draft_Edit",
|
||||
"Draft_Slope","Draft_AddConstruction"]
|
||||
self.snapList = ['Draft_Snap_Lock','Draft_Snap_Midpoint','Draft_Snap_Perpendicular',
|
||||
'Draft_Snap_Grid','Draft_Snap_Intersection','Draft_Snap_Parallel',
|
||||
'Draft_Snap_Endpoint','Draft_Snap_Angle','Draft_Snap_Center',
|
||||
'Draft_Snap_Extension','Draft_Snap_Near','Draft_Snap_Ortho','Draft_Snap_Special',
|
||||
'Draft_Snap_Dimensions','Draft_Snap_WorkingPlane']
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(scope, text): return text
|
||||
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Draft tools"), self.drafttools)
|
||||
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Draft mod tools"), self.draftmodtools)
|
||||
self.appendMenu(QT_TRANSLATE_NOOP("arch", "&Draft"), self.drafttools + self.draftmodtools + self.draftextratools)
|
||||
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"), QT_TRANSLATE_NOOP("arch", "Utilities")], self.draftutils + self.draftcontexttools)
|
||||
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"), QT_TRANSLATE_NOOP("arch", "Snapping")], self.snapList)
|
||||
|
||||
import Part
|
||||
self.measureTools = ["Part_Measure_Linear",
|
||||
"Part_Measure_Angular",
|
||||
"Separator",
|
||||
"Part_Measure_Refresh",
|
||||
"Part_Measure_Clear_All",
|
||||
"Part_Measure_Toggle_All",
|
||||
"Part_Measure_Toggle_3D",
|
||||
"Part_Measure_Toggle_Delta"
|
||||
]
|
||||
self.appendToolbar("Medir", self.measureTools)
|
||||
self.appendMenu("&Medir", self.measureTools)
|
||||
|
||||
self.observer = None
|
||||
|
||||
from widgets import CountSelection
|
||||
|
||||
def Activated(self):
|
||||
"This function is executed when the workbench is activated"
|
||||
import SelectionObserver
|
||||
import FreeCADGui
|
||||
|
||||
self.observer = SelectionObserver.SelObserver()
|
||||
FreeCADGui.Selection.addObserver(self.observer) # installe la fonction en mode resident
|
||||
return
|
||||
|
||||
def Deactivated(self):
|
||||
"This function is executed when the workbench is deactivated"
|
||||
FreeCADGui.Selection.removeObserver(self.observer)
|
||||
return
|
||||
|
||||
def ContextMenu(self, recipient):
|
||||
"This is executed whenever the user right-clicks on screen"
|
||||
# "recipient" will be either "view" or "tree"
|
||||
|
||||
#if FreeCAD.activeDraftCommand is None:
|
||||
if recipient.lower() == "view":
|
||||
print("Menus en la 'View'")
|
||||
#if FreeCAD.activeDraftCommand is None:
|
||||
presel = FreeCADGui.Selection.getPreselection()
|
||||
print(presel.SubElementNames, " - ", presel.PickedPoints)
|
||||
if not presel is None:
|
||||
if presel.Object.Proxy.Type == "Road":
|
||||
self.appendContextMenu("Road", self.roads)
|
||||
elif presel.Object.Proxy.Type == "Pad":
|
||||
self.appendContextMenu("Pad", self.pads)
|
||||
|
||||
'''
|
||||
self.contextMenu = QtGui.QMenu()
|
||||
menu_item_remove_selected = self.contextMenu.addAction("Remove selected geometry")
|
||||
menu_item_remove_all = self.contextMenu.addAction("Clear list")
|
||||
if not self.references:
|
||||
menu_item_remove_selected.setDisabled(True)
|
||||
menu_item_remove_all.setDisabled(True)
|
||||
self.connect(
|
||||
menu_item_remove_selected,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.remove_selected_reference
|
||||
)
|
||||
self.connect(
|
||||
menu_item_remove_all,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.remove_all_references
|
||||
)
|
||||
parentPosition = self.list_References.mapToGlobal(QtCore.QPoint(0, 0))
|
||||
self.contextMenu.move(parentPosition + QPos)
|
||||
self.contextMenu.show()
|
||||
'''
|
||||
|
||||
def GetClassName(self):
|
||||
# this function is mandatory if this is a full python workbench
|
||||
return "Gui::PythonWorkbench"
|
||||
|
||||
|
||||
Gui.addWorkbench(PVPlantWorkbench())
|
||||
1770
Mechanical/Frame/PVPlantFrame.py
Normal file
1770
Mechanical/Frame/PVPlantFrame.py
Normal file
File diff suppressed because it is too large
Load Diff
877
Mechanical/Frame/PVPlantFrame.ui
Normal file
877
Mechanical/Frame/PVPlantFrame.ui
Normal file
@@ -0,0 +1,877 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>476</width>
|
||||
<height>1032</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Módulos:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Altura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.990000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Largura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.960000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.030000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Potencia (wp)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="editModulePower">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>150</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>350</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Estructura</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Columnas (un)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editFrontHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.800000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Orientación del módulo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editVerticalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="editRows">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboFrameType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fija</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Tracker 1 Eje</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editLeftOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Offset borde derecha (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Ángulo de inclinación (º)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editRightOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QSpinBox" name="editTilt">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QSpinBox" name="editInclination">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Filas (un)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Distancia al suelo en el frente (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="editCols">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap">
|
||||
<property name="text">
|
||||
<string>Separación vertical entre módulos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboModuleOrientation">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Landscape</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Portrait</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Separación horizontal entre módulos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Ängulo máximo de inclinación longitudinal (ª)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editHorizontalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tipo de estructura</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Offset borde izquierda (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widgetTracker" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap_2">
|
||||
<property name="text">
|
||||
<string>Separación entre uniones (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Separación Motor (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="editInternalGapNumber">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Número de uniones</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editInternalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editMotorGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Resultado</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Total de módulos</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="editTotalModules">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Potencia total (wp)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editTotalPower">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Longitud (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="editTotalLength">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="editTotalWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
31
MeshTools/MeshGetBoundary.py
Normal file
31
MeshTools/MeshGetBoundary.py
Normal file
@@ -0,0 +1,31 @@
|
||||
def get_boundary(mesh): # From trails
|
||||
""" Create triangulation boundary """
|
||||
import Part
|
||||
import itertools as itools
|
||||
from collections import Counter
|
||||
from ast import literal_eval
|
||||
|
||||
facet_pidx = mesh.Topology[1]
|
||||
edges = itools.chain(*(itools.permutations(pidx, 2) for pidx in facet_pidx))
|
||||
count = Counter((str(edge) for edge in edges))
|
||||
double_boundary = list((literal_eval(k) for k, v in count.items() if v == 1))
|
||||
|
||||
boundary = double_boundary[:1]
|
||||
for candidate in double_boundary[1:]:
|
||||
if candidate in boundary or candidate[::-1] in boundary:
|
||||
pass
|
||||
else:
|
||||
boundary.append(candidate)
|
||||
|
||||
def mkEdge(p1, p2):
|
||||
return Part.makeLine((p1.x, p1.y, p1.z), (p2.x, p2.y, p2.z))
|
||||
|
||||
points = mesh.Points
|
||||
edges = []
|
||||
for p1, p2 in boundary:
|
||||
edges.append(mkEdge(points[p1], points[p2]))
|
||||
|
||||
wires = []
|
||||
for opening in Part.sortEdges(edges):
|
||||
wires.append(Part.Wire(opening))
|
||||
return Part.makeCompound(wires)
|
||||
92
MeshTools/Triangulation.py
Normal file
92
MeshTools/Triangulation.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import FreeCAD
|
||||
import math
|
||||
|
||||
|
||||
def Triangulate(points, MaxlengthLE = 8000, MaxAngleLE = math.pi, use3d=True):
|
||||
import numpy as np
|
||||
from scipy.spatial import Delaunay
|
||||
from stl import mesh as stlmesh
|
||||
import Mesh
|
||||
|
||||
if points.__class__ is list:
|
||||
points = np.array(points)
|
||||
|
||||
tri = Delaunay(points[:, :2])
|
||||
faces = tri.simplices
|
||||
wireframe = stlmesh.Mesh(np.zeros(faces.shape[0], dtype=stlmesh.Mesh.dtype))
|
||||
|
||||
for i, f in enumerate(faces):
|
||||
if MaxLength(points[f[0]], points[f[1]], points[f[2]], MaxlengthLE) and \
|
||||
MaxAngle(points[f[0]], points[f[1]], points[f[2]], MaxAngleLE):
|
||||
for j in range(3):
|
||||
wireframe.vectors[i][j] = points[f[j], :]
|
||||
if not use3d:
|
||||
wireframe.vectors[i][j][2] = 0
|
||||
|
||||
MeshObject = Mesh.Mesh(wireframe.vectors.tolist())
|
||||
if len(MeshObject.Facets) == 0:
|
||||
return None
|
||||
MeshObject.harmonizeNormals()
|
||||
if MeshObject.Facets[0].Normal.z < 0:
|
||||
MeshObject.flipNormals()
|
||||
return MeshObject
|
||||
|
||||
|
||||
def MaxLength(P1, P2, P3, MaxlengthLE):
|
||||
""" Calculation of the 2D length between triangle edges """
|
||||
p1 = FreeCAD.Vector(P1[0], P1[1], 0)
|
||||
p2 = FreeCAD.Vector(P2[0], P2[1], 0)
|
||||
p3 = FreeCAD.Vector(P3[0], P3[1], 0)
|
||||
|
||||
List = [[p1, p2], [p2, p3], [p3, p1]]
|
||||
for i, j in List:
|
||||
vec = i.sub(j)
|
||||
if vec.Length > MaxlengthLE:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def MaxAngle(P1, P2, P3, MaxAngleLE):
|
||||
""" Calculation of the 2D angle between triangle edges """
|
||||
p1 = FreeCAD.Vector(P1[0], P1[1], 0)
|
||||
p2 = FreeCAD.Vector(P2[0], P2[1], 0)
|
||||
p3 = FreeCAD.Vector(P3[0], P3[1], 0)
|
||||
List = [[p1, p2, p3], [p2, p3, p1], [p3, p1, p2]]
|
||||
for j, k, l in List:
|
||||
vec1 = j.sub(k)
|
||||
vec2 = l.sub(k)
|
||||
radian = vec1.getAngle(vec2)
|
||||
if radian > MaxAngleLE:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# prueba para ver si es mejor:
|
||||
def Open3DTriangle(point_cloud):
|
||||
import numpy as np
|
||||
import open3d as o3d
|
||||
|
||||
'''
|
||||
input_path = "your_path_to_file/"
|
||||
output_path = "your_path_to_output_folder/"
|
||||
dataname = "sample.xyz"
|
||||
point_cloud = np.loadtxt(input_path + dataname, skiprows=1)
|
||||
'''
|
||||
|
||||
pcd = o3d.geometry.PointCloud()
|
||||
pcd.points = o3d.utility.Vector3dVector(point_cloud)
|
||||
|
||||
pcd.normals = o3d.utility.Vector3dVector(np.zeros((1, 3)))
|
||||
pcd.estimate_normals()
|
||||
pcd.orient_normals_consistent_tangent_plane(100)
|
||||
|
||||
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd,
|
||||
depth=8,
|
||||
width=0,
|
||||
scale=1.1,
|
||||
linear_fit=False,
|
||||
n_threads=8)
|
||||
o3d.visualization.draw_geometries([mesh])
|
||||
#bbox = pcd.get_axis_aligned_bounding_box()
|
||||
#p_mesh_crop = mesh.crop(bbox)
|
||||
return mesh
|
||||
554
PVPLantPlacement-old.py
Normal file
554
PVPLantPlacement-old.py
Normal file
@@ -0,0 +1,554 @@
|
||||
import ArchComponent
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
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
|
||||
|
||||
import threading
|
||||
|
||||
|
||||
def makePlacement(baseobj=None, diameter=0, length=0, placement=None, name="Placement"):
|
||||
"makePipe([baseobj,diamerter,length,placement,name]): creates an pipe object from the given base object"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
|
||||
obj.Label = name
|
||||
_PVPlantPlacement(obj)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderPVPlantPlacement(obj.ViewObject)
|
||||
if baseobj:
|
||||
baseobj.ViewObject.hide()
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class _CommandPVPlantPlacement:
|
||||
"the Arch Schedule command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Placement',
|
||||
'Accel': "P, S",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "Placement"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Crear un campo fotovoltaico")}
|
||||
|
||||
def Activated(self):
|
||||
taskd = _PVPlantPlacementTaskPanel()
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class _PVPlantPlacement(ArchComponent.Component):
|
||||
"the PVPlantPlacement object"
|
||||
|
||||
def __init__(self, obj):
|
||||
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
# Does a IfcType exist?
|
||||
# obj.IfcType = "Fence"
|
||||
obj.MoveWithHost = False
|
||||
|
||||
def setProperties(self, obj):
|
||||
ArchComponent.Component.setProperties(self, obj)
|
||||
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not "Section" in pl:
|
||||
obj.addProperty("App::PropertyLink", "Land", "Placement", QT_TRANSLATE_NOOP(
|
||||
"App::Property", "A single section of the fence"))
|
||||
|
||||
if not "Post" in pl:
|
||||
obj.addProperty("App::PropertyLink", "Structure", "Placement", QT_TRANSLATE_NOOP(
|
||||
"App::Property", "A single fence post"))
|
||||
|
||||
if not "Path" in pl:
|
||||
obj.addProperty("App::PropertyLink", "Path", "Placement", QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The Path the fence should follow"))
|
||||
|
||||
if not "NumberOfSections" in pl:
|
||||
obj.addProperty("App::PropertyInteger", "NumberOfSections", "Count", QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The number of sections the fence is built of"))
|
||||
obj.setEditorMode("NumberOfSections", 1)
|
||||
|
||||
if not "NumberOfPosts" in pl:
|
||||
obj.addProperty("App::PropertyInteger", "NumberOfPosts", "Count", QT_TRANSLATE_NOOP(
|
||||
"App::Property", "The number of posts used to build the fence"))
|
||||
obj.setEditorMode("NumberOfPosts", 1)
|
||||
|
||||
self.Type = "Fence"
|
||||
|
||||
def execute(self, obj):
|
||||
# fills columns A, B and C of the spreadsheet
|
||||
if not obj.Description:
|
||||
return
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
|
||||
class _ViewProviderPVPlantPlacement:
|
||||
"A View Provider for PVPlantPlacement"
|
||||
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Arch_Schedule.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
|
||||
def setEdit(self, vobj, mode):
|
||||
# taskd = _ArchScheduleTaskPanel(vobj.Object)
|
||||
# FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
# taskd = _ArchScheduleTaskPanel(vobj.Object)
|
||||
# FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode):
|
||||
# FreeCADGui.Control.closeDialog()
|
||||
return
|
||||
|
||||
def claimChildren(self):
|
||||
# if hasattr(self,"Object"):
|
||||
# return [self.Object.Result]
|
||||
return None
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
return ["Default"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
return "Default"
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
return mode
|
||||
|
||||
|
||||
class _PVPlantPlacementTaskPanel:
|
||||
'''The editmode TaskPanel for Schedules'''
|
||||
|
||||
def __init__(self, obj=None):
|
||||
self.Terrain = None
|
||||
self.Rack = None
|
||||
self.Gap = 200
|
||||
self.Pitch = 4500
|
||||
|
||||
# form:
|
||||
self.form = QtGui.QWidget()
|
||||
self.form.resize(800, 640)
|
||||
self.form.setWindowTitle("Curvas de nivel")
|
||||
self.form.setWindowIcon(QtGui.QIcon(":/icons/Arch_Schedule.svg"))
|
||||
self.grid = QtGui.QGridLayout(self.form)
|
||||
|
||||
# parameters
|
||||
self.labelTerrain = QtGui.QLabel()
|
||||
self.labelTerrain.setText("Terreno:")
|
||||
self.lineTerrain = QtGui.QLineEdit(self.form)
|
||||
self.lineTerrain.setObjectName(_fromUtf8("lineTerrain"))
|
||||
self.lineTerrain.readOnly = True
|
||||
self.grid.addWidget(self.labelTerrain, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.lineTerrain, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
self.buttonAddTerrain = QtGui.QPushButton('Sel')
|
||||
self.grid.addWidget(self.buttonAddTerrain, self.grid.rowCount() - 1, 2, 1, 1)
|
||||
|
||||
self.labelRack = QtGui.QLabel()
|
||||
self.labelRack.setText("Rack:")
|
||||
self.lineRack = QtGui.QLineEdit(self.form)
|
||||
self.lineRack.setObjectName(_fromUtf8("lineRack"))
|
||||
self.lineRack.readOnly = True
|
||||
self.grid.addWidget(self.labelRack, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.lineRack, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
self.buttonAddRack = QtGui.QPushButton('Sel')
|
||||
self.grid.addWidget(self.buttonAddRack, self.grid.rowCount() - 1, 2, 1, 1)
|
||||
|
||||
self.line1 = QtGui.QFrame()
|
||||
self.line1.setFrameShape(QtGui.QFrame.HLine)
|
||||
self.line1.setFrameShadow(QtGui.QFrame.Sunken)
|
||||
self.grid.addWidget(self.line1, self.grid.rowCount(), 0, 1, -1)
|
||||
|
||||
self.labelTypeStructure = QtGui.QLabel()
|
||||
self.labelTypeStructure.setText("Tipo de estructura:")
|
||||
self.valueTypeStructure = QtGui.QComboBox()
|
||||
self.valueTypeStructure.addItems(["Fixed", "Tracker 1 Axis"])
|
||||
self.valueTypeStructure.setCurrentIndex(0)
|
||||
self.grid.addWidget(self.labelTypeStructure, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueTypeStructure, self.grid.rowCount() - 1, 1, 1, -1)
|
||||
|
||||
self.labelOrientation = QtGui.QLabel()
|
||||
self.labelOrientation.setText("Orientacion:")
|
||||
self.valueOrientation = QtGui.QComboBox()
|
||||
self.valueOrientation.addItems(["Norte-Sur", "Este-Oeste"])
|
||||
self.valueOrientation.setCurrentIndex(0)
|
||||
self.grid.addWidget(self.labelOrientation, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueOrientation, self.grid.rowCount() - 1, 1, 1, -1)
|
||||
|
||||
self.labelGap = QtGui.QLabel()
|
||||
self.labelGap.setText("Espacio entre Columnas:")
|
||||
self.valueGap = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueGap.setText(str(self.Gap) + " mm")
|
||||
self.grid.addWidget(self.labelGap, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueGap, self.grid.rowCount() - 1, 1, 1, -1)
|
||||
|
||||
self.labelPitch = QtGui.QLabel()
|
||||
self.labelPitch.setText("Separacion entre Filas:")
|
||||
self.valuePitch = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valuePitch.setText(str(self.Pitch) + " mm")
|
||||
self.grid.addWidget(self.labelPitch, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valuePitch, self.grid.rowCount() - 1, 1, 1, -1)
|
||||
|
||||
self.labelAlign = QtGui.QLabel()
|
||||
self.labelAlign.setText("Método de alineación:")
|
||||
self.valueAlign = QtGui.QComboBox()
|
||||
self.valueAlign.addItems(["Si", "No"])
|
||||
self.valueAlign.setCurrentIndex(0)
|
||||
self.grid.addWidget(self.labelAlign, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueAlign, self.grid.rowCount() - 1, 1, 1, -1)
|
||||
|
||||
self.line2 = QtGui.QFrame()
|
||||
self.line2.setFrameShape(QtGui.QFrame.HLine)
|
||||
self.line2.setFrameShadow(QtGui.QFrame.Sunken)
|
||||
self.grid.addWidget(self.line2, self.grid.rowCount(), 0, 1, -1)
|
||||
|
||||
self.labelSideSlope = QtGui.QLabel()
|
||||
self.labelSideSlope.setText("Maxima inclinacion longitudinal:")
|
||||
self.valueSideSlope = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueSideSlope.setText("15")
|
||||
self.grid.addWidget(self.labelSideSlope, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueSideSlope, self.grid.rowCount() - 1, 1, 1, -1)
|
||||
|
||||
QtCore.QObject.connect(self.buttonAddTerrain, QtCore.SIGNAL("clicked()"), self.addTerrain)
|
||||
QtCore.QObject.connect(self.buttonAddRack, QtCore.SIGNAL("clicked()"), self.addRack)
|
||||
# QtCore.QObject.connect(self.form.buttonDel, QtCore.SIGNAL("clicked()"), self.remove)
|
||||
# QtCore.QObject.connect(self.form.buttonClear, QtCore.SIGNAL("clicked()"), self.clear)
|
||||
# QtCore.QObject.connect(self.form.buttonSelect, QtCore.SIGNAL("clicked()"), self.select)
|
||||
|
||||
def addTerrain(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.Terrain = sel[0]
|
||||
self.lineTerrain.setText(self.Terrain.Label)
|
||||
|
||||
def addRack(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.Rack = sel[0]
|
||||
self.lineRack.setText(self.Rack.Label)
|
||||
|
||||
def accept(self):
|
||||
if self.Terrain is not None and self.Rack is not None:
|
||||
self.Gap = FreeCAD.Units.Quantity(self.valueGap.text()).Value
|
||||
self.Pitch = FreeCAD.Units.Quantity(self.valuePitch.text()).Value
|
||||
self.placement()
|
||||
return True
|
||||
|
||||
def placement(self):
|
||||
if self.valueTypeStructure.currentIndex() == 0: # Fixed
|
||||
print("Rack")
|
||||
else:
|
||||
print("Tracker")
|
||||
if self.Rack.Height < self.Rack.Length:
|
||||
print("rotar")
|
||||
aux = self.Rack.Length
|
||||
self.Rack.Length = self.Rack.Height
|
||||
self.Rack.Height = aux
|
||||
|
||||
self.Rack.Placement.Base.x = self.Terrain.Shape.BoundBox.XMin
|
||||
self.Rack.Placement.Base.y = self.Terrain.Shape.BoundBox.YMin
|
||||
|
||||
DistColls = self.Rack.Length.Value + self.Gap
|
||||
DistRows = self.Rack.Height.Value + self.Pitch
|
||||
area = self.Rack.Shape.Faces[0].Area # * 0.999999999
|
||||
|
||||
import Draft
|
||||
rec = Draft.makeRectangle(length=self.Terrain.Shape.BoundBox.XLength, height=self.Rack.Height, face=True,
|
||||
support=None)
|
||||
rec.Placement.Base.x = self.Terrain.Shape.BoundBox.XMin
|
||||
rec.Placement.Base.y = self.Terrain.Shape.BoundBox.YMin
|
||||
|
||||
try:
|
||||
while rec.Shape.BoundBox.YMax <= self.Terrain.Shape.BoundBox.YMax:
|
||||
common = self.Terrain.Shape.common(rec.Shape)
|
||||
for shape in common.Faces:
|
||||
if shape.Area >= area:
|
||||
if False:
|
||||
minorPoint = FreeCAD.Vector(0, 0, 0)
|
||||
for spoint in shape.OuterWire.Vertexes:
|
||||
if minorPoint.y >= spoint.Point.y:
|
||||
if minorPoint.x >= spoint.x:
|
||||
minorPoint = spoint
|
||||
self.Rack.Placement.Base = spoint
|
||||
else:
|
||||
# más rápido
|
||||
self.Rack.Placement.Base.x = shape.BoundBox.XMin
|
||||
self.Rack.Placement.Base.y = shape.BoundBox.YMin
|
||||
|
||||
while self.Rack.Shape.BoundBox.XMax <= shape.BoundBox.XMax:
|
||||
verts = [v.Point for v in rackClone.Shape.OuterWire.OrderedVertexes]
|
||||
inside = True
|
||||
for vert in verts:
|
||||
if not shape.isInside(vert, 0, True):
|
||||
inside = False
|
||||
break
|
||||
|
||||
if inside:
|
||||
raise
|
||||
else:
|
||||
# ajuste fino hasta encontrar el primer sitio:
|
||||
rackClone.Placement.Base.x += 100 # un metro
|
||||
|
||||
'''old version
|
||||
common1 = shape.common(self.Rack.Shape)
|
||||
if common1.Area >= area:
|
||||
raise
|
||||
else:
|
||||
# ajuste fino hasta encontrar el primer sitio:
|
||||
self.Rack.Placement.Base.x += 500 # un metro
|
||||
del common1
|
||||
'''
|
||||
# ajuste fino hasta encontrar el primer sitio:
|
||||
rec.Placement.Base.y += 100
|
||||
del common
|
||||
except:
|
||||
pass
|
||||
#print("Found")
|
||||
|
||||
FreeCAD.ActiveDocument.removeObject(rec.Name)
|
||||
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
if self.valueOrientation.currentIndex() == 0:
|
||||
# Código para crear filas:
|
||||
self.Rack.Placement.Base.x = self.Terrain.Shape.BoundBox.XMin
|
||||
i = 1
|
||||
yy = self.Rack.Placement.Base.y
|
||||
while yy < self.Terrain.Shape.BoundBox.YMax:
|
||||
CreateRow1(self.Rack.Placement.Base.x, yy, self.Rack, self.Terrain, DistColls, area, i)
|
||||
i += 1
|
||||
yy += DistRows
|
||||
elif self.valueOrientation.currentIndex() == 2:
|
||||
# Código para crear columnas:
|
||||
while self.Rack.Placement.Base.x > self.Terrain.Shape.BoundBox.XMin:
|
||||
self.Rack.Placement.Base.x -= DistColls
|
||||
else:
|
||||
xx = self.Rack.Placement.Base.x
|
||||
while xx < self.Terrain.Shape.BoundBox.XMax:
|
||||
CreateGrid(xx, self.Rack.Placement.Base.y, self.Rack, self.Terrain, DistRows, area)
|
||||
xx += DistColls
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
print("Everything OK (", datetime.now() - starttime, ")")
|
||||
|
||||
|
||||
# Alinear solo filas. las columnas donde se pueda
|
||||
def CreateRow(XX, YY, rack, land, gap, area, rowNumber):
|
||||
import Draft
|
||||
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
|
||||
rackClone.Label = 'rackClone{a}'.format(a=rowNumber)
|
||||
rackClone.Placement.Base.x = XX
|
||||
rackClone.Placement.Base.y = YY
|
||||
|
||||
rec = Draft.makeRectangle(length=land.Shape.BoundBox.XLength, height=rack.Height, face=True, support=None)
|
||||
rec.Placement.Base.x = land.Shape.BoundBox.XMin
|
||||
rec.Placement.Base.y = YY
|
||||
FreeCAD.activeDocument().recompute()
|
||||
|
||||
common = land.Shape.common(rec.Shape)
|
||||
for shape in common.Faces:
|
||||
if shape.Area >= area:
|
||||
rackClone.Placement.Base.x = shape.BoundBox.XMin
|
||||
rackClone.Placement.Base.y = shape.BoundBox.YMin
|
||||
while rackClone.Shape.BoundBox.XMax <= shape.BoundBox.XMax:
|
||||
common1 = shape.common(rackClone.Shape)
|
||||
if common1.Area >= area:
|
||||
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height, placement=rackClone.Placement,
|
||||
face=True, support=None)
|
||||
tmp.Label = 'R{:03}-000'.format(rowNumber)
|
||||
rackClone.Placement.Base.x += gap
|
||||
else:
|
||||
# ajuste fino hasta encontrar el primer sitio:
|
||||
rackClone.Placement.Base.x += 500 # un metro
|
||||
del common1
|
||||
del common
|
||||
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
|
||||
FreeCAD.ActiveDocument.removeObject(rec.Name)
|
||||
|
||||
|
||||
# Alinear solo filas. las columnas donde se pueda
|
||||
def CreateRow1(XX, YY, rack, land, gap, area, rowNumber):
|
||||
import Draft
|
||||
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
|
||||
rackClone.Label = 'rackClone{a}'.format(a=rowNumber)
|
||||
rackClone.Placement.Base.x = XX
|
||||
rackClone.Placement.Base.y = YY
|
||||
|
||||
rec = Draft.makeRectangle(length=land.Shape.BoundBox.XLength, height=rack.Height, face=True, support=None)
|
||||
rec.Placement.Base.x = land.Shape.BoundBox.XMin
|
||||
rec.Placement.Base.y = YY
|
||||
FreeCAD.activeDocument().recompute()
|
||||
|
||||
common = land.Shape.common(rec.Shape)
|
||||
for shape in common.Faces:
|
||||
if shape.Area >= area:
|
||||
if False:
|
||||
minorPoint = FreeCAD.Vector(0, 0, 0)
|
||||
for spoint in shape.OuterWire.Vertexes:
|
||||
if minorPoint.y >= spoint.Point.y:
|
||||
if minorPoint.x >= spoint.x:
|
||||
minorPoint = spoint
|
||||
rackClone.Placement.Base = spoint
|
||||
else:
|
||||
# más rápido
|
||||
rackClone.Placement.Base.x = shape.BoundBox.XMin
|
||||
rackClone.Placement.Base.y = shape.BoundBox.YMin
|
||||
|
||||
while rackClone.Shape.BoundBox.XMax <= shape.BoundBox.XMax:
|
||||
verts = [v.Point for v in rackClone.Shape.OuterWire.OrderedVertexes]
|
||||
inside = True
|
||||
for vert in verts:
|
||||
if not shape.isInside(vert, 0, True):
|
||||
inside = False
|
||||
break
|
||||
if inside:
|
||||
#tmp = rack.Shape.copy()
|
||||
#tmp.Placement = rack.Placement
|
||||
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height, placement=rackClone.Placement,
|
||||
face=True, support=None)
|
||||
tmp.Label = 'R{:03}-000'.format(rowNumber)
|
||||
|
||||
rackClone.Placement.Base.x += gap
|
||||
else:
|
||||
# ajuste fino hasta encontrar el primer sitio:
|
||||
rackClone.Placement.Base.x += 500 # un metro
|
||||
del common
|
||||
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
|
||||
FreeCAD.ActiveDocument.removeObject(rec.Name)
|
||||
|
||||
|
||||
# Alinear columna y fila (grid perfecta)
|
||||
def CreateGrid(XX, YY, rack, land, gap, area):
|
||||
print("CreateGrid")
|
||||
import Draft
|
||||
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
|
||||
rackClone.Label = 'rackClone{a}'.format(a=XX)
|
||||
rackClone.Placement.Base.x = XX
|
||||
rackClone.Placement.Base.y = YY
|
||||
|
||||
# if False:
|
||||
while rackClone.Shape.BoundBox.YMax < land.Shape.BoundBox.YMax:
|
||||
common = land.Shape.common(rackClone.Shape)
|
||||
|
||||
if common.Area >= area:
|
||||
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height,
|
||||
placement=rackClone.Placement, face=True, support=None)
|
||||
tmp.Label = 'rackClone{a}'.format(a=XX)
|
||||
rackClone.Placement.Base.y += gap
|
||||
# else:
|
||||
# # ajuste fino hasta encontrar el primer sitio:
|
||||
# rackClone.Placement.Base.y += 1000
|
||||
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
|
||||
|
||||
|
||||
# Alinear solo filas. las columnas donde se pueda
|
||||
def CreateCol(XX, YY, rack, land, gap, area):
|
||||
import Draft
|
||||
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
|
||||
rackClone.Label = 'rackClone{a}'.format(a=XX)
|
||||
rackClone.Placement.Base.x = XX
|
||||
rackClone.Placement.Base.y = YY
|
||||
|
||||
while rackClone.Shape.BoundBox.YMax < land.Shape.BoundBox.YMax:
|
||||
common = land.Shape.common(rackClone.Shape)
|
||||
|
||||
if common.Area >= area:
|
||||
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height,
|
||||
placement=rackClone.Placement, face=True, support=None)
|
||||
tmp.Label = 'rackClone{a}'.format(a=XX)
|
||||
rackClone.Placement.Base.y += gap
|
||||
else:
|
||||
# ajuste fino hasta encontrar el primer sitio:
|
||||
rackClone.Placement.Base.y += 100
|
||||
|
||||
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
|
||||
|
||||
|
||||
# TODO: Probar a usar hilos:
|
||||
class _CreateCol(threading.Thread):
|
||||
def __init__(self, args=()):
|
||||
super().__init__()
|
||||
self.XX = args[0]
|
||||
self.YY = args[1]
|
||||
self.rack = args[2]
|
||||
self.land = args[3]
|
||||
self.gap = args[4]
|
||||
self.area = args[5]
|
||||
|
||||
def run(self):
|
||||
import Draft
|
||||
# rackClone = Draft.makeRectangle(length=land.Shape.BoundBox.XLength, height=rack.Height,
|
||||
# face=True, support=None)
|
||||
# rackClone = FreeCAD.activeDocument().addObject('Part::Feature')
|
||||
# rackClone.Shape = self.rack.Shape
|
||||
|
||||
rackClone = Draft.makeRectangle(length=self.rack.Length, height=self.rack.Height, face=True, support=None)
|
||||
rackClone.Label = 'rackClone{a}'.format(a=self.XX)
|
||||
rackClone.Placement.Base.x = self.XX
|
||||
rackClone.Placement.Base.y = self.YY
|
||||
|
||||
# if False:
|
||||
while rackClone.Shape.BoundBox.YMax < self.land.Shape.BoundBox.YMax:
|
||||
common = self.land.Shape.common(rackClone.Shape)
|
||||
|
||||
if common.Area >= self.area:
|
||||
rack = Draft.makeRectangle(length=self.rack.Length, height=self.rack.Height,
|
||||
placement=rackClone.Placement, face=True, support=None)
|
||||
rack.Label = 'rackClone{a}'.format(a=self.XX)
|
||||
rackClone.Placement.Base.y += self.gap
|
||||
# else:
|
||||
# # ajuste fino hasta encontrar el primer sitio:
|
||||
# rackClone.Placement.Base.y += 1000
|
||||
|
||||
# FreeCAD.ActiveDocument.removeObject(rackClone.Name)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantPlacement', _CommandPVPlantPlacement())
|
||||
345
PVPlantBuilding.py
Normal file
345
PVPlantBuilding.py
Normal file
@@ -0,0 +1,345 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 ArchComponent
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
import draftguitools.gui_tool_utils as gui_tool_utils
|
||||
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
|
||||
|
||||
import os
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
def makeBuilding(name="Building"):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Building")
|
||||
obj.Label = name
|
||||
_Building(obj)
|
||||
_ViewProviderBuilding(obj.ViewObject)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
|
||||
|
||||
class _Building(ArchComponent.Component):
|
||||
"A Building Obcject"
|
||||
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.rooftype = ""
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
# Dimensions: --------------------------------------------------------------------------------------------------
|
||||
if not "RoofWall" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"RoofWall",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).RoofWall = 0
|
||||
|
||||
if not "RoofWallWidth" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"RoofWallWidth",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).RoofWallWidth = 300
|
||||
|
||||
if not "Height" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Height",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).Height = 4000
|
||||
|
||||
if not "Width" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Width",
|
||||
"Building",
|
||||
"The width of this object"
|
||||
).Width = 7000
|
||||
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).Length = 14000
|
||||
|
||||
if not "RoofHeight" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"RoofHeight",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).RoofHeight = 1500
|
||||
|
||||
if not "TopCenter" in pl:
|
||||
obj.addProperty("App::PropertyPercent",
|
||||
"TopCenter",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).TopCenter = 50
|
||||
|
||||
if not "TopLength" in pl:
|
||||
obj.addProperty("App::PropertyPercent",
|
||||
"TopLength",
|
||||
"Building",
|
||||
"The height of this object"
|
||||
).TopLength = 0
|
||||
|
||||
# outputs:
|
||||
if not "InternalVolume" in pl:
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"InternalVolume",
|
||||
"Outputs",
|
||||
"The height of this object"
|
||||
)
|
||||
|
||||
if not "ExternalVolume" in pl:
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"ExternalVolume",
|
||||
"Outputs",
|
||||
"The height of this object"
|
||||
)
|
||||
|
||||
self.Type = "Building"
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and Arch wall properties."""
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
w = obj.Width.Value
|
||||
w_med = w / 2
|
||||
l_med = obj.Length.Value / 2
|
||||
|
||||
p1 = FreeCAD.Vector(-l_med, -w_med, 0)
|
||||
p2 = FreeCAD.Vector(-l_med, w_med, 0)
|
||||
p3 = FreeCAD.Vector(-l_med, w_med, obj.Height.Value)
|
||||
p4 = FreeCAD.Vector(-l_med, w * (obj.TopCenter - 50) / 100, obj.Height.Value + obj.RoofHeight.Value)
|
||||
p5 = FreeCAD.Vector(-l_med, -w_med, obj.Height.Value)
|
||||
profile = Part.Face(Part.makePolygon([p1, p2, p3, p4, p5, p1, ]))
|
||||
shape = profile.extrude(FreeCAD.Vector(obj.Length.Value, 0, 0))
|
||||
|
||||
if obj.TopLength > 0:
|
||||
p1 = FreeCAD.Vector(-l_med, w_med, obj.Height.Value)
|
||||
p2 = FreeCAD.Vector(-l_med, w * (obj.TopCenter - 50) / 100, obj.Height.Value + obj.RoofHeight.Value)
|
||||
p3 = FreeCAD.Vector(-l_med, -w_med, obj.Height.Value)
|
||||
p4 = FreeCAD.Vector(-l_med + (obj.TopLength * obj.Length.Value / 200),
|
||||
w * (obj.TopCenter - 50) / 100, obj.Height.Value + obj.RoofHeight.Value)
|
||||
f1 = Part.Face(Part.makePolygon([p1, p2, p3, p1, ]))
|
||||
f2 = Part.Face(Part.makePolygon([p1, p4, p3, p1, ]))
|
||||
f3 = Part.Face(Part.makePolygon([p1, p2, p4, p1, ]))
|
||||
f4 = Part.Face(Part.makePolygon([p3, p4, p2, p3, ]))
|
||||
tool = Part.makeSolid(Part.Shell([f1, f4, f2, f3]))
|
||||
shape = shape.cut(tool)
|
||||
|
||||
p1 = FreeCAD.Vector(l_med, w_med, obj.Height.Value)
|
||||
p2 = FreeCAD.Vector(l_med,
|
||||
w * (obj.TopCenter - 50) / 100,
|
||||
obj.Height.Value + obj.RoofHeight.Value)
|
||||
p3 = FreeCAD.Vector(l_med, -w_med, obj.Height.Value)
|
||||
p4 = FreeCAD.Vector(l_med - (obj.TopLength * obj.Length.Value / 200),
|
||||
w * (obj.TopCenter - 50) / 100,
|
||||
obj.Height.Value + obj.RoofHeight.Value)
|
||||
|
||||
f1 = Part.Face(Part.makePolygon([p1, p2, p3, p1, ]))
|
||||
f2 = Part.Face(Part.makePolygon([p1, p4, p3, p1, ]))
|
||||
f3 = Part.Face(Part.makePolygon([p1, p2, p4, p1, ]))
|
||||
f4 = Part.Face(Part.makePolygon([p3, p4, p2, p3, ]))
|
||||
tool = Part.makeSolid(Part.Shell([f1, f4, f2, f3]))
|
||||
shape = shape.cut(tool)
|
||||
|
||||
if obj.RoofWall.Value > 0 and obj.RoofWallWidth.Value > 0:
|
||||
offset = 2 * obj.RoofWallWidth.Value
|
||||
box1 = Part.makeBox(obj.Length.Value, obj.Width.Value, obj.RoofWall.Value)
|
||||
box2 = Part.makeBox(obj.Length.Value - offset, obj.Width.Value - offset, obj.RoofWall.Value)
|
||||
box2.Placement.Base.x += obj.RoofWallWidth.Value
|
||||
box2.Placement.Base.y += obj.RoofWallWidth.Value
|
||||
box1 = box1.cut(box2)
|
||||
box1.Placement.Base.x = -l_med
|
||||
box1.Placement.Base.y = -w_med
|
||||
box1.Placement.Base.z = obj.Height.Value
|
||||
shape = shape.fuse(box1).removeSplitter()
|
||||
|
||||
obj.Shape = shape
|
||||
|
||||
|
||||
class _ViewProviderBuilding(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(DirIcons, "house.svg"))
|
||||
|
||||
def setEdit(self, vobj, mode):
|
||||
"""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 Arch component 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"):
|
||||
taskd = _BuildingTaskPanel(self.Object)
|
||||
taskd.obj = self.Object
|
||||
# taskd.update()
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class _BuildingTaskPanel:
|
||||
def __init__(self, obj=None):
|
||||
self.new = False
|
||||
if obj is None:
|
||||
self.new = True
|
||||
obj = makeBuilding()
|
||||
|
||||
self.obj = obj
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantBuilding.ui")
|
||||
|
||||
self.node = None
|
||||
self.view = FreeCADGui.ActiveDocument.ActiveView
|
||||
self.tracker = DraftTrackers.ghostTracker(obj)
|
||||
self.tracker.on()
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
|
||||
def action(self, arg):
|
||||
"""Handle the 3D scene events.
|
||||
|
||||
This is installed as an EventCallback in the Inventor view.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg: dict
|
||||
Dictionary with strings that indicates the type of event received
|
||||
from the 3D view.
|
||||
"""
|
||||
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
|
||||
if info:
|
||||
self.tracker.move(FreeCAD.Vector(info["x"], info["y"], info["z"]))
|
||||
else:
|
||||
self.tracker.move(point)
|
||||
|
||||
elif (arg["Type"] == "SoMouseButtonEvent" and
|
||||
arg["State"] == "DOWN" and
|
||||
arg["Button"] == "BUTTON1"):
|
||||
|
||||
point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
|
||||
if info:
|
||||
self.obj.Placement.Base = FreeCAD.Vector(info["x"], info["y"], info["z"])
|
||||
else:
|
||||
self.obj.Placement.Base = point
|
||||
self.finish()
|
||||
|
||||
def finish(self):
|
||||
self.accept()
|
||||
|
||||
def accept(self):
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
if self.new:
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def closeForm(self):
|
||||
self.tracker.finalize()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
self.view.removeEventCallback("SoEvent", self.call)
|
||||
|
||||
|
||||
class _CommandBuilding:
|
||||
"the Arch Building command definition"
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "house.svg")),
|
||||
'MenuText': "Building",
|
||||
'Accel': "C, M",
|
||||
'ToolTip': "Creates a Building object from setup dialog."}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
if FreeCADGui.Selection.getCompleteSelection():
|
||||
for ob in FreeCAD.ActiveDocument.Objects:
|
||||
if ob.Name[:4] == "Site":
|
||||
return True
|
||||
|
||||
def Activated(self):
|
||||
TaskPanel = _BuildingTaskPanel()
|
||||
FreeCADGui.Control.showDialog(TaskPanel)
|
||||
return
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantBuilding', _CommandBuilding())
|
||||
218
PVPlantBuilding.ui
Normal file
218
PVPlantBuilding.ui
Normal file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>332</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Dimensions</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Heigth (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Largura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
172
PVPlantCCTV.py
Normal file
172
PVPlantCCTV.py
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
import FreeCAD
|
||||
import ArchComponent
|
||||
import PVPlantSite
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Frames"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import os
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
def makePole(diameter=48, length=3000, placement=None, name="Post"):
|
||||
"makePipe([baseobj,diamerter,length,placement,name]): creates an pipe object from the given base object"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
|
||||
obj.Label = name
|
||||
Poles(obj)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
ViewProviderPost(obj.ViewObject)
|
||||
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
return obj
|
||||
|
||||
class Poles(ArchComponent.Component):
|
||||
"A Base Frame Obcject - Class"
|
||||
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.obj = obj
|
||||
self.setCommonProperties(obj)
|
||||
|
||||
# Does a IfcType exist?
|
||||
obj.IfcType = "Structural Item"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
self.totalAreaShape = None
|
||||
self.changed = True
|
||||
|
||||
def setCommonProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
ArchComponent.Component.setProperties(self, obj)
|
||||
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not "TopDiameter" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"TopDiameter",
|
||||
"Post",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).TopDiameter = 40
|
||||
|
||||
if not "BottomDiameter" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"BottomDiameter",
|
||||
"Post",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The width of this object")
|
||||
).BottomDiameter = 60
|
||||
|
||||
if not "Height" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Height",
|
||||
"Post",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The Length of this object")
|
||||
).Height = 6000
|
||||
|
||||
if not "BaseWidth" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"BaseWidth",
|
||||
"Post",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The Length of this object")
|
||||
).BaseWidth = 300
|
||||
|
||||
if not "BaseHeight" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"BaseHeight",
|
||||
"Post",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The Length of this object")
|
||||
).BaseHeight = 6
|
||||
|
||||
self.Type = "Post"
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
''''''
|
||||
|
||||
def execute(self, obj):
|
||||
pl = obj.Placement
|
||||
|
||||
base = Part.makeBox(obj.BaseWidth, obj.BaseWidth, obj.BaseHeight)
|
||||
base1 = Part.show(Part.makeSphere(45, FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), 30, 90, 360))
|
||||
tube = Part.makeCone(obj.BottonDiameter / 2, obj.TopDiameter / 2, obj.Height)
|
||||
|
||||
obj.Shape = base.fuse([base1, tube])
|
||||
obj.Placement = pl
|
||||
|
||||
|
||||
class ViewProviderPost(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
import Arch_rc
|
||||
return ":/icons/Arch_Pipe_Tree.svg"
|
||||
|
||||
|
||||
class CommandMultiRowTracker:
|
||||
"the Arch Building command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "solar-tracker.svg")),
|
||||
'MenuText': "Multi-row Tracker",
|
||||
'Accel': "R, M",
|
||||
'ToolTip': "Creates a multi-row Tracker object from trackers."}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
if FreeCADGui.Selection.getCompleteSelection():
|
||||
for ob in FreeCAD.ActiveDocument.Objects:
|
||||
if ob.Name[:4] == "Site":
|
||||
return True
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _FixedRackTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandRackGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['PVPlantFixedRack',
|
||||
'PVPlantTracker'
|
||||
])
|
||||
|
||||
def GetResources(self):
|
||||
return {'MenuText': QT_TRANSLATE_NOOP("", 'Rack Types'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("", 'Rack Types')
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
|
||||
FreeCADGui.addCommand('PVPlantCreatePost', CommandFixedRack())
|
||||
271
PVPlantCreateTerrainMesh.py
Normal file
271
PVPlantCreateTerrainMesh.py
Normal file
@@ -0,0 +1,271 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD, FreeCADGui, Draft
|
||||
from PySide import QtCore, QtGui, QtSvg
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
import os, math
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
class _TaskPanel:
|
||||
def __init__(self, obj = None):
|
||||
self.obj = None
|
||||
self.select = 0
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantCreateTerrainMesh.ui")
|
||||
self.form.buttonAdd.clicked.connect(self.add)
|
||||
|
||||
def add(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.obj = sel[0]
|
||||
self.form.editCloud.setText(self.obj.Label)
|
||||
|
||||
def MaxLength(self, P1, P2, P3, MaxlengthLE):
|
||||
"""
|
||||
Calculation of the 2D length between triangle edges
|
||||
"""
|
||||
|
||||
p1 = FreeCAD.Vector(P1[0], P1[1], 0)
|
||||
p2 = FreeCAD.Vector(P2[0], P2[1], 0)
|
||||
p3 = FreeCAD.Vector(P3[0], P3[1], 0)
|
||||
|
||||
List = [[p1, p2], [p2, p3], [p3, p1]]
|
||||
for i, j in List:
|
||||
vec = i.sub(j)
|
||||
if vec.Length > MaxlengthLE:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def MaxAngle(self, P1, P2, P3, MaxAngleLE):
|
||||
"""
|
||||
Calculation of the 2D angle between triangle edges
|
||||
"""
|
||||
|
||||
p1 = FreeCAD.Vector(P1[0], P1[1], 0)
|
||||
p2 = FreeCAD.Vector(P2[0], P2[1], 0)
|
||||
p3 = FreeCAD.Vector(P3[0], P3[1], 0)
|
||||
|
||||
List = [[p1, p2, p3], [p2, p3, p1], [p3, p1, p2]]
|
||||
for j, k, l in List:
|
||||
vec1 = j.sub(k)
|
||||
vec2 = l.sub(k)
|
||||
radian = vec1.getAngle(vec2)
|
||||
if radian > MaxAngleLE:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def accept(self):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
import Part
|
||||
import numpy as np
|
||||
from scipy.spatial import Delaunay
|
||||
|
||||
bnd = FreeCAD.ActiveDocument.Site.Terrain.CuttingBoundary.Shape
|
||||
if len(bnd.Faces) == 0:
|
||||
bnd = Part.Face(bnd)
|
||||
|
||||
# Get user input
|
||||
MaxlengthLE = int(self.form.MaxlengthLE.text()) * 1000
|
||||
MaxAngleLE = math.radians(int(self.form.MaxAngleLE.text()))
|
||||
|
||||
firstPoint = self.obj.Points.Points[0]
|
||||
nbase = FreeCAD.Vector(firstPoint.x, firstPoint.y, firstPoint.z)
|
||||
data = []
|
||||
for point in self.obj.Points.Points:
|
||||
tmp = FreeCAD.Vector(0, 0, 0).add(point)
|
||||
tmp.z = 0
|
||||
if bnd.isInside(tmp, 0, True):
|
||||
p = point - nbase
|
||||
data.append([float(p.x), float(p.y), float(p.z)])
|
||||
|
||||
Data = np.array(data)
|
||||
data.clear()
|
||||
|
||||
''' not working:
|
||||
import multiprocessing
|
||||
rows = Data.shape[0]
|
||||
|
||||
cpus = multiprocessing.cpu_count()
|
||||
steps = math.ceil(rows / cpus)
|
||||
|
||||
for cpu in range(cpus - 1):
|
||||
start = steps * cpu
|
||||
end = steps * (cpu + 1)
|
||||
if end > rows:
|
||||
end = rows - start
|
||||
tmp = Data[start : end, :]
|
||||
p = multiprocessing.Process(target = Triangulate, args = (tmp,))
|
||||
p.start()
|
||||
p.join()
|
||||
return
|
||||
'''
|
||||
|
||||
# TODO: si es muy grande, dividir el cálculo de la maya en varias etapas
|
||||
# Create delaunay triangulation
|
||||
tri = Delaunay(Data[:, :2])
|
||||
print("tiempo delaunay:", datetime.now() - starttime)
|
||||
|
||||
faces = tri.simplices
|
||||
from stl import mesh
|
||||
wireframe = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
|
||||
for i, f in enumerate(faces):
|
||||
if self.MaxLength(Data[f[0]], Data[f[1]], Data[f[2]], MaxlengthLE) and \
|
||||
self.MaxAngle(Data[f[0]], Data[f[1]], Data[f[2]], MaxAngleLE):
|
||||
for j in range(3):
|
||||
wireframe.vectors[i][j] = Data[f[j], :]
|
||||
|
||||
import Mesh
|
||||
MeshObject = Mesh.Mesh(wireframe.vectors.tolist())
|
||||
MeshObject.Placement.move(nbase)
|
||||
MeshObject.harmonizeNormals()
|
||||
Surface = FreeCAD.ActiveDocument.addObject("Mesh::Feature", self.form.SurfaceNameLE.text())
|
||||
Surface.Mesh = MeshObject
|
||||
Surface.Label = self.form.SurfaceNameLE.text()
|
||||
|
||||
shape = MeshToShape(MeshObject)
|
||||
import Part
|
||||
Part.show(shape)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
print(" --- Tiempo tardado:", datetime.now() - starttime)
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------------------------
|
||||
#from PySide.QtWidgets import QVBoxLayout, QLabel, QPushButton, QWidget, QMainWindow, QApplication
|
||||
|
||||
def Triangulate(Points, MaxlengthLE = 8000, MaxAngleLE = math.pi, use3d=True):
|
||||
import numpy as np
|
||||
from scipy.spatial import Delaunay
|
||||
from stl import mesh as stlmesh
|
||||
import Mesh
|
||||
|
||||
if Points.__class__ is list:
|
||||
Points = np.array(Points)
|
||||
tri = Delaunay(Points[:, :2])
|
||||
faces = tri.simplices
|
||||
wireframe = stlmesh.Mesh(np.zeros(faces.shape[0], dtype=stlmesh.Mesh.dtype))
|
||||
|
||||
for i, f in enumerate(faces):
|
||||
if MaxLength(Points[f[0]], Points[f[1]], Points[f[2]], MaxlengthLE) and \
|
||||
MaxAngle(Points[f[0]], Points[f[1]], Points[f[2]], MaxAngleLE):
|
||||
for j in range(3):
|
||||
wireframe.vectors[i][j] = Points[f[j], :]
|
||||
if not use3d:
|
||||
wireframe.vectors[i][j][2] = 0
|
||||
|
||||
MeshObject = Mesh.Mesh(wireframe.vectors.tolist())
|
||||
if len(MeshObject.Facets) == 0:
|
||||
return None
|
||||
MeshObject.harmonizeNormals()
|
||||
if MeshObject.Facets[0].Normal.z < 0:
|
||||
MeshObject.flipNormals()
|
||||
return MeshObject
|
||||
|
||||
def MaxLength(P1, P2, P3, MaxlengthLE):
|
||||
""" Calculation of the 2D length between triangle edges """
|
||||
p1 = FreeCAD.Vector(P1[0], P1[1], 0)
|
||||
p2 = FreeCAD.Vector(P2[0], P2[1], 0)
|
||||
p3 = FreeCAD.Vector(P3[0], P3[1], 0)
|
||||
|
||||
List = [[p1, p2], [p2, p3], [p3, p1]]
|
||||
for i, j in List:
|
||||
vec = i.sub(j)
|
||||
if vec.Length > MaxlengthLE:
|
||||
return False
|
||||
return True
|
||||
|
||||
def MaxAngle(P1, P2, P3, MaxAngleLE):
|
||||
""" Calculation of the 2D angle between triangle edges """
|
||||
p1 = FreeCAD.Vector(P1[0], P1[1], 0)
|
||||
p2 = FreeCAD.Vector(P2[0], P2[1], 0)
|
||||
p3 = FreeCAD.Vector(P3[0], P3[1], 0)
|
||||
List = [[p1, p2, p3], [p2, p3, p1], [p3, p1, p2]]
|
||||
for j, k, l in List:
|
||||
vec1 = j.sub(k)
|
||||
vec2 = l.sub(k)
|
||||
radian = vec1.getAngle(vec2)
|
||||
if radian > MaxAngleLE:
|
||||
return False
|
||||
return True
|
||||
|
||||
def Open3DTriangle(point_cloud):
|
||||
import numpy as np
|
||||
import open3d as o3d
|
||||
|
||||
'''
|
||||
input_path = "your_path_to_file/"
|
||||
output_path = "your_path_to_output_folder/"
|
||||
dataname = "sample.xyz"
|
||||
point_cloud = np.loadtxt(input_path + dataname, skiprows=1)
|
||||
'''
|
||||
pcd = o3d.geometry.PointCloud()
|
||||
pcd.points = o3d.utility.Vector3dVector(point_cloud)
|
||||
|
||||
pcd.normals = o3d.utility.Vector3dVector(np.zeros((1, 3)))
|
||||
pcd.estimate_normals()
|
||||
pcd.orient_normals_consistent_tangent_plane(100)
|
||||
|
||||
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd,
|
||||
depth=8,
|
||||
width=0,
|
||||
scale=1.1,
|
||||
linear_fit=False,
|
||||
n_threads=8)
|
||||
o3d.visualization.draw_geometries([mesh])
|
||||
#bbox = pcd.get_axis_aligned_bounding_box()
|
||||
#p_mesh_crop = mesh.crop(bbox)
|
||||
return mesh
|
||||
|
||||
class _PVPlantCreateTerrainMesh:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "surface.svg")),
|
||||
'MenuText': QT_TRANSLATE_NOOP("PVPlant", "Create Surface"),
|
||||
'Accel': "C, S",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("PVPlant", "Creates a surface form a cloud of points.")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _TaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantCreateTerrainMesh', _PVPlantCreateTerrainMesh())
|
||||
167
PVPlantCreateTerrainMesh.ui
Normal file
167
PVPlantCreateTerrainMesh.ui
Normal file
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CreateSurface</class>
|
||||
<widget class="QDialog" name="CreateSurface">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>396</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Surface</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="SurfaceNameL">
|
||||
<property name="text">
|
||||
<string>Surface Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="SurfaceNameLE">
|
||||
<property name="text">
|
||||
<string>Surface</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="editBoundary"/>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="2" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Boundary</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="buttonBoundary">
|
||||
<property name="text">
|
||||
<string>add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="SelectPointGroupL">
|
||||
<property name="text">
|
||||
<string>Select Point Groups</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Nube de puntos</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="editCloud"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonAdd">
|
||||
<property name="text">
|
||||
<string>sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="MaxlengthL">
|
||||
<property name="text">
|
||||
<string>Maximum Triangle length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="MaxlengthLE">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="OtherValueL">
|
||||
<property name="text">
|
||||
<string>Maximum Triangle Angle:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="MaxAngleLE">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>90</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
967
PVPlantEarthWorks.py
Normal file
967
PVPlantEarthWorks.py
Normal file
@@ -0,0 +1,967 @@
|
||||
import math
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
import ArchComponent
|
||||
from pivy import coin
|
||||
import numpy as np
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
from PySide import QtCore, QtGui
|
||||
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
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
voltype = ["Fill", "Cut"]
|
||||
|
||||
|
||||
def makeEarthWorksVolume(vtype = 0):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", voltype[vtype])
|
||||
EarthWorksVolume(obj)
|
||||
ViewProviderEarthWorksVolume(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
|
||||
class EarthWorksVolume(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.obj = obj
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("VolumeType" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"VolumeType",
|
||||
"Volume",
|
||||
"Connection").VolumeType = voltype
|
||||
|
||||
if not ("SurfaceSlope" in pl):
|
||||
obj.addProperty("App::PropertyPercent",
|
||||
"SurfaceSlope",
|
||||
"Volume",
|
||||
"Connection").SurfaceSlope = 2
|
||||
|
||||
if not ("VolumeMesh" in pl):
|
||||
obj.addProperty("Mesh::PropertyMeshKernel",
|
||||
"VolumeMesh",
|
||||
"Volume",
|
||||
"Volume")
|
||||
obj.setEditorMode("VolumeMesh", 2)
|
||||
|
||||
if not ("Volume" in pl):
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"Volume",
|
||||
"Volume",
|
||||
"Volume")
|
||||
obj.setEditorMode("Volume", 1)
|
||||
|
||||
obj.Proxy = self
|
||||
obj.IfcType = "Civil Element"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChange(self, obj, prop):
|
||||
if prop == "VolumeMesh":
|
||||
if obj.VolumeMesh:
|
||||
obj.VolumeMesh = obj.VolumeMesh.Volume
|
||||
|
||||
def execute(self, obj):
|
||||
''' '''
|
||||
pass
|
||||
|
||||
|
||||
class ViewProviderEarthWorksVolume:
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
''' Set view properties. '''
|
||||
pl = vobj.PropertiesList
|
||||
|
||||
(r, g, b) = (1.0, 0.0, 0.0) if vobj.Object.VolumeType == "Cut" else (0.0, 0.0, 1.0)
|
||||
|
||||
# Triangulation properties.
|
||||
if not "Transparency" in pl:
|
||||
vobj.addProperty("App::PropertyIntegerConstraint",
|
||||
"Transparency", "Surface Style",
|
||||
"Set triangle face transparency")
|
||||
vobj.Transparency = (50, 0, 100, 1)
|
||||
|
||||
if not "ShapeColor" in pl:
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"ShapeColor",
|
||||
"Surface Style",
|
||||
"Set triangle face color")
|
||||
vobj.ShapeColor = (r, g, b, vobj.Transparency / 100)
|
||||
|
||||
if not "ShapeMaterial" in pl:
|
||||
vobj.addProperty("App::PropertyMaterial",
|
||||
"ShapeMaterial", "Surface Style",
|
||||
"Triangle face material")
|
||||
vobj.ShapeMaterial = FreeCAD.Material()
|
||||
|
||||
if not "LineTransparency" in pl:
|
||||
vobj.addProperty("App::PropertyIntegerConstraint",
|
||||
"LineTransparency", "Surface Style",
|
||||
"Set triangle edge transparency")
|
||||
vobj.LineTransparency = (50, 0, 100, 1)
|
||||
|
||||
if not "LineColor" in pl:
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"LineColor", "Surface Style",
|
||||
"Set triangle face color")
|
||||
vobj.LineColor = (0.5, 0.5, 0.5, vobj.LineTransparency / 100)
|
||||
|
||||
'''vobj.addProperty(
|
||||
"App::PropertyMaterial", "LineMaterial", "Surface Style",
|
||||
"Triangle face material").LineMaterial = FreeCAD.Material()
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyFloatConstraint", "LineWidth", "Surface Style",
|
||||
"Set triangle edge line width").LineWidth = (0.0, 1.0, 20.0, 1.0)
|
||||
|
||||
# Boundary properties.
|
||||
vobj.addProperty(
|
||||
"App::PropertyColor", "BoundaryColor", "Boundary Style",
|
||||
"Set boundary contour color").BoundaryColor = (0.0, 0.75, 1.0, 0.0)
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyFloatConstraint", "BoundaryWidth", "Boundary Style",
|
||||
"Set boundary contour line width").BoundaryWidth = (3.0, 1.0, 20.0, 1.0)
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyEnumeration", "BoundaryPattern", "Boundary Style",
|
||||
"Set a line pattern for boundary").BoundaryPattern = [*line_patterns]
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyIntegerConstraint", "PatternScale", "Boundary Style",
|
||||
"Scale the line pattern").PatternScale = (3, 1, 20, 1)
|
||||
|
||||
# Contour properties.
|
||||
vobj.addProperty(
|
||||
"App::PropertyColor", "MajorColor", "Contour Style",
|
||||
"Set major contour color").MajorColor = (1.0, 0.0, 0.0, 0.0)
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyFloatConstraint", "MajorWidth", "Contour Style",
|
||||
"Set major contour line width").MajorWidth = (4.0, 1.0, 20.0, 1.0)
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyColor", "MinorColor", "Contour Style",
|
||||
"Set minor contour color").MinorColor = (1.0, 1.0, 0.0, 0.0)
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyFloatConstraint", "MinorWidth", "Contour Style",
|
||||
"Set major contour line width").MinorWidth = (2.0, 1.0, 20.0, 1.0)
|
||||
'''
|
||||
vobj.Proxy = self
|
||||
vobj.ShapeMaterial.DiffuseColor = vobj.ShapeColor
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
'''
|
||||
Update Object visuals when a view property changed.
|
||||
'''
|
||||
if prop == "ShapeColor" or prop == "Transparency":
|
||||
if hasattr(vobj, "ShapeColor") and hasattr(vobj, "Transparency"):
|
||||
color = vobj.getPropertyByName("ShapeColor")
|
||||
transparency = vobj.getPropertyByName("Transparency")
|
||||
color = (color[0], color[1], color[2], transparency / 100)
|
||||
vobj.ShapeMaterial.DiffuseColor = color
|
||||
|
||||
if prop == "ShapeMaterial":
|
||||
if hasattr(vobj, "ShapeMaterial"):
|
||||
material = vobj.getPropertyByName("ShapeMaterial")
|
||||
self.face_material.diffuseColor.setValue(material.DiffuseColor[:3])
|
||||
self.face_material.transparency = material.DiffuseColor[3]
|
||||
|
||||
if prop == "LineColor" or prop == "LineTransparency":
|
||||
if hasattr(vobj, "LineColor") and hasattr(vobj, "LineTransparency"):
|
||||
color = vobj.getPropertyByName("LineColor")
|
||||
transparency = vobj.getPropertyByName("LineTransparency")
|
||||
color = (color[0], color[1], color[2], transparency / 100)
|
||||
vobj.LineMaterial.DiffuseColor = color
|
||||
|
||||
if prop == "LineMaterial":
|
||||
material = vobj.getPropertyByName(prop)
|
||||
self.edge_material.diffuseColor.setValue(material.DiffuseColor[:3])
|
||||
self.edge_material.transparency = material.DiffuseColor[3]
|
||||
|
||||
if prop == "LineWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.edge_style.lineWidth = width
|
||||
|
||||
if prop == "BoundaryColor":
|
||||
color = vobj.getPropertyByName(prop)
|
||||
self.boundary_color.rgb = color[:3]
|
||||
|
||||
if prop == "BoundaryWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.boundary_style.lineWidth = width
|
||||
|
||||
if prop == "BoundaryPattern":
|
||||
if hasattr(vobj, "BoundaryPattern"):
|
||||
pattern = vobj.getPropertyByName(prop)
|
||||
self.boundary_style.linePattern = line_patterns[pattern]
|
||||
|
||||
if prop == "PatternScale":
|
||||
if hasattr(vobj, "PatternScale"):
|
||||
scale = vobj.getPropertyByName(prop)
|
||||
self.boundary_style.linePatternScaleFactor = scale
|
||||
|
||||
if prop == "MajorColor":
|
||||
color = vobj.getPropertyByName(prop)
|
||||
self.major_color.rgb = color[:3]
|
||||
|
||||
if prop == "MajorWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.major_style.lineWidth = width
|
||||
|
||||
if prop == "MinorColor":
|
||||
color = vobj.getPropertyByName(prop)
|
||||
self.minor_color.rgb = color[:3]
|
||||
|
||||
if prop == "MinorWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.minor_style.lineWidth = width
|
||||
|
||||
|
||||
def attach(self, vobj):
|
||||
'''
|
||||
Create Object visuals in 3D view.
|
||||
'''
|
||||
# GeoCoords Node.
|
||||
self.geo_coords = coin.SoGeoCoordinate()
|
||||
|
||||
# Surface features.
|
||||
self.triangles = coin.SoIndexedFaceSet()
|
||||
self.face_material = coin.SoMaterial()
|
||||
self.edge_material = coin.SoMaterial()
|
||||
self.edge_color = coin.SoBaseColor()
|
||||
self.edge_style = coin.SoDrawStyle()
|
||||
self.edge_style.style = coin.SoDrawStyle.LINES
|
||||
|
||||
shape_hints = coin.SoShapeHints()
|
||||
shape_hints.vertex_ordering = coin.SoShapeHints.COUNTERCLOCKWISE
|
||||
mat_binding = coin.SoMaterialBinding()
|
||||
mat_binding.value = coin.SoMaterialBinding.PER_FACE
|
||||
offset = coin.SoPolygonOffset()
|
||||
offset.styles = coin.SoPolygonOffset.LINES
|
||||
offset.factor = -2.0
|
||||
|
||||
# Boundary features.
|
||||
self.boundary_color = coin.SoBaseColor()
|
||||
self.boundary_coords = coin.SoGeoCoordinate()
|
||||
self.boundary_lines = coin.SoLineSet()
|
||||
self.boundary_style = coin.SoDrawStyle()
|
||||
self.boundary_style.style = coin.SoDrawStyle.LINES
|
||||
|
||||
# Boundary root.
|
||||
boundaries = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
boundaries.style = 'EMISSIVE_DIFFUSE'
|
||||
boundaries.addChild(self.boundary_color)
|
||||
boundaries.addChild(self.boundary_style)
|
||||
boundaries.addChild(self.boundary_coords)
|
||||
boundaries.addChild(self.boundary_lines)
|
||||
|
||||
# Major Contour features.
|
||||
self.major_color = coin.SoBaseColor()
|
||||
self.major_coords = coin.SoGeoCoordinate()
|
||||
self.major_lines = coin.SoLineSet()
|
||||
self.major_style = coin.SoDrawStyle()
|
||||
self.major_style.style = coin.SoDrawStyle.LINES
|
||||
|
||||
# Major Contour root.
|
||||
major_contours = coin.SoSeparator()
|
||||
major_contours.addChild(self.major_color)
|
||||
major_contours.addChild(self.major_style)
|
||||
major_contours.addChild(self.major_coords)
|
||||
major_contours.addChild(self.major_lines)
|
||||
|
||||
# Minor Contour features.
|
||||
self.minor_color = coin.SoBaseColor()
|
||||
self.minor_coords = coin.SoGeoCoordinate()
|
||||
self.minor_lines = coin.SoLineSet()
|
||||
self.minor_style = coin.SoDrawStyle()
|
||||
self.minor_style.style = coin.SoDrawStyle.LINES
|
||||
|
||||
# Minor Contour root.
|
||||
minor_contours = coin.SoSeparator()
|
||||
minor_contours.addChild(self.minor_color)
|
||||
minor_contours.addChild(self.minor_style)
|
||||
minor_contours.addChild(self.minor_coords)
|
||||
minor_contours.addChild(self.minor_lines)
|
||||
|
||||
# Highlight for selection.
|
||||
highlight = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
highlight.style = 'EMISSIVE_DIFFUSE'
|
||||
highlight.addChild(shape_hints)
|
||||
highlight.addChild(mat_binding)
|
||||
highlight.addChild(self.geo_coords)
|
||||
highlight.addChild(self.triangles)
|
||||
highlight.addChild(boundaries)
|
||||
|
||||
# Face root.
|
||||
face = coin.SoSeparator()
|
||||
face.addChild(self.face_material)
|
||||
face.addChild(highlight)
|
||||
|
||||
# Edge root.
|
||||
edge = coin.SoSeparator()
|
||||
edge.addChild(self.edge_material)
|
||||
edge.addChild(self.edge_style)
|
||||
edge.addChild(highlight)
|
||||
|
||||
# Surface root.
|
||||
surface_root = coin.SoSeparator()
|
||||
surface_root.addChild(face)
|
||||
surface_root.addChild(offset)
|
||||
surface_root.addChild(edge)
|
||||
surface_root.addChild(major_contours)
|
||||
surface_root.addChild(minor_contours)
|
||||
vobj.addDisplayMode(surface_root, "Surface")
|
||||
|
||||
# Boundary root.
|
||||
boundary_root = coin.SoSeparator()
|
||||
boundary_root.addChild(boundaries)
|
||||
vobj.addDisplayMode(boundary_root, "Boundary")
|
||||
|
||||
# Elevation/Shaded root.
|
||||
shaded_root = coin.SoSeparator()
|
||||
shaded_root.addChild(face)
|
||||
vobj.addDisplayMode(shaded_root, "Elevation")
|
||||
vobj.addDisplayMode(shaded_root, "Slope")
|
||||
vobj.addDisplayMode(shaded_root, "Shaded")
|
||||
|
||||
# Flat Lines root.
|
||||
flatlines_root = coin.SoSeparator()
|
||||
flatlines_root.addChild(face)
|
||||
flatlines_root.addChild(offset)
|
||||
flatlines_root.addChild(edge)
|
||||
vobj.addDisplayMode(flatlines_root, "Flat Lines")
|
||||
|
||||
# Wireframe root.
|
||||
wireframe_root = coin.SoSeparator()
|
||||
wireframe_root.addChild(edge)
|
||||
wireframe_root.addChild(major_contours)
|
||||
wireframe_root.addChild(minor_contours)
|
||||
vobj.addDisplayMode(wireframe_root, "Wireframe")
|
||||
|
||||
# Take features from properties.
|
||||
self.onChanged(vobj, "ShapeColor")
|
||||
self.onChanged(vobj, "LineColor")
|
||||
self.onChanged(vobj, "LineWidth")
|
||||
'''self.onChanged(vobj, "BoundaryColor")
|
||||
self.onChanged(vobj, "BoundaryWidth")
|
||||
self.onChanged(vobj, "BoundaryPattern")
|
||||
self.onChanged(vobj, "PatternScale")
|
||||
self.onChanged(vobj, "MajorColor")
|
||||
self.onChanged(vobj, "MajorWidth")
|
||||
self.onChanged(vobj, "MinorColor")
|
||||
self.onChanged(vobj, "MinorWidth")'''
|
||||
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
'''
|
||||
Update Object visuals when a data property changed.
|
||||
'''
|
||||
|
||||
# Set System.
|
||||
geo_system = ["UTM", FreeCAD.ActiveDocument.Site.UtmZone, "FLAT"]
|
||||
self.geo_coords.geoSystem.setValues(geo_system)
|
||||
self.boundary_coords.geoSystem.setValues(geo_system)
|
||||
self.major_coords.geoSystem.setValues(geo_system)
|
||||
self.minor_coords.geoSystem.setValues(geo_system)
|
||||
|
||||
if prop == "VolumeMesh":
|
||||
mesh = obj.VolumeMesh
|
||||
copy_mesh = mesh.copy()
|
||||
#copy_mesh.Placement.move(origin.Origin)
|
||||
|
||||
triangles = []
|
||||
for i in copy_mesh.Topology[1]:
|
||||
triangles.extend(list(i))
|
||||
triangles.append(-1)
|
||||
|
||||
self.geo_coords.point.values = copy_mesh.Topology[0]
|
||||
self.triangles.coordIndex.values = triangles
|
||||
del copy_mesh
|
||||
|
||||
'''if prop == "ContourShapes":
|
||||
contour_shape = obj.getPropertyByName(prop)
|
||||
|
||||
if contour_shape.SubShapes:
|
||||
major_shape = contour_shape.SubShapes[0]
|
||||
points, vertices = self.wire_view(major_shape, origin.Origin)
|
||||
|
||||
self.major_coords.point.values = points
|
||||
self.major_lines.numVertices.values = vertices
|
||||
|
||||
minor_shape = contour_shape.SubShapes[1]
|
||||
points, vertices = self.wire_view(minor_shape, origin.Origin)
|
||||
|
||||
self.minor_coords.point.values = points
|
||||
self.minor_lines.numVertices.values = vertices
|
||||
|
||||
if prop == "BoundaryShapes":
|
||||
boundary_shape = obj.getPropertyByName(prop)
|
||||
points, vertices = self.wire_view(boundary_shape, origin.Origin, True)
|
||||
|
||||
self.boundary_coords.point.values = points
|
||||
self.boundary_lines.numVertices.values = vertices
|
||||
|
||||
if prop == "AnalysisType" or prop == "Ranges":
|
||||
analysis_type = obj.getPropertyByName("AnalysisType")
|
||||
ranges = obj.getPropertyByName("Ranges")
|
||||
|
||||
if analysis_type == "Default":
|
||||
if hasattr(obj.ViewObject, "ShapeMaterial"):
|
||||
material = obj.ViewObject.ShapeMaterial
|
||||
self.face_material.diffuseColor = material.DiffuseColor[:3]
|
||||
|
||||
if analysis_type == "Elevation":
|
||||
colorlist = self.elevation_analysis(obj.Mesh, ranges)
|
||||
self.face_material.diffuseColor.setValues(0, len(colorlist), colorlist)
|
||||
|
||||
elif analysis_type == "Slope":
|
||||
colorlist = self.slope_analysis(obj.Mesh, ranges)
|
||||
self.face_material.diffuseColor.setValues(0, len(colorlist), colorlist)
|
||||
'''
|
||||
def getIcon(self):
|
||||
""" Return the path to the appropriate icon. """
|
||||
return str(os.path.join(DirIcons, "solar-fixed.svg"))
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
'''
|
||||
Return a list of display modes.
|
||||
'''
|
||||
modes = ["Surface", "Boundary", "Flat Lines", "Shaded", "Wireframe"]
|
||||
|
||||
return modes
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
'''
|
||||
Return the name of the default display mode.
|
||||
'''
|
||||
|
||||
return "Surface"
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
'''
|
||||
Map the display mode defined in attach with
|
||||
those defined in getDisplayModes.
|
||||
'''
|
||||
return mode
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Save variables to file.
|
||||
"""
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Get variables from file.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
class _EarthWorksTaskPanel:
|
||||
def __init__(self):
|
||||
self.To = None
|
||||
|
||||
# self.form:
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(PVPlantResources.__dir__, "PVPlantEarthworks.ui"))
|
||||
self.form.setWindowIcon(QtGui.QIcon(os.path.join(PVPlantResources.DirIcons, "convert.svg")))
|
||||
|
||||
def accept(self):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
import MeshPart as mp
|
||||
land = FreeCAD.ActiveDocument.Terrain.Mesh.copy()
|
||||
frames = []
|
||||
for obj in FreeCADGui.Selection.getSelection():
|
||||
if hasattr(obj, "Proxy"):
|
||||
if obj.Proxy.Type == "Tracker":
|
||||
if not (obj in frames):
|
||||
frames.append(obj)
|
||||
elif obj.Proxy.Type == "FrameArea":
|
||||
for fr in obj.Frames:
|
||||
if not (fr in frames):
|
||||
frames.append(fr)
|
||||
if len(frames) == 0:
|
||||
return False
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction("Calcular movimiento de tierras")
|
||||
def calculateEarthWorks(line, extreme=False):
|
||||
pts = []
|
||||
pts1 = []
|
||||
line1 = line.copy()
|
||||
angles = line.Placement.Rotation.toEulerAngles("XYZ")
|
||||
line1.Placement.Rotation.setEulerAngles("XYZ", 0, 0, angles[2])
|
||||
line1.Placement.Base.z = 0
|
||||
pro = mp.projectShapeOnMesh(line1, land, FreeCAD.Vector(0, 0, 1))
|
||||
flat = []
|
||||
for points in pro:
|
||||
flat.extend(points)
|
||||
pro = Part.makePolygon(flat)
|
||||
points = pro.discretize(Distance=500)
|
||||
|
||||
for point in points:
|
||||
ver = Part.Vertex(point)
|
||||
dist = ver.distToShape(line)
|
||||
linepoint = dist[1][0][1]
|
||||
|
||||
if not extreme:
|
||||
if self.form.groupTolerances.isChecked():
|
||||
if linepoint.z > point.z:
|
||||
if linepoint.sub(point).Length > self.form.editToleranceCut.value():
|
||||
pts.append(linepoint)
|
||||
elif linepoint.z < point.z:
|
||||
if linepoint.sub(point).Length > self.form.editToleranceFill.value():
|
||||
pts1.append(linepoint)
|
||||
else:
|
||||
if linepoint.z > point.z:
|
||||
pts.append(linepoint)
|
||||
elif linepoint.z < point.z:
|
||||
pts1.append(linepoint)
|
||||
#pts.append(linepoint)
|
||||
else:
|
||||
if linepoint.z > point.z:
|
||||
if linepoint.sub(point).Length > 200:
|
||||
pts.append(linepoint)
|
||||
|
||||
return pts, pts1
|
||||
|
||||
tools = [[],[]]
|
||||
ver = 2
|
||||
if ver == 0:
|
||||
frames = sorted(frames, key=lambda x: (x.Placement.Base.x, x.Placement.Base.y))
|
||||
for frame in frames:
|
||||
length = frame.Setup.Length.Value / 2
|
||||
p1 = FreeCAD.Vector(-length, 0, 0)
|
||||
p2 = FreeCAD.Vector(length, 0, 0)
|
||||
line = Part.LineSegment(p1, p2).toShape()
|
||||
line.Placement = frame.Placement.copy()
|
||||
line.Placement.Base.x = frame.Shape.BoundBox.XMin
|
||||
step = (frame.Shape.BoundBox.XMax - frame.Shape.BoundBox.XMin) / 2
|
||||
for n in range(3):
|
||||
ret = calculateEarthWorks(line, n % 2)
|
||||
tools[0].extend(ret[0])
|
||||
tools[1].extend(ret[1])
|
||||
line.Placement.Base.x += step
|
||||
elif ver == 1:
|
||||
from PVPlantPlacement import getCols
|
||||
columns = getCols(frames)
|
||||
|
||||
'''colelements = set()
|
||||
rowelements = set()
|
||||
for groups in columns:
|
||||
for group in groups:
|
||||
for frame in group:
|
||||
colelements.add(frame.Placement.Base.x)
|
||||
rowelements.add(frame.Placement.Base.y)
|
||||
colelements = sorted(colelements)
|
||||
rowelements = sorted(rowelements, reverse=True)
|
||||
print("Cols: ", len(colelements), " - ", colelements)
|
||||
print("Rows: ", len(rowelements), " - ", rowelements)
|
||||
|
||||
a = []
|
||||
colnum = len(colelements)
|
||||
for r in range(len(rowelements)):
|
||||
a.append([None] * colnum)
|
||||
mat = np.array(a, dtype=object)
|
||||
for groups in columns:
|
||||
for group in groups:
|
||||
for frame in group:
|
||||
colidx = colelements.index(frame.Placement.Base.x)
|
||||
rowidx = rowelements.index(frame.Placement.Base.y)
|
||||
mat[rowidx][colidx] = frame
|
||||
print(mat)
|
||||
return'''
|
||||
|
||||
for groups in columns:
|
||||
for group in groups:
|
||||
first = group[0]
|
||||
last = group[-1]
|
||||
for frame in group:
|
||||
length = frame.Setup.Length.Value / 2
|
||||
p1 = FreeCAD.Vector(-(length + (self.form.editOffset.value() if frame == first else -1000)),
|
||||
0, 0)
|
||||
p2 = FreeCAD.Vector(length + (self.form.editOffset.value() if frame == last else -1000),
|
||||
0, 0)
|
||||
line = Part.LineSegment(p1, p2).toShape()
|
||||
line.Placement = frame.Placement.copy()
|
||||
line.Placement.Base.x = frame.Shape.BoundBox.XMin
|
||||
step = (frame.Shape.BoundBox.XMax - frame.Shape.BoundBox.XMin) / 2
|
||||
for n in range(3):
|
||||
ret = calculateEarthWorks(line, n % 2 == 1)
|
||||
tools[0].extend(ret[0])
|
||||
tools[1].extend(ret[1])
|
||||
line.Placement.Base.x += step
|
||||
elif ver == 2:
|
||||
print("versión 2")
|
||||
import PVPlantPlacement
|
||||
rows, columns = PVPlantPlacement.getRows(frames)
|
||||
if (rows is None) or (columns is None):
|
||||
print("Nada que procesar")
|
||||
return False
|
||||
tools = []
|
||||
lofts = []
|
||||
for group in rows:
|
||||
lines = []
|
||||
cont = 0
|
||||
while cont < len(group):
|
||||
aw = 0
|
||||
if cont > 0:
|
||||
p0 = FreeCAD.Vector(group[cont - 1].Placement.Base)
|
||||
p1 = FreeCAD.Vector(group[cont].Placement.Base)
|
||||
aw = getAngle(p0, p1)
|
||||
|
||||
ae = 0
|
||||
if cont < (len(group) - 1):
|
||||
p1 = FreeCAD.Vector(group[cont].Placement.Base)
|
||||
p2 = FreeCAD.Vector(group[cont + 1].Placement.Base)
|
||||
ae = getAngle(p1, p2)
|
||||
|
||||
lng = int(group[cont].Setup.Length / 2)
|
||||
wdt = int(group[cont].Setup.Width / 2)
|
||||
line = Part.LineSegment(FreeCAD.Vector(-lng, 0, 0),
|
||||
FreeCAD.Vector(lng, 0, 0)).toShape()
|
||||
|
||||
line = Part.LineSegment(FreeCAD.Vector(group[cont].Setup.Shape.SubShapes[1].SubShapes[0].SubShapes[0].Placement.Base.x, 0, 0),
|
||||
FreeCAD.Vector(group[cont].Setup.Shape.SubShapes[1].SubShapes[0].SubShapes[-1].Placement.Base.x, 0, 0)).toShape()
|
||||
|
||||
anf = (aw + ae) / 2
|
||||
if anf > FreeCAD.ActiveDocument.MaximumWestEastSlope.Value:
|
||||
anf = FreeCAD.ActiveDocument.MaximumWestEastSlope.Value
|
||||
zz = wdt * math.sin(math.radians(anf))
|
||||
|
||||
li = line.copy()
|
||||
li.Placement = group[cont].Placement
|
||||
li.Placement.Rotation = group[cont].Placement.Rotation
|
||||
li.Placement.Base.x -= wdt #+ (3000 if cont == 0 else 0))
|
||||
li.Placement.Base.z -= zz
|
||||
lines.append(li)
|
||||
|
||||
ld = line.copy()
|
||||
ld.Placement = group[cont].Placement
|
||||
ld.Placement.Rotation = group[cont].Placement.Rotation
|
||||
ld.Placement.Base.x += wdt #+ (3000 if cont == len(group) - 1 else 0))
|
||||
ld.Placement.Base.z += zz
|
||||
lines.append(ld)
|
||||
tools.append([group[cont], li, ld])
|
||||
cont += 1
|
||||
loft = Part.makeLoft(lines, False, True, False)
|
||||
lofts.append(loft)
|
||||
|
||||
for group in rows:
|
||||
lines = []
|
||||
for frame in group:
|
||||
col, idx = searchFrameInColumns(frame, columns)
|
||||
tool = searchTool(frame, tools)
|
||||
if idx == 0:
|
||||
''' '''
|
||||
|
||||
if idx == (len(col) - 1):
|
||||
''' '''
|
||||
|
||||
if (idx + 1) < len(col):
|
||||
frame1 = col[idx + 1]
|
||||
tool1 = searchTool(frame1, tools)
|
||||
line = Part.LineSegment(tool[1].Vertexes[1].Point, tool1[1].Vertexes[0].Point).toShape()
|
||||
lines.append(line)
|
||||
line = Part.LineSegment(tool[2].Vertexes[1].Point, tool1[2].Vertexes[0].Point).toShape()
|
||||
lines.append(line)
|
||||
|
||||
if len(lines) > 0:
|
||||
loft = Part.makeLoft(lines, False, True, False)
|
||||
lofts.append(loft)
|
||||
|
||||
faces = []
|
||||
for loft in lofts:
|
||||
faces.extend(loft.Faces)
|
||||
sh = Part.makeShell(faces)
|
||||
import Utils.PVPlantUtils as utils
|
||||
import Mesh
|
||||
pro = utils.getProjected(sh)
|
||||
pro = utils.simplifyWire(pro)
|
||||
#pro = pro.makeOffset2D(20000, 2, False, False, True)
|
||||
Part.show(sh, "loft")
|
||||
Part.show(pro, "pro")
|
||||
pts = [ver.Point for ver in pro.Vertexes]
|
||||
'''if pts[0] != pts[-1]:
|
||||
pts.append(pts[0])'''
|
||||
land.trim(pts, 1)
|
||||
tmp = []
|
||||
for face in sh.Faces:
|
||||
wire = face.Wires[0].copy()
|
||||
pl = wire.Placement.Base
|
||||
wire.Placement.Base = wire.Placement.Base - pl
|
||||
wire = wire.scale(2)
|
||||
wire.Placement.Base = wire.Placement.Base + pl
|
||||
#wire = wire.makeOffset2D(10000, 0, False, False, True)
|
||||
wire.Placement.Base.z = wire.Placement.Base.z - 10000
|
||||
face1 = Part.makeLoft([face.Wires[0], wire], True, True, False)
|
||||
|
||||
|
||||
Part.show(face1, "tool")
|
||||
#tmp.append(face.extrude(FreeCAD.Vector(0, 0, -10000)))
|
||||
#Part.show(tmp[-1], "face-extrude")
|
||||
sh = sh.extrude(FreeCAD.Vector(0, 0, -10000))
|
||||
sh = Part.Solid(sh)
|
||||
Part.show(sh)
|
||||
import MeshPart as mp
|
||||
msh = mp.meshFromShape(Shape=sh) # , MaxLength=1)
|
||||
# msh = msh.smooth("Laplace", 3)
|
||||
Mesh.show(msh, "tool")
|
||||
Mesh.show(land, "trim")
|
||||
'''inner = msh.inner(land)
|
||||
Mesh.show(inner)
|
||||
outer = msh.inner(land)
|
||||
Mesh.show(outer)'''
|
||||
'''intersec = land.section(msh, MinDist=0.01)
|
||||
import Draft
|
||||
for sec in intersec:
|
||||
Draft.makeWire(sec)'''
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
import MeshTools.Triangulation as TriangulateMesh
|
||||
import MeshTools.MeshGetBoundary as mgb
|
||||
import Mesh
|
||||
|
||||
for ind, points in enumerate(tools):
|
||||
mesh = TriangulateMesh.Triangulate(points, MaxlengthLE=3000, MaxAngleLE=math.radians(100))
|
||||
if mesh:
|
||||
for mesh in mesh.getSeparateComponents():
|
||||
boundary = mgb.get_boundary(mesh)
|
||||
Part.show(boundary)
|
||||
'''if self.form.editOffset.value() != 0:
|
||||
import Utils.PVPlantUtils as utils
|
||||
pro = utils.getProjected(boundary)
|
||||
pro = pro.makeOffset2D(self.form.editOffset.value(), 0, False, False, True)
|
||||
# TODO: paso intermedio de restar las areas prohibidas
|
||||
pro = mp.projectShapeOnMesh(pro, land, FreeCAD.Vector(0, 0, 1))
|
||||
cnt = 0
|
||||
for lp in pro:
|
||||
cnt += len(lp)
|
||||
# points.extend(boundary.Wires[0].discretize(Number=cnt))
|
||||
points = boundary.Wires[0].discretize(Distance=cnt)
|
||||
for lp in pro:
|
||||
points.extend(lp)
|
||||
mesh1 = TriangulateMesh.Triangulate(points, MaxlengthLE=5000) # , MaxAngleLE=math.pi / 1.334)
|
||||
import Mesh
|
||||
Mesh.show(mesh1)
|
||||
boundary = Part.makeCompound([])
|
||||
for section in pro:
|
||||
if len(section) > 0:
|
||||
try:
|
||||
boundary.add(Part.makePolygon(section))
|
||||
except:
|
||||
pass
|
||||
Part.show(boundary)'''
|
||||
#mesh.smooth("Laplace", 3)
|
||||
#Mesh.show(mesh)
|
||||
#Part.show(boundary)
|
||||
vol = makeEarthWorksVolume(ind)
|
||||
vol.VolumeMesh = mesh.copy()
|
||||
if ind == 0:
|
||||
''' put inside fills group '''
|
||||
else:
|
||||
''' put inside fills group '''
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def closeForm(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
|
||||
def getAngle(vec1, vec2):
|
||||
dX = vec2.x - vec1.x
|
||||
dZ = vec2.z - vec1.z
|
||||
return math.degrees(math.atan2(float(dZ), float(dX)))
|
||||
|
||||
|
||||
def searchFrameInColumns(obj, columns):
|
||||
for colidx, col in enumerate(columns):
|
||||
for group in col:
|
||||
if obj in group:
|
||||
return group, group.index(obj) #groupidx
|
||||
|
||||
|
||||
def searchTool(obj, tools):
|
||||
for tool in tools:
|
||||
if obj in tool:
|
||||
return tool
|
||||
|
||||
|
||||
class _CommandCalculateEarthworks:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "pico.svg")),
|
||||
'Accel': "C, E",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "Movimiento de tierras"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Calcular el movimiento de tierras")}
|
||||
|
||||
def Activated(self):
|
||||
TaskPanel = _EarthWorksTaskPanel()
|
||||
FreeCADGui.Control.showDialog(TaskPanel)
|
||||
|
||||
def IsActive(self):
|
||||
active = not (FreeCAD.ActiveDocument is None)
|
||||
if not (FreeCAD.ActiveDocument.getObject("Terrain") is None):
|
||||
active = active and not (FreeCAD.ActiveDocument.getObject("Terrain").Mesh is None)
|
||||
return active
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantEarthworks', _CommandCalculateEarthworks())
|
||||
|
||||
|
||||
def accept():
|
||||
import MeshPart as mp
|
||||
land = FreeCAD.ActiveDocument.Terrain.Mesh
|
||||
frames = []
|
||||
for obj in FreeCADGui.Selection.getSelection():
|
||||
if hasattr(obj, "Proxy"):
|
||||
if obj.Proxy.Type == "Tracker":
|
||||
if not (obj in frames):
|
||||
frames.append(obj)
|
||||
elif obj.Proxy.Type == "FrameArea":
|
||||
for fr in obj.Frames:
|
||||
if not (fr in frames):
|
||||
frames.append(fr)
|
||||
if len(frames) == 0:
|
||||
return False
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction("Calcular movimiento de tierras")
|
||||
import PVPlantPlacement
|
||||
rows, columns = PVPlantPlacement.getRows(frames)
|
||||
if (rows is None) or (columns is None):
|
||||
print("Nada que procesar")
|
||||
return False
|
||||
tools = []
|
||||
|
||||
for group in rows:
|
||||
lines = []
|
||||
cont = 0
|
||||
while cont < len(group):
|
||||
aw = 0
|
||||
if cont > 0:
|
||||
p0 = FreeCAD.Vector(group[cont - 1].Placement.Base)
|
||||
p1 = FreeCAD.Vector(group[cont].Placement.Base)
|
||||
aw = getAngle(p0, p1)
|
||||
|
||||
ae = 0
|
||||
if cont < (len(group) - 1):
|
||||
p1 = FreeCAD.Vector(group[cont].Placement.Base)
|
||||
p2 = FreeCAD.Vector(group[cont + 1].Placement.Base)
|
||||
ae = getAngle(p1, p2)
|
||||
|
||||
lng = int(group[cont].Setup.Length / 2)
|
||||
wdt = int(group[cont].Setup.Width / 2)
|
||||
line = Part.LineSegment(FreeCAD.Vector(-lng, 0, 0),
|
||||
FreeCAD.Vector(lng, 0, 0)).toShape()
|
||||
|
||||
line = Part.LineSegment(FreeCAD.Vector(group[cont].Setup.Shape.SubShapes[1].SubShapes[0].SubShapes[0].Placement.Base.x, 0, 0),
|
||||
FreeCAD.Vector(group[cont].Setup.Shape.SubShapes[1].SubShapes[0].SubShapes[-1].Placement.Base.x, 0, 0)).toShape()
|
||||
|
||||
anf = (aw + ae) / 2
|
||||
if anf > FreeCAD.ActiveDocument.MaximumWestEastSlope.Value:
|
||||
anf = FreeCAD.ActiveDocument.MaximumWestEastSlope.Value
|
||||
zz = wdt * math.sin(math.radians(anf))
|
||||
|
||||
li = line.copy()
|
||||
li.Placement = group[cont].Placement
|
||||
li.Placement.Rotation = group[cont].Placement.Rotation
|
||||
li.Placement.Base.x -= wdt #+ (3000 if cont == 0 else 0))
|
||||
li.Placement.Base.z -= zz
|
||||
lines.append(li)
|
||||
|
||||
ld = line.copy()
|
||||
ld.Placement = group[cont].Placement
|
||||
ld.Placement.Rotation = group[cont].Placement.Rotation
|
||||
ld.Placement.Base.x += wdt #+ (3000 if cont == len(group) - 1 else 0))
|
||||
ld.Placement.Base.z += zz
|
||||
lines.append(ld)
|
||||
tools.append([group[cont], li, ld])
|
||||
cont += 1
|
||||
|
||||
loft = Part.makeLoft(lines, False, True, False)
|
||||
import MeshPart as mp
|
||||
msh = mp.meshFromShape(Shape=loft) #, MaxLength=1)
|
||||
#msh = msh.smooth("Laplace", 3)
|
||||
import Mesh
|
||||
Mesh.show(msh)
|
||||
'''intersec = land.section(msh, MinDist=0.01)
|
||||
import Draft
|
||||
for sec in intersec:
|
||||
Draft.makeWire(sec)'''
|
||||
|
||||
for group in rows:
|
||||
lines = []
|
||||
for frame in group:
|
||||
col, idx = searchFrameInColumns(frame, columns)
|
||||
tool = searchTool(frame, tools)
|
||||
if idx == 0:
|
||||
''' '''
|
||||
if idx == (len(col) - 1):
|
||||
''' '''
|
||||
|
||||
if (idx + 1) < len(col):
|
||||
frame1 = col[idx + 1]
|
||||
tool1 = searchTool(frame1, tools)
|
||||
line = Part.LineSegment(tool[1].Vertexes[1].Point, tool1[1].Vertexes[0].Point).toShape()
|
||||
Part.show(line)
|
||||
lines.append(line)
|
||||
line = Part.LineSegment(tool[2].Vertexes[1].Point, tool1[2].Vertexes[0].Point).toShape()
|
||||
Part.show(line)
|
||||
lines.append(line)
|
||||
|
||||
|
||||
if len(lines) > 0:
|
||||
loft = Part.makeLoft(lines, False, True, False)
|
||||
import MeshPart as mp
|
||||
msh = mp.meshFromShape(Shape=loft) # , MaxLength=1)
|
||||
#msh = msh.smooth("Laplace", 3)
|
||||
import Mesh
|
||||
Mesh.show(msh)
|
||||
intersec = land.section(msh, MinDist=0.01)
|
||||
import Draft
|
||||
for sec in intersec:
|
||||
Draft.makeWire(sec)
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
self.closeForm()
|
||||
return True
|
||||
180
PVPlantEarthworks.ui
Normal file
180
PVPlantEarthworks.ui
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>291</width>
|
||||
<height>141</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Calculate Earthworks for frames</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupTolerances">
|
||||
<property name="title">
|
||||
<string>Use tolerances</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Tolerancia para el corte:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="editToleranceFill">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> mm</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>200</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Tolerancia para el relleno:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="editToleranceCut">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> mm</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>200</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Distancia offset:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="editOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> mm</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
895
PVPlantFence.py
Normal file
895
PVPlantFence.py
Normal file
@@ -0,0 +1,895 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 copy
|
||||
import math
|
||||
|
||||
import ArchComponent
|
||||
import Draft
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
import PVPlantFencePost
|
||||
import PVPlantSite
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import PySide.QtGui as QtGui
|
||||
from pivy import coin
|
||||
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
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
EAST = FreeCAD.Vector(1, 0, 0)
|
||||
|
||||
def makeprojection(pathwire):
|
||||
site = FreeCAD.ActiveDocument.Site
|
||||
land = site.Terrain.Shape
|
||||
proj = land.makeParallelProjection(pathwire, FreeCAD.Vector(0, 0, 1))
|
||||
return proj
|
||||
|
||||
def makePVPlantFence(section, post, path):
|
||||
obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Fence')
|
||||
|
||||
_Fence(obj)
|
||||
obj.Post = post
|
||||
obj.Base = path
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderFence(obj.ViewObject)
|
||||
|
||||
hide(section)
|
||||
hide(post)
|
||||
hide(path)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
|
||||
def hide(obj):
|
||||
if hasattr(obj, 'ViewObject') and obj.ViewObject:
|
||||
obj.ViewObject.Visibility = False
|
||||
|
||||
def getAngle(Line1, Line2):
|
||||
v1 = Line1.Vertexes[1].Point - Line1.Vertexes[0].Point
|
||||
v2 = Line2.Vertexes[1].Point - Line2.Vertexes[0].Point
|
||||
return v1.getAngle(v2)
|
||||
|
||||
|
||||
def get_parameter_from_v0(edge, offset):
|
||||
"""Return parameter at distance offset from edge.Vertexes[0].
|
||||
sb method in Part.TopoShapeEdge???
|
||||
"""
|
||||
import DraftVecUtils
|
||||
|
||||
lpt = edge.valueAt(edge.getParameterByLength(0))
|
||||
vpt = edge.Vertexes[0].Point
|
||||
|
||||
if not DraftVecUtils.equals(vpt, lpt):
|
||||
# this edge is flipped
|
||||
length = edge.Length - offset
|
||||
else:
|
||||
# this edge is right way around
|
||||
length = offset
|
||||
return edge.getParameterByLength(length)
|
||||
|
||||
|
||||
def calculatePlacement(globalRotation, edge, offset, RefPt, xlate, align, normal=None):
|
||||
"""Orient shape to tangent at parm offset along edge."""
|
||||
import functools
|
||||
import DraftVecUtils
|
||||
# http://en.wikipedia.org/wiki/Euler_angles
|
||||
# start with null Placement point so translate goes to right place.
|
||||
|
||||
placement = FreeCAD.Placement()
|
||||
placement.Rotation = globalRotation
|
||||
placement.move(RefPt + xlate)
|
||||
|
||||
if not align:
|
||||
return placement
|
||||
|
||||
# unit +Z Probably defined elsewhere?
|
||||
z = FreeCAD.Vector(0, 0, 1)
|
||||
# y = FreeCAD.Vector(0, 1, 0) # unit +Y
|
||||
x = FreeCAD.Vector(1, 0, 0) # unit +X
|
||||
nullv = FreeCAD.Vector(0, 0, 0)
|
||||
|
||||
# get local coord system - tangent, normal, binormal, if possible
|
||||
t = edge.tangentAt(get_parameter_from_v0(edge, offset))
|
||||
t.normalize()
|
||||
n = normal
|
||||
b = t.cross(n)
|
||||
b.normalize()
|
||||
|
||||
lnodes = z.cross(b)
|
||||
try:
|
||||
# Can't normalize null vector.
|
||||
lnodes.normalize()
|
||||
except:
|
||||
# pathological cases:
|
||||
pass
|
||||
|
||||
print(b, " - ", b.dot(z))
|
||||
if abs(b.dot(z)) == 1.0: # 2) binormal is || z
|
||||
# align shape to tangent only
|
||||
psi = math.degrees(DraftVecUtils.angle(x, t, z))
|
||||
theta = 0.0
|
||||
phi = 0.0
|
||||
FreeCAD.Console.PrintWarning("Draft PathArray.orientShape - Gimbal lock. Infinite lnodes. Change Path or Base.\n")
|
||||
else: # regular case
|
||||
psi = math.degrees(DraftVecUtils.angle(x, lnodes, z))
|
||||
theta = math.degrees(DraftVecUtils.angle(z, b, lnodes))
|
||||
phi = math.degrees(DraftVecUtils.angle(lnodes, t, b))
|
||||
|
||||
rotations = [placement.Rotation]
|
||||
|
||||
if psi != 0.0:
|
||||
rotations.insert(0, FreeCAD.Rotation(z, psi))
|
||||
if theta != 0.0:
|
||||
rotations.insert(0, FreeCAD.Rotation(lnodes, theta))
|
||||
if phi != 0.0:
|
||||
rotations.insert(0, FreeCAD.Rotation(b, phi))
|
||||
|
||||
if len(rotations) == 1:
|
||||
finalRotation = rotations[0]
|
||||
else:
|
||||
finalRotation = functools.reduce(lambda rot1, rot2: rot1.multiply(rot2), rotations)
|
||||
|
||||
placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), finalRotation.toEuler()[2])
|
||||
|
||||
return placement
|
||||
|
||||
def calculatePlacementsOnPath(shapeRotation, pathwire, count, xlate, align):
|
||||
""" Calculates the placements of a shape along a given path so that each copy will be distributed evenly
|
||||
- shapeRotation: rotation offset
|
||||
- pathwire: path where place the shapes
|
||||
- count: number of sections
|
||||
- xlate: transformation offset
|
||||
"""
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
|
||||
closedpath = DraftGeomUtils.isReallyClosed(pathwire)
|
||||
normal = DraftGeomUtils.getNormal(pathwire)
|
||||
if normal:
|
||||
if normal.z < 0: # asegurarse de que siempre se dibuje por encima del suelo
|
||||
normal.z *= -1
|
||||
else:
|
||||
normal = FreeCAD.Vector(0, 0, 1)
|
||||
path = Part.__sortEdges__(pathwire.Edges)
|
||||
ends = []
|
||||
cdist = 0
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
totalEdges = len(path)
|
||||
if not closedpath:
|
||||
totalEdges -= 1
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
for e in path: # find cumulative edge end distance
|
||||
cdist += e.Length
|
||||
ends.append(cdist)
|
||||
|
||||
placements = []
|
||||
# place the start shape
|
||||
pt = path[0].Vertexes[0].Point
|
||||
placements.append(calculatePlacement(shapeRotation, path[0], 0, pt, xlate, align, normal))
|
||||
|
||||
# closed path doesn't need shape on last vertex
|
||||
if not closedpath:
|
||||
# place the end shape
|
||||
pt = path[-1].Vertexes[-1].Point
|
||||
placements.append(calculatePlacement(shapeRotation, path[-1], path[-1].Length, pt, xlate, align, normal))
|
||||
|
||||
if count < 3:
|
||||
return placements
|
||||
|
||||
# place the middle shapes
|
||||
if closedpath:
|
||||
stop = count
|
||||
else:
|
||||
stop = count - 1
|
||||
step = float(cdist) / stop
|
||||
travel = step
|
||||
for i in range(1, stop):
|
||||
# which edge in path should contain this shape?
|
||||
# avoids problems with float math travel > ends[-1]
|
||||
iend = len(ends) - 1
|
||||
for j in range(0, len(ends)):
|
||||
if travel <= ends[j]:
|
||||
iend = j
|
||||
break
|
||||
# place shape at proper spot on proper edge
|
||||
remains = ends[iend] - travel
|
||||
offset = path[iend].Length - remains
|
||||
pt = path[iend].valueAt(get_parameter_from_v0(path[iend], offset))
|
||||
placements.append(calculatePlacement(shapeRotation, path[iend], offset, pt, xlate, align, normal))
|
||||
travel += step
|
||||
|
||||
return placements
|
||||
|
||||
class _Fence(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
self.Posts = []
|
||||
self.Foundations = []
|
||||
|
||||
# Does a IfcType exist?
|
||||
# obj.IfcType = "Fence"
|
||||
|
||||
def setProperties(self, obj):
|
||||
ArchComponent.Component.setProperties(self, obj)
|
||||
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not "Gate" in pl:
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"Gate",
|
||||
"Fence",
|
||||
"A single fence post")
|
||||
|
||||
if not "Post" in pl:
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Post",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post"))
|
||||
|
||||
if not "Foundation" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Foundation",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post"))
|
||||
|
||||
if not "Depth" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Depth",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Depth = 650
|
||||
|
||||
if not "Gap" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Gap",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Gap = 4000
|
||||
|
||||
if not "Angle" in pl:
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"Angle",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Angle = 60
|
||||
|
||||
if not "MeshOffsetZ" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"MeshOffsetZ",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).MeshOffsetZ = 0
|
||||
|
||||
if not "MeshHeight" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"MeshHeight",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).MeshHeight = 2000
|
||||
|
||||
if not "Reinforce" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Reinforce",
|
||||
"Fence",
|
||||
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Reinforce = 50000
|
||||
|
||||
|
||||
########## Datos informativos:
|
||||
if not "NumberOfSections" in pl:
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"NumberOfSections",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The number of sections the fence is built of"))
|
||||
obj.setEditorMode("NumberOfSections", 1)
|
||||
|
||||
if not "NumberOfPosts" in pl:
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"NumberOfPosts",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The number of posts used to build the fence"))
|
||||
obj.setEditorMode("NumberOfPosts", 1)
|
||||
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The number of posts used to build the fence"))
|
||||
obj.setEditorMode("Length", 1)
|
||||
|
||||
if not "Concrete" in pl:
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"Concrete",
|
||||
"Output",
|
||||
"Concrete Volume")
|
||||
obj.setEditorMode("Concrete", 1)
|
||||
|
||||
if not "PlacementList" in pl:
|
||||
obj.addProperty("App::PropertyPlacementList",
|
||||
"PlacementList",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The number of posts used to build the fence"))
|
||||
obj.setEditorMode("Length", 1)
|
||||
|
||||
|
||||
self.Type = "PVPlatFence"
|
||||
|
||||
def __getstate__(self):
|
||||
if hasattr(self, 'sectionFaceNumbers'):
|
||||
return (self.sectionFaceNumbers)
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
if state is not None and isinstance(state, tuple):
|
||||
self.sectionFaceNumbers = state[0]
|
||||
return None
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
pathwire = self.calculatePathWire(obj)
|
||||
if pathwire is None:
|
||||
# FreeCAD.Console.PrintLog("ArchFence.execute: path " + obj.Base.Name + " has no edges\n")
|
||||
return
|
||||
|
||||
if not obj.Post:
|
||||
FreeCAD.Console.PrintLog("ArchFence.execute: Post not set\n")
|
||||
return
|
||||
|
||||
self.Posts = []
|
||||
self.Foundations = []
|
||||
site = PVPlantSite.get()
|
||||
if True: # prueba
|
||||
import MeshPart as mp
|
||||
land = FreeCAD.ActiveDocument.Terrain.Mesh
|
||||
segments = mp.projectShapeOnMesh(pathwire, land, FreeCAD.Vector(0, 0, 1))
|
||||
points=[]
|
||||
for segment in segments:
|
||||
points.extend(segment)
|
||||
pathwire = Part.makePolygon(points)
|
||||
else:
|
||||
if PVPlantSite.get().Terrain.TypeId == 'Mesh::Feature':
|
||||
import MeshPart as mp
|
||||
land = PVPlantSite.get().Terrain.Mesh
|
||||
pathwire = mp.projectShapeOnMesh(pathwire, land, FreeCAD.Vector(0, 0, 1))
|
||||
|
||||
else:
|
||||
land = site.Terrain.Shape
|
||||
pathwire = land.makeParallelProjection(pathwire, FreeCAD.Vector(0, 0, 1))
|
||||
|
||||
if pathwire is None:
|
||||
return
|
||||
|
||||
''' no sirve:
|
||||
if len(pathwire.Wires) > 1:
|
||||
import draftgeoutils
|
||||
pathwire = draftgeoutils.wires.superWire(pathwire.Edges, True)
|
||||
Part.show(pathwire)
|
||||
'''
|
||||
|
||||
''' unir todas en una '''
|
||||
'''
|
||||
if len(pathwire.Wires) > 1:
|
||||
import Utils.PVPlantUtils as utils
|
||||
wires = pathwire.Wires
|
||||
new_wire = []
|
||||
to_compare = utils.getPoints(wires.pop(0))
|
||||
new_wire.extend(to_compare)
|
||||
while len(wires)>0:
|
||||
wire = wires[0]
|
||||
points = utils.getPoints(wire)
|
||||
to_remove = None
|
||||
if points[0] in to_compare:
|
||||
to_remove = points[0]
|
||||
if points[-1] in to_compare:
|
||||
to_remove = points[-1]
|
||||
if to_remove:
|
||||
to_compare = points.copy()
|
||||
points.remove(to_remove)
|
||||
new_wire.extend(points)
|
||||
wires.pop()
|
||||
continue
|
||||
wires.append(wires.pop())
|
||||
pathwire = Part.makePolygon(new_wire)
|
||||
#Part.show(pathwire)
|
||||
#return
|
||||
'''
|
||||
|
||||
sectionLength = obj.Gap.Value
|
||||
postLength = 0 #obj.Post.Diameter.Value #considerarlo 0 porque no influye
|
||||
postPlacements = []
|
||||
pathsegments = self.calculateSegments(obj, pathwire)
|
||||
|
||||
count = 0
|
||||
drawFirstPost = True
|
||||
pathLength = 0
|
||||
for segment in pathsegments:
|
||||
segwire = Part.Wire(Part.__sortEdges__(segment))
|
||||
pathLength += segwire.Length
|
||||
|
||||
obj.NumberOfSections = self.calculateNumberOfSections(segwire.Length, sectionLength, postLength)
|
||||
obj.NumberOfPosts = obj.NumberOfSections + 1
|
||||
|
||||
count += obj.NumberOfSections
|
||||
|
||||
downRotation = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), -90)
|
||||
placements = self.calculatePostPlacements(obj, segwire, downRotation)
|
||||
|
||||
if drawFirstPost:
|
||||
drawFirstPost = False
|
||||
else:
|
||||
placements.pop(0)
|
||||
|
||||
postPlacements.extend(placements)
|
||||
|
||||
postShapes, postFoundation = self.calculatePosts(obj, postPlacements)
|
||||
sections, num = self.calculateSections(obj, postPlacements)
|
||||
|
||||
postShapes = Part.makeCompound(postShapes)
|
||||
postFoundation = Part.makeCompound(postFoundation)
|
||||
sections = Part.makeCompound(sections)
|
||||
compound = Part.makeCompound([postShapes, postFoundation, sections])
|
||||
obj.Shape = compound
|
||||
|
||||
# Give information
|
||||
obj.NumberOfSections = count
|
||||
obj.NumberOfPosts = obj.NumberOfSections + 1
|
||||
obj.Length = pathLength
|
||||
obj.Concrete = count * postFoundation.SubShapes[0].Volume
|
||||
|
||||
def calculateSegments(self, obj, pathwire):
|
||||
''' Calcular los segmentos de la ruta '''
|
||||
import math
|
||||
segments = []
|
||||
segment = [pathwire.Edges[0]]
|
||||
segments.append(segment)
|
||||
for ind in range(len(pathwire.Edges) - 1):
|
||||
ed1 = pathwire.Edges[ind]
|
||||
ed2 = pathwire.Edges[ind + 1]
|
||||
vec1 = ed1.Vertexes[1].Point - ed1.Vertexes[0].Point
|
||||
vec2 = ed2.Vertexes[1].Point - ed2.Vertexes[0].Point
|
||||
angle = math.degrees(vec1.getAngle(vec2))
|
||||
if angle > obj.Angle.Value:
|
||||
segment = []
|
||||
segments.append(segment)
|
||||
segment.append(ed2)
|
||||
return segments
|
||||
|
||||
def calculateNumberOfSections(self, pathLength, sectionLength, postLength):
|
||||
withoutLastPost = pathLength - postLength
|
||||
realSectionLength = sectionLength + postLength
|
||||
return math.ceil(withoutLastPost / realSectionLength)
|
||||
|
||||
def calculatePostPlacements(self, obj, pathwire, rotation):
|
||||
postWidth = obj.Post.Diameter.Value
|
||||
transformationVector = FreeCAD.Vector(0, postWidth / 2, 0)
|
||||
placements = calculatePlacementsOnPath(rotation, pathwire, int(obj.NumberOfSections) + 1, transformationVector, True)
|
||||
# The placement of the last object is always the second entry in the list.
|
||||
# So we move it to the end:
|
||||
if len(placements) > 1:
|
||||
placements.append(placements.pop(1))
|
||||
return placements
|
||||
|
||||
def calculatePosts(self, obj, postPlacements):
|
||||
posts = []
|
||||
foundations = []
|
||||
for placement in postPlacements:
|
||||
postCopy = obj.Post.Shape.copy()
|
||||
postCopy = Part.Solid(postCopy)
|
||||
postCopy.Placement = placement
|
||||
postCopy.Placement.Base.z += 100
|
||||
posts.append(postCopy)
|
||||
|
||||
foundation = Part.makeCylinder(150, 700)
|
||||
foundation.Placement = placement
|
||||
foundation.Placement.Base.z -= obj.Depth.Value
|
||||
foundation = foundation.cut(postCopy)
|
||||
foundations.append(foundation)
|
||||
|
||||
return posts, foundations
|
||||
|
||||
def calculateSections(self, obj, postPlacements):
|
||||
shapes = []
|
||||
faceNumbers = []
|
||||
|
||||
offsetz = obj.MeshOffsetZ.Value
|
||||
meshHeight = obj.MeshHeight.Value
|
||||
for i in range(len(postPlacements) - 1):
|
||||
startPlacement = postPlacements[i]
|
||||
endPlacement = postPlacements[i + 1]
|
||||
|
||||
p1 = startPlacement.Base + FreeCAD.Vector(0, 0, offsetz)
|
||||
p2 = endPlacement.Base + FreeCAD.Vector(0, 0, offsetz)
|
||||
p3 = p2 + FreeCAD.Vector(0, 0, meshHeight)
|
||||
p4 = p1 + FreeCAD.Vector(0, 0, meshHeight)
|
||||
pointlist = [p1, p2, p3, p4, p1]
|
||||
|
||||
try:
|
||||
pol = Part.makePolygon(pointlist)
|
||||
face = Part.Face(pol)
|
||||
shapes.append(face)
|
||||
faceNumbers.append(1)
|
||||
except:
|
||||
print("No es posible crear la cara: ---------------------------------------------------")
|
||||
print(" +++++ Start: ", startPlacement.Base, " - end: ", endPlacement.Base)
|
||||
print(" +++++ algo: ", pointlist, "\n")
|
||||
print("---------------------------------------------------\n")
|
||||
return (shapes, faceNumbers)
|
||||
|
||||
def calculatePathWire(self, obj):
|
||||
if obj.Base:
|
||||
wire = None
|
||||
if hasattr(obj.Base.Shape, 'Wires') and obj.Base.Shape.Wires:
|
||||
wire = obj.Base.Shape.Wires[0]
|
||||
elif obj.Base.Shape.Edges:
|
||||
wire = Part.Wire(obj.Base.Shape.Edges)
|
||||
return wire
|
||||
return None
|
||||
|
||||
|
||||
class _ViewProviderFence(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Fence object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
vobj.Proxy = self
|
||||
#vobj.addExtension("Gui::ViewProviderGroupExtensionPython")
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(DirIcons, "fence.svg"))
|
||||
|
||||
def attach(self, vobj):
|
||||
'''
|
||||
Create Object visuals in 3D view.
|
||||
'''
|
||||
|
||||
self.Object = vobj.Object
|
||||
|
||||
# GeoCoords Node.
|
||||
self.geo_coords = coin.SoGeoCoordinate()
|
||||
|
||||
# Surface features.
|
||||
self.triangles = coin.SoIndexedFaceSet()
|
||||
self.face_material = coin.SoMaterial()
|
||||
self.edge_material = coin.SoMaterial()
|
||||
self.edge_color = coin.SoBaseColor()
|
||||
self.edge_style = coin.SoDrawStyle()
|
||||
self.edge_style.style = coin.SoDrawStyle.LINES
|
||||
|
||||
shape_hints = coin.SoShapeHints()
|
||||
shape_hints.vertex_ordering = coin.SoShapeHints.COUNTERCLOCKWISE
|
||||
mat_binding = coin.SoMaterialBinding()
|
||||
mat_binding.value = coin.SoMaterialBinding.PER_FACE
|
||||
offset = coin.SoPolygonOffset()
|
||||
|
||||
# Face root.
|
||||
faces = coin.SoSeparator()
|
||||
faces.addChild(shape_hints)
|
||||
faces.addChild(self.face_material)
|
||||
faces.addChild(mat_binding)
|
||||
faces.addChild(self.geo_coords)
|
||||
faces.addChild(self.triangles)
|
||||
|
||||
# Highlight for selection.
|
||||
highlight = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
highlight.style = 'EMISSIVE_DIFFUSE'
|
||||
faces.addChild(shape_hints)
|
||||
highlight.addChild(self.edge_material)
|
||||
highlight.addChild(mat_binding)
|
||||
highlight.addChild(self.edge_style)
|
||||
highlight.addChild(self.geo_coords)
|
||||
highlight.addChild(self.triangles)
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
'''
|
||||
Update Object visuals when a data property changed.
|
||||
'''
|
||||
origin = PVPlantSite.get()
|
||||
base = copy.deepcopy(origin.Origin)
|
||||
base.z = 0
|
||||
#print(" - Propiedad: ", prop)
|
||||
if prop == "Shape":
|
||||
shape = obj.getPropertyByName(prop)
|
||||
# Get GeoOrigin.
|
||||
points = [ver.Point for ver in shape.Vertexes]
|
||||
# Set GeoCoords.
|
||||
geo_system = ["UTM", origin.UtmZone, "FLAT"]
|
||||
self.geo_coords.geoSystem.setValues(geo_system)
|
||||
self.geo_coords.point.values = points
|
||||
|
||||
def claimChildren(self):
|
||||
children = []
|
||||
if self.Object.Post:
|
||||
children.append(self.Object.Post)
|
||||
if self.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
if self.Object.Gate:
|
||||
children.append(self.Object.Gate)
|
||||
return children
|
||||
|
||||
class _FenceTaskPanel:
|
||||
'''The TaskPanel to setup the fence'''
|
||||
|
||||
def __init__(self):
|
||||
self.section = None
|
||||
self.post = None
|
||||
self.path = None
|
||||
|
||||
# form: -----------------------------------------------------------------------------------
|
||||
self.formFence = QtGui.QWidget()
|
||||
self.formFence.resize(800, 640)
|
||||
self.formFence.setWindowTitle("Fence setup")
|
||||
self.formFence.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
|
||||
self.grid = QtGui.QGridLayout(self.formFence)
|
||||
|
||||
# parameters
|
||||
self.labelPath = QtGui.QLabel()
|
||||
self.labelPath.setText("Recorrido:")
|
||||
self.linePath = QtGui.QLineEdit(self.formFence)
|
||||
self.linePath.setObjectName(_fromUtf8("lineEdit1"))
|
||||
self.linePath.readOnly = True
|
||||
self.grid.addWidget(self.labelPath, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.linePath, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.buttonPathSelect = QtGui.QPushButton('Add')
|
||||
self.grid.addWidget(self.buttonPathSelect, self.grid.rowCount() - 1, 2, 1, 1)
|
||||
|
||||
self.line1 = QtGui.QFrame()
|
||||
self.line1.setFrameShape(QtGui.QFrame.HLine)
|
||||
self.line1.setFrameShadow(QtGui.QFrame.Sunken)
|
||||
self.grid.addWidget(self.line1, self.grid.rowCount(), 0, 1, -1)
|
||||
|
||||
self.label = QtGui.QLabel()
|
||||
self.label.setText("Separación entre apoyos:")
|
||||
self.grid.addWidget(self.label, self.grid.rowCount(), 0, 1, -1)
|
||||
|
||||
self.labelInterval = QtGui.QLabel()
|
||||
self.labelInterval.setText("Intervalo:")
|
||||
self.valueInterval = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueInterval.setText("4,0 m")
|
||||
self.grid.addWidget(self.labelInterval, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueInterval, self.grid.rowCount() - 1, 1, 1, 2)
|
||||
|
||||
self.line1 = QtGui.QFrame()
|
||||
self.line1.setFrameShape(QtGui.QFrame.HLine)
|
||||
self.line1.setFrameShadow(QtGui.QFrame.Sunken)
|
||||
self.grid.addWidget(self.line1, self.grid.rowCount(), 0, 1, -1)
|
||||
|
||||
self.label = QtGui.QLabel()
|
||||
self.label.setText("Mayado:")
|
||||
self.grid.addWidget(self.label, self.grid.rowCount(), 0, 1, -1)
|
||||
|
||||
self.labelHeight = QtGui.QLabel()
|
||||
self.labelHeight.setText("Altura:")
|
||||
self.valueHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueHeight.setText("2 m")
|
||||
self.grid.addWidget(self.labelHeight, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueHeight, self.grid.rowCount() - 1, 1, 1, 2)
|
||||
|
||||
self.labelOffset = QtGui.QLabel()
|
||||
self.labelOffset.setText("Separación del suelo:")
|
||||
self.valueOffset = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueOffset.setText("0 m")
|
||||
self.grid.addWidget(self.labelOffset, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueOffset, self.grid.rowCount() - 1, 1, 1, 2)
|
||||
|
||||
self.buttonPathSelect.clicked.connect(self.addPath)
|
||||
self.valueInterval.valueChanged.connect(self.SetupGrid)
|
||||
self.valueHeight.valueChanged.connect(self.SetupGrid)
|
||||
# self.valueDepth.valueChanged.connect(self.SetupPost)
|
||||
|
||||
# Form para configurar el poste: -------------------------------------------------------------------
|
||||
self.formPost = QtGui.QWidget()
|
||||
self.formPost.resize(800, 640)
|
||||
self.formPost.setWindowTitle("Post setup")
|
||||
self.formPost.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
|
||||
self.grid = QtGui.QGridLayout(self.formPost)
|
||||
|
||||
# parameters
|
||||
self.labelDiameter = QtGui.QLabel()
|
||||
self.labelDiameter.setText("Diámetro:")
|
||||
self.valueDiameter = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueDiameter.setText("48 mm")
|
||||
self.grid.addWidget(self.labelDiameter, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueDiameter, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.labelLength = QtGui.QLabel()
|
||||
self.labelLength.setText("Longitud:")
|
||||
self.valueLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueLength.setText("3,0 m")
|
||||
self.grid.addWidget(self.labelLength, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueLength, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.labelDepth = QtGui.QLabel()
|
||||
self.labelDepth.setText("Profundidad:")
|
||||
self.valueDepth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueDepth.setText("700,0 mm")
|
||||
self.grid.addWidget(self.labelDepth, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueDepth, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.valueDiameter.valueChanged.connect(self.SetupPost)
|
||||
self.valueLength.valueChanged.connect(self.SetupPost)
|
||||
self.valueDepth.valueChanged.connect(self.SetupPost)
|
||||
|
||||
# Form para configurar la zapata: ----------------------------------------------------------
|
||||
self.formFoundation = QtGui.QWidget()
|
||||
self.formFoundation.resize(800, 640)
|
||||
self.formFoundation.setWindowTitle("Post setup")
|
||||
self.formFoundation.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
|
||||
self.grid = QtGui.QGridLayout(self.formFoundation)
|
||||
|
||||
# parameters
|
||||
self.labelFoundationDiameter = QtGui.QLabel()
|
||||
self.labelFoundationDiameter.setText("Cimentación:")
|
||||
self.grid.addWidget(self.labelFoundationDiameter, self.grid.rowCount(), 0, 1, 1)
|
||||
|
||||
self.labelFoundationDiameter = QtGui.QLabel()
|
||||
self.labelFoundationDiameter.setText("Diámetro:")
|
||||
self.valueFoundationDiameter = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueFoundationDiameter.setText("200,0 mm")
|
||||
self.grid.addWidget(self.labelFoundationDiameter, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueFoundationDiameter, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.labelFoundationDepth = QtGui.QLabel()
|
||||
self.labelFoundationDepth.setText("Profundidad:")
|
||||
self.valueFoundationDepth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.valueFoundationDepth.setText("700,0 mm")
|
||||
self.grid.addWidget(self.labelFoundationDepth, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.valueFoundationDepth, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.form = [self.formFence, self.formPost, self.formFoundation]
|
||||
|
||||
# valores iniciales y creación del la valla:
|
||||
import Draft
|
||||
self.post = PVPlantFencePost.makeFencePost() # Arch.makePipe()
|
||||
self.post.Label = "Post"
|
||||
Draft.autogroup(self.post)
|
||||
|
||||
'''
|
||||
self.section = self.makeGrid()
|
||||
self.path = self.section.Base
|
||||
'''
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
self.fence = makePVPlantFence(self.section, self.post, self.path)
|
||||
|
||||
def addPath(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.path = sel[0]
|
||||
self.linePath.setText(self.path.Label)
|
||||
self.fence.Base = self.path
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def SetupPost(self):
|
||||
if self.post.Diameter != FreeCAD.Units.Quantity(self.valueDiameter.text()).Value:
|
||||
self.post.Diameter = FreeCAD.Units.Quantity(self.valueDiameter.text()).Value
|
||||
if self.post.Length != FreeCAD.Units.Quantity(self.valueLength.text()).Value:
|
||||
self.post.Length = FreeCAD.Units.Quantity(self.valueLength.text()).Value
|
||||
|
||||
if self.post.Placement.Base.z != -FreeCAD.Units.Quantity(self.valueDepth.text()).Value:
|
||||
self.post.Placement.Base.z = -FreeCAD.Units.Quantity(self.valueDepth.text()).Value
|
||||
self.fence.Depth = FreeCAD.Units.Quantity(self.valueDepth.text()).Value
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def SetupGrid(self):
|
||||
return
|
||||
if self.path.End.x != FreeCAD.Units.Quantity(self.valueInterval.text()).Value:
|
||||
self.path.End.x = FreeCAD.Units.Quantity(self.valueInterval.text()).Value
|
||||
if self.section.LengthFwd != FreeCAD.Units.Quantity(self.valueHeight.text()).Value:
|
||||
self.section.LengthFwd = FreeCAD.Units.Quantity(self.valueHeight.text()).Value
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def makeGrid(self):
|
||||
return None
|
||||
|
||||
import Draft
|
||||
|
||||
p1 = FreeCAD.Vector(0, 0, 0)
|
||||
p2 = FreeCAD.Vector(4000, 0, 0)
|
||||
line = Draft.makeLine(p1, p2)
|
||||
|
||||
section = FreeCAD.ActiveDocument.addObject('Part::Extrusion', 'Extrude')
|
||||
section.Base = line
|
||||
section.DirMode = "Custom"
|
||||
section.Dir = FreeCAD.Vector(0.0, 0.0, 1.0)
|
||||
section.DirLink = None
|
||||
section.LengthFwd = 2000.0
|
||||
section.LengthRev = 0.0
|
||||
section.Solid = False
|
||||
section.Reversed = False
|
||||
section.Symmetric = False
|
||||
section.TaperAngle = 0.0
|
||||
section.TaperAngleRev = 0.0
|
||||
line.Visibility = False
|
||||
|
||||
return section
|
||||
|
||||
|
||||
# Commands ---------------------------------------------------------------------------------
|
||||
class _CommandPVPlantFence:
|
||||
"the PVPlant Fence command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "fence.svg")),
|
||||
'Accel': "C, F",
|
||||
'MenuText': QT_TRANSLATE_NOOP("PVPlantFence", "Fence"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("PVPlantFence",
|
||||
"Creates a fence object from a selected section, post and path")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _FenceTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandFenceGroup:
|
||||
def GetCommands(self):
|
||||
return tuple(['PVPlantFence',
|
||||
'PVPlantGate',
|
||||
'PVPlantFencePost'
|
||||
])
|
||||
|
||||
def GetResources(self):
|
||||
return {'MenuText': QT_TRANSLATE_NOOP("", 'PVPlantFence'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("", 'PVPlantFence')
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return (not (FreeCAD.ActiveDocument is None) and
|
||||
not (FreeCAD.ActiveDocument.getObject("Site") is None) and
|
||||
not (FreeCAD.ActiveDocument.getObject("Terrain") is None))
|
||||
|
||||
import PVPlantFenceGate
|
||||
FreeCADGui.addCommand('PVPlantFence', _CommandPVPlantFence())
|
||||
FreeCADGui.addCommand('PVPlantGate', PVPlantFenceGate._CommandPVPlantGate())
|
||||
FreeCADGui.addCommand('PVPlantFencePost', PVPlantFencePost._CommandFencePost())
|
||||
FreeCADGui.addCommand('PVPlantFenceGroup', CommandFenceGroup())
|
||||
|
||||
def movep(obj):
|
||||
pl = obj.Shape.BoundBox.Center
|
||||
points = []
|
||||
for ind in range(len(obj.Shape.Vertexes)):
|
||||
points.append(obj.Shape.Vertexes[ind].Point - pl)
|
||||
Draft.makeWire(points)
|
||||
768
PVPlantFence.ui
Normal file
768
PVPlantFence.ui
Normal file
@@ -0,0 +1,768 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>476</width>
|
||||
<height>641</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Configuración de la valla</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.960000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Separación entre apoyos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Recorrido:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Configuración del poste</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Columnas (un)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editFrontHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.800000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Orientación del módulo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editVerticalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="editRows">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboFrameType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fija</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Tracker 1 Eje</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editLeftOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Offset borde derecha (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Ángulo de inclinación (º)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editRightOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QSpinBox" name="editTilt">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QSpinBox" name="editInclination">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Filas (un)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Distancia al suelo en el frente (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="editCols">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap">
|
||||
<property name="text">
|
||||
<string>Separación vertical entre módulos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboModuleOrientation">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Landscape</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Portrait</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Separación horizontal entre módulos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Ängulo máximo de inclinación longitudinal (ª)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editHorizontalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tipo de estructura</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Offset borde izquierda (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widgetTracker" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap_2">
|
||||
<property name="text">
|
||||
<string>Separación entre uniones (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Separación Motor (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="editInternalGapNumber">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Número de uniones</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editInternalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editMotorGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Cimentación</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Total de módulos</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="editTotalModules">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Potencia total (wp)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editTotalPower">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Longitud (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="editTotalLength">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="editTotalWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
425
PVPlantFenceGate.py
Normal file
425
PVPlantFenceGate.py
Normal file
@@ -0,0 +1,425 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 ArchComponent
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui, QtSvg
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import PySide.QtGui as QtGui
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
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
|
||||
|
||||
import os
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
def makePVPlantFence():
|
||||
obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'FenceGate')
|
||||
FenceGate(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
ViewProviderGate(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
|
||||
class FenceGate(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("GateType" in pl):
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"GateType",
|
||||
"Gate",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The facemaker type to use to build the profile of this object")
|
||||
).GateType = ["Single", "Double"]
|
||||
|
||||
if not ("GateWidth" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"GateWidth",
|
||||
"Gate",
|
||||
"Base wire"
|
||||
).GateWidth = 3000
|
||||
|
||||
if not ("GateHeight" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"GateHeight",
|
||||
"Gate",
|
||||
"Base wire"
|
||||
).GateHeight = 2000
|
||||
|
||||
if not ("PostWidth" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"PostWidth",
|
||||
"Gate",
|
||||
"Base wire"
|
||||
).PostWidth = 60
|
||||
|
||||
if not ("PostHeight" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"PostHeight",
|
||||
"Gate",
|
||||
"Base wire"
|
||||
).PostHeight = 2000
|
||||
|
||||
if not "PostDepth" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"PostDepth",
|
||||
"Fence",
|
||||
"A single fence post").PostDepth = 700
|
||||
|
||||
self.Type = "PVPlatFenceGate"
|
||||
#obj.Type = self.Type
|
||||
obj.Proxy = self
|
||||
self.obj = obj
|
||||
|
||||
def __getstate__(self):
|
||||
if hasattr(self, 'sectionFaceNumbers'):
|
||||
return (self.sectionFaceNumbers)
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
if state is not None and isinstance(state, tuple):
|
||||
self.sectionFaceNumbers = state[0]
|
||||
return None
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored."""
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
def execute(self, obj):
|
||||
tubewidth = 50
|
||||
gap = 20
|
||||
posts = Part.makeCompound([])
|
||||
gates = Part.makeCompound([])
|
||||
pl = obj.Placement
|
||||
|
||||
post = Part.makeBox(obj.PostWidth.Value,
|
||||
obj.PostWidth.Value,
|
||||
obj.PostHeight.Value + obj.PostDepth.Value)
|
||||
|
||||
gate = Part.makeBox(obj.GateWidth.Value,
|
||||
tubewidth,
|
||||
obj.GateHeight.Value)
|
||||
|
||||
cut = Part.makeBox(obj.GateWidth.Value - tubewidth * 2,
|
||||
tubewidth,
|
||||
obj.GateHeight.Value - tubewidth * 2)
|
||||
cut.Placement.Base += FreeCAD.Vector(tubewidth, 0, tubewidth)
|
||||
gate = gate.cut(cut)
|
||||
|
||||
if obj.GateType == "Single":
|
||||
post.Placement.Base = FreeCAD.Vector(-(obj.PostWidth.Value + gap + obj.GateWidth.Value / 2),
|
||||
-obj.PostWidth.Value / 2,
|
||||
-obj.PostDepth.Value)
|
||||
posts.add(post)
|
||||
post = post.copy()
|
||||
post.Placement.Base.x = -(post.Placement.Base.x + obj.PostWidth.Value)
|
||||
posts.add(post)
|
||||
gate.Placement.Base += FreeCAD.Vector(-obj.GateWidth.Value / 2,
|
||||
obj.PostWidth.Value / 2 - tubewidth,
|
||||
0)
|
||||
gates.add(gate)
|
||||
else:
|
||||
post.Placement.Base = FreeCAD.Vector(-(obj.PostWidth.Value + gap * 1.5 + obj.GateWidth.Value),
|
||||
-obj.PostWidth.Value / 2,
|
||||
-obj.PostDepth.Value)
|
||||
posts.add(post)
|
||||
post = post.copy()
|
||||
post.Placement.Base.x = -(post.Placement.Base.x + obj.PostWidth.Value)
|
||||
posts.add(post)
|
||||
|
||||
gate.Placement.Base += FreeCAD.Vector(-(obj.GateWidth.Value + gap * 0.5),
|
||||
obj.PostWidth.Value / 2 - tubewidth,
|
||||
0)
|
||||
gates.add(gate)
|
||||
gate = gate.copy()
|
||||
gate.Placement.Base.x = gap * 0.5
|
||||
gates.add(gate)
|
||||
|
||||
obj.Shape = Part.makeCompound([gates, posts])
|
||||
obj.Placement = pl
|
||||
|
||||
|
||||
class ViewProviderGate:
|
||||
def __init__(self, vobj):
|
||||
''' Set view properties. '''
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon. '''
|
||||
return str(os.path.join(DirIcons, "gate.svg"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
return children
|
||||
|
||||
class _CommandPVPlantGate:
|
||||
"the PVPlant Fence command definition"
|
||||
|
||||
def __init__(self):
|
||||
''' p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
|
||||
self.Thickness = p.GetFloat("WindowThickness", 50)
|
||||
self.Width = p.GetFloat("WindowWidth", 1000)
|
||||
self.Height = p.GetFloat("DoorHeight", 2100)'''
|
||||
|
||||
self.Width = 0
|
||||
self.Height = 0
|
||||
self.Length = 0
|
||||
self.tracker = None
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "gate.svg")),
|
||||
'Accel': "C, F",
|
||||
'MenuText': QT_TRANSLATE_NOOP("PVPlantFence", "Gate"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("PVPlantFence",
|
||||
"Creates a fence object from a selected section, post and path")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.tracker = DraftTrackers.boxTracker()
|
||||
self.tracker.length(self.Length)
|
||||
self.tracker.width(self.Width)
|
||||
self.tracker.height(self.Height)
|
||||
self.tracker.on()
|
||||
FreeCAD.Console.PrintMessage("Choose a face on an existing object or select a preset" + "\n")
|
||||
FreeCADGui.Snapper.getPoint(callback=self.getPoint,
|
||||
movecallback=self.update,
|
||||
extradlg=self.taskbox())
|
||||
|
||||
def getPoint(self, point=None, obj=None):
|
||||
"this function is called by the snapper when it has a 3D point"
|
||||
|
||||
if obj.Name[:5] == "Fence":
|
||||
self.tracker.finalize()
|
||||
if point is None:
|
||||
return
|
||||
ver = Part.Vertex(point)
|
||||
dist = ver.distToShape(obj.Base.Shape)
|
||||
point1 = dist[1][0][1]
|
||||
ed = None
|
||||
if dist[2][0][3] == "Edge":
|
||||
ed = obj.Base.Shape.Edges[int(dist[-1][0][4])]
|
||||
vec = ed.Vertexes[1].Point.sub(ed.Vertexes[0].Point)
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Gate")
|
||||
gate = makePVPlantFence()
|
||||
try:
|
||||
import MeshPart as mp
|
||||
point1 = mp.projectPointsOnMesh([point1,], FreeCAD.ActiveDocument.Terrain.Mesh, FreeCAD.Vector(0, 0, 1))[0]
|
||||
|
||||
except:
|
||||
FreeCAD.Console.PrintError("No se puede encontrar punto 3D.." + "\n")
|
||||
pass
|
||||
|
||||
gate.Placement.Base = point1
|
||||
gate.Placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(-1, 0, 0), vec)
|
||||
tmp = obj.Gate
|
||||
tmp.append(gate)
|
||||
obj.Gate = tmp
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return
|
||||
else:
|
||||
FreeCADGui.Snapper.getPoint(callback=self.getPoint,
|
||||
movecallback=self.update,
|
||||
extradlg=self.taskbox())
|
||||
def update(self, point, info):
|
||||
''' this function is called by the Snapper when the mouse is moved '''
|
||||
|
||||
delta = FreeCAD.Vector(self.Length / 2, self.Width / 2, self.Height / 2)
|
||||
rot = FreeCAD.Rotation()
|
||||
|
||||
#self.tracker.setRotation(rot)
|
||||
self.tracker.pos(point)
|
||||
return
|
||||
|
||||
delta = FreeCAD.Vector(self.Length / 2, self.Width / 2, self.Height / 2)
|
||||
delta = delta.add(FreeCAD.Vector(0, 0, self.Sill))
|
||||
rot = FreeCAD.Rotation()
|
||||
if info:
|
||||
if "Face" in info['Component']:
|
||||
import WorkingPlane
|
||||
o = FreeCAD.ActiveDocument.getObject(info['Object'])
|
||||
self.baseFace = [o, int(info['Component'][4:]) - 1]
|
||||
# print("switching to ",o.Label," face ",self.baseFace[1])
|
||||
f = o.Shape.Faces[self.baseFace[1]]
|
||||
p = WorkingPlane.getPlacementFromFace(f, rotated=True)
|
||||
if p:
|
||||
rot = p.Rotation
|
||||
self.tracker.setRotation(rot)
|
||||
r = self.tracker.trans.rotation.getValue().getValue()
|
||||
if r != (0, 0, 0, 1):
|
||||
delta = FreeCAD.Rotation(r[0], r[1], r[2], r[3]).multVec(FreeCAD.Vector(delta.x, -delta.y, -delta.z))
|
||||
self.tracker.pos(point.add(delta))
|
||||
|
||||
def taskbox(self):
|
||||
"sets up a taskbox widget"
|
||||
|
||||
w = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantFenceGate.ui")
|
||||
self.Width = 80
|
||||
self.Height = 2000
|
||||
self.Length = 6146
|
||||
return w
|
||||
|
||||
w = QtGui.QWidget()
|
||||
ui = FreeCADGui.UiLoader()
|
||||
|
||||
w.setWindowTitle("Window options")
|
||||
grid = QtGui.QGridLayout(w)
|
||||
|
||||
# include box
|
||||
include = QtGui.QCheckBox(translate("Arch","Auto include in host object"))
|
||||
include.setChecked(True)
|
||||
grid.addWidget(include,0,0,1,2)
|
||||
QtCore.QObject.connect(include,QtCore.SIGNAL("stateChanged(int)"),self.setInclude)
|
||||
|
||||
# sill height
|
||||
labels = QtGui.QLabel(translate("Arch","Sill height"))
|
||||
values = ui.createWidget("Gui::InputField")
|
||||
grid.addWidget(labels,1,0,1,1)
|
||||
grid.addWidget(values,1,1,1,1)
|
||||
QtCore.QObject.connect(values,QtCore.SIGNAL("valueChanged(double)"),self.setSill)
|
||||
|
||||
# check for Parts library and Arch presets
|
||||
|
||||
# because of the use of FreeCADGui.doCommand() backslashes in the
|
||||
# paths in librarypresets need to be double escaped "\\\\", so let's
|
||||
# use forward slashes instead...
|
||||
self.librarypresets = []
|
||||
librarypath = FreeCAD.ParamGet("User parameter:Plugins/parts_library").GetString("destination", "")
|
||||
# librarypath should have only forward slashes already, but let's use replace() anyway just to be sure:
|
||||
librarypath = librarypath.replace("\\", "/") + "/Architectural Parts"
|
||||
presetdir = FreeCAD.getUserAppDataDir().replace("\\", "/") + "/Arch"
|
||||
for path in [librarypath, presetdir]:
|
||||
if os.path.isdir(path):
|
||||
for wtype in ["Windows", "Doors"]:
|
||||
wdir = path + "/" + wtype
|
||||
if os.path.isdir(wdir):
|
||||
for subtype in os.listdir(wdir):
|
||||
subdir = wdir + "/" + subtype
|
||||
if os.path.isdir(subdir):
|
||||
for subfile in os.listdir(subdir):
|
||||
if (os.path.isfile(subdir + "/" + subfile)
|
||||
and subfile.lower().endswith(".fcstd")):
|
||||
self.librarypresets.append([wtype + " - " + subtype + " - " + subfile[:-6],
|
||||
subdir + "/" + subfile])
|
||||
|
||||
# presets box
|
||||
labelp = QtGui.QLabel(translate("Arch","Preset"))
|
||||
valuep = QtGui.QComboBox()
|
||||
valuep.setMinimumContentsLength(6)
|
||||
valuep.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
valuep.addItems(WindowPresets)
|
||||
valuep.setCurrentIndex(self.Preset)
|
||||
grid.addWidget(labelp,2,0,1,1)
|
||||
grid.addWidget(valuep,2,1,1,1)
|
||||
QtCore.QObject.connect(valuep,QtCore.SIGNAL("currentIndexChanged(int)"),self.setPreset)
|
||||
for it in self.librarypresets:
|
||||
valuep.addItem(it[0])
|
||||
|
||||
# image display
|
||||
self.pic = QtGui.QLabel()
|
||||
grid.addWidget(self.pic,3,0,1,2)
|
||||
self.pic.setFixedHeight(128)
|
||||
self.pic.hide()
|
||||
|
||||
# SVG display
|
||||
self.im = QtSvg.QSvgWidget(":/ui/ParametersWindowFixed.svg")
|
||||
self.im.setMaximumWidth(200)
|
||||
self.im.setMinimumHeight(120)
|
||||
grid.addWidget(self.im,4,0,1,2)
|
||||
#self.im.hide()
|
||||
|
||||
# parameters
|
||||
i = 5
|
||||
for param in self.wparams:
|
||||
lab = QtGui.QLabel(translate("Arch",param))
|
||||
setattr(self,"val"+param,ui.createWidget("Gui::InputField"))
|
||||
wid = getattr(self,"val"+param)
|
||||
if param == "Width":
|
||||
wid.setText(FreeCAD.Units.Quantity(self.Width,FreeCAD.Units.Length).UserString)
|
||||
elif param == "Height":
|
||||
wid.setText(FreeCAD.Units.Quantity(self.Height,FreeCAD.Units.Length).UserString)
|
||||
elif param == "O1":
|
||||
n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowO1",0.0)
|
||||
wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
|
||||
setattr(self,param,n)
|
||||
elif param == "W1":
|
||||
n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowW1",self.Thickness*2)
|
||||
wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
|
||||
setattr(self,param,n)
|
||||
else:
|
||||
n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("Window"+param,self.Thickness)
|
||||
wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
|
||||
setattr(self,param,n)
|
||||
grid.addWidget(lab,i,0,1,1)
|
||||
grid.addWidget(wid,i,1,1,1)
|
||||
i += 1
|
||||
valueChanged = self.getValueChanged(param)
|
||||
FreeCAD.wid = wid
|
||||
QtCore.QObject.connect(getattr(self,"val"+param),QtCore.SIGNAL("valueChanged(double)"), valueChanged)
|
||||
|
||||
# restore saved states
|
||||
if self.doormode:
|
||||
i = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("DoorPreset",0)
|
||||
d = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("DoorSill",0)
|
||||
else:
|
||||
i = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("WindowPreset",0)
|
||||
d = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowSill",0)
|
||||
if i < valuep.count():
|
||||
valuep.setCurrentIndex(i)
|
||||
values.setText(FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).UserString)
|
||||
|
||||
return w
|
||||
352
PVPlantFenceGate.ui
Normal file
352
PVPlantFenceGate.ui
Normal file
@@ -0,0 +1,352 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formGate</class>
|
||||
<widget class="QWidget" name="formGate">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>317</width>
|
||||
<height>289</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Puerta:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Puerta</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tipo de puerta</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editGateHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap">
|
||||
<property name="text">
|
||||
<string>Ancho (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editGateWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.850000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Alto (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboFrameType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Simple</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Doble</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Poste</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="3" column="2">
|
||||
<widget class="QDoubleSpinBox" name="editPostBuried">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>700.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Alto (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Enterramiento (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDoubleSpinBox" name="editPostHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>500.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Ancho (mm)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="editPostWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>80</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Espacio (mm)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="editGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
285
PVPlantFencePost.py
Normal file
285
PVPlantFencePost.py
Normal file
@@ -0,0 +1,285 @@
|
||||
import ArchComponent
|
||||
import FreeCAD
|
||||
|
||||
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
|
||||
|
||||
|
||||
def makeFencePost(diameter=48, length=3000, placement=None, name="Post"):
|
||||
"makePipe([baseobj,diamerter,length,placement,name]): creates an pipe object from the given base object"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
|
||||
obj.Label = name
|
||||
_FencePost(obj)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderFencePost(obj.ViewObject)
|
||||
|
||||
obj.Length = length
|
||||
obj.Diameter = diameter
|
||||
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
return obj
|
||||
|
||||
|
||||
def makeFenceReinforcePost(diameter=48, length=3000, placement=None, name="Post"):
|
||||
"makePipe([baseobj,diamerter,length,placement,name]): creates an pipe object from the given base object"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
|
||||
obj.Label = name
|
||||
_FenceReinforcePostPost(obj)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderFencePost(obj.ViewObject)
|
||||
|
||||
obj.Length = length
|
||||
obj.Diameter = diameter
|
||||
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
return obj
|
||||
|
||||
|
||||
class _FencePost(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
obj.IfcType = "Pipe Segment"
|
||||
self.Type = "FencePost"
|
||||
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Diameter" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Diameter", "Pipe",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The diameter of this pipe, if not based on a profile")
|
||||
).Diameter = 48
|
||||
if not "Thickness" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Thickness", "Pipe",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The Thickness of this pipe, if not based on a profile")
|
||||
).Thickness = 4
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Length", "Pipe",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The length of this pipe, if not based on an edge")
|
||||
).Length = 3000
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self, obj):
|
||||
import Part
|
||||
pl = obj.Placement
|
||||
|
||||
if obj.CloneOf:
|
||||
obj.Shape = obj.CloneOf.Shape
|
||||
else:
|
||||
w = self.getProfile(obj)
|
||||
try:
|
||||
# sh = w.makePipeShell([p], True, False, 2)
|
||||
sh = w.revolve(FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Vector(0.0, 0.0, 1.0), 360)
|
||||
sh = Part.Solid(sh)
|
||||
except:
|
||||
FreeCAD.Console.PrintError("Unable to build the pipe \n")
|
||||
else:
|
||||
obj.Shape = sh
|
||||
obj.Placement = pl
|
||||
|
||||
return
|
||||
|
||||
# ------------------------- Prueba para apoyos de refuerzo:
|
||||
import math
|
||||
L = math.pi / 2 * (obj.Diameter.Value - 2 * obj.Thickness.Value)
|
||||
|
||||
v1 = FreeCAD.Vector(L / 2, 0, obj.Thickness.Value)
|
||||
vc1 = FreeCAD.Vector(L / 2 + obj.Thickness.Value, 0, 0)
|
||||
v2 = FreeCAD.Vector(L / 2, 0, -obj.Thickness.Value)
|
||||
|
||||
v11 = FreeCAD.Vector(-L / 2, 0, obj.Thickness.Value)
|
||||
vc11 = FreeCAD.Vector(-(L / 2 + obj.Thickness.Value), 0, 0)
|
||||
v21 = FreeCAD.Vector(-L / 2, 0, -obj.Thickness.Value)
|
||||
|
||||
arc1 = Part.Arc(v1, vc1, v2).toShape()
|
||||
arc11 = Part.Arc(v11, vc11, v21).toShape()
|
||||
line1 = Part.LineSegment(v11, v1).toShape()
|
||||
line2 = Part.LineSegment(v21, v2).toShape()
|
||||
w = Part.Wire([arc1, line2, arc11, line1])
|
||||
face = Part.Face(w)
|
||||
pro = face.extrude(FreeCAD.Vector(0, 40, 0))
|
||||
|
||||
#Part.Circle(Center, Normal, Radius)
|
||||
cir1 = Part.Face(Part.Wire(Part.Circle(FreeCAD.Vector(0, -200, 0), FreeCAD.Vector(0, 1, 0), obj.Diameter.Value / 2).toShape()))
|
||||
ext = cir1.extrude(FreeCAD.Vector(0, 170, 0))
|
||||
cir2 = Part.Circle(FreeCAD.Vector(0, -30, 0), FreeCAD.Vector(0, 1, 0), obj.Diameter.Value/2).toShape()
|
||||
loft = Part.makeLoft([cir2, w], True)
|
||||
ext = ext.fuse([loft, pro])
|
||||
Part.show(ext)
|
||||
|
||||
|
||||
def getProfile(self, obj):
|
||||
import Part
|
||||
sin45 = 0.707106781
|
||||
radio = obj.Diameter.Value / 2
|
||||
taph = 20
|
||||
tapw = radio + 2
|
||||
chamfer = 5
|
||||
chamfer2 = chamfer * sin45
|
||||
|
||||
edge1 = Part.makeLine(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(radio, 0, 0))
|
||||
edge2 = Part.makeLine(FreeCAD.Vector(radio, 0, 0), FreeCAD.Vector(radio, 0, obj.Length.Value - taph))
|
||||
edge3 = Part.makeLine(FreeCAD.Vector(radio, 0, obj.Length.Value - taph),
|
||||
FreeCAD.Vector(tapw, 0, obj.Length.Value - taph))
|
||||
edge4 = Part.makeLine(FreeCAD.Vector(tapw, 0, obj.Length.Value - taph),
|
||||
FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer))
|
||||
if True:
|
||||
edge5 = Part.makeLine(FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer),
|
||||
FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value))
|
||||
else:
|
||||
edge5 = Part.Arc(FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer),
|
||||
FreeCAD.Vector(tapw - chamfer2, 0, obj.Length.Value - chamfer2),
|
||||
FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value)
|
||||
).toShape()
|
||||
edge6 = Part.makeLine(FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value),
|
||||
FreeCAD.Vector(0, 0, obj.Length.Value))
|
||||
w = Part.Wire([edge1, edge2, edge3, edge4, edge5, edge6])
|
||||
|
||||
return w
|
||||
|
||||
|
||||
class _FenceReinforcePost(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
obj.IfcType = "Pipe Segment"
|
||||
self.Type = "FencePost"
|
||||
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Diameter" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Diameter", "Pipe",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The diameter of this pipe, if not based on a profile")
|
||||
).Diameter = 48
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Length", "Pipe",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The length of this pipe, if not based on an edge")
|
||||
).Length = 3000
|
||||
self.Type = "Pipe"
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
pl = obj.Placement
|
||||
w = self.getWire(obj)
|
||||
|
||||
try:
|
||||
# sh = w.makePipeShell([p], True, False, 2)
|
||||
sh = w.revolve(FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Vector(0.0, 0.0, 1.0), 360)
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Unable to build the pipe") + "\n")
|
||||
else:
|
||||
obj.Shape = sh
|
||||
obj.Placement = pl
|
||||
|
||||
def getWire(self, obj):
|
||||
|
||||
import Part
|
||||
sin45 = 0.707106781
|
||||
radio = obj.Diameter.Value / 2
|
||||
taph = 20
|
||||
tapw = radio + 2
|
||||
chamfer = 5
|
||||
chamfer2 = chamfer * sin45
|
||||
|
||||
edge1 = Part.makeLine(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(radio, 0, 0))
|
||||
edge2 = Part.makeLine(FreeCAD.Vector(radio, 0, 0), FreeCAD.Vector(radio, 0, obj.Length.Value - taph))
|
||||
edge3 = Part.makeLine(FreeCAD.Vector(radio, 0, obj.Length.Value - taph),
|
||||
FreeCAD.Vector(tapw, 0, obj.Length.Value - taph))
|
||||
edge4 = Part.makeLine(FreeCAD.Vector(tapw, 0, obj.Length.Value - taph),
|
||||
FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer))
|
||||
|
||||
if True:
|
||||
edge5 = Part.makeLine(FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer),
|
||||
FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value))
|
||||
else:
|
||||
edge5 = Part.Arc(FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer),
|
||||
FreeCAD.Vector(tapw - chamfer2, 0, obj.Length.Value - chamfer2),
|
||||
FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value)
|
||||
).toShape()
|
||||
edge6 = Part.makeLine(FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value),
|
||||
FreeCAD.Vector(0, 0, obj.Length.Value))
|
||||
w = Part.Wire([edge1, edge2, edge3, edge4, edge5, edge6])
|
||||
|
||||
return w
|
||||
|
||||
|
||||
class _ViewProviderFencePost(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Arch_Pipe_Tree.svg"
|
||||
|
||||
|
||||
class _CommandFencePost:
|
||||
"the Arch Pipe command definition"
|
||||
|
||||
def GetResources(self):
|
||||
|
||||
return {'Pixmap': 'Arch_Pipe',
|
||||
'MenuText': QT_TRANSLATE_NOOP("Arch_Pipe", "Pipe"),
|
||||
'Accel': "P, I",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_Pipe", "Creates a pipe object from a given Wire or Line")}
|
||||
|
||||
def IsActive(self):
|
||||
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
if True:
|
||||
makeFencePost()
|
||||
else:
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch", "Create Pipe"))
|
||||
FreeCADGui.addModule("Arch")
|
||||
FreeCADGui.doCommand("obj = Arch.makePipe()")
|
||||
FreeCADGui.addModule("Draft")
|
||||
FreeCADGui.doCommand("Draft.autogroup(obj)")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('FencePost', _CommandFencePost())
|
||||
877
PVPlantFixed.ui
Normal file
877
PVPlantFixed.ui
Normal file
@@ -0,0 +1,877 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>476</width>
|
||||
<height>1038</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tracker:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Módulos:</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Altura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.990000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Largura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.960000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.030000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Potencia (wp)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="editModulePower">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>150</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>350</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Estructura</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Columnas (un)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editFrontHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.800000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Orientación del módulo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editVerticalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="editRows">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboFrameType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fija</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Tracker 1 Eje</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editLeftOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Offset borde derecha (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Ángulo de inclinación (º)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editRightOffset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QSpinBox" name="editTilt">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QSpinBox" name="editInclination">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Filas (un)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Distancia al suelo en el frente (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="editCols">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap">
|
||||
<property name="text">
|
||||
<string>Separación vertical entre módulos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboModuleOrientation">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Landscape</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Portrait</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Separación horizontal entre módulos (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Ängulo máximo de inclinación longitudinal (ª)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editHorizontalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tipo de estructura</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Offset borde izquierda (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widgetTracker" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelVerticalGap_2">
|
||||
<property name="text">
|
||||
<string>Separación entre uniones (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Separación Motor (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="editInternalGapNumber">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Número de uniones</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editInternalGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editMotorGap">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Resultado</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Total de módulos</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="editTotalModules">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Potencia total (wp)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editTotalPower">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Longitud (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="editTotalLength">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="editTotalWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
225
PVPlantFoundation.py
Normal file
225
PVPlantFoundation.py
Normal file
@@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2016 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * *
|
||||
# * 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 FreeCAD, ArchComponent
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
__title__="FreeCAD Fotovoltaic Power Plant Toolkit"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "sn"
|
||||
|
||||
|
||||
def makeFoundation(baseobj=None, diameter=200, length=700, placement=None, name="Foundation"):
|
||||
"makeFoundation([baseobj,diamerter,length,placement,name]):"
|
||||
"creates an Foundation object from the given base object"
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
|
||||
obj.Label = name
|
||||
_PVPlantFoundation(obj)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderFoundation(obj.ViewObject)
|
||||
if baseobj:
|
||||
baseobj.ViewObject.hide()
|
||||
if baseobj:
|
||||
obj.Base = baseobj
|
||||
else:
|
||||
if length:
|
||||
obj.Length = length
|
||||
else:
|
||||
obj.Length = 1000
|
||||
if diameter:
|
||||
obj.Diameter = diameter
|
||||
else:
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
|
||||
obj.Diameter = p.GetFloat("PipeDiameter", 50)
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
return obj
|
||||
|
||||
|
||||
class _PVPlantFoundation(ArchComponent.Component):
|
||||
"the PVPlant Foundation object"
|
||||
|
||||
def __init__(self, obj):
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.Type = ""
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Diameter" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Diameter", "Foundation", QT_TRANSLATE_NOOP("App::Property",
|
||||
"The diameter of this Foundation, if not based on a profile"))
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength", "Length", "Foundation", QT_TRANSLATE_NOOP("App::Property",
|
||||
"The length of this Foundation, if not based on an edge"))
|
||||
if not "Profile" in pl:
|
||||
obj.addProperty("App::PropertyLink", "Profile", "Foundation",
|
||||
QT_TRANSLATE_NOOP("App::Property", "An optional closed profile to base this Foundation on"))
|
||||
|
||||
self.Type = "Foundation"
|
||||
obj.IfcType = "Element"
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
import DraftGeomUtils, math
|
||||
pl = obj.Placement
|
||||
w = self.getWire(obj)
|
||||
if not w:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Unable to build the base path") + "\n")
|
||||
return
|
||||
|
||||
p = self.getProfile(obj)
|
||||
if not p:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Unable to build the profile") + "\n")
|
||||
return
|
||||
|
||||
# move and rotate the profile to the first point
|
||||
delta = w.Vertexes[0].Point - p.CenterOfMass
|
||||
p.translate(delta)
|
||||
import Draft
|
||||
if Draft.getType(obj.Base) == "BezCurve":
|
||||
v1 = obj.Base.Placement.multVec(obj.Base.Points[1]) - w.Vertexes[0].Point
|
||||
else:
|
||||
v1 = w.Vertexes[1].Point - w.Vertexes[0].Point
|
||||
v2 = DraftGeomUtils.getNormal(p)
|
||||
rot = FreeCAD.Rotation(v2, v1)
|
||||
p.rotate(p.CenterOfMass, rot.Axis, math.degrees(rot.Angle))
|
||||
|
||||
try:
|
||||
sh = w.makePipeShell([p], True, False, 2)
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Unable to build the Foundation -- ") + "\n")
|
||||
else:
|
||||
obj.Shape = sh
|
||||
if obj.Base:
|
||||
obj.Length = w.Length
|
||||
else:
|
||||
obj.Placement = pl
|
||||
|
||||
def getWire(self, obj):
|
||||
|
||||
import Part
|
||||
if obj.Base:
|
||||
if not hasattr(obj.Base, 'Shape'):
|
||||
FreeCAD.Console.PrintError(translate("Arch", "The base object is not a Part") + "\n")
|
||||
return
|
||||
if len(obj.Base.Shape.Wires) != 1:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Too many wires in the base shape") + "\n")
|
||||
return
|
||||
if obj.Base.Shape.Wires[0].isClosed():
|
||||
FreeCAD.Console.PrintError(translate("Arch", "The base wire is closed") + "\n")
|
||||
return
|
||||
w = obj.Base.Shape.Wires[0]
|
||||
else:
|
||||
if obj.Length.Value == 0:
|
||||
return
|
||||
w = Part.Wire([Part.LineSegment(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, obj.Length.Value)).toShape()])
|
||||
return w
|
||||
|
||||
def getProfile(self, obj):
|
||||
|
||||
import Part
|
||||
if obj.Profile:
|
||||
if not obj.Profile.getLinkedObject().isDerivedFrom("Part::Part2DObject"):
|
||||
FreeCAD.Console.PrintError(translate("Arch", "The profile is not a 2D Part") + "\n")
|
||||
return
|
||||
if len(obj.Profile.Shape.Wires) != 1:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Too many wires in the profile") + "\n")
|
||||
return
|
||||
if not obj.Profile.Shape.Wires[0].isClosed():
|
||||
FreeCAD.Console.PrintError(translate("Arch", "The profile is not closed") + "\n")
|
||||
return
|
||||
p = obj.Profile.Shape.Wires[0]
|
||||
else:
|
||||
if obj.Diameter.Value == 0:
|
||||
return
|
||||
p = Part.Wire(
|
||||
[Part.Circle(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), obj.Diameter.Value / 2).toShape()])
|
||||
return p
|
||||
|
||||
|
||||
class _ViewProviderFoundation(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Foundation object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Arch_Pipe_Tree.svg"
|
||||
|
||||
|
||||
def _FoundationTaskPanel():
|
||||
''''''
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class _CommandFoundation:
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "trench.svg")),
|
||||
'MenuText': "Trench",
|
||||
'Accel': "C, T",
|
||||
'ToolTip': "Creates a Trench object from setup dialog."}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
task = _FoundationTaskPanel();
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantFoundation', _CommandFoundation())
|
||||
314
PVPlantGeoreferencing.py
Normal file
314
PVPlantGeoreferencing.py
Normal file
@@ -0,0 +1,314 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
import utm
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
from PySide2.QtWebEngineWidgets import QWebEngineView
|
||||
from PySide2.QtWebChannel import QWebChannel
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
from PVPlantResources import DirResources as DirResources
|
||||
|
||||
|
||||
class MapWindow(QtGui.QWidget):
|
||||
def __init__(self, WinTitle="MapWindow"):
|
||||
super(MapWindow, self).__init__()
|
||||
self.raise_()
|
||||
self.lat = 0
|
||||
self.lon = 0
|
||||
self.WinTitle = WinTitle
|
||||
|
||||
self.setupUi()
|
||||
|
||||
def setupUi(self):
|
||||
self.ui = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantGeoreferencing.ui", self)
|
||||
|
||||
self.resize(1200, 800)
|
||||
self.setWindowTitle(self.WinTitle)
|
||||
self.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "Location.svg")))
|
||||
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
|
||||
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||
|
||||
LeftWidget = QtGui.QWidget(self)
|
||||
LeftLayout = QtGui.QVBoxLayout(LeftWidget)
|
||||
LeftWidget.setLayout(LeftLayout)
|
||||
LeftLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
RightWidget = QtGui.QWidget(self)
|
||||
RightWidget.setFixedWidth(350)
|
||||
RightLayout = QtGui.QVBoxLayout(RightWidget)
|
||||
RightWidget.setLayout(RightLayout)
|
||||
RightLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.layout.addWidget(LeftWidget)
|
||||
self.layout.addWidget(RightWidget)
|
||||
|
||||
# Left Widgets:
|
||||
# -- Search Bar:
|
||||
self.valueSearch = QtGui.QLineEdit(self)
|
||||
self.valueSearch.setPlaceholderText("Search")
|
||||
self.valueSearch.returnPressed.connect(self.onSearch)
|
||||
|
||||
searchbutton = QtGui.QPushButton('Search')
|
||||
searchbutton.setFixedWidth(80)
|
||||
searchbutton.clicked.connect(self.onSearch)
|
||||
|
||||
SearchBarLayout = QtGui.QHBoxLayout(self)
|
||||
SearchBarLayout.addWidget(self.valueSearch)
|
||||
SearchBarLayout.addWidget(searchbutton)
|
||||
LeftLayout.addLayout(SearchBarLayout)
|
||||
|
||||
# -- Webbroser:
|
||||
self.view = QWebEngineView()
|
||||
self.channel = QWebChannel(self.view.page())
|
||||
self.view.page().setWebChannel(self.channel)
|
||||
self.channel.registerObject("MyApp", self)
|
||||
file = os.path.join(DirResources, "webs", "main.html")
|
||||
self.view.page().loadFinished.connect(self.onLoadFinished)
|
||||
self.view.page().load(QtCore.QUrl.fromLocalFile(file))
|
||||
LeftLayout.addWidget(self.view)
|
||||
# self.layout.addWidget(self.view, 1, 0, 1, 3)
|
||||
|
||||
# -- Latitud y longitud:
|
||||
self.labelCoordinates = QtGui.QLabel()
|
||||
self.labelCoordinates.setFixedHeight(21)
|
||||
LeftLayout.addWidget(self.labelCoordinates)
|
||||
# self.layout.addWidget(self.labelCoordinates, 2, 0, 1, 3)
|
||||
|
||||
# Right Widgets:
|
||||
labelKMZ = QtGui.QLabel()
|
||||
labelKMZ.setText("Cargar un archivo KMZ/KML:")
|
||||
self.kmlButton = QtGui.QPushButton()
|
||||
self.kmlButton.setFixedSize(32, 32)
|
||||
self.kmlButton.setIcon(QtGui.QIcon(os.path.join(DirIcons, "googleearth.svg")))
|
||||
widget = QtGui.QWidget(self)
|
||||
layout = QtGui.QHBoxLayout(widget)
|
||||
widget.setLayout(layout)
|
||||
layout.addWidget(labelKMZ)
|
||||
layout.addWidget(self.kmlButton)
|
||||
RightLayout.addWidget(widget)
|
||||
|
||||
# -----------------------
|
||||
self.groupbox = QtGui.QGroupBox("Importar datos desde:")
|
||||
self.groupbox.setCheckable(True)
|
||||
self.groupbox.setChecked(True)
|
||||
radio1 = QtGui.QRadioButton("Google Elevation")
|
||||
radio2 = QtGui.QRadioButton("Nube de Puntos")
|
||||
radio3 = QtGui.QRadioButton("Datos GPS")
|
||||
radio1.setChecked(True)
|
||||
|
||||
# buttonDialog = QtGui.QPushButton('...')
|
||||
# buttonDialog.setEnabled(False)
|
||||
|
||||
vbox = QtGui.QVBoxLayout(self)
|
||||
vbox.addWidget(radio1)
|
||||
vbox.addWidget(radio2)
|
||||
vbox.addWidget(radio3)
|
||||
|
||||
self.groupbox.setLayout(vbox)
|
||||
RightLayout.addWidget(self.groupbox)
|
||||
# ------------------------
|
||||
|
||||
verticalSpacer = QtGui.QSpacerItem(20, 48, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
RightLayout.addItem(verticalSpacer)
|
||||
|
||||
self.bAccept = QtGui.QPushButton('Accept')
|
||||
self.bAccept.clicked.connect(self.onAcceptClick)
|
||||
RightLayout.addWidget(self.bAccept)
|
||||
|
||||
# signals/slots
|
||||
QtCore.QObject.connect(self.kmlButton, QtCore.SIGNAL("clicked()"), self.importKML)
|
||||
|
||||
|
||||
def onLoadFinished(self):
|
||||
file = os.path.join(DirResources, "webs", "map.js")
|
||||
frame = self.view.page()
|
||||
with open(file, 'r') as f:
|
||||
frame.runJavaScript(f.read())
|
||||
|
||||
def onSearch(self):
|
||||
if self.valueSearch.text() == "":
|
||||
return
|
||||
|
||||
from geopy.geocoders import Nominatim
|
||||
|
||||
geolocator = Nominatim(user_agent="http")
|
||||
location = geolocator.geocode(self.valueSearch.text())
|
||||
print(location.raw)
|
||||
self.valueSearch.setText(location.address)
|
||||
self.panMap(location.longitude, location.latitude, location.raw['boundingbox'])
|
||||
|
||||
def onAcceptClick(self):
|
||||
frame = self.view.page()
|
||||
# 1. georeferenciar
|
||||
frame.runJavaScript(
|
||||
"MyApp.georeference(drawnItems.getBounds().getCenter().lat, drawnItems.getBounds().getCenter().lng);"
|
||||
)
|
||||
|
||||
# 2. importar todos los elementos dibujados:
|
||||
frame.runJavaScript(
|
||||
"var data = drawnItems.toGeoJSON();"
|
||||
"MyApp.shapes(JSON.stringify(data));"
|
||||
)
|
||||
self.close()
|
||||
|
||||
@QtCore.Slot(float, float)
|
||||
def onMapMove(self, lat, lng):
|
||||
self.lat = lat
|
||||
self.lon = lng
|
||||
x, y, zone_number, zone_letter = utm.from_latlon(lat, lng)
|
||||
self.labelCoordinates.setText('Longitud: {:.5f}, Latitud: {:.5f}'.format(lng, lat) +
|
||||
' | UTM: ' + str(zone_number) + zone_letter +
|
||||
', {:.5f}m E, {:.5f}m N'.format(x, y))
|
||||
|
||||
@QtCore.Slot(float, float)
|
||||
def georeference(self, lat, lng):
|
||||
import PVPlantSite
|
||||
from geopy.geocoders import Nominatim
|
||||
Site = PVPlantSite.get(create=True)
|
||||
Site.Proxy.setLatLon(lat, lng)
|
||||
|
||||
geolocator = Nominatim(user_agent="http")
|
||||
location = geolocator.reverse('{:.5f}, {:.5f}'.format(lat, lng))
|
||||
if location:
|
||||
if location.raw["address"].get("road"):
|
||||
str = location.raw["address"]["road"]
|
||||
if location.raw["address"].get("house_number"):
|
||||
str += ' ({0})'.format(location.raw["address"]["house_number"])
|
||||
Site.Address = str
|
||||
if location.raw["address"].get("city"):
|
||||
Site.City = location.raw["address"]["city"]
|
||||
if location.raw["address"].get("postcode"):
|
||||
Site.PostalCode = location.raw["address"]["postcode"]
|
||||
if location.raw["address"].get("address"):
|
||||
Site.Region = '{0}'.format(location.raw["address"]["province"])
|
||||
if location.raw["address"].get("state"):
|
||||
if Site.Region != "":
|
||||
Site.Region += " - "
|
||||
Site.Region += '{0}'.format(location.raw["address"]["state"]) # province - state
|
||||
Site.Country = location.raw["address"]["country"]
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def shapes(self, drawnItems):
|
||||
import geojson
|
||||
import PVPlantImportGrid as ImportElevation
|
||||
import Draft
|
||||
|
||||
items = geojson.loads(drawnItems)
|
||||
for item in items['features']:
|
||||
if item['geometry']['type'] == "Point": # 1. if the feature is a Point or Circle:
|
||||
coord = item['geometry']['coordinates']
|
||||
point = ImportElevation.getElevationFromOE([[coord[0], coord[1]],])
|
||||
c = FreeCAD.Vector(point[0][0], point[0][1], point[0][2])
|
||||
if item['properties'].get('radius'):
|
||||
r = round(item['properties']['radius'] * 1000, 0)
|
||||
p = FreeCAD.Placement()
|
||||
p.Base = c
|
||||
obj = Draft.makeCircle(r, placement=p, face=False)
|
||||
else:
|
||||
''' do something '''
|
||||
obj = Draft.make_point(c * 1000, color=(0.5, 0.3, 0.6), point_size=10)
|
||||
else: # 2. if the feature is a Polygon or Line:
|
||||
cw = False
|
||||
name = "Línea"
|
||||
lp = item['geometry']['coordinates']
|
||||
if item['geometry']['type'] == "Polygon":
|
||||
cw = True
|
||||
name = "Area"
|
||||
lp = item['geometry']['coordinates'][0]
|
||||
|
||||
pts = []
|
||||
for cords in lp:
|
||||
pts.append([cords[1], cords[0]])
|
||||
tmp = ImportElevation.getElevationFromOE(pts)
|
||||
pts = []
|
||||
for p in tmp:
|
||||
pts.append(p.sub(FreeCAD.ActiveDocument.Site.Origin))
|
||||
|
||||
obj = Draft.makeWire(pts, closed=cw, face=False)
|
||||
obj.Placement.Base = FreeCAD.ActiveDocument.Site.Origin
|
||||
obj.Label = name
|
||||
Draft.autogroup(obj)
|
||||
|
||||
if item['properties'].get('name'):
|
||||
obj.Label = item['properties']['name']
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
FreeCADGui.updateGui()
|
||||
FreeCADGui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def panMap(self, lng, lat, geometry=""):
|
||||
frame = self.view.page()
|
||||
bbox = "[{0}, {1}], [{2}, {3}]".format(float(geometry[0]), float(geometry[2]),
|
||||
float(geometry[1]), float(geometry[3]))
|
||||
command = 'map.panTo(L.latLng({lt}, {lg}));'.format(lt=lat, lg=lng)
|
||||
command += 'map.fitBounds([{box}]);'.format(box=bbox)
|
||||
frame.runJavaScript(command)
|
||||
|
||||
def importKML(self):
|
||||
file = QtGui.QFileDialog.getOpenFileName(None, "FileDialog", "", "Google Earth (*.kml *.kmz)")[0]
|
||||
|
||||
from lib.kml2geojson import kmz_convert
|
||||
layers = kmz_convert(file, "", )
|
||||
frame = self.view.page()
|
||||
for layer in layers:
|
||||
command = "drawnItems.addLayer(L.geoJSON({0}));".format(layer)
|
||||
frame.runJavaScript(command)
|
||||
|
||||
|
||||
class _CommandPVPlantGeoreferencing:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "Location.svg")),
|
||||
'Accel': "G, R",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Georeferencing","Georeferencing"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Georeferencing","Referenciar el lugar")}
|
||||
|
||||
def Activated(self):
|
||||
self.form = MapWindow()
|
||||
self.form.show()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantGeoreferencing',_CommandPVPlantGeoreferencing())
|
||||
|
||||
191
PVPlantGeoreferencing.ui
Normal file
191
PVPlantGeoreferencing.ui
Normal file
@@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Georeferencing</class>
|
||||
<widget class="QDialog" name="Georeferencing">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>574</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Surface</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetLeft" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetSearch" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWebEngineView" name="widget_4" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetRight" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_5" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="pushButton_4">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Cargar un archivo KMZ/KML:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Georeferenciar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_6" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>Cancelar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_3">
|
||||
<property name="text">
|
||||
<string>Aceptar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebEngineView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qwebengineview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
213
PVPlantGeoreferencing.ui.autosave
Normal file
213
PVPlantGeoreferencing.ui.autosave
Normal file
@@ -0,0 +1,213 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Georeferencing</class>
|
||||
<widget class="QDialog" name="Georeferencing">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>574</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Surface</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetLeft" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetSearch" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWebEngineView" name="widget_4" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetRight" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Configuraciones:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Georeferenciar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Cargar un archivo KMZ/KML:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_4">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>New Item</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_6" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>Cancelar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_3">
|
||||
<property name="text">
|
||||
<string>Aceptar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebEngineView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qwebengineview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
660
PVPlantImportGrid.py
Normal file
660
PVPlantImportGrid.py
Normal file
@@ -0,0 +1,660 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 json
|
||||
import urllib.request
|
||||
|
||||
import Draft
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
import PVPlantSite
|
||||
|
||||
|
||||
def getElevationFromOE(coordinates):
|
||||
if len(coordinates) == 0:
|
||||
return None
|
||||
|
||||
from requests import get
|
||||
import utm
|
||||
|
||||
str=""
|
||||
total = len(coordinates) - 1
|
||||
for i, point in enumerate(coordinates):
|
||||
str += '{:.6f},{:.6f}'.format(point[0], point[1])
|
||||
if i != total:
|
||||
str += '|'
|
||||
query = 'https://api.open-elevation.com/api/v1/lookup?locations=' + str
|
||||
r = get(query, timeout=20)
|
||||
|
||||
# Only get the json response in case of 200 or 201
|
||||
points = []
|
||||
if r.status_code == 200 or r.status_code == 201:
|
||||
results = r.json()
|
||||
for point in results["results"]:
|
||||
c = utm.from_latlon(point["latitude"], point["longitude"])
|
||||
v = FreeCAD.Vector(round(c[0] * 1000, 0),
|
||||
round(c[1] * 1000, 0),
|
||||
round(point["elevation"] * 1000, 0))
|
||||
points.append(v)
|
||||
return points
|
||||
|
||||
def getSinglePointElevationFromBing(lat, lng):
|
||||
#http://dev.virtualearth.net/REST/v1/Elevation/List?points={lat1,long1,lat2,long2,latN,longnN}&heights={heights}&key={BingMapsAPIKey}
|
||||
source = "http://dev.virtualearth.net/REST/v1/Elevation/List?points="
|
||||
source += str(lat) + "," + str(lng)
|
||||
source += "&heights=sealevel"
|
||||
source += "&key=AmsPZA-zRt2iuIdQgvXZIxme2gWcgLaz7igOUy7VPB8OKjjEd373eCnj1KFv2CqX"
|
||||
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['resourceSets'][0]['resources'][0]['elevations']
|
||||
|
||||
import utm
|
||||
for elevation in res:
|
||||
c = utm.from_latlon(lat, lng)
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0] * 1000, 0),
|
||||
round(c[1] * 1000, 0),
|
||||
round(elevation * 1000, 0))
|
||||
return v
|
||||
|
||||
def getGridElevationFromBing(polygon, lat, lng, resolution = 1000):
|
||||
#http://dev.virtualearth.net/REST/v1/Elevation/Polyline?points=35.89431,-110.72522,35.89393,-110.72578,35.89374,-110.72606,35.89337,-110.72662
|
||||
# &heights=ellipsoid&samples=10&key={BingMapsAPIKey}
|
||||
import utm
|
||||
import math
|
||||
import requests
|
||||
|
||||
|
||||
geo = utm.from_latlon(lat, lng)
|
||||
# result = (679434.3578335291, 4294023.585627955, 30, 'S')
|
||||
# EASTING, NORTHING, ZONE NUMBER, ZONE LETTER
|
||||
|
||||
#StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution*1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
xx = polygon.Shape.BoundBox.XMin
|
||||
while xx < polygon.Shape.BoundBox.XMax:
|
||||
StepsXX = int(math.ceil((polygon.Shape.BoundBox.XMax - xx) / resolution))
|
||||
|
||||
if StepsXX > 1000:
|
||||
StepsXX = 1000
|
||||
xx1 = xx + 1000 * resolution
|
||||
else:
|
||||
xx1 = xx + StepsXX * resolution
|
||||
|
||||
point1 = utm.to_latlon(xx / 1000, yy / 1000, geo[2], geo[3])
|
||||
point2 = utm.to_latlon(xx1 / 1000, yy / 1000, geo[2], geo[3])
|
||||
|
||||
source = "http://dev.virtualearth.net/REST/v1/Elevation/Polyline?points="
|
||||
source += "{lat1},{lng1}".format(lat1=point1[0], lng1=point1[1])
|
||||
source += ","
|
||||
source += "{lat2},{lng2}".format(lat2=point2[0], lng2=point2[1])
|
||||
source += "&heights=sealevel"
|
||||
source += "&samples={steps}".format(steps=StepsXX)
|
||||
source += "&key=AmsPZA-zRt2iuIdQgvXZIxme2gWcgLaz7igOUy7VPB8OKjjEd373eCnj1KFv2CqX"
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['resourceSets'][0]['resources'][0]['elevations']
|
||||
|
||||
i = 0
|
||||
for elevation in res:
|
||||
v = FreeCAD.Vector(xx + resolution * i, yy, round(elevation * 1000, 4))
|
||||
points.append(v)
|
||||
i += 1
|
||||
xx = xx1 + resolution # para no repetir un mismo punto
|
||||
yy -= resolution
|
||||
|
||||
return points
|
||||
|
||||
def getSinglePointElevation(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
#print (source)
|
||||
|
||||
#response = request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
from geopy.distance import geodesic
|
||||
for r in res:
|
||||
|
||||
reference = (0.0, 0.0)
|
||||
v = FreeCAD.Vector(
|
||||
round(geodesic(reference, (0.0, r['location']['lng'])).m, 2),
|
||||
round(geodesic(reference, (r['location']['lat'], 0.0)).m, 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
|
||||
return v
|
||||
|
||||
def _getSinglePointElevation(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
#print (source)
|
||||
|
||||
#response = request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
import pymap3d as pm
|
||||
for r in res:
|
||||
x, y, z = pm.geodetic2ecef(round(r['location']['lng'], 2),
|
||||
round(r['location']['lat'], 2),
|
||||
0)
|
||||
v = FreeCAD.Vector(x,y,z)
|
||||
|
||||
return v
|
||||
|
||||
def getSinglePointElevation1(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 4),
|
||||
round(c[1], 4),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
return v
|
||||
|
||||
def getSinglePointElevationUtm(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
print(source)
|
||||
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
print (res)
|
||||
|
||||
import utm
|
||||
for r in res:
|
||||
c = utm.from_latlon(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0] * 1000, 4),
|
||||
round(c[1] * 1000, 4),
|
||||
round(r['elevation'] * 1000, 2))
|
||||
print (v)
|
||||
return v
|
||||
|
||||
|
||||
def getElevationUTM(polygon, lat, lng, resolution = 10000):
|
||||
|
||||
import utm
|
||||
geo = utm.from_latlon(lat, lng)
|
||||
# result = (679434.3578335291, 4294023.585627955, 30, 'S')
|
||||
# EASTING, NORTHING, ZONE NUMBER, ZONE LETTER
|
||||
|
||||
StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution*1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
# utm.to_latlon(EASTING, NORTHING, ZONE NUMBER, ZONE LETTER).
|
||||
# result = (LATITUDE, LONGITUDE)
|
||||
point1 = utm.to_latlon(polygon.Shape.BoundBox.XMin / 1000, yy / 1000, geo[2], geo[3])
|
||||
point2 = utm.to_latlon(polygon.Shape.BoundBox.XMax / 1000, yy / 1000, geo[2], geo[3])
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += "{a},{b}".format(a = point1[0], b = point1[1])
|
||||
source += "|"
|
||||
source += "{a},{b}".format(a = point2[0], b = point2[1])
|
||||
source += "&samples={a}".format(a = StepsXX)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
for r in res:
|
||||
c = utm.from_latlon(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0] * 1000, 2),
|
||||
round(c[1] * 1000, 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
points.append(v)
|
||||
yy -= (resolution*1000)
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
return points
|
||||
|
||||
def getElevation1(polygon,resolution=10):
|
||||
|
||||
StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution * 1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
point1 = tm.toGeographic(polygon.Shape.BoundBox.XMin, yy)
|
||||
point2 = tm.toGeographic(polygon.Shape.BoundBox.XMax, yy)
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += "{a},{b}".format(a = point1[0], b = point1[1])
|
||||
source += "|"
|
||||
source += "{a},{b}".format(a = point2[0], b = point2[1])
|
||||
source += "&samples={a}".format(a = StepsXX)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
try:
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
except:
|
||||
continue
|
||||
|
||||
#points = []
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 2),
|
||||
round(c[1], 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
yy -= (resolution*1000)
|
||||
|
||||
return points
|
||||
|
||||
## download the heights from google:
|
||||
def getElevation(lat, lon, b=50.35, le=11.17, size=40):
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?path=36.578581,-118.291994|36.23998,-116.83171&samples=3&key=YOUR_API_KEY
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&key=YOUR_API_KEY
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += str(b-size*0.001) + "," + str(le) + "|" + str(b+size*0.001) + "," + str(le)
|
||||
source += "&samples=" + str(100)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
response = urllib.request.urlopen(source)
|
||||
ans = response.read()
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
from geopy.distance import geodesic
|
||||
points = []
|
||||
for r in res:
|
||||
reference = (0.0, 0.0)
|
||||
v = FreeCAD.Vector(
|
||||
round(geodesic(reference, (0.0, r['location']['lat'])).m, 2),
|
||||
round(geodesic(reference, (r['location']['lng'], 0.0)).m, 2),
|
||||
round(r['elevation'] * 1000, 2) - baseheight
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
line = Draft.makeWire(points, closed=False, face=False, support=None)
|
||||
line.ViewObject.Visibility = False
|
||||
#FreeCAD.activeDocument().recompute()
|
||||
FreeCADGui.updateGui()
|
||||
return FreeCAD.activeDocument().ActiveObject
|
||||
|
||||
|
||||
'''
|
||||
# original::
|
||||
def getElevation(lat, lon, b=50.35, le=11.17, size=40):
|
||||
tm.lat = lat
|
||||
tm.lon = lon
|
||||
baseheight = 0 #getheight(tm.lat, tm.lon)
|
||||
center = tm.fromGeographic(tm.lat, tm.lon)
|
||||
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?path=36.578581,-118.291994|36.23998,-116.83171&samples=3&key=YOUR_API_KEY
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&key=YOUR_API_KEY
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += str(b-size*0.001) + "," + str(le) + "|" + str(b+size*0.001) + "," + str(le)
|
||||
source += "&samples=" + str(100)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
response = urllib.request.urlopen(source)
|
||||
ans = response.read()
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
points = []
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 2),
|
||||
round(c[1], 2),
|
||||
round(r['elevation'] * 1000, 2) - baseheight
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
line = Draft.makeWire(points, closed=False, face=False, support=None)
|
||||
line.ViewObject.Visibility = False
|
||||
#FreeCAD.activeDocument().recompute()
|
||||
FreeCADGui.updateGui()
|
||||
return FreeCAD.activeDocument().ActiveObject
|
||||
'''
|
||||
|
||||
class _ImportPointsTaskPanel:
|
||||
|
||||
def __init__(self, obj = None):
|
||||
self.obj = None
|
||||
self.Boundary = None
|
||||
self.select = 0
|
||||
self.filename = ""
|
||||
|
||||
# form:
|
||||
self.form1 = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantImportGrid.ui")
|
||||
self.form1.radio1.toggled.connect(lambda: self.mainToggle(self.form1.radio1))
|
||||
self.form1.radio2.toggled.connect(lambda: self.mainToggle(self.form1.radio2))
|
||||
self.form1.radio1.setChecked(True) # << --------------Poner al final para que no dispare antes de crear los componentes a los que va a llamar
|
||||
#self.form.buttonAdd.clicked.connect(self.add)
|
||||
self.form1.buttonDEM.clicked.connect(self.openFileDEM)
|
||||
|
||||
self.form2 = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantCreateTerrainMesh.ui")
|
||||
#self.form2.buttonAdd.clicked.connect(self.add)
|
||||
self.form2.buttonBoundary.clicked.connect(self.addBoundary)
|
||||
|
||||
|
||||
#self.form = [self.form1, self.form2]
|
||||
self.form = self.form1
|
||||
|
||||
''' future:
|
||||
def retranslateUi(self, dialog):
|
||||
self.form1.setWindowTitle("Configuracion del Rack")
|
||||
self.labelModule.setText(QtGui.QApplication.translate("PVPlant", "Modulo:", None))
|
||||
self.labelModuleLength.setText(QtGui.QApplication.translate("PVPlant", "Longitud:", None))
|
||||
self.labelModuleWidth.setText(QtGui.QApplication.translate("PVPlant", "Ancho:", None))
|
||||
self.labelModuleHeight.setText(QtGui.QApplication.translate("PVPlant", "Alto:", None))
|
||||
self.labelModuleFrame.setText(QtGui.QApplication.translate("PVPlant", "Ancho del marco:", None))
|
||||
self.labelModuleColor.setText(QtGui.QApplication.translate("PVPlant", "Color del modulo:", None))
|
||||
self.labelModules.setText(QtGui.QApplication.translate("Arch", "Colocacion de los Modulos", None))
|
||||
self.labelModuleOrientation.setText(QtGui.QApplication.translate("Arch", "Orientacion del modulo:", None))
|
||||
self.labelModuleGapX.setText(QtGui.QApplication.translate("Arch", "Separacion Horizontal (mm):", None))
|
||||
self.labelModuleGapY.setText(QtGui.QApplication.translate("Arch", "Separacion Vertical (mm):", None))
|
||||
self.labelModuleRows.setText(QtGui.QApplication.translate("Arch", "Filas de modulos:", None))
|
||||
self.labelModuleCols.setText(QtGui.QApplication.translate("Arch", "Columnas de modulos:", None))
|
||||
self.labelRack.setText(QtGui.QApplication.translate("Arch", "Configuracion de la estructura", None))
|
||||
self.labelRackType.setText(QtGui.QApplication.translate("Arch", "Tipo de estructura:", None))
|
||||
self.labelLevel.setText(QtGui.QApplication.translate("Arch", "Nivel:", None))
|
||||
self.labelOffset.setText(QtGui.QApplication.translate("Arch", "Offset", None))
|
||||
'''
|
||||
|
||||
def add(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.obj = sel[0]
|
||||
self.lineEdit1.setText(self.obj.Label)
|
||||
|
||||
def addBoundary(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.Boundary = sel[0]
|
||||
self.form2.editBoundary.setText(self.Boundary.Label)
|
||||
|
||||
def openFileDEM(self):
|
||||
filters = "Esri ASC (*.asc);;CSV (*.csv);;All files (*.*)"
|
||||
filename = QtGui.QFileDialog.getOpenFileName(None,
|
||||
"Open DEM,",
|
||||
"",
|
||||
filters)
|
||||
self.filename = filename[0]
|
||||
self.form1.editDEM.setText(filename[0])
|
||||
|
||||
def mainToggle(self, radiobox):
|
||||
if radiobox is self.form1.radio1:
|
||||
self.select = 0
|
||||
self.form1.gbLocalFile.setVisible(True)
|
||||
elif radiobox is self.form1.radio2:
|
||||
self.select = 1
|
||||
self.form1.gbLocalFile.setVisible(True)
|
||||
|
||||
def accept(self):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
site = PVPlantSite.get()
|
||||
|
||||
try:
|
||||
PointGroups = FreeCAD.ActiveDocument.Point_Groups
|
||||
except:
|
||||
PointGroups = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Point_Groups')
|
||||
PointGroups.Label = "Point Groups"
|
||||
|
||||
PointGroup = FreeCAD.ActiveDocument.addObject('Points::Feature', "Point_Group")
|
||||
PointGroup.Label = "Land_Grid_Points"
|
||||
FreeCAD.ActiveDocument.Point_Groups.addObject(PointGroup)
|
||||
PointObject = PointGroup.Points.copy()
|
||||
|
||||
if self.select == 0: # Google or bing or ...
|
||||
#for item in self.obj:
|
||||
#if self.groupbox.isChecked:break
|
||||
resol = FreeCAD.Units.Quantity(self.valueResolution.text()).Value
|
||||
Site = FreeCAD.ActiveDocument.Site
|
||||
pts = getGridElevationFromBing(self.obj, Site.Latitude, Site.Longitude, resol)
|
||||
PointObject.addPoints(pts)
|
||||
PointGroup.Points = PointObject
|
||||
|
||||
else:
|
||||
if self.filename == "":
|
||||
return
|
||||
|
||||
import Utils.importDEM as openDEM
|
||||
if self.select == 1: # DEM.
|
||||
import numpy as np
|
||||
root, extension = os.path.splitext(self.filename)
|
||||
if extension.lower() == ".asc":
|
||||
x, y, datavals, cellsize, nodata_value = openDEM.openEsri(self.filename)
|
||||
|
||||
if self.Boundary:
|
||||
inc_x = self.Boundary.Shape.BoundBox.XLength * 0.05
|
||||
inc_y = self.Boundary.Shape.BoundBox.YLength * 0.05
|
||||
|
||||
min_x = 0
|
||||
max_x = 0
|
||||
|
||||
comp = (self.Boundary.Shape.BoundBox.XMin - inc_x) / 1000
|
||||
for i in range(nx):
|
||||
if x[i] > comp:
|
||||
min_x = i - 1
|
||||
break
|
||||
comp = (self.Boundary.Shape.BoundBox.XMax + inc_x) / 1000
|
||||
for i in range(min_x, nx):
|
||||
if x[i] > comp:
|
||||
max_x = i
|
||||
break
|
||||
|
||||
min_y = 0
|
||||
max_y = 0
|
||||
|
||||
comp = (self.Boundary.Shape.BoundBox.YMax + inc_y) / 1000
|
||||
for i in range(ny):
|
||||
if y[i] < comp:
|
||||
max_y = i
|
||||
break
|
||||
comp = (self.Boundary.Shape.BoundBox.YMin - inc_y) / 1000
|
||||
for i in range(max_y, ny):
|
||||
if y[i] < comp:
|
||||
min_y = i
|
||||
break
|
||||
|
||||
x = x[min_x:max_x]
|
||||
y = y[max_y:min_y]
|
||||
datavals = datavals[max_y:min_y, min_x:max_x]
|
||||
|
||||
pts = []
|
||||
if True: # faster but more memory 46s - 4,25 gb
|
||||
x, y = np.meshgrid(x, y)
|
||||
xx = x.flatten()
|
||||
yy = y.flatten()
|
||||
zz = datavals.flatten()
|
||||
x[:] = 0
|
||||
y[:] = 0
|
||||
datavals[:] = 0
|
||||
|
||||
pts = []
|
||||
for i in range(0, len(xx)):
|
||||
pts.append(FreeCAD.Vector(xx[i], yy[i], zz[i]) * 1000)
|
||||
|
||||
xx[:] = 0
|
||||
yy[:] = 0
|
||||
zz[:] = 0
|
||||
|
||||
else: # 51s 3,2 gb
|
||||
createmesh = True
|
||||
if createmesh:
|
||||
import Part, Draft
|
||||
|
||||
lines=[]
|
||||
for j in range(len(y)):
|
||||
edges = []
|
||||
for i in range(0, len(x) - 1):
|
||||
ed = Part.makeLine(FreeCAD.Vector(x[i], y[j], datavals[j][i]) * 1000,
|
||||
FreeCAD.Vector(x[i + 1], y[j], datavals[j][i + 1]) * 1000)
|
||||
edges.append(ed)
|
||||
|
||||
#bspline = Draft.makeBSpline(pts)
|
||||
#bspline.ViewObject.hide()
|
||||
line = Part.Wire(edges)
|
||||
lines.append(line)
|
||||
|
||||
'''
|
||||
for i in range(0, len(bsplines), 100):
|
||||
p = Part.makeLoft(bsplines[i:i + 100], False, False, False)
|
||||
Part.show(p)
|
||||
'''
|
||||
p = Part.makeLoft(lines, False, True, False)
|
||||
p = Part.Solid(p)
|
||||
Part.show(p)
|
||||
|
||||
else:
|
||||
pts = []
|
||||
for j in range(ny):
|
||||
for i in range(nx):
|
||||
pts.append(FreeCAD.Vector(x[i], y[j], datavals[j][i]) * 1000)
|
||||
|
||||
elif extension.lower() == ".csv" or extension.lower() == ".txt": # x, y, z from gps
|
||||
pts = openDEM.interpolatePoints(openDEM.openCSV(self.filename))
|
||||
|
||||
PointObject.addPoints(pts)
|
||||
PointGroup.Points = PointObject
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
print("tiempo: ", datetime.now() - starttime)
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
## Comandos -----------------------------------------------------------------------------------------------------------
|
||||
class CommandImportPoints:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "cloud.svg")),
|
||||
'MenuText': QT_TRANSLATE_NOOP("PVPlant", "Importer Grid"),
|
||||
'Accel': "B, U",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("PVPlant", "Creates a cloud of points.")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _ImportPointsTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandPointsGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['ImportPoints'
|
||||
])
|
||||
def GetResources(self):
|
||||
return { 'MenuText': QT_TRANSLATE_NOOP("",'Cloud of Points'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("",'Cloud of Points')
|
||||
}
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand('ImportPoints', CommandImportPoints())
|
||||
FreeCADGui.addCommand('PointsGroup', CommandPointsGroup())
|
||||
|
||||
60
PVPlantImportGrid.ui
Normal file
60
PVPlantImportGrid.ui
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formImportData</class>
|
||||
<widget class="QDialog" name="formImportData">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>408</width>
|
||||
<height>164</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Surface</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Importar datos desde:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio1">
|
||||
<property name="text">
|
||||
<string>Google Elevation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio2">
|
||||
<property name="text">
|
||||
<string>Archivo DEM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="gbLocalFile" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editDEM"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonDEM">
|
||||
<property name="text">
|
||||
<string>Sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
61
PVPlantImportGridAjust.ui
Normal file
61
PVPlantImportGridAjust.ui
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formSlopeAnalisys</class>
|
||||
<widget class="QDialog" name="formSlopeAnalisys">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>442</width>
|
||||
<height>109</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Surface</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Cloud of points</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="editCloud"/>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="buttonCloud">
|
||||
<property name="text">
|
||||
<string>Sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Boundary</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="editBoundary"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="buttonBoundary">
|
||||
<property name="text">
|
||||
<string>Sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
278
PVPlantManhole.py
Normal file
278
PVPlantManhole.py
Normal file
@@ -0,0 +1,278 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 ArchComponent
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
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
|
||||
|
||||
import os
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
|
||||
def makeManhole(name="Manhole"):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Manhole")
|
||||
obj.Label = name
|
||||
_Manhole(obj)
|
||||
_ViewProviderManhole(obj.ViewObject)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
|
||||
class _Manhole(ArchComponent.Component):
|
||||
"A Manhole Obcject"
|
||||
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
# Dimensions: --------------------------------------------------------------------------------------------------
|
||||
if not "Height" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Height",
|
||||
"Manhole",
|
||||
"The height of this object"
|
||||
).Height = 1000
|
||||
|
||||
if not "Width" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Width",
|
||||
"Manhole",
|
||||
"The width of this object"
|
||||
).Width = 1000
|
||||
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Manhole",
|
||||
"The height of this object"
|
||||
).Length = 2000
|
||||
|
||||
if not "Thickness" in pl:
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Thickness",
|
||||
"Manhole",
|
||||
"The height of this object"
|
||||
).Thickness = 100
|
||||
|
||||
# outputs:
|
||||
if not "InternalVolume" in pl:
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"InternalVolume",
|
||||
"Outputs",
|
||||
"The height of this object"
|
||||
)
|
||||
|
||||
if not "ExternalVolume" in pl:
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"ExternalVolume",
|
||||
"Outputs",
|
||||
"The height of this object"
|
||||
)
|
||||
|
||||
self.Type = "Manhole"
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and Arch wall properties."""
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
def execute(self, obj):
|
||||
w_med = obj.Width.Value / 2
|
||||
l_med = obj.Length.Value / 2
|
||||
|
||||
p1 = FreeCAD.Vector(-l_med, -w_med, 0)
|
||||
p2 = FreeCAD.Vector( l_med, -w_med, 0)
|
||||
p3 = FreeCAD.Vector( l_med, w_med, 0)
|
||||
p4 = FreeCAD.Vector(-l_med, w_med, 0)
|
||||
ext = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1, ]))
|
||||
ins = ext.makeOffset2D(-obj.Thickness.Value, join=2, openResult=True)
|
||||
ext_sol = ext.extrude(FreeCAD.Vector(0, 0, -obj.Height.Value))
|
||||
ins_sol = ins.extrude(FreeCAD.Vector(0, 0, -(obj.Height.Value - obj.Thickness.Value)))
|
||||
|
||||
obj.Shape = ext_sol.cut([ins_sol, ], 0.0)
|
||||
|
||||
|
||||
|
||||
|
||||
class _ViewProviderManhole(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(DirIcons, "manhole.svg"))
|
||||
|
||||
def setEdit(self, vobj, mode):
|
||||
"""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 Arch component 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"):
|
||||
taskd = _ManholeTaskPanel(self.Object)
|
||||
taskd.obj = self.Object
|
||||
# taskd.update()
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
import draftguitools.gui_tool_utils as gui_tool_utils
|
||||
|
||||
class _ManholeTaskPanel:
|
||||
def __init__(self, obj=None):
|
||||
self.new = False
|
||||
if obj is None:
|
||||
self.new = True
|
||||
obj = makeManhole()
|
||||
|
||||
self.obj = obj
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantManhole.ui")
|
||||
|
||||
self.node = None
|
||||
self.view = FreeCADGui.ActiveDocument.ActiveView
|
||||
self.tracker = DraftTrackers.ghostTracker(obj)
|
||||
self.tracker.on()
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
|
||||
def action(self, arg):
|
||||
"""Handle the 3D scene events.
|
||||
|
||||
This is installed as an EventCallback in the Inventor view.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg: dict
|
||||
Dictionary with strings that indicates the type of event received
|
||||
from the 3D view.
|
||||
"""
|
||||
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
|
||||
if info:
|
||||
self.tracker.move(FreeCAD.Vector(info["x"], info["y"], info["z"]))
|
||||
else:
|
||||
self.tracker.move(point)
|
||||
|
||||
elif (arg["Type"] == "SoMouseButtonEvent" and
|
||||
arg["State"] == "DOWN" and
|
||||
arg["Button"] == "BUTTON1"):
|
||||
|
||||
point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
|
||||
if info:
|
||||
self.obj.Placement.Base = FreeCAD.Vector(info["x"], info["y"], info["z"])
|
||||
else:
|
||||
self.obj.Placement.Base = point
|
||||
self.finish()
|
||||
|
||||
def finish(self):
|
||||
self.accept()
|
||||
|
||||
def accept(self):
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
if self.new:
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def closeForm(self):
|
||||
self.tracker.finalize()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
self.view.removeEventCallback("SoEvent", self.call)
|
||||
|
||||
|
||||
class _CommandManhole:
|
||||
"the Arch Building command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "manhole.svg")),
|
||||
'MenuText': "Manhole",
|
||||
'Accel': "C, M",
|
||||
'ToolTip': "Creates a Manhole object from setup dialog."}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
if FreeCADGui.Selection.getCompleteSelection():
|
||||
for ob in FreeCAD.ActiveDocument.Objects:
|
||||
if ob.Name[:4] == "Site":
|
||||
return True
|
||||
|
||||
def Activated(self):
|
||||
TaskPanel = _ManholeTaskPanel()
|
||||
FreeCADGui.Control.showDialog(TaskPanel)
|
||||
return
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantManhole', _CommandManhole())
|
||||
|
||||
218
PVPlantManhole.ui
Normal file
218
PVPlantManhole.ui
Normal file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>332</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Dimensions</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Heigth (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Largura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
218
PVPlantMenuEditor.ui
Normal file
218
PVPlantMenuEditor.ui
Normal file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>332</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Dimensions</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Heigth (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleLenght">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Largura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
439
PVPlantPad.py
Normal file
439
PVPlantPad.py
Normal file
@@ -0,0 +1,439 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD, Part
|
||||
import BOPTools.SplitAPI as splitter
|
||||
import ArchComponent
|
||||
import PVPlantSite
|
||||
import math
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Trench"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
def makePad(base=None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Pad")
|
||||
Pad(obj)
|
||||
ViewProviderPad(obj.ViewObject)
|
||||
obj.Base = base
|
||||
return obj
|
||||
|
||||
class Pad(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.obj = obj
|
||||
self.base = None
|
||||
|
||||
self.setProperties(obj)
|
||||
|
||||
obj.Proxy = self
|
||||
obj.IfcType = "Civil Element"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
obj.ViewObject.ShapeColor = (0.305, 0.230, 0.191)
|
||||
|
||||
def setProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
|
||||
#TODO: Los parametros width y length desaparecerán. Se tiene que selecionar objeto base
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Width",
|
||||
"Pad",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).Width = 5000
|
||||
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Length",
|
||||
"Pad",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).Length = 10000
|
||||
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"FillSlope",
|
||||
"Pad",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).FillSlope = 45.00
|
||||
|
||||
obj.addProperty("App::PropertyAngle",
|
||||
"CutSlope",
|
||||
"Pad",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).CutSlope = 60.00
|
||||
|
||||
obj.addProperty("App::PropertyBool",
|
||||
"TopsoilCalculation",
|
||||
"Pad",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).TopsoilCalculation = False
|
||||
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"TopsoilHeight",
|
||||
"Pad",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).TopsoilHeight = 300
|
||||
|
||||
# Output values:
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"CutVolume",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection"))
|
||||
obj.setEditorMode("CutVolume", 1)
|
||||
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"FillVolume",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection"))
|
||||
obj.setEditorMode("FillVolume", 1)
|
||||
|
||||
obj.addProperty("App::PropertyArea",
|
||||
"PadArea",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection"))
|
||||
obj.setEditorMode("PadArea", 1)
|
||||
|
||||
obj.addProperty("App::PropertyArea",
|
||||
"TopSoilArea",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection"))
|
||||
obj.setEditorMode("TopSoilArea", 1)
|
||||
|
||||
obj.addProperty("App::PropertyVolume",
|
||||
"TopSoilVolume",
|
||||
"Output",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection"))
|
||||
obj.setEditorMode("TopSoilVolume", 1)
|
||||
obj.setEditorMode("Placement", 1)
|
||||
|
||||
self.Type = "Pad"
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and object properties."""
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.obj = obj
|
||||
self.Type = "Pad"
|
||||
obj.Proxy = self
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
def execute(self, obj):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
pb = obj.Placement.Base
|
||||
land = PVPlantSite.get().Terrain
|
||||
shapes = []
|
||||
pad = None
|
||||
|
||||
if obj.Base:
|
||||
if hasattr(obj.Base.Shape, 'Wires') and obj.Base.Shape.Wires:
|
||||
pad = obj.Base.Shape.Wires[0]
|
||||
elif obj.Base.Shape.Edges:
|
||||
pad = Part.Wire(obj.Base.Shape.Edges)
|
||||
pb = obj.Base.Placement.Base
|
||||
else:
|
||||
# Si no hay una base seleccionada se crea una rectangular:
|
||||
halfWidth = obj.Width.Value / 2
|
||||
halfLength = obj.Length.Value / 2
|
||||
|
||||
p1 = FreeCAD.Vector(-halfLength, -halfWidth, 0)
|
||||
p2 = FreeCAD.Vector( halfLength, -halfWidth, 0)
|
||||
p3 = FreeCAD.Vector( halfLength, halfWidth, 0)
|
||||
p4 = FreeCAD.Vector(-halfLength, halfWidth, 0)
|
||||
pad = Part.makePolygon([p1, p2, p3, p4, p1])
|
||||
'''pad = Draft.makeWire([p1, p2, p3, p4, p1])
|
||||
obj.Base = pad
|
||||
pad = obj.Base.Shape.Wires[0]'''
|
||||
|
||||
# 1. Terraplén (fill):
|
||||
fill = None
|
||||
fillcommon = None
|
||||
if land.Shape.BoundBox.ZMin < pb.z:
|
||||
tool = self.createSolid(obj, pad, land, -1)
|
||||
fillcommon, fill = self.calculateFill(obj, tool)
|
||||
else:
|
||||
print("- PAD: NOOOO Calculete fill solid:")
|
||||
|
||||
# 2. Desmonte (cut):
|
||||
cut = None
|
||||
'''cutcommon = None
|
||||
if land.Shape.BoundBox.ZMax > pb.z:
|
||||
cut = self.createSolid(obj, pad, land, 1)
|
||||
cut.Placement.Base += pb
|
||||
cutcommon, cut = self.calculateCut(obj, cut)
|
||||
else:
|
||||
print("- PAD: NOOOO Calcalete cut solid:")'''
|
||||
|
||||
topsoilArea = 0
|
||||
topsoilVolume = 0
|
||||
if fill:
|
||||
if obj.TopsoilCalculation:
|
||||
filltopsoil = fillcommon.extrude(FreeCAD.Vector(0, 0, -obj.TopsoilHeight))
|
||||
topsoilVolume += filltopsoil.Volume
|
||||
filltopsoil.Placement.Base -= pb
|
||||
shapes.append(filltopsoil)
|
||||
fill.Placement.Base -= pb
|
||||
shapes.append(fill)
|
||||
topsoilArea += fill.Area
|
||||
if cut:
|
||||
cut.Placement.Base -= pb
|
||||
shapes.append(cut)
|
||||
topsoilArea += cut.Area
|
||||
if obj.TopsoilCalculation:
|
||||
cuttopsoil = cutcommon.extrude(FreeCAD.Vector(0, 0, -obj.TopsoilHeight))
|
||||
topsoilVolume += cuttopsoil.Volume
|
||||
obj.CutVolume = obj.CutVolume.Value - cuttopsoil.Volume
|
||||
|
||||
pad = Part.Face(pad)
|
||||
if len(shapes) == 0:
|
||||
shapes.append(pad)
|
||||
|
||||
shape = Part.makeCompound(shapes)
|
||||
#shape.Placement.Base = FreeCAD.Vector(0)
|
||||
obj.Shape = shape
|
||||
obj.Placement.Base = pb
|
||||
obj.PadArea = pad.Area
|
||||
obj.TopSoilArea = topsoilArea
|
||||
obj.TopSoilVolume = topsoilVolume
|
||||
|
||||
total_time = datetime.now() - starttime
|
||||
print(" -- Tiempo tardado:", total_time)
|
||||
|
||||
def createSolid(self, obj, base, land, dir = -1):
|
||||
base_copy = base.copy()
|
||||
base_copy.Placement.Base = FreeCAD.Vector(0,0,0)
|
||||
if dir == -1:
|
||||
zz = land.Mesh.BoundBox.ZMin
|
||||
angle = obj.FillSlope.Value
|
||||
else:
|
||||
zz = land.Mesh.BoundBox.ZMax
|
||||
angle = obj.CutSlope.Value
|
||||
height = abs(zz - base.Placement.Base.z)
|
||||
offset = base_copy.makeOffset2D(height / math.tan(math.radians(angle)), 0, False, False, True)
|
||||
offset.Placement.Base.z = dir * height
|
||||
|
||||
import DraftGeomUtils
|
||||
base_fillet = DraftGeomUtils.filletWire(base_copy, 1) #trick to get a nice shape: (fillet of 1 mm)
|
||||
pad = Part.makeLoft([base_fillet, offset], True)
|
||||
pad.Placement.Base = base.Placement.Base
|
||||
return pad
|
||||
|
||||
def calculateFill(self, obj, solid):
|
||||
common = solid.common(PVPlantSite.get().Terrain.Shape)
|
||||
if common.Area > 0:
|
||||
sp = splitter.slice(solid, [common, ], "Split")
|
||||
commoncopy = common.copy()
|
||||
commoncopy.Placement.Base.z += 10
|
||||
volume = 0
|
||||
fills = []
|
||||
for sol in sp.Solids:
|
||||
common1 = sol.common(commoncopy)
|
||||
if common1.Area > 0:
|
||||
volume += sol.Volume
|
||||
fills.append(sol)
|
||||
obj.FillVolume = volume
|
||||
if len(fills) > 0:
|
||||
base = fills.pop(0)
|
||||
if len(fills) > 0:
|
||||
base = base.fuse(fills)
|
||||
return common, base
|
||||
else:
|
||||
obj.FillVolume = 0
|
||||
print("--- Fill: no common Area --------------------------")
|
||||
return None, None
|
||||
|
||||
def calculateCut(self, obj, solid):
|
||||
common = solid.common(PVPlantSite.get().Terrain.Shape)
|
||||
if common.Area > 0:
|
||||
sp = splitter.slice(solid, [common, ], "Split")
|
||||
shells = []
|
||||
volume = 0
|
||||
commoncopy = common.copy()
|
||||
commoncopy.Placement.Base.z -= 1
|
||||
for sol in sp.Solids:
|
||||
common1 = sol.common(commoncopy)
|
||||
if common1.Area > 0:
|
||||
volume += sol.Volume
|
||||
shell = sol.Shells[0]
|
||||
shell = shell.cut(common)
|
||||
shells.append(shell)
|
||||
obj.CutVolume = volume
|
||||
if len(shells) > 0:
|
||||
base = shells.pop(0)
|
||||
if len(shells) > 0:
|
||||
base = base.fuse(shells)
|
||||
return common, base
|
||||
else:
|
||||
obj.CutVolume = 0
|
||||
print("--- Cut: no common Area --------------------------")
|
||||
|
||||
return None, None
|
||||
|
||||
class ViewProviderPad(ArchComponent.ViewProviderComponent):
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(PVPlantResources.DirIcons, "pad.svg"))
|
||||
|
||||
class _PadTaskPanel:
|
||||
|
||||
def __init__(self, obj=None):
|
||||
|
||||
if obj is None:
|
||||
self.new = True
|
||||
self.obj = makeTrench()
|
||||
else:
|
||||
self.new = False
|
||||
self.obj = obj
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(PVPlantResources.__dir__, "PVPlantTrench.ui"))
|
||||
|
||||
def accept(self):
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Pad")
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
if self.new:
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
|
||||
import sys
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import draftutils.utils as utils
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.todo as todo
|
||||
import draftguitools.gui_base_original as gui_base_original
|
||||
import draftguitools.gui_tool_utils as gui_tool_utils
|
||||
|
||||
from draftutils.translate import translate
|
||||
|
||||
|
||||
class _CommandPad(gui_base_original.Creator):
|
||||
"""Gui command for the Line tool."""
|
||||
|
||||
def __init__(self):
|
||||
# super(_CommandTrench, self).__init__()
|
||||
gui_base_original.Creator.__init__(self)
|
||||
self.path = None
|
||||
self.obj = None
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "pad.svg")),
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PVPlantPad", "Pad"),
|
||||
'Accel': "C, P",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PVPlantPad",
|
||||
"Creates a Pad object from setup dialog.")}
|
||||
|
||||
def Activated(self, name=translate("draft", "Line")):
|
||||
"""Execute when the command is called."""
|
||||
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
base = None
|
||||
needbase = True
|
||||
if len(sel) > 0:
|
||||
needbase = False
|
||||
base = sel[0]
|
||||
self.obj = makePad(base)
|
||||
|
||||
if needbase:
|
||||
gui_base_original.Creator.Activated(self, name=translate("draft", "Line"))
|
||||
self.ui.wireUi(name)
|
||||
self.ui.setTitle("Pad")
|
||||
#self.obj = self.doc.addObject("Part::Feature", self.featureName)
|
||||
#gui_utils.format_object(self.obj)
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
|
||||
def action(self, arg):
|
||||
"""Handle the 3D scene events.
|
||||
|
||||
This is installed as an EventCallback in the Inventor view.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg: dict
|
||||
Dictionary with strings that indicates the type of event received
|
||||
from the 3D view.
|
||||
"""
|
||||
|
||||
print(self.obj)
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
self.point, ctrlPoint, self.info = gui_tool_utils.getPoint(self, arg)
|
||||
gui_tool_utils.redraw3DView()
|
||||
self.obj.Placement.Base = FreeCAD.Vector(self.info["x"], self.info["y"], self.info["z"])
|
||||
|
||||
elif (arg["Type"] == "SoMouseButtonEvent"
|
||||
and arg["State"] == "DOWN"
|
||||
and arg["Button"] == "BUTTON1"):
|
||||
|
||||
gui_tool_utils.getSupport(arg)
|
||||
self.point, ctrlPoint, self.info = gui_tool_utils.getPoint(self, arg)
|
||||
|
||||
if self.point:
|
||||
self.point = FreeCAD.Vector(self.info["x"], self.info["y"], self.info["z"])
|
||||
self.ui.redraw()
|
||||
self.obj.Placement.Base = FreeCAD.Vector(self.info["x"], self.info["y"], self.info["z"])
|
||||
self.finish()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def finish(self, closed=False, cont=False):
|
||||
"""Terminate the operation and close the polyline if asked.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
closed: bool, optional
|
||||
Close the line if `True`.
|
||||
"""
|
||||
|
||||
# super(_CommandTrench, self).finish()
|
||||
gui_base_original.Creator.finish(self)
|
||||
if self.ui and self.ui.continueMode:
|
||||
self.Activated()
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantPad', _CommandPad())
|
||||
1132
PVPlantPlacement.py
Normal file
1132
PVPlantPlacement.py
Normal file
File diff suppressed because it is too large
Load Diff
519
PVPlantPlacement.ui
Normal file
519
PVPlantPlacement.ui
Normal file
@@ -0,0 +1,519 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<author>Javier Braña</author>
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>388</width>
|
||||
<height>576</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Park Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="6" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="groupCorridor">
|
||||
<property name="title">
|
||||
<string>Corridor settings</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Row amount</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Vertical distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editRowGap">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>4.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Column amount</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Horizontal distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editColGap">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>4.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="editRowCount">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="editColCount">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonPVArea">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAddFrame">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonRemoveFrame">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Area:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editPVArea"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Configuración</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="horizontalSpacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offset Vertical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Orientación</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="cbAlignFrames">
|
||||
<property name="text">
|
||||
<string>Alinear estructuras</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Espacio entre filas</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dirección Horizontal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offset Horizontal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pitch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dirección Vertical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboOrientation">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Norte - Sur</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Este - Oeste</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editGapCols">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="comboDirH">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De izquierda a derecha</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De derecha a izquiera</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De centro a los lados</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="comboDirV">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De arriba a abajo</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De abajo a arriba</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Del centro a los lados</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editOffsetHorizontal">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editOffsetVertical">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-10000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="editGapRows">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> mm</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" alignment="Qt::AlignTop">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Estructura:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QListWidget" name="listFrameSetups">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>54</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>buttonAddFrame</tabstop>
|
||||
<tabstop>buttonRemoveFrame</tabstop>
|
||||
<tabstop>editPVArea</tabstop>
|
||||
<tabstop>buttonPVArea</tabstop>
|
||||
<tabstop>comboOrientation</tabstop>
|
||||
<tabstop>editGapCols</tabstop>
|
||||
<tabstop>editGapRows</tabstop>
|
||||
<tabstop>comboDirH</tabstop>
|
||||
<tabstop>comboDirV</tabstop>
|
||||
<tabstop>editOffsetHorizontal</tabstop>
|
||||
<tabstop>editOffsetVertical</tabstop>
|
||||
<tabstop>cbAlignFrames</tabstop>
|
||||
<tabstop>groupCorridor</tabstop>
|
||||
<tabstop>editColCount</tabstop>
|
||||
<tabstop>editColGap</tabstop>
|
||||
<tabstop>editRowCount</tabstop>
|
||||
<tabstop>editRowGap</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
161
PVPlantPlacementAdjust.ui
Normal file
161
PVPlantPlacementAdjust.ui
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<author>Javier Braña</author>
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>310</width>
|
||||
<height>210</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Park Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Configuración</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="comboDirH">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De izquierda a derecha</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De derecha a izquiera</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De centro a los lados</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="comboMethod">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Individual</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Conjunto</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Dirección Vertical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Dirección Horizontal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Método:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="comboDirV">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De arriba a abajo</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>De abajo a arriba</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Del centro a los lados</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>GroupBox</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="editStepSize">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> mm</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>250</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Escalón</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkTrenck">
|
||||
<property name="text">
|
||||
<string>Ajustal a la media de la curva</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>comboMethod</tabstop>
|
||||
<tabstop>comboDirH</tabstop>
|
||||
<tabstop>comboDirV</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
59
PVPlantPlacementConvert.ui
Normal file
59
PVPlantPlacementConvert.ui
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>497</width>
|
||||
<height>520</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Convertir a...</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonTo">
|
||||
<property name="text">
|
||||
<string>Sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>1. Primero seleccióna el objeto al que quieres transformar
|
||||
2. Selecciiona todos los objetos que quieres tansfomrar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Objeto al que quieres transformar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editTo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
93
PVPlantRackChecking.py
Normal file
93
PVPlantRackChecking.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Frames"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
def checkSingleTracker(frame, val):
|
||||
doc = FreeCAD.ActiveDocument
|
||||
if val:
|
||||
if frame.AngleY < doc.MaximumTiltNegative.Value:
|
||||
frame.ViewObject.ShapeColor = doc.MaximumTiltNegativeColor
|
||||
elif frame.AngleY > doc.MaximumTiltPositive.Value:
|
||||
frame.ViewObject.ShapeColor = doc.MaximumTiltPositiveColor
|
||||
else:
|
||||
frame.ViewObject.ShapeColor = frame.Setup.ViewObject.ShapeColor
|
||||
else:
|
||||
frame.ViewObject.ShapeColor = frame.Setup.ViewObject.ShapeColor
|
||||
|
||||
|
||||
def checkTrackers(val):
|
||||
from Utils.PVPlantUtils import findObjects
|
||||
tlist = findObjects("Tracker")
|
||||
for obj in tlist:
|
||||
checkSingleTracker(obj, val)
|
||||
|
||||
|
||||
class CommandRackCheck:
|
||||
|
||||
def GetResources(self):
|
||||
checked = False
|
||||
if hasattr(FreeCAD.ActiveDocument, "FramesChecking"):
|
||||
checked = FreeCAD.ActiveDocument.FramesChecking
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "checked.png")),
|
||||
'MenuText': "Tracker slope checker",
|
||||
'Accel': "R, C",
|
||||
'ToolTip': "Tracker slope checker.",
|
||||
'CmdType': "NoTransaction",
|
||||
'Checkable': checked}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self, val):
|
||||
val = bool(val)
|
||||
if not hasattr(FreeCAD.ActiveDocument, "FramesChecking"):
|
||||
''' Abrir dialogo '''
|
||||
else:
|
||||
FreeCAD.ActiveDocument.FramesChecking = val
|
||||
checkTrackers(val)
|
||||
return
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantRackCheck', CommandRackCheck())
|
||||
|
||||
274
PVPlantRackFixedPiling.ui
Normal file
274
PVPlantRackFixedPiling.ui
Normal file
@@ -0,0 +1,274 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>363</width>
|
||||
<height>596</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Piling</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBreadthways">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>210</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Distancias a lo ancho</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Número de postes:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="editBreadthwaysNumOfPost">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QTableWidget" name="tableBreadthwaysPosts">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AllEditTriggers</set>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>3</string>
|
||||
</property>
|
||||
</row>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Tramo</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Distancia</string>
|
||||
</property>
|
||||
</column>
|
||||
<item row="0" column="0">
|
||||
<property name="text">
|
||||
<string notr="true">Side - 1</string>
|
||||
</property>
|
||||
<property name="textAlignment">
|
||||
<set>AlignCenter</set>
|
||||
</property>
|
||||
<property name="flags">
|
||||
<set>NoItemFlags</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="flags">
|
||||
<set>ItemIsSelectable|ItemIsEditable|ItemIsEnabled</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<property name="text">
|
||||
<string>1 - 2</string>
|
||||
</property>
|
||||
<property name="textAlignment">
|
||||
<set>AlignCenter</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<property name="text">
|
||||
<string>2 - Side</string>
|
||||
</property>
|
||||
<property name="textAlignment">
|
||||
<set>AlignCenter</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="flags">
|
||||
<set>NoItemFlags</set>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupAlong">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Distancias a lo largo</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Número de postes:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="editAlongNumOfPost">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QTableWidget" name="tableAlongPosts">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AllEditTriggers</set>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>3</string>
|
||||
</property>
|
||||
</row>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Tramo</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Distancia</string>
|
||||
</property>
|
||||
</column>
|
||||
<item row="0" column="0">
|
||||
<property name="text">
|
||||
<string notr="true">Side - 1</string>
|
||||
</property>
|
||||
<property name="textAlignment">
|
||||
<set>AlignCenter</set>
|
||||
</property>
|
||||
<property name="flags">
|
||||
<set>NoItemFlags</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="flags">
|
||||
<set>ItemIsSelectable|ItemIsEditable|ItemIsEnabled</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<property name="text">
|
||||
<string>1 - 2</string>
|
||||
</property>
|
||||
<property name="textAlignment">
|
||||
<set>AlignCenter</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<property name="text">
|
||||
<string>2 - Side</string>
|
||||
</property>
|
||||
<property name="textAlignment">
|
||||
<set>AlignCenter</set>
|
||||
</property>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="flags">
|
||||
<set>NoItemFlags</set>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
11
PVPlantResources.py
Normal file
11
PVPlantResources.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
|
||||
import FreeCAD
|
||||
|
||||
__dir__ = os.path.join(FreeCAD.getUserAppDataDir(), 'Mod', 'PVPlant')
|
||||
DirResources = os.path.join(__dir__, 'Resources')
|
||||
DirIcons = os.path.join(DirResources, 'Icons')
|
||||
DirImages = os.path.join(DirResources, 'Images')
|
||||
DirDocuments = os.path.join(DirResources, 'Documents')
|
||||
DirDDDDocuments = os.path.join(DirResources, '3dObjects')
|
||||
|
||||
616
PVPlantRoad.py
Normal file
616
PVPlantRoad.py
Normal file
@@ -0,0 +1,616 @@
|
||||
import FreeCAD
|
||||
import ArchComponent
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import Part
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Road"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
def makeRoad(base=None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Road")
|
||||
_Road(obj)
|
||||
_ViewProviderRoad(obj.ViewObject)
|
||||
obj.Base = base
|
||||
|
||||
from Project.Area import PVPlantArea
|
||||
offset = PVPlantArea.makeOffsetArea(obj, 4000)
|
||||
PVPlantArea.makeProhibitedArea(offset)
|
||||
return obj
|
||||
|
||||
|
||||
class _Road(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
# Definición de Variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.obj = obj
|
||||
self.setProperties(obj)
|
||||
self.Type = "Road"
|
||||
obj.Proxy = self
|
||||
|
||||
self.route = False
|
||||
|
||||
obj.IfcType = "Civil Element" ## puede ser: Cable Carrier Segment
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
|
||||
self.count = 0
|
||||
|
||||
def setProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
'''[
|
||||
'App::PropertyBool',
|
||||
'App::PropertyBoolList',
|
||||
'App::PropertyFloat',
|
||||
'App::PropertyFloatList',
|
||||
'App::PropertyFloatConstraint',
|
||||
'App::PropertyPrecision',
|
||||
'App::PropertyQuantity',
|
||||
'App::PropertyQuantityConstraint',
|
||||
'App::PropertyAngle',
|
||||
'App::PropertyDistance',
|
||||
'App::PropertyLength',
|
||||
'App::PropertyArea',
|
||||
'App::PropertyVolume',
|
||||
'App::PropertyFrequency',
|
||||
'App::PropertySpeed',
|
||||
'App::PropertyAcceleration',
|
||||
'App::PropertyForce',
|
||||
'App::PropertyPressure',
|
||||
'App::PropertyVacuumPermittivity',
|
||||
'App::PropertyInteger',
|
||||
'App::PropertyIntegerConstraint',
|
||||
'App::PropertyPercent',
|
||||
'App::PropertyEnumeration',
|
||||
'App::PropertyIntegerList',
|
||||
'App::PropertyIntegerSet',
|
||||
'App::PropertyMap',
|
||||
'App::PropertyString',
|
||||
'App::PropertyPersistentObject',
|
||||
'App::PropertyUUID',
|
||||
'App::PropertyFont',
|
||||
'App::PropertyStringList',
|
||||
'p::PropertyLink',
|
||||
'App::PropertyLinkChild',
|
||||
'App::PropertyLinkGlobal',
|
||||
'App::PropertyLinkHidden',
|
||||
'App::PropertyLinkSub',
|
||||
'App::PropertyLinkSubChild',
|
||||
'App::PropertyLinkSubGlobal',
|
||||
'App::PropertyLinkSubHidden',
|
||||
'App::PropertyLinkList',
|
||||
'App::PropertyLinkListChild',
|
||||
'App::PropertyLinkListGlobal',
|
||||
'App::PropertyLinkListHidden',
|
||||
'App::PropertyLinkSubList',
|
||||
'App::PropertyLinkSubListChild',
|
||||
'App::PropertyLinkSubListGlobal',
|
||||
'App::PropertyLinkSubListHidden',
|
||||
'App::PropertyXLink',
|
||||
'App::PropertyXLinkSub',
|
||||
'App::PropertyXLinkSubList',
|
||||
'App::PropertyXLinkList',
|
||||
'App::PropertyMatrix',
|
||||
'App::PropertyVector',
|
||||
'App::PropertyVectorDistance',
|
||||
'App::PropertyPosition',
|
||||
'App::PropertyDirection',
|
||||
'App::PropertyVectorList',
|
||||
'App::PropertyPlacement',
|
||||
'App::PropertyPlacementList',
|
||||
'App::PropertyPlacementLink',
|
||||
'App::PropertyColor',
|
||||
'App::PropertyColorList',
|
||||
'App::PropertyMaterial',
|
||||
'App::PropertyMaterialList',
|
||||
'App::PropertyPath',
|
||||
'App::PropertyFile',
|
||||
'App::PropertyFileIncluded',
|
||||
'App::PropertyPythonObject',
|
||||
'App::PropertyExpressionEngine',
|
||||
'Part::PropertyPartShape',
|
||||
'Part::PropertyGeometryList',
|
||||
'Part::PropertyShapeHistory',
|
||||
'Part::PropertyFilletEdges',
|
||||
'Mesh::PropertyNormalList',
|
||||
'Mesh::PropertyCurvatureList',
|
||||
'Mesh::PropertyMeshKernel',
|
||||
'Sketcher::PropertyConstraintList'
|
||||
]'''
|
||||
|
||||
obj.addProperty("App::PropertyPercent",
|
||||
"SurfaceSlope",
|
||||
"Road",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).SurfaceSlope = 2
|
||||
|
||||
obj.addProperty("App::PropertyPercent",
|
||||
"SurfaceDrainSlope",
|
||||
"Road",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).SurfaceDrainSlope = int(3 / 2 * 100)
|
||||
|
||||
obj.addProperty("App::PropertyPercent",
|
||||
"SubbaseDrainSlope",
|
||||
"Road",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).SubbaseDrainSlope = int(2 / 3 * 100)
|
||||
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Width",
|
||||
"Road",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).Width = 4000
|
||||
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Height",
|
||||
"Road",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).Height = 250
|
||||
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"Subbase",
|
||||
"Road",
|
||||
QT_TRANSLATE_NOOP("App::Property", "Connection")).Subbase = 400
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored.
|
||||
Re-adds the Arch component, and object properties."""
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.obj = obj
|
||||
self.Type = "Road"
|
||||
obj.Proxy = self
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
import Part, math
|
||||
|
||||
w = obj.Base.Shape
|
||||
profiles = []
|
||||
|
||||
SurfaceDrainSlope = obj.SurfaceDrainSlope / 100
|
||||
SubbaseDrainSlope = obj.SubbaseDrainSlope / 100
|
||||
|
||||
vec_up_left = FreeCAD.Vector(-obj.Width.Value / 2, 0, obj.Height.Value)
|
||||
vec_up_center = FreeCAD.Vector(0, 0, obj.SurfaceSlope * obj.Width.Value / 200 + obj.Height.Value)
|
||||
vec_up_right = FreeCAD.Vector(obj.Width.Value / 2, 0, obj.Height.Value)
|
||||
|
||||
vec_down_left = FreeCAD.Vector(-(obj.Width.Value / 2 + obj.Height.Value / SurfaceDrainSlope), 0, 0)
|
||||
vec_down_right = FreeCAD.Vector((obj.Width.Value / 2 + obj.Height.Value / SurfaceDrainSlope), 0, 0)
|
||||
|
||||
vec_sand_left = FreeCAD.Vector(-(obj.Width.Value / 2 + obj.Height.Value * (1 / SurfaceDrainSlope + SubbaseDrainSlope)), 0, - obj.Subbase.Value)
|
||||
vec_sand_right = FreeCAD.Vector((obj.Width.Value / 2 + obj.Height.Value * (1 / SurfaceDrainSlope + SubbaseDrainSlope)), 0, - obj.Subbase.Value)
|
||||
|
||||
edge1 = Part.makeLine(vec_down_left, vec_down_right)
|
||||
edge2 = Part.makeLine(vec_down_right, vec_up_right)
|
||||
edge3 = Part.makeLine(vec_up_right, vec_up_center)
|
||||
edge4 = Part.makeLine(vec_up_center, vec_up_left)
|
||||
edge5 = Part.makeLine(vec_up_left, vec_down_left)
|
||||
|
||||
edge6 = Part.makeLine(vec_sand_left, vec_sand_right)
|
||||
edge7 = Part.makeLine(vec_sand_left, vec_down_left)
|
||||
edge8 = Part.makeLine(vec_sand_right, vec_down_right)
|
||||
|
||||
p = Part.Wire([edge1, edge2, edge3, edge4, edge5])
|
||||
profiles.append(p)
|
||||
p = Part.Wire([edge6, edge8, edge1, edge7])
|
||||
profiles.append(p)
|
||||
shapes = self.makeSolids(obj, profiles, w, (vec_down_right + vec_down_left) / 2)
|
||||
|
||||
angle = 30
|
||||
height = FreeCAD.ActiveDocument.Site.Terrain.Shape.BoundBox.ZMax - obj.Height.Value
|
||||
offset = height / math.tan(math.radians(angle))
|
||||
|
||||
'''cutProfile = Part.makePolygon([vec_sand_left, vec_sand_right, vec_sand_right + FreeCAD.Vector(offset, 0, FreeCAD.ActiveDocument.Site.Terrain.Shape.BoundBox.ZMax),
|
||||
vec_sand_left + FreeCAD.Vector(-offset, 0, FreeCAD.ActiveDocument.Site.Terrain.Shape.BoundBox.ZMax), vec_sand_left])
|
||||
|
||||
height = obj.Height.Value - FreeCAD.ActiveDocument.Site.Terrain.Shape.BoundBox.ZMin
|
||||
offset = height / math.tan(math.radians(angle))
|
||||
fillProfile = Part.makePolygon([vec_sand_left, vec_sand_right, vec_sand_right + FreeCAD.Vector(offset, 0, FreeCAD.ActiveDocument.Site.Terrain.Shape.BoundBox.ZMin),
|
||||
vec_sand_left + FreeCAD.Vector(-offset, 0, FreeCAD.ActiveDocument.Site.Terrain.Shape.BoundBox.ZMin), vec_sand_left])
|
||||
|
||||
cutshapes, fillshapes = self.makeSolids(obj, [cutProfile, fillProfile], w, (vec_up_right + vec_up_left) / 2)
|
||||
cuts = self.calculateCut(obj, cutshapes)
|
||||
fills = self.calculateFill(obj, fillshapes)
|
||||
if cuts:
|
||||
for cut in cuts:
|
||||
Part.show(cut, "RoadCut")
|
||||
if fills:
|
||||
for fill in fills:
|
||||
Part.show(fill, "RoadFill")'''
|
||||
|
||||
obj.Shape = Part.makeCompound(shapes)
|
||||
|
||||
def makeSolids(self, obj, profiles, w, origen):
|
||||
import Draft
|
||||
import DraftGeomUtils
|
||||
|
||||
shapes = []
|
||||
for p in profiles:
|
||||
if hasattr(p, "CenterOfMass"):
|
||||
c = p.CenterOfMass
|
||||
else:
|
||||
c = p.BoundBox.Center
|
||||
c = origen
|
||||
delta = w.Vertexes[0].Point - c
|
||||
p.translate(delta)
|
||||
|
||||
if Draft.getType(obj.Base) == "BezCurve":
|
||||
v1 = obj.Base.Placement.multVec(obj.Base.Points[1]) - w.Vertexes[0].Point
|
||||
else:
|
||||
v1 = w.Vertexes[1].Point - w.Vertexes[0].Point
|
||||
v2 = DraftGeomUtils.getNormal(p)
|
||||
rot = FreeCAD.Rotation(v2, v1)
|
||||
#p.rotate(w.Vertexes[0].Point, rot.Axis, math.degrees(rot.Angle))
|
||||
ang = rot.toEuler()[0]
|
||||
p.Placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), ang)
|
||||
|
||||
if p.Faces:
|
||||
for f in p.Faces:
|
||||
sh = w.makePipeShell([f.OuterWire], True, False, 2)
|
||||
for shw in f.Wires:
|
||||
if shw.hashCode() != f.OuterWire.hashCode():
|
||||
sh2 = w.makePipeShell([shw], True, False, 2)
|
||||
sh = sh.cut(sh2)
|
||||
shapes.append(sh)
|
||||
elif p.Wires:
|
||||
for pw in p.Wires:
|
||||
sh = w.makePipeShell([pw], True, False, 2)
|
||||
shapes.append(sh)
|
||||
return shapes
|
||||
|
||||
def calculateFill(self, obj, solid):
|
||||
import BOPTools.SplitAPI as splitter
|
||||
common = solid.common(FreeCAD.ActiveDocument.Site.Terrain.Shape)
|
||||
if common.Area > 0:
|
||||
sp = splitter.slice(solid, [common, ], "Split")
|
||||
common.Placement.Base.z += 1
|
||||
solids = []
|
||||
for sol in sp.Solids:
|
||||
common1 = sol.common(common)
|
||||
if common1.Area > 0:
|
||||
solids.append(sol)
|
||||
if len(solids) > 0:
|
||||
return solids
|
||||
return None
|
||||
|
||||
def calculateCut(self, obj, solid):
|
||||
import BOPTools.SplitAPI as splitter
|
||||
common = solid.common(FreeCAD.ActiveDocument.Site.Terrain.Shape)
|
||||
if common.Area > 0:
|
||||
sp = splitter.slice(solid, [common, ], "Split")
|
||||
shells = []
|
||||
commoncopy = common.copy()
|
||||
commoncopy.Placement.Base.z -= 1
|
||||
for sol in sp.Solids:
|
||||
common1 = sol.common(commoncopy)
|
||||
if common1.Area > 0:
|
||||
shell = sol.Shells[0]
|
||||
shell = shell.cut(common)
|
||||
shells.append(shell)
|
||||
if len(shells) > 0:
|
||||
return shells
|
||||
return None
|
||||
|
||||
def makeLoft(self, profile):
|
||||
return
|
||||
|
||||
|
||||
class _ViewProviderRoad(ArchComponent.ViewProviderComponent):
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(PVPlantResources.DirIcons, "road.svg"))
|
||||
|
||||
class _RoadTaskPanel:
|
||||
|
||||
def __init__(self, obj=None):
|
||||
|
||||
if obj is None:
|
||||
self.new = True
|
||||
self.obj = makeRoad()
|
||||
else:
|
||||
self.new = False
|
||||
self.obj = obj
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(PVPlantResources.__dir__, "PVPlantRoad.ui"))
|
||||
|
||||
def accept(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
if self.new:
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import DraftVecUtils
|
||||
import draftutils.utils as utils
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.todo as todo
|
||||
import draftguitools.gui_base_original as gui_base_original
|
||||
import draftguitools.gui_tool_utils as gui_tool_utils
|
||||
|
||||
from draftutils.messages import _msg
|
||||
from draftutils.translate import translate
|
||||
|
||||
|
||||
class _CommandRoad(gui_base_original.Creator):
|
||||
"""Gui command for the Line tool."""
|
||||
|
||||
def __init__(self):
|
||||
# super(_CommandRoad, self).__init__()
|
||||
gui_base_original.Creator.__init__(self)
|
||||
self.path = None
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "road.svg")),
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PVPlantRoad", "Road"),
|
||||
'Accel': "C, R",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PVPlantRoad",
|
||||
"Creates a Road object from setup dialog.")}
|
||||
|
||||
def Activated(self, name=translate("draft", "Line")):
|
||||
"""Execute when the command is called."""
|
||||
|
||||
gui_base_original.Creator.Activated(self, name=translate("draft", "Line"))
|
||||
|
||||
self.obj = None # stores the temp shape
|
||||
self.oldWP = None # stores the WP if we modify it
|
||||
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
|
||||
done = False
|
||||
self.existing = []
|
||||
if len(sel) > 0:
|
||||
print("Crear una carretera a lo largo de un trayecto")
|
||||
# TODO: chequear que el objeto seleccionado sea un "wire"
|
||||
import Draft
|
||||
if Draft.getType(sel[0]) == "Wire":
|
||||
self.path = sel[0]
|
||||
done = True
|
||||
|
||||
if not done:
|
||||
self.ui.wireUi(name)
|
||||
self.ui.setTitle("Road")
|
||||
self.obj = self.doc.addObject("Part::Feature", self.featureName)
|
||||
gui_utils.format_object(self.obj)
|
||||
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
_msg(translate("draft", "Pick first point"))
|
||||
|
||||
def action(self, arg):
|
||||
"""Handle the 3D scene events.
|
||||
|
||||
This is installed as an EventCallback in the Inventor view.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg: dict
|
||||
Dictionary with strings that indicates the type of event received
|
||||
from the 3D view.
|
||||
"""
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
self.point, ctrlPoint, self.info = gui_tool_utils.getPoint(self, arg)
|
||||
gui_tool_utils.redraw3DView()
|
||||
elif (arg["Type"] == "SoMouseButtonEvent"
|
||||
and arg["State"] == "DOWN"
|
||||
and arg["Button"] == "BUTTON1"):
|
||||
if arg["Position"] == self.pos:
|
||||
return self.finish(False, cont=True)
|
||||
if (not self.node) and (not self.support):
|
||||
gui_tool_utils.getSupport(arg)
|
||||
self.point, ctrlPoint, self.info = gui_tool_utils.getPoint(self, arg)
|
||||
|
||||
if self.point:
|
||||
self.point = FreeCAD.Vector(self.info["x"], self.info["y"], self.info["z"])
|
||||
self.ui.redraw()
|
||||
self.pos = arg["Position"]
|
||||
self.node.append(self.point)
|
||||
self.drawSegment(self.point)
|
||||
if len(self.node) > 2:
|
||||
# The wire is closed
|
||||
if (self.point - self.node[0]).Length < utils.tolerance():
|
||||
self.undolast()
|
||||
if len(self.node) > 2:
|
||||
self.finish(True, cont=True)
|
||||
else:
|
||||
self.finish(False, cont=True)
|
||||
|
||||
def finish(self, closed=False, cont=False):
|
||||
"""Terminate the operation and close the polyline if asked.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
closed: bool, optional
|
||||
Close the line if `True`.
|
||||
"""
|
||||
self.removeTemporaryObject()
|
||||
if self.oldWP:
|
||||
App.DraftWorkingPlane = self.oldWP
|
||||
if hasattr(Gui, "Snapper"):
|
||||
Gui.Snapper.setGrid()
|
||||
Gui.Snapper.restack()
|
||||
self.oldWP = None
|
||||
|
||||
if len(self.node) > 1:
|
||||
|
||||
if False:
|
||||
Gui.addModule("Draft")
|
||||
# The command to run is built as a series of text strings
|
||||
# to be committed through the `draftutils.todo.ToDo` class.
|
||||
if (len(self.node) == 2
|
||||
and utils.getParam("UsePartPrimitives", False)):
|
||||
# Insert a Part::Primitive object
|
||||
p1 = self.node[0]
|
||||
p2 = self.node[-1]
|
||||
|
||||
_cmd = 'FreeCAD.ActiveDocument.'
|
||||
_cmd += 'addObject("Part::Line", "Line")'
|
||||
_cmd_list = ['line = ' + _cmd,
|
||||
'line.X1 = ' + str(p1.x),
|
||||
'line.Y1 = ' + str(p1.y),
|
||||
'line.Z1 = ' + str(p1.z),
|
||||
'line.X2 = ' + str(p2.x),
|
||||
'line.Y2 = ' + str(p2.y),
|
||||
'line.Z2 = ' + str(p2.z),
|
||||
'Draft.autogroup(line)',
|
||||
'FreeCAD.ActiveDocument.recompute()']
|
||||
self.commit(translate("draft", "Create Line"),
|
||||
_cmd_list)
|
||||
else:
|
||||
# Insert a Draft line
|
||||
rot, sup, pts, fil = self.getStrings()
|
||||
|
||||
_base = DraftVecUtils.toString(self.node[0])
|
||||
_cmd = 'Draft.makeWire'
|
||||
_cmd += '('
|
||||
_cmd += 'points, '
|
||||
_cmd += 'placement=pl, '
|
||||
_cmd += 'closed=' + str(closed) + ', '
|
||||
_cmd += 'face=' + fil + ', '
|
||||
_cmd += 'support=' + sup
|
||||
_cmd += ')'
|
||||
_cmd_list = ['pl = FreeCAD.Placement()',
|
||||
'pl.Rotation.Q = ' + rot,
|
||||
'pl.Base = ' + _base,
|
||||
'points = ' + pts,
|
||||
'line = ' + _cmd,
|
||||
'Draft.autogroup(line)',
|
||||
'FreeCAD.ActiveDocument.recompute()']
|
||||
self.commit(translate("draft", "Create Wire"),
|
||||
_cmd_list)
|
||||
else:
|
||||
import Draft
|
||||
self.path = Draft.makeWire(self.node, closed=False, face=False)
|
||||
|
||||
# super(_CommandRoad, self).finish()
|
||||
gui_base_original.Creator.finish(self)
|
||||
if self.ui and self.ui.continueMode:
|
||||
self.Activated()
|
||||
|
||||
self.makeRoad()
|
||||
|
||||
def makeRoad(self):
|
||||
makeRoad(self.path)
|
||||
|
||||
def removeTemporaryObject(self):
|
||||
"""Remove temporary object created."""
|
||||
if self.obj:
|
||||
try:
|
||||
old = self.obj.Name
|
||||
except ReferenceError:
|
||||
# object already deleted, for some reason
|
||||
pass
|
||||
else:
|
||||
todo.ToDo.delay(self.doc.removeObject, old)
|
||||
self.obj = None
|
||||
|
||||
def undolast(self):
|
||||
"""Undoes last line segment."""
|
||||
import Part
|
||||
if len(self.node) > 1:
|
||||
self.node.pop()
|
||||
# last = self.node[-1]
|
||||
if self.obj.Shape.Edges:
|
||||
edges = self.obj.Shape.Edges
|
||||
if len(edges) > 1:
|
||||
newshape = Part.makePolygon(self.node)
|
||||
self.obj.Shape = newshape
|
||||
else:
|
||||
self.obj.ViewObject.hide()
|
||||
# DNC: report on removal
|
||||
# _msg(translate("draft", "Removing last point"))
|
||||
_msg(translate("draft", "Pick next point"))
|
||||
|
||||
def drawSegment(self, point):
|
||||
"""Draws new line segment."""
|
||||
import Part
|
||||
if self.planetrack and self.node:
|
||||
self.planetrack.set(self.node[-1])
|
||||
if len(self.node) == 1:
|
||||
_msg(translate("draft", "Pick next point"))
|
||||
elif len(self.node) == 2:
|
||||
last = self.node[len(self.node) - 2]
|
||||
newseg = Part.LineSegment(last, point).toShape()
|
||||
self.obj.Shape = newseg
|
||||
self.obj.ViewObject.Visibility = True
|
||||
_msg(translate("draft", "Pick next point"))
|
||||
else:
|
||||
currentshape = self.obj.Shape.copy()
|
||||
last = self.node[len(self.node) - 2]
|
||||
if not DraftVecUtils.equals(last, point):
|
||||
newseg = Part.LineSegment(last, point).toShape()
|
||||
newshape = currentshape.fuse(newseg)
|
||||
self.obj.Shape = newshape
|
||||
_msg(translate("draft", "Pick next point"))
|
||||
|
||||
def wipe(self):
|
||||
"""Remove all previous segments and starts from last point."""
|
||||
if len(self.node) > 1:
|
||||
# self.obj.Shape.nullify() # For some reason this fails
|
||||
self.obj.ViewObject.Visibility = False
|
||||
self.node = [self.node[-1]]
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.node[0])
|
||||
_msg(translate("draft", "Pick next point"))
|
||||
|
||||
def orientWP(self):
|
||||
"""Orient the working plane."""
|
||||
import DraftGeomUtils
|
||||
if hasattr(App, "DraftWorkingPlane"):
|
||||
if len(self.node) > 1 and self.obj:
|
||||
n = DraftGeomUtils.getNormal(self.obj.Shape)
|
||||
if not n:
|
||||
n = App.DraftWorkingPlane.axis
|
||||
p = self.node[-1]
|
||||
v = self.node[-2].sub(self.node[-1])
|
||||
v = v.negative()
|
||||
if not self.oldWP:
|
||||
self.oldWP = App.DraftWorkingPlane.copy()
|
||||
App.DraftWorkingPlane.alignToPointAndAxis(p, n, upvec=v)
|
||||
if hasattr(Gui, "Snapper"):
|
||||
Gui.Snapper.setGrid()
|
||||
Gui.Snapper.restack()
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.node[-1])
|
||||
|
||||
def numericInput(self, numx, numy, numz):
|
||||
"""Validate the entry fields in the user interface.
|
||||
|
||||
This function is called by the toolbar or taskpanel interface
|
||||
when valid x, y, and z have been entered in the input fields.
|
||||
"""
|
||||
self.point = App.Vector(numx, numy, numz)
|
||||
self.node.append(self.point)
|
||||
self.drawSegment(self.point)
|
||||
self.ui.setNextFocus()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantRoad', _CommandRoad())
|
||||
105
PVPlantSetMatrixManual.ui
Normal file
105
PVPlantSetMatrixManual.ui
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<author>Javier Braña</author>
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>466</width>
|
||||
<height>568</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Park Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Columnas:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonFrame">
|
||||
<property name="text">
|
||||
<string>Detectar columnas automáticamente</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Columnas:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Filas</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget_2"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
1192
PVPlantSite.py
Normal file
1192
PVPlantSite.py
Normal file
File diff suppressed because it is too large
Load Diff
212
PVPlantStringSetup.ui
Normal file
212
PVPlantStringSetup.ui
Normal file
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>form</class>
|
||||
<widget class="QDialog" name="form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>470</width>
|
||||
<height>478</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Terrain Analisys</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="editFrame">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonSelFrame">
|
||||
<property name="text">
|
||||
<string>sel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Frame information: </string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="editLeft">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QListWidget" name="listStrings"/>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAddString">
|
||||
<property name="text">
|
||||
<string>Add String</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Delete String</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" rowspan="2" colspan="2">
|
||||
<widget class="QListWidget" name="listModules"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editTotal">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="editUsed">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Totales</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Usados</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Restantes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Paneles:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Frame type: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="editName"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>String Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
593
PVPlantStringing.py
Normal file
593
PVPlantStringing.py
Normal file
@@ -0,0 +1,593 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 math
|
||||
|
||||
import ArchComponent
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
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
|
||||
|
||||
import os
|
||||
__dir__ = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", "PVPlant")
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
Dir3dObjects = os.path.join(PVPlantResources.DirResources, "3dObjects")
|
||||
|
||||
def makeStringSetup():
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "StringSetup")
|
||||
_StringSetup(obj)
|
||||
_ViewProviderStringSetup(obj.ViewObject)
|
||||
|
||||
try:
|
||||
if FreeCAD.ActiveDocument.StringsSetup:
|
||||
FreeCAD.ActiveDocument.StringsSetup.addObject(obj)
|
||||
except:
|
||||
pass
|
||||
return obj
|
||||
|
||||
class _StringSetup:
|
||||
def __init__(self, obj):
|
||||
self.setCommonProperties(obj)
|
||||
self.obj = obj
|
||||
self.StringCount = 1
|
||||
|
||||
def setCommonProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("NumberOfStrings" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"NumberOfStrings",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).NumberOfStrings = 0
|
||||
obj.setEditorMode("NumberOfStrings", 1)
|
||||
|
||||
self.Type = "StringSetup"
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
self.setProperties(obj)
|
||||
|
||||
def addString(self, modulelist):
|
||||
stringName = "String" + str(self.StringCount)
|
||||
self.obj.addProperty("App::PropertyIntegerList",
|
||||
stringName,
|
||||
"Setup",
|
||||
"String: " + stringName
|
||||
)
|
||||
setattr(self.obj, stringName, modulelist)
|
||||
|
||||
'''
|
||||
self.obj.addProperty("App::PropertyInteger",
|
||||
stringName + "_Power",
|
||||
"Outputs",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
)
|
||||
setattr(self.obj, stringName + "_Power", len(modulelist) * 450)
|
||||
'''
|
||||
self.obj.NumberOfStrings = self.StringCount
|
||||
self.StringCount += 1
|
||||
|
||||
|
||||
class _ViewProviderStringSetup:
|
||||
def __init__(self, vobj):
|
||||
'''
|
||||
Set view properties.
|
||||
'''
|
||||
self.Object = vobj.Object
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
'''
|
||||
Create Object visuals in 3D view.
|
||||
'''
|
||||
self.Object = vobj.Object
|
||||
return
|
||||
|
||||
def getIcon(self):
|
||||
'''
|
||||
Return object treeview icon.
|
||||
'''
|
||||
|
||||
return str(os.path.join(DirIcons, "stringsetup.svg"))
|
||||
'''
|
||||
def claimChildren(self):
|
||||
"""
|
||||
Provides object grouping
|
||||
"""
|
||||
return self.Object.Group
|
||||
'''
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Enable edit
|
||||
"""
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Disable edit
|
||||
"""
|
||||
return False
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
"""
|
||||
Detect double click
|
||||
"""
|
||||
pass
|
||||
|
||||
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 _SelObserver:
|
||||
def __init__(self, form):
|
||||
self.form = form
|
||||
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
rack = FreeCAD.ActiveDocument.getObjectsByLabel(obj)[0].Shape
|
||||
modules = rack.SubShapes[0].SubShapes[0].SubShapes
|
||||
if sub[0:4] == 'Face':
|
||||
numFace = int(sub.replace('Face', '')) - 1
|
||||
selFace = rack.Faces[numFace]
|
||||
for module in modules:
|
||||
for num, face in enumerate(module.Faces):
|
||||
if selFace.isSame(face):
|
||||
self.form.setModule(modules.index(module))
|
||||
FreeCADGui.Selection
|
||||
return True
|
||||
|
||||
elif sub[0:4] == 'Edge':
|
||||
numEdge = int(sub.replace('Edge', '')) - 1
|
||||
selEdge = rack.Edge[numEdge]
|
||||
for module in modules:
|
||||
for num, edge in enumerate(module.Edges):
|
||||
if selEdge.isSame(edge):
|
||||
print("Encontrado: ", modules.index(module))
|
||||
return True
|
||||
return True
|
||||
|
||||
def removeSelection(self, doc, obj, sub): # Delete the selected object
|
||||
'''print("FSO-RemSel:" + str(obj) + ":" + str(sub) + "\n")'''
|
||||
return True
|
||||
|
||||
def setSelection(self, doc): # Selection in ComboView
|
||||
'''print("FSO-SetSel:" + "\n")'''
|
||||
return True
|
||||
|
||||
def clearSelection(self, doc): # If click on the screen, clear the selection
|
||||
'''print("FSO-ClrSel:" + "\n")'''
|
||||
return True
|
||||
|
||||
class _StringSetupPanel:
|
||||
def __init__(self, obj=None):
|
||||
self.obj = obj
|
||||
self.new = False
|
||||
|
||||
if obj is None:
|
||||
self.new = True
|
||||
self.obj = makeStringSetup()
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(__dir__ + "/PVPlantStringSetup.ui")
|
||||
self.form.buttonSelFrame.clicked.connect(self.selFrame)
|
||||
self.form.buttonAddString.clicked.connect(self.addString)
|
||||
self.form.listStrings.currentRowChanged.connect(self.listStringsCurrentRowChanged)
|
||||
self.form.editName.editingFinished.connect(self.setStringName)
|
||||
|
||||
self.selobserver = _SelObserver(self)
|
||||
self.stringslist = []
|
||||
self.currentstring = 0
|
||||
self.totalModules = 0
|
||||
self.left = 0
|
||||
|
||||
self.frameColor = None
|
||||
|
||||
def selFrame(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
frame = None
|
||||
if len(sel) == 0:
|
||||
# TODO: lanzar un error
|
||||
return
|
||||
elif len(sel) == 1:
|
||||
frame = sel[0]
|
||||
else:
|
||||
for obj in sel:
|
||||
if not hasattr(obj, 'Proxy'):
|
||||
continue
|
||||
print(obj.Proxy.__class__)
|
||||
print(issubclass(obj.Proxy.__class__, PVPlantRack._Frame))
|
||||
if issubclass(obj.Proxy.__class__, PVPlantRack._Frame):
|
||||
frame = obj
|
||||
break
|
||||
|
||||
if frame == None:
|
||||
# TODO: lanzar un error
|
||||
print("No frame selected")
|
||||
return
|
||||
|
||||
self.frame = frame
|
||||
self.form.editFrame.setText(frame.Label)
|
||||
self.totalModules = frame.ModuleCols * frame.ModuleRows
|
||||
self.left = self.totalModules
|
||||
self.form.editTotal.setText(str(int(self.totalModules)))
|
||||
self.form.editUsed.setText("0")
|
||||
self.form.editLeft.setText(str(int(self.left)))
|
||||
|
||||
FreeCADGui.Selection.removeObserver(self.selobserver)
|
||||
FreeCADGui.Selection.addObserver(self.selobserver)
|
||||
|
||||
self.frameColor = self.obj.ViewObject.ShapeColor
|
||||
self.colorlist = []
|
||||
for face in self.frame.Shape.Faces:
|
||||
self.colorlist.append((1.0, 0.50, 0.40, 0.25))
|
||||
self.frame.ViewObject.DiffuseColor = self.colorlist
|
||||
|
||||
def addString(self):
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
self.stringslist.append([])
|
||||
self.currentstring = len(self.stringslist) - 1
|
||||
self.form.listStrings.addItem("String" + str(self.form.listStrings.count()))
|
||||
self.form.listStrings.setCurrentRow(self.form.listStrings.count() - 1)
|
||||
|
||||
def listStringsCurrentRowChanged(self, row):
|
||||
self.currentstring = row
|
||||
self.form.listModules.clear()
|
||||
for num in self.stringslist[row]:
|
||||
self.form.listModules.addItem(str(num))
|
||||
|
||||
def setModule(self, numModule):
|
||||
if len(self.stringslist) == 0:
|
||||
return
|
||||
|
||||
if self.left == 0:
|
||||
return
|
||||
|
||||
if numModule in self.stringslist[self.currentstring]:
|
||||
'''remove module ?? '''
|
||||
self.stringslist[self.currentstring].remove(int(numModule))
|
||||
item = self.form.listModules.findItems(str(numModule), QtCore.Qt.MatchExactly)[0]
|
||||
self.form.listModules.takeItem(self.form.listModules.row(item))
|
||||
for moduleFace in self.frame.Shape.Solids[numModule].Faces:
|
||||
for i, face in enumerate(self.frame.Shape.Faces):
|
||||
if moduleFace.isEqual(face):
|
||||
self.colorlist[i] = (1.0, 0.50, 0.40, 0.25)
|
||||
self.frame.ViewObject.DiffuseColor = self.colorlist
|
||||
break
|
||||
else:
|
||||
self.stringslist[self.currentstring].append(int(numModule))
|
||||
self.form.listModules.addItem(str(numModule))
|
||||
for moduleFace in self.frame.Shape.Solids[numModule].Faces:
|
||||
for i, face in enumerate(self.frame.Shape.Faces):
|
||||
if moduleFace.isEqual(face):
|
||||
self.colorlist[i] = (0.0, 0.0, 1.0, 0.0)
|
||||
self.frame.ViewObject.DiffuseColor = self.colorlist
|
||||
break
|
||||
|
||||
self.calculateModules()
|
||||
|
||||
def calculateModules(self):
|
||||
num = 0
|
||||
for string in self.stringslist:
|
||||
num += len(string)
|
||||
|
||||
self.left = int(self.totalModules - num)
|
||||
self.form.editUsed.setText(str(num))
|
||||
self.form.editLeft.setText(str(self.left))
|
||||
|
||||
def setStringName(self):
|
||||
self.obj.Label = self.form.editName.text()
|
||||
|
||||
def accept(self):
|
||||
for string in self.stringslist:
|
||||
self.obj.Proxy.addString(string.copy())
|
||||
self.FormClosing()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
self.FormClosing()
|
||||
return True
|
||||
|
||||
def FormClosing(self):
|
||||
FreeCADGui.Selection.removeObserver(self.selobserver)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
self.frame.ViewObject.DiffuseColor = self.frameColor
|
||||
|
||||
def makeString(base=None):
|
||||
if base is None:
|
||||
return
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "String")
|
||||
_String(obj)
|
||||
obj.Frame = base
|
||||
_ViewProviderString(obj.ViewObject)
|
||||
|
||||
if FreeCAD.ActiveDocument.Strings:
|
||||
FreeCAD.ActiveDocument.Strings.addObject(obj)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
|
||||
class _String(ArchComponent.Component):
|
||||
def __init__(self, obj):
|
||||
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
obj.Proxy = self
|
||||
obj.IfcType = "Cable Segment"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not ("Frame" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Frame",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).Frame = None
|
||||
|
||||
if not ("StringSetup" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"StringSetup",
|
||||
"Setup",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).StringSetup = None
|
||||
|
||||
if not ("StringPoles" in pl):
|
||||
obj.addProperty("App::PropertyVectorList",
|
||||
"StringPoles",
|
||||
"StringOutput",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||||
).StringPoles = []
|
||||
obj.setEditorMode("StringPoles", 1)
|
||||
|
||||
self.Type = "String"
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
obj.Proxy = self
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
def onBeforeChange(self, obj, prop):
|
||||
''''''
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
def getDownFace(module):
|
||||
area_max = max([face.Area for face in module.Faces])
|
||||
faces = []
|
||||
for face in module.Faces:
|
||||
if face.Area == area_max:
|
||||
faces.append(face)
|
||||
return faces[0] if faces[0].Placement.Base.z > faces[1].Placement.Base.z else faces[1]
|
||||
|
||||
if (prop == "Frame") or (prop == "StringSetup"):
|
||||
if not (obj.Frame is None) and not (obj.StringSetup is None):
|
||||
JuntionBoxPosition = 200
|
||||
portrait = obj.Frame.ModuleOrientation == "Portrait"
|
||||
cableLength = 1200
|
||||
if hasattr(obj.Frame, "PoleCableLength"):
|
||||
cableLength = obj.Frame.PoleCableLength.Value
|
||||
|
||||
moduleWidth = obj.Frame.ModuleWidth.Value
|
||||
moduleHeight = obj.Frame.ModuleHeight.Value
|
||||
dist_x = JuntionBoxPosition + obj.Frame.ModuleColGap.Value + (
|
||||
moduleWidth if portrait else moduleHeight) / 2
|
||||
dist_y = obj.Frame.ModuleRowGap.Value + (moduleHeight if portrait else moduleWidth)
|
||||
|
||||
PolePosition = 0
|
||||
if portrait:
|
||||
PolePosition = moduleWidth / 2 - JuntionBoxPosition
|
||||
|
||||
FrameModules = obj.Frame.Shape.SubShapes[0].SubShapes[0].SubShapes
|
||||
cableProfile = Part.Face(Part.Wire(Part.Circle(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(1, 0, 0), 6).toShape()))
|
||||
positiveMC4 = Part.Shape()
|
||||
positiveMC4.read(os.path.join(Dir3dObjects, "MC4 POSITIVE.IGS"))
|
||||
negativeMC4 = Part.Shape()
|
||||
negativeMC4.read(os.path.join(Dir3dObjects, "MC4 NEGATIVE.IGS"))
|
||||
|
||||
vec = None
|
||||
if obj.Frame.Route:
|
||||
vertexes = obj.Frame.Route.Shape.Vertexes
|
||||
vec = vertexes[1].Point - vertexes[0].Point
|
||||
else:
|
||||
poles = obj.Frame.Shape.SubShapes[1].SubShapes
|
||||
vec = poles[1].BoundBox.Center - poles[0].BoundBox.Center
|
||||
vecp= FreeCAD.Vector(-vec.y, vec.x, vec.z)
|
||||
# V1:
|
||||
for stringnum in range(obj.StringSetup.NumberOfStrings):
|
||||
''''''
|
||||
|
||||
return
|
||||
# V0:
|
||||
for stringnum in range(obj.StringSetup.NumberOfStrings):
|
||||
string = obj.StringSetup.getPropertyByName("String" + str(stringnum + 1))
|
||||
total = len(string) - 1
|
||||
dir = 0
|
||||
ndir = 0
|
||||
# dirvec = FrameModules(string[-]).Placement.Base - FrameModules(string[0]).Placement.Base
|
||||
for i, num in enumerate(string):
|
||||
face = getDownFace(FrameModules[num])
|
||||
|
||||
if i < total:
|
||||
dir = string[i + 1] - num
|
||||
dir /= abs(dir)
|
||||
ndir = -dir
|
||||
|
||||
positivePolePosition = FreeCAD.Vector(0, ndir * PolePosition, 0) + face.CenterOfMass
|
||||
negativePolePosition = FreeCAD.Vector(0, dir * PolePosition, 0) + face.CenterOfMass
|
||||
|
||||
# dibujar +:
|
||||
p1 = positivePolePosition
|
||||
p2 = p1 + ndir * FreeCAD.Vector(0, 50, 0)
|
||||
p3 = p2 + ndir * FreeCAD.Vector(cableLength - dist_x, 0, 0)
|
||||
p4 = p3 + ndir * FreeCAD.Vector(0, dist_x - 50, 0)
|
||||
w = Part.makePolygon([p1, p2, p3, p4])
|
||||
#cableProfile.Placement.Base = p1
|
||||
#cable = w.makePipeShell([cableProfile], True, False, 2)
|
||||
Part.show(w)
|
||||
mc4copy = positiveMC4.copy()
|
||||
mc4copy.Placement.Base = p4 + FreeCAD.Vector(0, mc4copy.BoundBox.XLength/2 + 1.3, 0)
|
||||
positiveMC4.Placement.Rotation.Angle = math.radians(ndir * 90)
|
||||
Part.show(mc4copy)
|
||||
|
||||
# dibujar -:
|
||||
p1 = negativePolePosition
|
||||
p2 = p1 + dir * FreeCAD.Vector(0, 50, 0)
|
||||
p3 = p2 + ndir * FreeCAD.Vector(cableLength - dist_x, 0, 0)
|
||||
p4 = p3 + dir * FreeCAD.Vector(0, dist_x - 50, 0)
|
||||
w = Part.makePolygon([p1, p2, p3, p4])
|
||||
Part.show(w)
|
||||
mc4copy = negativeMC4.copy()
|
||||
mc4copy.Placement.Base = p4 - FreeCAD.Vector(0, mc4copy.BoundBox.XLength/2 + 1.3, 0)
|
||||
mc4copy.Placement.Rotation.Angle = math.radians(dir * 90)
|
||||
Part.show(mc4copy)
|
||||
|
||||
if i == 0 or i == total:
|
||||
list = obj.StringPoles.copy()
|
||||
list.append(p3)
|
||||
obj.StringPoles = list
|
||||
break
|
||||
|
||||
def execute(self, obj):
|
||||
'''Do something when recompute'''
|
||||
|
||||
|
||||
class _ViewProviderString(ArchComponent.ViewProviderComponent):
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(DirIcons, "string.svg"))
|
||||
|
||||
|
||||
|
||||
class _CommandStringSetup:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "stringsetup.svg")),
|
||||
'Accel': "E, C",
|
||||
'MenuText': "String Setup",
|
||||
'ToolTip': "Configure strings of a Frame"}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _StringSetupPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
class _CommandStringing:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "string.svg")),
|
||||
'Accel': "E, S",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Placement", "String"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Make string on a Frame")}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
# issubclass(Car, Vehicles)
|
||||
# isinstance(Car, Vehicles)
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
for obj in sel:
|
||||
if obj.Name.__contains__("Tracker"):
|
||||
makeString(obj)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class _CommandStringingGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['PVPlantStringSetup',
|
||||
'PVPlantStringing'
|
||||
])
|
||||
|
||||
def GetResources(self):
|
||||
return {'MenuText': 'Stringing',
|
||||
'ToolTip': 'Tools to setup and make strings'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand('PVPlantStringSetup', _CommandStringSetup())
|
||||
FreeCADGui.addCommand('PVPlantStringing', _CommandStringing())
|
||||
FreeCADGui.addCommand('Stringing', _CommandStringingGroup())
|
||||
|
||||
|
||||
292
PVPlantSurface.py
Normal file
292
PVPlantSurface.py
Normal file
@@ -0,0 +1,292 @@
|
||||
import copy
|
||||
import random
|
||||
|
||||
import FreeCAD
|
||||
import Mesh
|
||||
from freecad.trails import ICONPATH, geo_origin
|
||||
from pivy import coin
|
||||
|
||||
|
||||
def create(name='Surface'):
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Surface")
|
||||
obj.Label = name
|
||||
Surface(obj)
|
||||
ViewProviderSurface(obj.ViewObject)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
#class Surface(SurfaceFunc):
|
||||
class Surface(ArchComponent.Component):
|
||||
"""
|
||||
This class is about Surface Object data features.
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
'''
|
||||
Set data properties.
|
||||
'''
|
||||
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
|
||||
self.Type = 'PVPlant::Surface'
|
||||
self.setproperties()
|
||||
obj.Proxy = self
|
||||
|
||||
# Does a IfcType exist?
|
||||
obj.IfcType = "Civil Element"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
def setproperties(self):
|
||||
# Triangulation properties.
|
||||
obj.addProperty(
|
||||
'App::PropertyLinkList', "PointGroups", "Base",
|
||||
"List of Point Groups").PointGroups = []
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerList", "Delaunay", "Base",
|
||||
"Index of Delaunay vertices", 4).Delaunay = []
|
||||
|
||||
obj.addProperty(
|
||||
"Mesh::PropertyMeshKernel", "Mesh", "Base",
|
||||
"Mesh object of triangulation").Mesh = Mesh.Mesh()
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyLength", "MaxLength", "Base",
|
||||
"Maximum length of triangle edge").MaxLength = 50000
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyAngle", "MaxAngle", "Base",
|
||||
"Maximum angle of triangle edge").MaxAngle = 170
|
||||
|
||||
# Contour properties.
|
||||
obj.addProperty(
|
||||
"App::PropertyFloatConstraint", "ContourInterval", "Contour",
|
||||
"Size of the point group").ContourInterval = (1.0, 0.0, 100.0, 1.0)
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyVectorList", "ContourPoints", "Contour",
|
||||
"Points of contours", 4).ContourPoints = []
|
||||
|
||||
obj.addProperty(
|
||||
"App::PropertyIntegerList", "ContourVertices", "Contour",
|
||||
"Vertices of contours.", 4).ContourVertices = []
|
||||
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''
|
||||
Do something when a data property has changed.
|
||||
'''
|
||||
|
||||
points = []
|
||||
pgs = obj.getPropertyByName("PointGroups")
|
||||
for pg in pgs:
|
||||
points.extend(pg.Points)
|
||||
if points:
|
||||
origin = geo_origin.get(points[0])
|
||||
else:
|
||||
origin = geo_origin.get()
|
||||
|
||||
if prop == "PointGroups":
|
||||
if len(points) > 2:
|
||||
obj.Delaunay = self.triangulate(points)
|
||||
else:
|
||||
obj.Mesh = Mesh.Mesh()
|
||||
|
||||
if prop == "Delaunay" or prop == "MaxLength" or prop == "MaxAngle":
|
||||
delaunay = obj.getPropertyByName("Delaunay")
|
||||
lmax = obj.getPropertyByName("MaxLength")
|
||||
amax = obj.getPropertyByName("MaxAngle")
|
||||
|
||||
if delaunay:
|
||||
obj.Mesh = self.test_delaunay(
|
||||
origin.Origin, points, delaunay, lmax, amax)
|
||||
|
||||
if prop == "Mesh" or prop == "ContourInterval":
|
||||
deltaH = obj.getPropertyByName("ContourInterval")
|
||||
mesh = obj.getPropertyByName("Mesh")
|
||||
|
||||
coords, num_vert = self.contour_points(origin.Origin, mesh, deltaH)
|
||||
|
||||
obj.ContourPoints = coords
|
||||
obj.ContourVertices = num_vert
|
||||
|
||||
def execute(self, obj):
|
||||
'''
|
||||
Do something when doing a recomputation.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class ViewProviderSurface:
|
||||
"""
|
||||
This class is about Surface Object view features.
|
||||
"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
'''
|
||||
Set view properties.
|
||||
'''
|
||||
(r, g, b) = (random.random(), random.random(), random.random())
|
||||
|
||||
vobj.addProperty(
|
||||
"App::PropertyColor", "TriangleColor", "Surface Style",
|
||||
"Color of the point group").TriangleColor = (r, g, b)
|
||||
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
'''
|
||||
Create Object visuals in 3D view.
|
||||
'''
|
||||
# GeoCoords Node.
|
||||
self.geo_coords = coin.SoGeoCoordinate()
|
||||
|
||||
# Surface features.
|
||||
self.triangles = coin.SoIndexedFaceSet()
|
||||
shape_hints = coin.SoShapeHints()
|
||||
shape_hints.vertex_ordering = coin.SoShapeHints.COUNTERCLOCKWISE
|
||||
self.mat_color = coin.SoMaterial()
|
||||
mat_binding = coin.SoMaterialBinding()
|
||||
mat_binding.value = coin.SoMaterialBinding.OVERALL
|
||||
edge_color = coin.SoBaseColor()
|
||||
edge_color.rgb = (0.5, 0.5, 0.5)
|
||||
offset = coin.SoPolygonOffset()
|
||||
|
||||
# Line style.
|
||||
line_style = coin.SoDrawStyle()
|
||||
line_style.style = coin.SoDrawStyle.LINES
|
||||
line_style.lineWidth = 2
|
||||
|
||||
# Contour features.
|
||||
cont_color = coin.SoBaseColor()
|
||||
cont_color.rgb = (1, 1, 0)
|
||||
self.cont_coords = coin.SoGeoCoordinate()
|
||||
self.cont_lines = coin.SoLineSet()
|
||||
|
||||
# Contour root.
|
||||
contours = coin.SoSeparator()
|
||||
contours.addChild(cont_color)
|
||||
contours.addChild(line_style)
|
||||
contours.addChild(self.cont_coords)
|
||||
contours.addChild(self.cont_lines)
|
||||
|
||||
# Face root.
|
||||
faces = coin.SoSeparator()
|
||||
faces.addChild(shape_hints)
|
||||
faces.addChild(self.mat_color)
|
||||
faces.addChild(mat_binding)
|
||||
faces.addChild(self.geo_coords)
|
||||
faces.addChild(self.triangles)
|
||||
|
||||
# Highlight for selection.
|
||||
highlight = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
highlight.style = 'EMISSIVE_DIFFUSE'
|
||||
highlight.addChild(edge_color)
|
||||
highlight.addChild(line_style)
|
||||
highlight.addChild(self.geo_coords)
|
||||
highlight.addChild(self.triangles)
|
||||
|
||||
# Surface root.
|
||||
surface_root = coin.SoSeparator()
|
||||
surface_root.addChild(contours)
|
||||
surface_root.addChild(offset)
|
||||
surface_root.addChild(faces)
|
||||
surface_root.addChild(offset)
|
||||
surface_root.addChild(highlight)
|
||||
vobj.addDisplayMode(surface_root, "Surface")
|
||||
|
||||
# Take features from properties.
|
||||
self.onChanged(vobj, "TriangleColor")
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
'''
|
||||
Update Object visuals when a view property changed.
|
||||
'''
|
||||
try:
|
||||
if prop == "TriangleColor":
|
||||
color = vobj.getPropertyByName("TriangleColor")
|
||||
self.mat_color.diffuseColor = (color[0], color[1], color[2])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
'''
|
||||
Update Object visuals when a data property changed.
|
||||
'''
|
||||
if prop == "Mesh":
|
||||
mesh = obj.getPropertyByName("Mesh")
|
||||
topo_points = mesh.Topology[0]
|
||||
topo_tri = mesh.Topology[1]
|
||||
|
||||
# Get GeoOrigin.
|
||||
points = []
|
||||
triangles = []
|
||||
origin = geo_origin.get()
|
||||
base = copy.deepcopy(origin.Origin)
|
||||
base.z = 0
|
||||
|
||||
for i in topo_points:
|
||||
point = copy.deepcopy(i)
|
||||
points.append(point.add(base))
|
||||
|
||||
for i in topo_tri:
|
||||
triangles.extend(list(i))
|
||||
triangles.append(-1)
|
||||
|
||||
# Set GeoCoords.
|
||||
geo_system = ["UTM", origin.UtmZone, "FLAT"]
|
||||
self.geo_coords.geoSystem.setValues(geo_system)
|
||||
self.geo_coords.point.values = points
|
||||
|
||||
# Set contour system.
|
||||
self.cont_coords.geoSystem.setValues(geo_system)
|
||||
self.triangles.coordIndex.values = triangles
|
||||
|
||||
if prop == "Mesh" or prop == "ContourInterval":
|
||||
cont_points = obj.getPropertyByName("ContourPoints")
|
||||
cont_vert = obj.getPropertyByName("ContourVertices")
|
||||
|
||||
self.cont_coords.point.values = cont_points
|
||||
self.cont_lines.numVertices.values = cont_vert
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
'''
|
||||
Return a list of display modes.
|
||||
'''
|
||||
modes = []
|
||||
modes.append("Surface")
|
||||
|
||||
return modes
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
'''
|
||||
Return the name of the default display mode.
|
||||
'''
|
||||
return "Surface"
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
'''
|
||||
Map the display mode defined in attach with
|
||||
those defined in getDisplayModes.
|
||||
'''
|
||||
return mode
|
||||
|
||||
def getIcon(self):
|
||||
'''
|
||||
Return object treeview icon.
|
||||
'''
|
||||
return ICONPATH + '/icons/Surface.svg'
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Save variables to file.
|
||||
"""
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Get variables from file.
|
||||
"""
|
||||
return None
|
||||
695
PVPlantTerrain.py
Normal file
695
PVPlantTerrain.py
Normal file
@@ -0,0 +1,695 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 copy
|
||||
|
||||
import ArchComponent
|
||||
import FreeCAD
|
||||
import Part
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
import PVPlantSite
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from pivy import coin
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "FreeCAD Fixed Rack"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
__dir__ = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", "PVPlant")
|
||||
|
||||
DirResources = os.path.join(__dir__, "Resources")
|
||||
DirIcons = os.path.join(DirResources, "Icons")
|
||||
DirImages = os.path.join(DirResources, "Images")
|
||||
|
||||
line_patterns = {
|
||||
"Continues _______________________________": 0xFFFF,
|
||||
"Border __ . __ __ . __ __ . __ __ . __": 0x3CF2,
|
||||
"Border (.5x) __.__.__.__.__.__.__.__.__.__._": 0x3939,
|
||||
"Border (2x) ____ ____ . ____ ____ . _": 0xFDFA,
|
||||
"Center ____ _ ____ _ ____ _ ____ _ ___": 0xFF3C,
|
||||
"Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ _": 0xFC78,
|
||||
"Center (2x) ________ __ ________ __ ___": 0xFFDE,
|
||||
"Dash dot __ . __ . __ . __ . __ . __ . _": 0xE4E4,
|
||||
"Dash dot (.5x) _._._._._._._._._._._._._._._._": 0xEBAE,
|
||||
"Dash dot (2x) ____ . ____ . ____ . ____": 0xFF08,
|
||||
"Dashed __ __ __ __ __ __ __ __ __ __ _": 0x739C,
|
||||
"Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _": 0xDB6E,
|
||||
"Dashed (2x) ____ ____ ____ ____ ____ _": 0xFFE0,
|
||||
"Divide ____ . . ____ . . ____ . . ____": 0xFF24,
|
||||
"Divide (.5x) __..__..__..__..__..__..__..__.": 0xEAEA,
|
||||
"Divide (2x) ________ . . ________ . . ": 0xFFEA,
|
||||
"Dot . . . . . . . . . . . . . . . .": 0x4924,
|
||||
"Dot (.5x) ...............................": 0x5555,
|
||||
"Dot (2x) . . . . . . . . . . .": 0x8888}
|
||||
|
||||
def makeTerrain(name="Terrain"):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Terrain")
|
||||
obj.Label = name
|
||||
Terrain(obj)
|
||||
ViewProviderTerrain(obj.ViewObject)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
|
||||
|
||||
class Terrain(ArchComponent.Component):
|
||||
"A Shadow Terrain Obcject"
|
||||
|
||||
def __init__(self, obj):
|
||||
# Definición de variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
self.obj = obj
|
||||
# Does a IfcType exist?
|
||||
# obj.IfcType = "Fence"
|
||||
# obj.MoveWithHost = False
|
||||
|
||||
self.site = PVPlantSite.get()
|
||||
self.site.Terrain = obj
|
||||
obj.ViewObject.ShapeColor = (0.0000, 0.6667, 0.4980)
|
||||
obj.ViewObject.LineColor = (0.0000, 0.6000, 0.4392)
|
||||
|
||||
def setProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
pl = obj.PropertiesList
|
||||
if not ("CuttingBoundary" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"CuttingBoundary",
|
||||
"Surface",
|
||||
"A boundary line to delimit the surface")
|
||||
|
||||
if not ("DEM" in pl):
|
||||
obj.addProperty("App::PropertyFile",
|
||||
"DEM",
|
||||
"Surface",
|
||||
"Load a ASC file to generate the surface")
|
||||
|
||||
if not ("PointsGroup" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"PointsGroup",
|
||||
"Surface",
|
||||
"Use a Point Group to generate the surface")
|
||||
|
||||
if not ("Mesh" in pl):
|
||||
obj.addProperty("Mesh::PropertyMeshKernel",
|
||||
"Mesh",
|
||||
"Surface",
|
||||
"Mesh")
|
||||
obj.setEditorMode("Mesh", 1)
|
||||
|
||||
if not ("InitialMesh" in pl):
|
||||
obj.addProperty("Mesh::PropertyMeshKernel",
|
||||
"InitialMesh",
|
||||
"Surface",
|
||||
"Mesh")
|
||||
obj.setEditorMode("InitialMesh", 1)
|
||||
|
||||
'''
|
||||
#obj.setEditorMode("Volume", 1)
|
||||
if not "AllowedAreas" in pl:
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"AllowedAreas",
|
||||
"Areas",
|
||||
"A boundary to delimitated the terrain").AllowedAreas = []
|
||||
if not "ProhibitedAreas" in pl:
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"ProhibitedAreas",
|
||||
"Areas",
|
||||
"A boundary to delimitated the terrain").ProhibitedAreas = []
|
||||
'''
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
if prop == "InitialMesh":
|
||||
obj.Mesh = obj.InitialMesh.copy()
|
||||
|
||||
if prop == "DEM" or prop == "CuttingBoundary":
|
||||
from datetime import datetime
|
||||
if obj.DEM and obj.CuttingBoundary:
|
||||
'''
|
||||
Parámetro Descripción Requisitos
|
||||
NCOLS: Cantidad de columnas de celdas Entero mayor que 0.
|
||||
NROWS: Cantidad de filas de celdas Entero mayor que 0.
|
||||
XLLCENTER o XLLCORNER: Coordenada X del origen (por el centro o la esquina inferior izquierda de la celda) Hacer coincidir con el tipo de coordenada y.
|
||||
YLLCENTER o YLLCORNER: Coordenada Y del origen (por el centro o la esquina inferior izquierda de la celda) Hacer coincidir con el tipo de coordenada x.
|
||||
CELLSIZE: Tamaño de celda Mayor que 0.
|
||||
NODATA_VALUE: Los valores de entrada que serán NoData en el ráster de salida Opcional. El valor predeterminado es -9999
|
||||
'''
|
||||
grid_space = 1
|
||||
file = open(obj.DEM, "r")
|
||||
templist = [line.split() for line in file.readlines()]
|
||||
file.close()
|
||||
del file
|
||||
|
||||
# Read meta data:
|
||||
meta = templist[0:6]
|
||||
nx = int(meta[0][1]) # NCOLS
|
||||
ny = int(meta[1][1]) # NROWS
|
||||
xllref = meta[2][0] # XLLCENTER / XLLCORNER
|
||||
xllvalue = round(float(meta[2][1]), 3)
|
||||
yllref = meta[3][0] # YLLCENTER / XLLCORNER
|
||||
yllvalue = round(float(meta[3][1]), 3)
|
||||
cellsize = round(float(meta[4][1]), 3) # CELLSIZE
|
||||
nodata_value = float(meta[5][1]) # NODATA_VALUE
|
||||
|
||||
# set coarse_factor
|
||||
coarse_factor = max(round(grid_space / cellsize), 1)
|
||||
|
||||
# Get z values
|
||||
templist = templist[6:(6 + ny)]
|
||||
templist = [templist[i][0::coarse_factor] for i in np.arange(0, len(templist), coarse_factor)]
|
||||
datavals = np.array(templist).astype(float)
|
||||
del templist
|
||||
|
||||
# create xy coordinates
|
||||
import PVPlantSite
|
||||
offset = PVPlantSite.get().Origin
|
||||
x = 1000 * (cellsize * np.arange(nx)[0::coarse_factor] + xllvalue) - offset.x
|
||||
y = 1000 * (cellsize * np.arange(ny)[-1::-1][0::coarse_factor] + yllvalue) - offset.y
|
||||
datavals = 1000 * datavals # - offset.z
|
||||
|
||||
# remove points out of area
|
||||
# 1. coarse:
|
||||
if obj.CuttingBoundary:
|
||||
inc_x = obj.CuttingBoundary.Shape.BoundBox.XLength * 0.0
|
||||
inc_y = obj.CuttingBoundary.Shape.BoundBox.YLength * 0.0
|
||||
tmp = np.where(np.logical_and(x >= (obj.CuttingBoundary.Shape.BoundBox.XMin - inc_x),
|
||||
x <= (obj.CuttingBoundary.Shape.BoundBox.XMax + inc_x)))[0]
|
||||
print(tmp)
|
||||
x_max = np.ndarray.max(tmp)
|
||||
x_min = np.ndarray.min(tmp)
|
||||
|
||||
tmp = np.where(np.logical_and(y >= (obj.CuttingBoundary.Shape.BoundBox.YMin - inc_y),
|
||||
y <= (obj.CuttingBoundary.Shape.BoundBox.YMax + inc_y)))[0]
|
||||
y_max = np.ndarray.max(tmp)
|
||||
y_min = np.ndarray.min(tmp)
|
||||
del tmp
|
||||
|
||||
x = x[x_min:x_max+1]
|
||||
y = y[y_min:y_max+1]
|
||||
datavals = datavals[y_min:y_max+1, x_min:x_max+1]
|
||||
|
||||
# Create mesh - surface:
|
||||
import MeshTools.Triangulation as Triangulation
|
||||
import Mesh
|
||||
stepsize = 75
|
||||
stepx = math.ceil(nx / stepsize)
|
||||
stepy = math.ceil(ny / stepsize)
|
||||
|
||||
mesh = Mesh.Mesh()
|
||||
for indx in range(stepx):
|
||||
inix = indx * stepsize - 1
|
||||
finx = min([stepsize * (indx + 1), len(x)-1])
|
||||
for indy in range(stepy):
|
||||
iniy = indy * stepsize - 1
|
||||
finy = min([stepsize * (indy + 1), len(y) - 1])
|
||||
pts = []
|
||||
for i in range(inix, finx):
|
||||
for j in range(iniy, finy):
|
||||
if datavals[j][i] != nodata_value:
|
||||
if obj.CuttingBoundary:
|
||||
if obj.CuttingBoundary.Shape.isInside(FreeCAD.Vector(x[i], y[j], 0), 0, True):
|
||||
pts.append([x[i], y[j], datavals[j][i]])
|
||||
else:
|
||||
pts.append([x[i], y[j], datavals[j][i]])
|
||||
if len(pts) > 3:
|
||||
try:
|
||||
mesh.addMesh(Triangulation.Triangulate(pts))
|
||||
#Mesh.show(mesh)
|
||||
except TypeError:
|
||||
print("error al procesar: {0} puntos".format(len(pts)))
|
||||
|
||||
mesh.removeDuplicatedPoints()
|
||||
mesh.removeFoldsOnSurface()
|
||||
obj.InitialMesh = mesh.copy()
|
||||
Mesh.show(mesh)
|
||||
|
||||
if prop == "PointsGroup" or prop == "CuttingBoundary":
|
||||
if obj.PointsGroup and obj.CuttingBoundary:
|
||||
bnd = obj.CuttingBoundary.Shape
|
||||
if len(bnd.Faces) == 0:
|
||||
pts = [ver.Point for ver in bnd.Vertexes]
|
||||
pts.append(pts[0])
|
||||
bnd = Part.makePolygon(pts)
|
||||
|
||||
# TODO: not use the first point, else the Origin in "Site".
|
||||
# It is standard for everything.
|
||||
firstPoint = self.obj.PointsGroup.Points.Points[0]
|
||||
nbase = FreeCAD.Vector(firstPoint.x, firstPoint.y, firstPoint.z)
|
||||
data = []
|
||||
for point in self.obj.PointsGroup.Points.Points:
|
||||
tmp = FreeCAD.Vector(0, 0, 0).add(point)
|
||||
tmp.z = 0
|
||||
if bnd.isInside(tmp, 0, True):
|
||||
p = point - nbase
|
||||
data.append([float(p.x), float(p.y), float(p.z)])
|
||||
|
||||
Data = np.array(data)
|
||||
data.clear()
|
||||
|
||||
import MeshTools.Triangulation as Triangulation
|
||||
mesh = Triangulation.Triangulate(Data)
|
||||
'''shape = PVPlantCreateTerrainMesh.MeshToShape(mesh)
|
||||
shape.Placement.move(nbase)'''
|
||||
|
||||
obj.Shape = shape
|
||||
if obj.DEM:
|
||||
obj.DEM = None
|
||||
|
||||
def execute(self, obj):
|
||||
''''''
|
||||
#print(" ----- Terrain - EXECUTE ----------")
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
|
||||
class ViewProviderTerrain:
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
self.boundary_color = None
|
||||
self.edge_style = None
|
||||
self.edge_color = None
|
||||
self.edge_material = None
|
||||
self.face_material = None
|
||||
self.triangles = None
|
||||
self.geo_coords = None
|
||||
self.setProperties(vobj)
|
||||
|
||||
def setProperties(self, vobj):
|
||||
# Triangulation properties.
|
||||
pl = vobj.PropertiesList
|
||||
if not ("Transparency" in pl):
|
||||
vobj.addProperty("App::PropertyIntegerConstraint",
|
||||
"Transparency",
|
||||
"Surface Style",
|
||||
"Set triangle face transparency").Transparency = (50, 0, 100, 1)
|
||||
|
||||
if not ("ShapeColor" in pl):
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"ShapeColor",
|
||||
"Surface Style",
|
||||
"Set triangle face color").ShapeColor = (r, g, b, vobj.Transparency / 100)
|
||||
|
||||
if not ("ShapeMaterial" in pl):
|
||||
vobj.addProperty("App::PropertyMaterial",
|
||||
"ShapeMaterial",
|
||||
"Surface Style",
|
||||
"Triangle face material").ShapeMaterial = FreeCAD.Material()
|
||||
|
||||
if not ("LineTransparency" in pl):
|
||||
vobj.addProperty("App::PropertyIntegerConstraint",
|
||||
"LineTransparency",
|
||||
"Surface Style",
|
||||
"Set triangle edge transparency").LineTransparency = (50, 0, 100, 1)
|
||||
|
||||
if not ("LineColor" in pl):
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"LineColor",
|
||||
"Surface Style",
|
||||
"Set triangle face color").LineColor = (0.5, 0.5, 0.5, vobj.LineTransparency / 100)
|
||||
|
||||
if not ("LineMaterial" in pl):
|
||||
vobj.addProperty("App::PropertyMaterial",
|
||||
"LineMaterial",
|
||||
"Surface Style",
|
||||
"Triangle face material").LineMaterial = FreeCAD.Material()
|
||||
|
||||
if not ("LineWidth" in pl):
|
||||
vobj.addProperty("App::PropertyFloatConstraint",
|
||||
"LineWidth",
|
||||
"Surface Style",
|
||||
"Set triangle edge line width").LineWidth = (0.0, 1.0, 20.0, 1.0)
|
||||
|
||||
# Boundary properties.
|
||||
if not ("BoundaryColor" in pl):
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"BoundaryColor",
|
||||
"Boundary Style",
|
||||
"Set boundary contour color").BoundaryColor = (0.0, 0.75, 1.0, 0.0)
|
||||
|
||||
if not ("BoundaryWidth" in pl):
|
||||
vobj.addProperty("App::PropertyFloatConstraint",
|
||||
"BoundaryWidth",
|
||||
"Boundary Style",
|
||||
"Set boundary contour line width").BoundaryWidth = (3.0, 1.0, 20.0, 1.0)
|
||||
|
||||
if not ("BoundaryPattern" in pl):
|
||||
vobj.addProperty("App::PropertyEnumeration",
|
||||
"BoundaryPattern",
|
||||
"Boundary Style",
|
||||
"Set a line pattern for boundary").BoundaryPattern = [*line_patterns]
|
||||
|
||||
if not ("PatternScale" in pl):
|
||||
vobj.addProperty("App::PropertyIntegerConstraint",
|
||||
"PatternScale",
|
||||
"Boundary Style",
|
||||
"Scale the line pattern").PatternScale = (3, 1, 20, 1)
|
||||
|
||||
# Contour properties.
|
||||
if not ("MajorColor" in pl):
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"MajorColor",
|
||||
"Contour Style",
|
||||
"Set major contour color").MajorColor = (1.0, 0.0, 0.0, 0.0)
|
||||
|
||||
if not ("MajorWidth" in pl):
|
||||
vobj.addProperty("App::PropertyFloatConstraint",
|
||||
"MajorWidth",
|
||||
"Contour Style",
|
||||
"Set major contour line width").MajorWidth = (4.0, 1.0, 20.0, 1.0)
|
||||
|
||||
if not ("MinorColor" in pl):
|
||||
vobj.addProperty("App::PropertyColor",
|
||||
"MinorColor",
|
||||
"Contour Style",
|
||||
"Set minor contour color").MinorColor = (1.0, 1.0, 0.0, 0.0)
|
||||
|
||||
if not ("MinorWidth" in pl):
|
||||
vobj.addProperty("App::PropertyFloatConstraint",
|
||||
"MinorWidth",
|
||||
"Contour Style",
|
||||
"Set major contour line width").MinorWidth = (2.0, 1.0, 20.0, 1.0)
|
||||
|
||||
vobj.Proxy = self
|
||||
vobj.ShapeMaterial.DiffuseColor = vobj.ShapeColor
|
||||
|
||||
def onDocumentRestored(self, vobj):
|
||||
self.setProperties(vobj)
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
''' Update Object visuals when a view property changed. '''
|
||||
if prop == "ShapeColor" or prop == "Transparency":
|
||||
if hasattr(vobj, "ShapeColor") and hasattr(vobj, "Transparency"):
|
||||
color = vobj.getPropertyByName("ShapeColor")
|
||||
transparency = vobj.getPropertyByName("Transparency")
|
||||
color = (color[0], color[1], color[2], transparency / 100)
|
||||
vobj.ShapeMaterial.DiffuseColor = color
|
||||
|
||||
if prop == "ShapeMaterial":
|
||||
if hasattr(vobj, "ShapeMaterial"):
|
||||
material = vobj.getPropertyByName("ShapeMaterial")
|
||||
self.face_material.diffuseColor.setValue(material.DiffuseColor[:3])
|
||||
self.face_material.transparency = material.DiffuseColor[3]
|
||||
|
||||
if prop == "LineColor" or prop == "LineTransparency":
|
||||
if hasattr(vobj, "LineColor") and hasattr(vobj, "LineTransparency"):
|
||||
color = vobj.getPropertyByName("LineColor")
|
||||
transparency = vobj.getPropertyByName("LineTransparency")
|
||||
color = (color[0], color[1], color[2], transparency / 100)
|
||||
vobj.LineMaterial.DiffuseColor = color
|
||||
|
||||
if prop == "LineMaterial":
|
||||
material = vobj.getPropertyByName(prop)
|
||||
self.edge_material.diffuseColor.setValue(material.DiffuseColor[:3])
|
||||
self.edge_material.transparency = material.DiffuseColor[3]
|
||||
|
||||
if prop == "LineWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.edge_style.lineWidth = width
|
||||
|
||||
if prop == "BoundaryColor":
|
||||
color = vobj.getPropertyByName(prop)
|
||||
self.boundary_color.rgb = color[:3]
|
||||
|
||||
if prop == "BoundaryWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.boundary_style.lineWidth = width
|
||||
|
||||
if prop == "BoundaryPattern":
|
||||
if hasattr(vobj, "BoundaryPattern"):
|
||||
pattern = vobj.getPropertyByName(prop)
|
||||
self.boundary_style.linePattern = line_patterns[pattern]
|
||||
|
||||
if prop == "PatternScale":
|
||||
if hasattr(vobj, "PatternScale"):
|
||||
scale = vobj.getPropertyByName(prop)
|
||||
self.boundary_style.linePatternScaleFactor = scale
|
||||
|
||||
if prop == "MajorColor":
|
||||
color = vobj.getPropertyByName(prop)
|
||||
self.major_color.rgb = color[:3]
|
||||
|
||||
if prop == "MajorWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.major_style.lineWidth = width
|
||||
|
||||
if prop == "MinorColor":
|
||||
color = vobj.getPropertyByName(prop)
|
||||
self.minor_color.rgb = color[:3]
|
||||
|
||||
if prop == "MinorWidth":
|
||||
width = vobj.getPropertyByName(prop)
|
||||
self.minor_style.lineWidth = width
|
||||
|
||||
def attach(self, vobj):
|
||||
''' Create Object visuals in 3D view.'''
|
||||
|
||||
# GeoCoords Node.
|
||||
self.geo_coords = coin.SoGeoCoordinate()
|
||||
|
||||
# Surface features.
|
||||
self.triangles = coin.SoIndexedFaceSet()
|
||||
self.face_material = coin.SoMaterial()
|
||||
self.edge_material = coin.SoMaterial()
|
||||
self.edge_color = coin.SoBaseColor()
|
||||
self.edge_style = coin.SoDrawStyle()
|
||||
self.edge_style.style = coin.SoDrawStyle.LINES
|
||||
|
||||
shape_hints = coin.SoShapeHints()
|
||||
shape_hints.vertex_ordering = coin.SoShapeHints.COUNTERCLOCKWISE
|
||||
mat_binding = coin.SoMaterialBinding()
|
||||
mat_binding.value = coin.SoMaterialBinding.PER_FACE
|
||||
offset = coin.SoPolygonOffset()
|
||||
offset.styles = coin.SoPolygonOffset.LINES
|
||||
offset.factor = -2.0
|
||||
|
||||
# Boundary features.
|
||||
'''self.boundary_color = coin.SoBaseColor()
|
||||
self.boundary_coords = coin.SoGeoCoordinate()
|
||||
self.boundary_lines = coin.SoLineSet()
|
||||
self.boundary_style = coin.SoDrawStyle()
|
||||
self.boundary_style.style = coin.SoDrawStyle.LINES'''
|
||||
|
||||
# Boundary root.
|
||||
'''boundaries = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
boundaries.style = 'EMISSIVE_DIFFUSE'
|
||||
boundaries.addChild(self.boundary_color)
|
||||
boundaries.addChild(self.boundary_style)
|
||||
boundaries.addChild(self.boundary_coords)
|
||||
boundaries.addChild(self.boundary_lines)'''
|
||||
|
||||
# Major Contour features.
|
||||
'''self.major_color = coin.SoBaseColor()
|
||||
self.major_coords = coin.SoGeoCoordinate()
|
||||
self.major_lines = coin.SoLineSet()
|
||||
self.major_style = coin.SoDrawStyle()
|
||||
self.major_style.style = coin.SoDrawStyle.LINES'''
|
||||
|
||||
# Major Contour root.
|
||||
'''major_contours = coin.SoSeparator()
|
||||
major_contours.addChild(self.major_color)
|
||||
major_contours.addChild(self.major_style)
|
||||
major_contours.addChild(self.major_coords)
|
||||
major_contours.addChild(self.major_lines)'''
|
||||
|
||||
# Minor Contour features.
|
||||
'''self.minor_color = coin.SoBaseColor()
|
||||
self.minor_coords = coin.SoGeoCoordinate()
|
||||
self.minor_lines = coin.SoLineSet()
|
||||
self.minor_style = coin.SoDrawStyle()
|
||||
self.minor_style.style = coin.SoDrawStyle.LINES'''
|
||||
|
||||
# Minor Contour root.
|
||||
'''minor_contours = coin.SoSeparator()
|
||||
minor_contours.addChild(self.minor_color)
|
||||
minor_contours.addChild(self.minor_style)
|
||||
minor_contours.addChild(self.minor_coords)
|
||||
minor_contours.addChild(self.minor_lines)'''
|
||||
|
||||
# Highlight for selection.
|
||||
highlight = coin.SoType.fromName('SoFCSelection').createInstance()
|
||||
highlight.style = 'EMISSIVE_DIFFUSE'
|
||||
highlight.addChild(shape_hints)
|
||||
highlight.addChild(mat_binding)
|
||||
highlight.addChild(self.geo_coords)
|
||||
highlight.addChild(self.triangles)
|
||||
highlight.addChild(boundaries)
|
||||
|
||||
# Face root.
|
||||
face = coin.SoSeparator()
|
||||
face.addChild(self.face_material)
|
||||
face.addChild(highlight)
|
||||
|
||||
# Edge root.
|
||||
edge = coin.SoSeparator()
|
||||
edge.addChild(self.edge_material)
|
||||
edge.addChild(self.edge_style)
|
||||
edge.addChild(highlight)
|
||||
|
||||
# Surface root.
|
||||
surface_root = coin.SoSeparator()
|
||||
surface_root.addChild(face)
|
||||
surface_root.addChild(offset)
|
||||
surface_root.addChild(edge)
|
||||
surface_root.addChild(major_contours)
|
||||
surface_root.addChild(minor_contours)
|
||||
vobj.addDisplayMode(surface_root, "Surface")
|
||||
|
||||
# Boundary root.
|
||||
boundary_root = coin.SoSeparator()
|
||||
boundary_root.addChild(boundaries)
|
||||
vobj.addDisplayMode(boundary_root, "Boundary")
|
||||
|
||||
# Elevation/Shaded root.
|
||||
'''shaded_root = coin.SoSeparator()
|
||||
shaded_root.addChild(face)
|
||||
vobj.addDisplayMode(shaded_root, "Elevation")
|
||||
vobj.addDisplayMode(shaded_root, "Slope")
|
||||
vobj.addDisplayMode(shaded_root, "Shaded")'''
|
||||
|
||||
# Flat Lines root.
|
||||
flatlines_root = coin.SoSeparator()
|
||||
flatlines_root.addChild(face)
|
||||
flatlines_root.addChild(offset)
|
||||
flatlines_root.addChild(edge)
|
||||
vobj.addDisplayMode(flatlines_root, "Flat Lines")
|
||||
|
||||
# Wireframe root.
|
||||
wireframe_root = coin.SoSeparator()
|
||||
wireframe_root.addChild(edge)
|
||||
wireframe_root.addChild(major_contours)
|
||||
wireframe_root.addChild(minor_contours)
|
||||
vobj.addDisplayMode(wireframe_root, "Wireframe")
|
||||
|
||||
# Take features from properties.
|
||||
self.onChanged(vobj, "ShapeColor")
|
||||
self.onChanged(vobj, "LineColor")
|
||||
self.onChanged(vobj, "LineWidth")
|
||||
#self.onChanged(vobj, "BoundaryColor")
|
||||
#self.onChanged(vobj, "BoundaryWidth")
|
||||
#self.onChanged(vobj, "BoundaryPattern")
|
||||
#self.onChanged(vobj, "PatternScale")
|
||||
#self.onChanged(vobj, "MajorColor")
|
||||
#self.onChanged(vobj, "MajorWidth")
|
||||
#self.onChanged(vobj, "MinorColor")
|
||||
#self.onChanged(vobj, "MinorWidth")
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
''' Update Object visuals when a data property changed. '''
|
||||
|
||||
# Set geosystem.
|
||||
geo_system = ["UTM", FreeCAD.ActiveDocument.Site.UtmZone, "FLAT"]
|
||||
self.geo_coords.geoSystem.setValues(geo_system)
|
||||
'''
|
||||
self.boundary_coords.geoSystem.setValues(geo_system)
|
||||
self.major_coords.geoSystem.setValues(geo_system)
|
||||
self.minor_coords.geoSystem.setValues(geo_system)
|
||||
'''
|
||||
|
||||
if prop == "Mesh":
|
||||
print("update terrain mesh")
|
||||
mesh = obj.Mesh
|
||||
copy_mesh = mesh.copy()
|
||||
# copy_mesh.Placement.move(origin.Origin)
|
||||
|
||||
triangles = []
|
||||
for i in copy_mesh.Topology[1]:
|
||||
triangles.extend(list(i))
|
||||
triangles.append(-1)
|
||||
|
||||
self.geo_coords.point.values = copy_mesh.Topology[0]
|
||||
self.triangles.coordIndex.values = triangles
|
||||
del copy_mesh
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
''' Return a list of display modes. '''
|
||||
modes = ["Surface", "Boundary"]
|
||||
|
||||
return modes
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
'''
|
||||
Return the name of the default display mode.
|
||||
'''
|
||||
return "Surface"
|
||||
|
||||
def claimChildren(self):
|
||||
return [self.Object.CuttingBoundary, ]
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(DirIcons, "terrain.svg"))
|
||||
|
||||
def __getstate__(self):
|
||||
""" Save variables to file. """
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
""" Get variables from file. """
|
||||
return None
|
||||
|
||||
|
||||
class _CommandTerrain:
|
||||
"the PVPlant Terrain command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "terrain.svg")),
|
||||
'MenuText': "Terrain",
|
||||
'Accel': "S, T",
|
||||
'ToolTip': "Creates a Terrain object from setup dialog."}
|
||||
|
||||
def IsActive(self):
|
||||
return (not (FreeCAD.ActiveDocument is None) and
|
||||
not (FreeCAD.ActiveDocument.getObject("Site") is None) and
|
||||
(FreeCAD.ActiveDocument.getObject("Terrain") is None))
|
||||
|
||||
def Activated(self):
|
||||
makeTerrain()
|
||||
# task = _TerrainTaskPanel()
|
||||
# FreeCADGui.Control.showDialog(task)
|
||||
return
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Terrain', _CommandTerrain())
|
||||
806
PVPlantTerrainAnalisys.py
Normal file
806
PVPlantTerrainAnalisys.py
Normal file
@@ -0,0 +1,806 @@
|
||||
import Draft
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
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
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
def Mest2FemMesh(obj):
|
||||
import Fem
|
||||
|
||||
fm = Fem.FemMesh()
|
||||
|
||||
#i = 0
|
||||
#nodes = []
|
||||
for mp in obj.Mesh.Points:
|
||||
fm.addNode(mp.Vector.x, mp.Vector.y, mp.Vector.z)
|
||||
# nodes.append(mp)
|
||||
# i += 1
|
||||
for mf in obj.Mesh.Facets:
|
||||
fm.addFace([mf.PointIndices[0] + 1, mf.PointIndices[1] + 1, mf.PointIndices[2] + 1])
|
||||
|
||||
obj2 = FreeCAD.ActiveDocument.addObject("Fem::FemMeshObject")
|
||||
obj2.FemMesh = fm
|
||||
obj2.ViewObject.DisplayMode = "Faces"
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
return obj2
|
||||
|
||||
def makeContours(land, minor = 1000, mayor = 5000,
|
||||
minorColor=(0.0, 0.00, 0.80), mayorColor=(0.00, 0.00, 1.00),
|
||||
minorThickness = 2, mayorThickness = 5,
|
||||
filter_size = 5):
|
||||
if not land:
|
||||
return
|
||||
|
||||
if land.TypeId == 'Mesh::Feature':
|
||||
Contours_Mesh(land.Mesh, minor, mayor, minorColor, mayorColor, minorThickness, mayorThickness, filter_size)
|
||||
else:
|
||||
Contours_Part(land, minor, mayor, minorColor, mayorColor, minorThickness, mayorThickness, filter_size)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def Contours_Mesh(Mesh, minor, mayor,
|
||||
minorColor, mayorColor,
|
||||
minorLineWidth, mayorLineWidth,
|
||||
filter_size): #filter_size de 3 a 21 y siempre impar
|
||||
|
||||
def calculateSection(cuts):
|
||||
for inc in cuts:
|
||||
CrossSections = Mesh.crossSections([((0, 0, inc), (0, 0, 1))], 0.000001)
|
||||
for PointList in CrossSections[0]:
|
||||
if len(PointList) > 1:
|
||||
if PointList[0].sub(PointList[-1]).Length <= 10000.0:
|
||||
PointList.append(PointList[0])
|
||||
|
||||
# 1. Smooth the points
|
||||
if (len(PointList) > filter_size) and (filter_size > 0):
|
||||
for a in range(len(PointList)):
|
||||
x = 0
|
||||
y = 0
|
||||
for p in range(-filter_radius, filter_radius + 1):
|
||||
point_id = a + p
|
||||
if point_id < 0:
|
||||
point_id = 0
|
||||
|
||||
if point_id >= len(PointList):
|
||||
point_id = len(PointList) - 1
|
||||
|
||||
x += PointList[point_id].x
|
||||
y += PointList[point_id].y
|
||||
|
||||
x /= filter_size
|
||||
y /= filter_size
|
||||
PointList[a].x = x
|
||||
PointList[a].y = y
|
||||
|
||||
for a in reversed(range(len(PointList))):
|
||||
x = 0
|
||||
y = 0
|
||||
for p in range(-filter_radius, filter_radius + 1):
|
||||
point_id = a + p
|
||||
if point_id < 0:
|
||||
point_id = 0
|
||||
|
||||
if point_id >= len(PointList):
|
||||
point_id = len(PointList) - 1
|
||||
|
||||
x += PointList[point_id].x
|
||||
y += PointList[point_id].y
|
||||
|
||||
x /= filter_size
|
||||
y /= filter_size
|
||||
PointList[a].x = x
|
||||
PointList[a].y = y
|
||||
|
||||
# 2. Make lines
|
||||
#Contour = Draft.makeWire(PointList, closed=False, face=None)
|
||||
#Contour.Label = str(int(inc / 1000)) + "m"
|
||||
Contour = Part.makePolygon(PointList)
|
||||
Part.show(Contour, str(int(inc / 1000)) + "m")
|
||||
'''Contours.addObject(Contour)
|
||||
if inc % mayor == 0:
|
||||
Contour.ViewObject.LineWidth = mayorLineWidth
|
||||
Contour.ViewObject.LineColor = mayorColor
|
||||
else:
|
||||
Contour.ViewObject.LineWidth = minorLineWidth
|
||||
Contour.ViewObject.LineColor = minorColor'''
|
||||
|
||||
del Contour, PointList
|
||||
del CrossSections
|
||||
|
||||
filter_radius = int(filter_size / 2)
|
||||
try:
|
||||
Contours = FreeCAD.ActiveDocument.Contours
|
||||
except:
|
||||
Contours = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Contours')
|
||||
|
||||
ZMin = Mesh.BoundBox.ZMin // 10000
|
||||
ZMin *= 10000
|
||||
ZMax = Mesh.BoundBox.ZMax
|
||||
|
||||
import numpy as np
|
||||
minor_array = np.arange(ZMin, ZMax, minor)
|
||||
mayor_array = np.arange(ZMin, ZMax, mayor)
|
||||
minor_array = np.array(list(filter(lambda x: x not in mayor_array, minor_array)))
|
||||
calculateSection(minor_array)
|
||||
calculateSection(mayor_array)
|
||||
|
||||
def Contours_Part(Terrain, minor, mayor,
|
||||
minorColor, mayorColor,
|
||||
minorLineWidth, mayorLineWidth,
|
||||
filter_size): #filter_size de 3 a 21 y siempre impar
|
||||
|
||||
def calculateSection(cuts):
|
||||
cnt = 0
|
||||
for inc in cuts:
|
||||
CrossSections = Terrain.Shape.slice(FreeCAD.Vector(0, 0, 1), inc)
|
||||
|
||||
for wire in CrossSections:
|
||||
PointList = []
|
||||
for vertex in wire.Vertexes:
|
||||
PointList.append(vertex.Point)
|
||||
|
||||
if len(PointList) > 1:
|
||||
# 1. Smooth the points
|
||||
if (len(PointList) > filter_size) and (filter_size > 0):
|
||||
for a in range(len(PointList)):
|
||||
x = 0
|
||||
y = 0
|
||||
for p in range(-filter_radius, filter_radius + 1):
|
||||
point_id = a + p
|
||||
if point_id < 0:
|
||||
point_id = 0
|
||||
|
||||
if point_id >= len(PointList):
|
||||
point_id = len(PointList) - 1
|
||||
|
||||
x += PointList[point_id].x
|
||||
y += PointList[point_id].y
|
||||
|
||||
x /= filter_size
|
||||
y /= filter_size
|
||||
PointList[a].x = x
|
||||
PointList[a].y = y
|
||||
|
||||
for a in reversed(range(len(PointList))):
|
||||
x = 0
|
||||
y = 0
|
||||
for p in range(-filter_radius, filter_radius + 1):
|
||||
point_id = a + p
|
||||
if point_id < 0:
|
||||
point_id = 0
|
||||
|
||||
if point_id >= len(PointList):
|
||||
point_id = len(PointList) - 1
|
||||
|
||||
x += PointList[point_id].x
|
||||
y += PointList[point_id].y
|
||||
|
||||
x /= filter_size
|
||||
y /= filter_size
|
||||
PointList[a].x = x
|
||||
PointList[a].y = y
|
||||
# 2. TODO: close wire
|
||||
|
||||
# 3. Make lines
|
||||
Contour = Draft.makeWire(PointList, closed=False, face=None, support=None)
|
||||
Contour.MakeFace = False
|
||||
Contour.Label = str(int(inc / 1000)) + "m"
|
||||
Contours.addObject(Contour)
|
||||
|
||||
if inc % mayor == 0:
|
||||
Contour.ViewObject.LineWidth = mayorLineWidth
|
||||
Contour.ViewObject.LineColor = mayorColor
|
||||
else:
|
||||
Contour.ViewObject.LineWidth = minorLineWidth
|
||||
Contour.ViewObject.LineColor = minorColor
|
||||
cnt += 1
|
||||
if cnt == 10:
|
||||
return
|
||||
|
||||
filter_radius = int(filter_size / 2)
|
||||
try:
|
||||
Contours = FreeCAD.ActiveDocument.Contours
|
||||
except:
|
||||
Contours = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Contours')
|
||||
|
||||
ZMin = Terrain.Shape.BoundBox.ZMin // 10000
|
||||
ZMin *= 10000
|
||||
ZMax = Terrain.Shape.BoundBox.ZMax
|
||||
|
||||
import numpy as np
|
||||
minor_array = np.arange(ZMin, ZMax, minor)
|
||||
mayor_array = np.arange(ZMin, ZMax, mayor)
|
||||
minor_array = np.array(list(filter(lambda x: x not in mayor_array, minor_array)))
|
||||
calculateSection(minor_array)
|
||||
calculateSection(mayor_array)
|
||||
|
||||
# Base widget for task panel terrain analisys
|
||||
class _generalTaskPanel:
|
||||
'''The TaskPanel for Slope setup'''
|
||||
|
||||
def __init__(self):
|
||||
self.ranges = []
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantTerrainAnalisys.ui")
|
||||
self.tableWidget = self.form.tableWidget
|
||||
self.form.editSteps.valueChanged.connect(self.changeDivision)
|
||||
self.tableWidget.itemChanged.connect(self.cellChanged)
|
||||
|
||||
def cellChanged(self, item):
|
||||
if (item.column() == 1) and (item.row() != (self.tableWidget.rowCount() - 1)):
|
||||
item2 = self.tableWidget.item(item.row() + 1, 0)
|
||||
item2.setText(item.text())
|
||||
|
||||
def updateTableValues(self):
|
||||
maxval = self.form.editTo.value() - self.form.editFrom.value()
|
||||
ran = maxval / self.tableWidget.rowCount()
|
||||
|
||||
for i in range(self.tableWidget.rowCount()):
|
||||
for j in range(2):
|
||||
item = self.tableWidget.item(i, j)
|
||||
val = ran * (i + j) + self.form.editFrom.value()
|
||||
item.setText('{:.1f}'.format(val))
|
||||
self.ranges[i][j] = val
|
||||
|
||||
#self.tableWidget.item(0, 0).setText('{:.1f}'.format(self.form.editFrom.value()))
|
||||
#self.tableWidget.item(self.tableWidget.rowCount() - 1, 1).setText('{:.1f}'.format(self.form.editTo.value()))
|
||||
|
||||
def changeDivision(self):
|
||||
self.tableWidget.blockSignals(True)
|
||||
rows = self.tableWidget.rowCount()
|
||||
to = self.form.editSteps.value()
|
||||
if to > rows:
|
||||
for i in range(0, to - rows):
|
||||
self.ranges.append([0.0, 0.0, (0.0, 0.0, 0.0)])
|
||||
self.createRow()
|
||||
elif to < rows:
|
||||
self.tableWidget.setRowCount(to)
|
||||
self.ranges = self.ranges[:to]
|
||||
self.updateTableValues()
|
||||
self.tableWidget.blockSignals(False)
|
||||
|
||||
def createRow(self):
|
||||
row = self.tableWidget.rowCount()
|
||||
self.tableWidget.setRowCount(self.tableWidget.rowCount() + 1)
|
||||
|
||||
newItem = QtGui.QTableWidgetItem("item")
|
||||
self.tableWidget.setItem(row, 0, newItem)
|
||||
newItem.setTextAlignment(QtCore.Qt.AlignCenter)
|
||||
newItem.setText("0.0")
|
||||
newItem.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEditable|QtCore.Qt.ItemIsDragEnabled|
|
||||
QtCore.Qt.ItemIsDropEnabled|QtCore.Qt.ItemIsUserCheckable)
|
||||
|
||||
newItem = QtGui.QTableWidgetItem("item")
|
||||
self.tableWidget.setItem(row, 1, newItem)
|
||||
newItem.setTextAlignment(QtCore.Qt.AlignCenter)
|
||||
newItem.setText("0.0")
|
||||
|
||||
#import random
|
||||
# r = random.randint(0, 255)
|
||||
# g = random.randint(0, 255)
|
||||
# b = random.randint(0, 255)
|
||||
|
||||
val = int(127 * row / (self.form.editSteps.value() / 2))
|
||||
g = (127 + val) if val <= 127 else 0
|
||||
r = (328 - val if val >= 127 else 0)
|
||||
color = QtGui.QColor(r, g, 0)
|
||||
colorPix = QtGui.QPixmap(16, 16)
|
||||
colorPix.fill(color)
|
||||
self.ranges[row][2] = (color.red()/255, color.green()/255, color.blue()/255)
|
||||
buttonColor = QtGui.QPushButton('')
|
||||
buttonColor.setIcon(QtGui.QIcon(colorPix))
|
||||
buttonColor.setMaximumSize(QtCore.QSize(20, 20))
|
||||
buttonColor.clicked.connect(lambda: self.selColor(buttonColor))
|
||||
self.tableWidget.setCellWidget(row, 2, buttonColor)
|
||||
|
||||
def selColor(self, button):
|
||||
color = QtGui.QColorDialog.getColor()
|
||||
if color.isValid():
|
||||
print("añadir color")
|
||||
colorPix = QtGui.QPixmap(16, 16)
|
||||
colorPix.fill(color)
|
||||
button.setIcon(QtGui.QIcon(colorPix))
|
||||
curentIndex = self.tableWidget.currentIndex()
|
||||
self.ranges[curentIndex.row()][2] = (color.red()/255, color.green()/255, color.blue()/255)
|
||||
|
||||
# Contours Analisys: ---------------------------------------------------------------------------------
|
||||
class _ContourTaskPanel():
|
||||
'''The editmode TaskPanel for contours generator'''
|
||||
|
||||
def __init__(self):
|
||||
self.MinorColor = (0.5, 0.5, 0.5)
|
||||
self.MayorColor = (0.5, 0.5, 0.5)
|
||||
land = None
|
||||
self.intervals = ["0.1 m", "0.5 m", "1 m", "5 m", "10 m", "50 m", "100 m", "500 m"]
|
||||
self.intervalvalues = [0.1, 0.5, 1, 5, 10, 50, 100, 500]
|
||||
|
||||
# form:
|
||||
self.form = QtGui.QWidget()
|
||||
self.form.resize(800,640)
|
||||
self.form.setWindowTitle("Curvas de nivel")
|
||||
self.form.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
|
||||
self.grid = QtGui.QGridLayout(self.form)
|
||||
|
||||
# parameters
|
||||
self.labelTerrain = QtGui.QLabel()
|
||||
self.labelTerrain.setText("Terreno:")
|
||||
self.lineEdit1 = QtGui.QLineEdit(self.form)
|
||||
self.lineEdit1.setObjectName(_fromUtf8("lineEdit1"))
|
||||
self.lineEdit1.readOnly = True
|
||||
self.grid.addWidget(self.labelTerrain, self.grid.rowCount(), 0, 1, 1)
|
||||
self.grid.addWidget(self.lineEdit1, self.grid.rowCount() - 1, 1, 1, 1)
|
||||
|
||||
self.buttonAdd = QtGui.QPushButton('Seleccionar Terreno')
|
||||
self.buttonAdd.clicked.connect(self.add)
|
||||
self.grid.addWidget(self.buttonAdd, self.grid.rowCount(), 1, 1, 1)
|
||||
|
||||
###----------------------
|
||||
|
||||
self.widgetDivisions = QtGui.QGroupBox(self.form)
|
||||
self.grid.addWidget(self.widgetDivisions, self.grid.rowCount(), 0, 1, -1)
|
||||
self.gridDivisions = QtGui.QGridLayout(self.widgetDivisions)
|
||||
|
||||
self.labelTitle1 = QtGui.QLabel()
|
||||
self.labelTitle1.setText("Intervalo")
|
||||
self.labelTitle2 = QtGui.QLabel()
|
||||
self.labelTitle2.setText("Grosor")
|
||||
self.labelTitle3 = QtGui.QLabel()
|
||||
self.labelTitle3.setText("Color")
|
||||
self.gridDivisions.addWidget(self.labelTitle1, self.gridDivisions.rowCount(), 1, 1, -1)
|
||||
self.gridDivisions.addWidget(self.labelTitle2, self.gridDivisions.rowCount() - 1, 2, 1, -1)
|
||||
self.gridDivisions.addWidget(self.labelTitle3, self.gridDivisions.rowCount() - 1, 3, 1, -1)
|
||||
|
||||
self.labelMinorContour = QtGui.QLabel(self.form)
|
||||
self.labelMinorContour.setText("Menor:")
|
||||
self.inputMinorContourMargin = QtGui.QComboBox(self.form)
|
||||
self.inputMinorContourMargin.addItems(self.intervals)
|
||||
self.inputMinorContourMargin.setCurrentIndex(2)
|
||||
self.inputMinorContourThickness = QtGui.QSpinBox(self.form)
|
||||
self.inputMinorContourThickness.setRange(1, 10)
|
||||
self.inputMinorContourThickness.setValue(2)
|
||||
|
||||
self.gridDivisions.addWidget(self.labelMinorContour, self.gridDivisions.rowCount(), 0, 1, 1)
|
||||
self.gridDivisions.addWidget(self.inputMinorContourMargin, self.gridDivisions.rowCount() - 1, 1, 1, 1)
|
||||
self.gridDivisions.addWidget(self.inputMinorContourThickness, self.gridDivisions.rowCount() - 1, 2, 1, 1)
|
||||
|
||||
self.buttonMinorContourColor = QtGui.QPushButton('')
|
||||
self.color = QtGui.QColor(128, 128, 128)
|
||||
colorPix = QtGui.QPixmap(16, 16)
|
||||
colorPix.fill(self.color)
|
||||
self.buttonMinorContourColor.setIcon(QtGui.QIcon(colorPix))
|
||||
self.buttonMinorContourColor.clicked.connect(lambda: self.selColor(self.buttonMinorContourColor))
|
||||
self.gridDivisions.addWidget(self.buttonMinorContourColor, self.gridDivisions.rowCount() - 1, 3, 1, 1)
|
||||
|
||||
###----------------------
|
||||
|
||||
self.labelMayorContour = QtGui.QLabel(self.form)
|
||||
self.labelMayorContour.setText("Mayor:")
|
||||
|
||||
self.inputMayorContourMargin = QtGui.QComboBox(self.form)
|
||||
self.inputMayorContourMargin.addItems(self.intervals)
|
||||
self.inputMayorContourMargin.setCurrentIndex(3)
|
||||
|
||||
self.inputMayorContourThickness = QtGui.QSpinBox(self.form)
|
||||
self.inputMayorContourThickness.setRange(1, 10)
|
||||
self.inputMayorContourThickness.setValue(5)
|
||||
|
||||
self.gridDivisions.addWidget(self.labelMayorContour, self.gridDivisions.rowCount(), 0, 1, 1)
|
||||
self.gridDivisions.addWidget(self.inputMayorContourMargin, self.gridDivisions.rowCount() - 1, 1, 1, 1)
|
||||
self.gridDivisions.addWidget(self.inputMayorContourThickness, self.gridDivisions.rowCount() - 1, 2, 1, 1)
|
||||
|
||||
self.buttonMayorContourColor = QtGui.QPushButton('')
|
||||
self.color = QtGui.QColor(128, 128, 128)
|
||||
colorPix = QtGui.QPixmap(16, 16)
|
||||
colorPix.fill(self.color)
|
||||
self.buttonMayorContourColor.setIcon(QtGui.QIcon(colorPix))
|
||||
self.buttonMayorContourColor.clicked.connect(lambda: self.selColor(self.buttonMayorContourColor))
|
||||
self.gridDivisions.addWidget(self.buttonMayorContourColor, self.gridDivisions.rowCount() - 1, 3, 1, 1)
|
||||
|
||||
|
||||
def add(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.land = sel[0]
|
||||
self.lineEdit1.setText(self.land.Label)
|
||||
|
||||
def selColor(self, button):
|
||||
color = QtGui.QColorDialog.getColor()
|
||||
colorPix = QtGui.QPixmap(16, 16)
|
||||
colorPix.fill(color)
|
||||
button.setIcon(QtGui.QIcon(colorPix))
|
||||
|
||||
r = float(color.red()/255.0)
|
||||
g = float(color.green()/255.0)
|
||||
b = float(color.blue()/255.0)
|
||||
col = (r, g, b)
|
||||
|
||||
if button is self.buttonMinorContourColor:
|
||||
self.MinorColor = col
|
||||
elif button is self.buttonMayorContourColor:
|
||||
self.MayorColor = col
|
||||
|
||||
def accept(self):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
if self.land is None:
|
||||
print("No hay objetos para procesar")
|
||||
return False
|
||||
else:
|
||||
minor = FreeCAD.Units.Quantity(self.inputMinorContourMargin.currentText()).Value
|
||||
mayor = FreeCAD.Units.Quantity(self.inputMayorContourMargin.currentText()).Value
|
||||
|
||||
i = 2
|
||||
if i == 0:
|
||||
makeContours(self.land, minor, mayor, self.MinorColor, self.MayorColor,
|
||||
self.inputMinorContourThickness.value(), self.inputMayorContourThickness.value())
|
||||
elif i == 1:
|
||||
import multiprocessing
|
||||
p = multiprocessing.Process(target=makeContours,
|
||||
args=(self.land, minor, mayor,
|
||||
self.MinorColor, self.MayorColor,
|
||||
self.inputMinorContourThickness.value(),
|
||||
self.inputMayorContourThickness.value(), ))
|
||||
p.start()
|
||||
p.join()
|
||||
|
||||
else:
|
||||
import threading
|
||||
hilo = threading.Thread(target = makeContours,
|
||||
args = (self.land, minor, mayor,
|
||||
self.MinorColor, self.MayorColor,
|
||||
self.inputMinorContourThickness.value(),
|
||||
self.inputMayorContourThickness.value()))
|
||||
hilo.daemon = True
|
||||
hilo.start()
|
||||
|
||||
total_time = datetime.now() - starttime
|
||||
print(" -- Tiempo tardado:", total_time)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
# Height Analisys: ---------------------------------------------------------------------------------
|
||||
class _HeightTaskPanel(_generalTaskPanel):
|
||||
'''The TaskPanel for Slope setup'''
|
||||
|
||||
def __init__(self):
|
||||
_generalTaskPanel.__init__(self)
|
||||
|
||||
# Initial set-up:
|
||||
land = FreeCAD.ActiveDocument.Site.Terrain
|
||||
self.form.editFrom.setSuffix(" m")
|
||||
self.form.editFrom.setValue(land.Shape.BoundBox.ZMin / 1000)
|
||||
self.form.editTo.setSuffix(" m")
|
||||
self.form.editTo.setValue(land.Shape.BoundBox.ZMax / 1000)
|
||||
self.form.editSteps.setValue(10)
|
||||
self.form.editFrom.valueChanged.connect(self.updateTableValues)
|
||||
self.form.editTo.valueChanged.connect(self.updateTableValues)
|
||||
|
||||
def accept(self):
|
||||
land = FreeCAD.ActiveDocument.Site.Terrain
|
||||
if land.isDerivedFrom("Part::Feature"):
|
||||
colorlist = []
|
||||
for face in land.Shape.Faces:
|
||||
zz = face.CenterOfMass.z / 1000
|
||||
color = (.0, .0, .0)
|
||||
for i in range(1,len(self.ranges)):
|
||||
if self.ranges[i][0] <= zz <= self.ranges[i][1]:
|
||||
color = self.ranges[i][2]
|
||||
break
|
||||
colorlist.append(color)
|
||||
land.ViewObject.DiffuseColor = colorlist
|
||||
FreeCAD.activeDocument().recompute()
|
||||
return True
|
||||
|
||||
# Slope Analisys: ---------------------------------------------------------------------------------
|
||||
class _SlopeTaskPanel(_generalTaskPanel):
|
||||
'''The TaskPanel for Slope setup'''
|
||||
|
||||
def __init__(self):
|
||||
_generalTaskPanel.__init__(self)
|
||||
self.angles = self.getAngles()
|
||||
# Initial set-up:
|
||||
self.form.editFrom.setSuffix(" º")
|
||||
self.form.editFrom.setValue(0)
|
||||
self.form.editTo.setSuffix(" º")
|
||||
self.form.editTo.setValue(max(self.angles))
|
||||
self.form.editSteps.setValue(10)
|
||||
self.form.editFrom.valueChanged.connect(self.updateTableValues)
|
||||
self.form.editTo.valueChanged.connect(self.updateTableValues)
|
||||
|
||||
def getAngles(self):
|
||||
import math
|
||||
land = FreeCAD.ActiveDocument.Site.Terrain
|
||||
angles = []
|
||||
for face in land.Shape.Faces:
|
||||
normal = face.normalAt(0, 0)
|
||||
rad = normal.getAngle(FreeCAD.Vector(0, 0, 1))
|
||||
angle = math.degrees(rad)
|
||||
angles.append(angle)
|
||||
return angles
|
||||
|
||||
def getPointSlope(self, ranges = None):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
import math
|
||||
|
||||
land = FreeCAD.ActiveDocument.Site.Terrain
|
||||
if land.isDerivedFrom("Part::Feature"):
|
||||
colorlist = []
|
||||
for face in land.Shape.Faces:
|
||||
normal = face.normalAt(0, 0)
|
||||
rad = normal.getAngle(FreeCAD.Vector(0, 0, 1))
|
||||
angle = math.degrees(rad)
|
||||
if(angle > 90):
|
||||
angle -= 90
|
||||
color = (1.0, 1.0, 1.0)
|
||||
for i in range(0, len(ranges)):
|
||||
if ranges[i][0] <= angle <= ranges[i][1]:
|
||||
color = ranges[i][2]
|
||||
break
|
||||
colorlist.append(color)
|
||||
print(len(land.Shape.Faces) == len(colorlist))
|
||||
land.ViewObject.DiffuseColor = colorlist
|
||||
|
||||
# TODO: check this code:
|
||||
elif obj.isDerivedFrom("Mesh::Feature"):
|
||||
fMesh = Mest2FemMesh(land)
|
||||
import math
|
||||
setColors = []
|
||||
i = 1
|
||||
normals = land.Mesh.getPointNormals()
|
||||
for normal in normals:
|
||||
rad = normal.getAngle(FreeCAD.Vector(0, 0, 1))
|
||||
angle = math.degrees(rad)
|
||||
|
||||
# Cambiar esto a la lista de colores configurable
|
||||
if angle < 5:
|
||||
setColors[i] = (0.0, 0.5, 0.0)
|
||||
elif angle < 7.5:
|
||||
setColors[i] = (0.0, 1.0, 0.5)
|
||||
elif (angle < 10):
|
||||
setColors[i] = (0.0, 1.0, 1.0)
|
||||
elif (angle < 12.5):
|
||||
setColors[i] = (0.0, 0.0, 0.5)
|
||||
elif (angle < 14):
|
||||
setColors[i] = (0.0, 0.0, 1.0)
|
||||
elif (angle > 20):
|
||||
setColors[i] = (1.0, 0.0, 0.0)
|
||||
else:
|
||||
setColors[i] = (1.0, 1.0, 1.0)
|
||||
i += 1
|
||||
|
||||
fMesh.ViewObject.NodeColor = setColors
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
print("Everything OK (", datetime.now() - starttime, ")")
|
||||
|
||||
def accept(self):
|
||||
# self.getPointSlope()
|
||||
import threading
|
||||
hilo = threading.Thread(target=self.getPointSlope(self.ranges))
|
||||
hilo.start()
|
||||
return True
|
||||
|
||||
# Orientation Analisys: ---------------------------------------------------------------------------------
|
||||
class _OrientationTaskPanel(_generalTaskPanel):
|
||||
'''The TaskPanel for Orientation setup'''
|
||||
|
||||
def __init__(self):
|
||||
_generalTaskPanel.__init__(self)
|
||||
|
||||
self.getAngles()
|
||||
|
||||
# Initial set-up:
|
||||
self.form.editFrom.setSuffix(" º")
|
||||
self.form.editFrom.setValue(0.0)
|
||||
self.form.editTo.setSuffix(" º")
|
||||
self.form.editTo.setMaximum(360.0)
|
||||
self.form.editTo.setValue(360.0)
|
||||
self.form.editSteps.setValue(15)
|
||||
self.form.editFrom.valueChanged.connect(self.updateTableValues)
|
||||
self.form.editTo.valueChanged.connect(self.updateTableValues)
|
||||
|
||||
def getAngles(self):
|
||||
import math
|
||||
land = FreeCAD.ActiveDocument.Site.Terrain
|
||||
anglesx = []
|
||||
anglesy = []
|
||||
for face in land.Shape.Faces:
|
||||
normal = face.normalAt(0, 0)
|
||||
normal.z = 0
|
||||
anglesx.append(math.degrees(normal.getAngle(FreeCAD.Vector(1, 0, 0))))
|
||||
anglesy.append(math.degrees(normal.getAngle(FreeCAD.Vector(0, 1, 0))))
|
||||
|
||||
print("Min x: ", min(anglesx), " y: ", min(anglesy))
|
||||
print("Max x: ", max(anglesx), " y: ", max(anglesy))
|
||||
return anglesx, anglesy
|
||||
|
||||
def accept(self):
|
||||
import math
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
land = FreeCAD.ActiveDocument.Site.Terrain
|
||||
if land.isDerivedFrom("Part::Feature"):
|
||||
colorlist = []
|
||||
j = 0
|
||||
minx = 99999
|
||||
miny = 99999
|
||||
for face in land.Shape.Faces:
|
||||
normal = face.normalAt(0, 0)
|
||||
normal.z = 0
|
||||
anglex = math.degrees(normal.getAngle(FreeCAD.Vector(1, 0, 0)))
|
||||
angley = math.degrees(normal.getAngle(FreeCAD.Vector(0, 1, 0)))
|
||||
|
||||
minx = min([minx, anglex])
|
||||
miny = min([miny, angley])
|
||||
if angley >= 90:
|
||||
anglex = 360.0 - anglex
|
||||
|
||||
#print(anglex, " ", angley)
|
||||
for i in range(1, len(self.ranges)):
|
||||
if self.ranges[i][0] <= anglex <= self.ranges[i][1]:
|
||||
colorlist.append(self.ranges[i][2])
|
||||
break
|
||||
j += 1
|
||||
if j == 100:
|
||||
break
|
||||
land.ViewObject.DiffuseColor = colorlist
|
||||
print("Angulos: ", math.degrees(minx), " - ", miny)
|
||||
|
||||
# TODO: check this code:
|
||||
elif land.isDerivedFrom("Mesh::Feature"):
|
||||
fMesh = Mest2FemMesh(land)
|
||||
fMesh = Mest2FemMesh(land)
|
||||
|
||||
setColors = {}
|
||||
i = 1
|
||||
normals = land.Mesh.getPointNormals()
|
||||
print(" --------- time to FEMMESH: (", datetime.now() - starttime, ")")
|
||||
|
||||
for normal in normals:
|
||||
rad = normal.getAngle(FreeCAD.Vector(1, 1, 0))
|
||||
angle = math.degrees(rad)
|
||||
|
||||
# Cambiar esto a la lista de colores configurable
|
||||
if angle < 45:
|
||||
setColors[i] = (0.0, 1.0, 0.0)
|
||||
elif (angle < 90):
|
||||
setColors[i] = (0.0, 1.0, 1.0)
|
||||
elif (angle < 135):
|
||||
setColors[i] = (0.0, 0.0, 1.0)
|
||||
elif (angle <= 180):
|
||||
setColors[i] = (1.0, 0.0, 1.0)
|
||||
#else:
|
||||
# setColors[i] = (1.0, 0.0, 0.0)
|
||||
|
||||
i += 1
|
||||
if i== 1000:
|
||||
break
|
||||
|
||||
fMesh.ViewObject.NodeColor = setColors
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
print("Everything OK (", datetime.now() - starttime, ")")
|
||||
return True
|
||||
|
||||
## Commands ----------------------------------------------------------------------------------------------------------
|
||||
## 1. Contours:
|
||||
class _CommandContours:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "TerrainContours.svg")),
|
||||
'Accel': "T, C",
|
||||
'MenuText': 'Curvas de nivel',
|
||||
'ToolTip': 'Curvas de nivel'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
# return not FreeCAD.ActiveDocument is None
|
||||
if FreeCAD.ActiveDocument is None:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
if FreeCADGui.Selection.getSelection() is not None:
|
||||
selection = FreeCADGui.Selection.getSelection()[-1]
|
||||
if selection.TypeId == 'Mesh::Feature':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _ContourTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
## 2. Aspect:
|
||||
class _CommandSlopeAnalisys:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "TerrainSlope.svg")),
|
||||
'Accel': "T, S",
|
||||
'MenuText': 'Analisis de Pendiente',
|
||||
'ToolTip': 'Analisis de Pendiente'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _SlopeTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
## 3. Height:
|
||||
class _CommandHeightAnalisys:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "TerrainHeight.svg")),
|
||||
'Accel': "T, H",
|
||||
'MenuText': 'Analisis de Altura',
|
||||
'ToolTip': 'Analisis de Altura'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _HeightTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
## 4. Orientation:
|
||||
class _CommandOrientationAnalisys:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "TerrainOrientation.svg")),
|
||||
'Accel': "T, H",
|
||||
'MenuText': 'Analisis de Orientación',
|
||||
'ToolTip': 'Analisis de Orientación'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _OrientationTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
## 5. Commands
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandTerrainAnalisysGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['Contours',
|
||||
'HeightAnalisys',
|
||||
'SlopeAnalisys',
|
||||
'OrientationAnalisys'
|
||||
])
|
||||
def GetResources(self):
|
||||
return { 'MenuText': QT_TRANSLATE_NOOP("",'Terrain Analisys'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("",'Terrain Analisys')
|
||||
}
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand('Contours', _CommandContours())
|
||||
FreeCADGui.addCommand('SlopeAnalisys', _CommandSlopeAnalisys())
|
||||
FreeCADGui.addCommand('HeightAnalisys', _CommandHeightAnalisys())
|
||||
FreeCADGui.addCommand('OrientationAnalisys', _CommandOrientationAnalisys())
|
||||
FreeCADGui.addCommand('TerrainAnalisys', CommandTerrainAnalisysGroup())
|
||||
172
PVPlantTerrainAnalisys.ui
Normal file
172
PVPlantTerrainAnalisys.ui
Normal file
@@ -0,0 +1,172 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>form</class>
|
||||
<widget class="QDialog" name="form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>386</width>
|
||||
<height>511</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Terrain Analisys</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Table setup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editTo">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editFrom">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Valor final</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Valor inicial</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Pasos</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="editSteps">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Valor min</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Valor max</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
435
PVPlantTree.ui
Normal file
435
PVPlantTree.ui
Normal file
@@ -0,0 +1,435 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>222</width>
|
||||
<height>280</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tracker:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Canopy</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Divisiones</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editCrownExpansion">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Crown Expansion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editLeftUmbrellaEffect">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editSpikiness">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Umbrella effect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QSpinBox" name="editLeafCount">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Spikiness</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editCanopyRadius">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>20.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editCanopyHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>20.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>4.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Trunk</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editTrunkHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editTrunkRadius">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.150000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Faces</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="editTrunkFaces">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
368
PVPlantTreeGenerator.py
Normal file
368
PVPlantTreeGenerator.py
Normal file
@@ -0,0 +1,368 @@
|
||||
|
||||
import math
|
||||
|
||||
import ArchComponent
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import Part
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "FreeCAD Fixed Rack"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
__dir__ = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", "PVPlant")
|
||||
DirResources = os.path.join(__dir__, "Resources")
|
||||
DirIcons = os.path.join(DirResources, "Icons")
|
||||
DirImages = os.path.join(DirResources, "Images")
|
||||
|
||||
|
||||
def makeTree():
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Tree")
|
||||
Tree(obj)
|
||||
ViewProviderTree(obj.ViewObject)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
try:
|
||||
folder = FreeCAD.ActiveDocument.Vegetation
|
||||
except:
|
||||
folder = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Vegetation')
|
||||
folder.Label = "Vegetation"
|
||||
folder.addObject(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class Tree(ArchComponent.Component):
|
||||
""" A Shadow Tree Obcject """
|
||||
|
||||
def __init__(self, obj):
|
||||
# Definición de variables:
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.obj = obj
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
# Definicion de Propiedades:
|
||||
pl = obj.PropertiesList
|
||||
|
||||
# CANOPY: ---------------------------------------------------------
|
||||
if not ("CanopyHeight" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"CanopyHeight",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).CanopyHeight = 4000
|
||||
|
||||
if not ("CanopyRadius" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"CanopyRadius",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).CanopyRadius = 1500
|
||||
|
||||
if not ("Spikiness" in pl):
|
||||
obj.addProperty("App::PropertyFloatConstraint",
|
||||
"Spikiness",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).Spikiness = (0.5, 0.0, 1.0, 0.05) # (Default, Start, Finish, Step)
|
||||
|
||||
'''
|
||||
if not ("Lumpiness" in pl):
|
||||
obj.addProperty("App::PropertyFloatConstraint",
|
||||
"Lumpiness",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).Lumpiness = (0.0, 0.0, 1.0, 0.05) #(Default, Start, Finish, Step)'''
|
||||
|
||||
if not ("CrownExpansion" in pl):
|
||||
obj.addProperty("App::PropertyFloatConstraint",
|
||||
"CrownExpansion",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).CrownExpansion = (1.0, 0.0, 2.0, 0.05) # (Default, Start, Finish, Step)
|
||||
|
||||
if not ("UmbrellaEffect" in pl):
|
||||
obj.addProperty("App::PropertyFloatConstraint",
|
||||
"UmbrellaEffect",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).UmbrellaEffect = (0.0, 0.0, 1.0, 0.05) # (Default, Start, Finish, Step)
|
||||
|
||||
if not ("LeafCount" in pl):
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"LeafCount",
|
||||
"Canopy",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).LeafCount = 20
|
||||
|
||||
# TRUNK: ------------------------------------------------------------------------------------------------------
|
||||
if not ("TrunkHeight" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"TrunkHeight",
|
||||
"Trunk",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).TrunkHeight = 2000
|
||||
|
||||
if not ("TrunkRadius" in pl):
|
||||
obj.addProperty("App::PropertyLength",
|
||||
"TrunkRadius",
|
||||
"Trunk",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).TrunkRadius = 150
|
||||
|
||||
if not ("TrunkFaces" in pl):
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"TrunkFaces",
|
||||
"Trunk",
|
||||
QT_TRANSLATE_NOOP("App::Property", "The height of self object")
|
||||
).TrunkFaces = 6
|
||||
|
||||
if not ("Type" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Type",
|
||||
"Base",
|
||||
"Type").Type = "Vegetable-Tree"
|
||||
obj.setEditorMode("Type", 1)
|
||||
|
||||
self.Type = obj.Type
|
||||
obj.Proxy = self
|
||||
obj.IfcType = "Shading Device"
|
||||
obj.setEditorMode("IfcType", 1)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
ArchComponent.Component.onDocumentRestored(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''if prop in ["CanopyHeight", "CanopyHeight", "Spikiness", "CrownExpansion", "UmbrellaEffect",
|
||||
"LeafCount"]:
|
||||
self.canopy = self.createCanopy(obj)
|
||||
|
||||
if prop in ["TrunkHeight", "TrunkRadius", "TrunkFaces"]:
|
||||
self.trunk = self.createTrunk(obj)'''
|
||||
|
||||
def createTrunk(self, obj):
|
||||
import Part
|
||||
angle = (math.pi * 2) / obj.TrunkFaces.Value
|
||||
delta = obj.TrunkRadius.Value
|
||||
pts = [FreeCAD.Vector(delta, 0, 0)]
|
||||
for i in range(int(obj.TrunkFaces.Value) - 1):
|
||||
ang = (i + 1) * angle
|
||||
pts.append(FreeCAD.Vector(delta * math.cos(ang),
|
||||
delta * math.sin(ang),
|
||||
0))
|
||||
pts.append(pts[0])
|
||||
p1 = Part.makePolygon(pts)
|
||||
p0 = p1.makeOffset2D(90, 2, False, False, True)
|
||||
p2 = p1.makeOffset2D(-50, 2, False, False, True)
|
||||
p0.Placement.Base.z = -150
|
||||
p1.Placement.Base.z = 150
|
||||
p2.Placement.Base.z = obj.TrunkHeight.Value - 250
|
||||
return Part.makeLoft([p0, p1, p2], True, True, False)
|
||||
|
||||
def createCanopy(self, obj):
|
||||
import Part
|
||||
import random
|
||||
import Mesh
|
||||
import numpy as np
|
||||
|
||||
ncircles = int(obj.LeafCount.Value)
|
||||
if ncircles % 2 == 0:
|
||||
ncircles += 1
|
||||
half_ncircles = int(ncircles / 2)
|
||||
ncirclesumbrella = int(half_ncircles/2)
|
||||
ncirclestop = ncircles - ncirclesumbrella
|
||||
|
||||
# 1. Create circles to define the sphere
|
||||
circles = []
|
||||
dist = 2 * obj.CanopyRadius.Value / (ncircles - 1)
|
||||
margin = dist * 0.01
|
||||
'''for i in range(half_ncircles + 1):
|
||||
if i > 0:
|
||||
d = (obj.CanopyRadius.Value - dist * i)
|
||||
else:
|
||||
d = obj.CanopyRadius.Value - margin
|
||||
r = (obj.CanopyRadius.Value ** 2 - d ** 2) ** 0.5
|
||||
c = Part.makeCircle(r)
|
||||
circles.append(c)
|
||||
|
||||
ctmp = [c.copy() for c in circles]
|
||||
ctmp.pop()
|
||||
ctmp.reverse()
|
||||
circles.extend(ctmp)'''
|
||||
|
||||
d = - obj.CanopyRadius.Value - dist
|
||||
b = (obj.CanopyRadius.Value ** 2 - (dist * (ncirclesumbrella - 1)) ** 2) ** 0.5
|
||||
|
||||
for i in range(ncircles):
|
||||
d += dist
|
||||
r = (obj.CanopyRadius.Value ** 2 - d ** 2) ** 0.5
|
||||
if i > ncirclesumbrella:
|
||||
if obj.CrownExpansion < 1:
|
||||
r = r * obj.CrownExpansion
|
||||
if r == 0:
|
||||
r = obj.CanopyRadius.Value * 0.01
|
||||
c = Part.makeCircle(r)
|
||||
circles.append(c)
|
||||
|
||||
# 2. Place circles
|
||||
dist = obj.CanopyHeight.Value / ncircles
|
||||
z = 0
|
||||
#zmax = dist * half_ncircles
|
||||
for idx in range(1, half_ncircles):
|
||||
z += dist
|
||||
circles[idx].Placement.Base.z = (1 - obj.UmbrellaEffect) * z
|
||||
#c.Placement.Base.z = obj.UmbrellaEffect * (zmax - z) + z
|
||||
|
||||
dist1 = (obj.CanopyHeight.Value - z) / (half_ncircles + 1)
|
||||
for idx in range(half_ncircles, ncircles):
|
||||
c = circles[idx]
|
||||
z += dist1
|
||||
c.Placement.Base.z = z
|
||||
|
||||
# 3. noise generator
|
||||
pts = []
|
||||
val = (dist / 2 - margin) * obj.Spikiness
|
||||
for c in circles:
|
||||
tmppts = c.discretize(ncircles)
|
||||
for j in range(len(tmppts)):
|
||||
point = tmppts[j]
|
||||
point.x += random.uniform(-val, val)
|
||||
point.y += random.uniform(-val, val)
|
||||
point.z += random.uniform(-val, val)
|
||||
pts.append(point)
|
||||
|
||||
# 4. generate the mesh / solid
|
||||
from scipy import spatial as sp_spatial
|
||||
pts = np.array(pts)
|
||||
hull = sp_spatial.ConvexHull(pts)
|
||||
indices = hull.simplices
|
||||
faces = pts[indices]
|
||||
mesh = Mesh.Mesh(faces.tolist())
|
||||
if len(mesh.Facets) == 0:
|
||||
return None
|
||||
mesh.harmonizeNormals()
|
||||
'''if mesh.Facets[0].Normal.z < 0:
|
||||
mesh.flipNormals()'''
|
||||
shape = Part.Shape()
|
||||
shape.makeShapeFromMesh(mesh.Topology, 0.1)
|
||||
return Part.makeSolid(shape)
|
||||
|
||||
def execute(self, obj):
|
||||
pl = obj.Placement
|
||||
|
||||
trunk = self.createTrunk(obj)
|
||||
canopy = self.createCanopy(obj)
|
||||
canopy.Placement.Base.z = obj.TrunkHeight.Value - 250 # - obj.CanopyRadius.Value / 2
|
||||
obj.Shape = Part.makeCompound([trunk, canopy])
|
||||
obj.Placement = pl
|
||||
|
||||
color = [(0.2510, 0.1255, 0.0)] * len(trunk.Faces)
|
||||
color.extend([(0.0, 0.3922, 0.0)] * len(canopy.Faces))
|
||||
obj.ViewObject.DiffuseColor = color
|
||||
|
||||
|
||||
class ViewProviderTree(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Pipe object"
|
||||
|
||||
def __init__(self, vobj):
|
||||
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||||
|
||||
def getIcon(self):
|
||||
return str(os.path.join(DirIcons, "tree(1).svg"))
|
||||
|
||||
|
||||
class TreeTaskPanel(QtGui.QWidget):
|
||||
def __init__(self, obj=None):
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.obj = obj
|
||||
if self.obj is None:
|
||||
self.obj = makeTree()
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(__dir__ + "/PVPlantTree.ui")
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||
self.layout.addWidget(self.form)
|
||||
|
||||
self.form.editCanopyHeight.valueChanged.connect(self.Canopy)
|
||||
self.form.editCanopyRadius.valueChanged.connect(self.Canopy)
|
||||
self.form.editSpikiness.valueChanged.connect(self.Canopy)
|
||||
self.form.editCrownExpansion.valueChanged.connect(self.Canopy)
|
||||
self.form.editLeftUmbrellaEffect.valueChanged.connect(self.Canopy)
|
||||
self.form.editLeafCount.valueChanged.connect(self.Canopy)
|
||||
|
||||
def Canopy(self):
|
||||
self.obj.CanopyHeight = FreeCAD.Units.Quantity(self.form.editCanopyHeight.text()).Value
|
||||
self.obj.CanopyRadius = FreeCAD.Units.Quantity(self.form.editCanopyRadius.text()).Value
|
||||
self.obj.Spikiness = self.form.editSpikiness.value()
|
||||
self.obj.CrownExpansion = self.form.editCrownExpansion.value()
|
||||
self.obj.UmbrellaEffect = self.form.editLeftUmbrellaEffect.value()
|
||||
self.obj.LeafCount = self.form.editLeafCount.value()
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def accept(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
|
||||
class _CommandTree:
|
||||
"the PVPlant Tree command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "tree(1).svg")),
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PVPlantTree", "Tree"),
|
||||
'Accel': "S, T",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PVPlanTree",
|
||||
"Creates a Tree object from setup dialog.")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
import draftguitools.gui_trackers as DraftTrackers
|
||||
self.tree = makeTree()
|
||||
FreeCADGui.Snapper.getPoint(callback=self.getPoint,
|
||||
movecallback=self.mousemove,
|
||||
extradlg=self.taskbox(),
|
||||
title="Position of the tree:")
|
||||
|
||||
def getPoint(self, point=None, obj=None):
|
||||
self.tree.Placement.Base = point
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
self.tracker.finalize()
|
||||
|
||||
def mousemove(self, pt, snapInfo):
|
||||
self.tree.Placement.Base = pt
|
||||
|
||||
def taskbox(self):
|
||||
self.form = TreeTaskPanel(self.tree)
|
||||
return self.form
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PVPlantTree', _CommandTree())
|
||||
|
||||
1111
PVPlantTrench.py
Normal file
1111
PVPlantTrench.py
Normal file
File diff suppressed because it is too large
Load Diff
302
PVPlantTrench.ui
Normal file
302
PVPlantTrench.ui
Normal file
@@ -0,0 +1,302 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>361</width>
|
||||
<height>395</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tracker:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Shape</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Altura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Anchura (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.990000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Rectangle</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Trapeze</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editModuleWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.030000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Layers</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listLayers">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonUp">
|
||||
<property name="text">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonDown">
|
||||
<property name="text">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAddLayer">
|
||||
<property name="text">
|
||||
<string>Add Layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonDeleteLayer">
|
||||
<property name="text">
|
||||
<string>Delete Layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
803
Project/Area/PVPlantArea.py
Normal file
803
Project/Area/PVPlantArea.py
Normal file
@@ -0,0 +1,803 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
import Part
|
||||
import PVPlantSite
|
||||
import Utils.PVPlantUtils as utils
|
||||
import MeshPart as mp
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from DraftTools import translate
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
__title__ = "PVPlant Areas"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
Dir3dObjects = os.path.join(PVPlantResources.DirResources, "3dObjects")
|
||||
|
||||
''' Default Area: '''
|
||||
|
||||
|
||||
def makeArea(points = None, type = 0):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Area")
|
||||
if type == 0:
|
||||
_Area(obj)
|
||||
_ViewProviderArea(obj.ViewObject)
|
||||
elif type == 1:
|
||||
_ForbiddenArea(obj)
|
||||
_ViewProviderForbiddenArea(obj.ViewObject)
|
||||
if points:
|
||||
obj.Points = points
|
||||
return obj
|
||||
|
||||
|
||||
class _Area:
|
||||
def __init__(self, obj):
|
||||
''' Initialize the Area object '''
|
||||
self.Type = None
|
||||
self.obj = None
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("Base" in pl):
|
||||
obj.addProperty("App::PropertyLink",
|
||||
"Base",
|
||||
"Area",
|
||||
"Base wire"
|
||||
).Base = None
|
||||
|
||||
if not ("Type" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Type",
|
||||
"Area",
|
||||
"Points that define the area"
|
||||
).Type = "Area"
|
||||
obj.setEditorMode("Type", 1)
|
||||
|
||||
self.Type = obj.Type
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
""" Method run when the document is restored """
|
||||
self.setProperties(obj)
|
||||
|
||||
|
||||
class _ViewProviderArea:
|
||||
def __init__(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
'''
|
||||
Create Object visuals in 3D view.
|
||||
'''
|
||||
self.Object = vobj.Object
|
||||
return
|
||||
|
||||
def getIcon(self):
|
||||
'''
|
||||
Return object treeview icon.
|
||||
'''
|
||||
|
||||
return str(os.path.join(DirIcons, "area.svg"))
|
||||
'''
|
||||
def claimChildren(self):
|
||||
"""
|
||||
Provides object grouping
|
||||
"""
|
||||
return self.Object.Group
|
||||
'''
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Enable edit
|
||||
"""
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Disable edit
|
||||
"""
|
||||
return False
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
"""
|
||||
Detect double click
|
||||
"""
|
||||
pass
|
||||
|
||||
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
|
||||
|
||||
|
||||
''' Frame Area '''
|
||||
|
||||
def makeFramedArea(base = None, select = None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "FrameArea")
|
||||
FrameArea(obj)
|
||||
ViewProviderFrameArea(obj.ViewObject)
|
||||
if base:
|
||||
obj.Base = base
|
||||
|
||||
if select:
|
||||
frames = []
|
||||
for o in select:
|
||||
if hasattr(o, "Proxy") and (o.Proxy.Type == "Tracker"):
|
||||
if not (o in frames):
|
||||
frames.append(o)
|
||||
if len(frames) > 0:
|
||||
print(frames)
|
||||
obj.Frames = frames
|
||||
|
||||
try:
|
||||
group = FreeCAD.ActiveDocument.FrameZones
|
||||
except:
|
||||
group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'FrameZones')
|
||||
group.Label = "FrameZones"
|
||||
group.addObject(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class FrameArea(_Area):
|
||||
def __init__(self, obj):
|
||||
_Area.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
self.obj = None
|
||||
|
||||
def setProperties(self, obj):
|
||||
_Area.setProperties(self, obj)
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not ("Frames" in pl):
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"Frames",
|
||||
"Area",
|
||||
"All the frames inside this area."
|
||||
)
|
||||
|
||||
if not ("FrameNumber" in pl):
|
||||
obj.addProperty("App::PropertyInteger",
|
||||
"FrameNumber",
|
||||
"Area",
|
||||
"The number of frames inside this area."
|
||||
)
|
||||
obj.setEditorMode("FrameNumber", 1)
|
||||
|
||||
if not ("Type" in pl):
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Type",
|
||||
"Base",
|
||||
"The facemaker type to use to build the profile of this object"
|
||||
).Type = "FrameArea"
|
||||
obj.setEditorMode("Type", 1)
|
||||
|
||||
self.Type = "FrameArea"
|
||||
obj.Proxy = self
|
||||
self.obj = obj
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored."""
|
||||
self.setProperties(obj)
|
||||
|
||||
def onBeforeChange(self, obj, prop):
|
||||
''' '''
|
||||
pass
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "Base":
|
||||
if obj.Base.Shape is None:
|
||||
obj.Shape = Part.Shape()
|
||||
return
|
||||
|
||||
import Utils.PVPlantUtils as utils
|
||||
|
||||
base = obj.Base.Shape
|
||||
land = PVPlantSite.get().Terrain.Mesh
|
||||
vec = FreeCAD.Vector(0,0,1)
|
||||
wire = utils.getProjected(base, vec)
|
||||
tmp = mp.projectShapeOnMesh(wire, land, vec)
|
||||
shape = Part.makeCompound([])
|
||||
for section in tmp:
|
||||
shape.add(Part.makePolygon(section))
|
||||
obj.Shape = shape
|
||||
|
||||
if prop == "Frames":
|
||||
lf = []
|
||||
for o in obj.Frames:
|
||||
if not hasattr(o, "Proxy"):
|
||||
continue
|
||||
if o.Proxy.Type == "Tracker":
|
||||
lf.append(obj)
|
||||
obj.Frames = lf
|
||||
obj.FramesNumber = len(obj.Frames)
|
||||
|
||||
def addFrame(self, frame):
|
||||
list = self.obj.Frames.copy()
|
||||
list.append(frame)
|
||||
self.obj.Frames = sorted(list, key=lambda x: x.Name)
|
||||
|
||||
def execute(self, obj):
|
||||
''' execute '''
|
||||
#_Area.execute(self, obj)
|
||||
|
||||
obj.FrameNumber = len(obj.Frames)
|
||||
|
||||
|
||||
class ViewProviderFrameArea(_ViewProviderArea):
|
||||
def __init__(self, vobj):
|
||||
''' Set view properties. '''
|
||||
self.Object = vobj.Object
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon '''
|
||||
return str(os.path.join(DirIcons, "FrameArea.svg"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
return children
|
||||
|
||||
|
||||
''' offsets '''
|
||||
|
||||
|
||||
def makeOffsetArea(base = None, val=None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "OffsetArea")
|
||||
OffsetArea(obj)
|
||||
obj.Base = base
|
||||
ViewProviderOffsetArea(obj.ViewObject)
|
||||
if val:
|
||||
obj.Distance = val
|
||||
|
||||
offsets = None
|
||||
try:
|
||||
offsetsgroup = FreeCAD.ActiveDocument.Offsets
|
||||
except:
|
||||
offsetsgroup = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Offsets')
|
||||
offsetsgroup.Label = "Offsets"
|
||||
offsetsgroup.addObject(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class OffsetArea(_Area):
|
||||
def __init__(self, obj):
|
||||
_Area.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
_Area.setProperties(self, obj)
|
||||
pl = obj.PropertiesList
|
||||
if not ("OffsetDistance" in pl):
|
||||
obj.addProperty("App::PropertyDistance",
|
||||
"OffsetDistance",
|
||||
"OffsetArea",
|
||||
"Base wire"
|
||||
)
|
||||
|
||||
self.Type = obj.Type = "Area_Offset"
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored."""
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self, obj):
|
||||
import Utils.PVPlantUtils as utils
|
||||
|
||||
base = obj.Base.Shape
|
||||
land = PVPlantSite.get().Terrain.Mesh
|
||||
vec = FreeCAD.Vector(0, 0, 1)
|
||||
wire = utils.getProjected(base, vec)
|
||||
wire = wire.makeOffset2D(obj.OffsetDistance.Value, 2, False, False, True)
|
||||
tmp = mp.projectShapeOnMesh(wire, land, vec)
|
||||
pts = []
|
||||
for section in tmp:
|
||||
pts.extend(section)
|
||||
obj.Shape = Part.makePolygon(pts)
|
||||
|
||||
|
||||
class ViewProviderOffsetArea(_ViewProviderArea):
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon. '''
|
||||
return str(os.path.join(DirIcons, "offset.svg"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
return children
|
||||
|
||||
|
||||
''' Forbidden Area: '''
|
||||
|
||||
|
||||
def makeProhibitedArea(base = None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "ProhibitedArea")
|
||||
ProhibitedArea(obj)
|
||||
ViewProviderForbiddenArea(obj.ViewObject)
|
||||
if base:
|
||||
obj.Base = base
|
||||
try:
|
||||
group = FreeCAD.ActiveDocument.Exclusion
|
||||
except:
|
||||
group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Exclusion')
|
||||
group.Label = "Exclusions"
|
||||
group.addObject(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class ProhibitedArea(OffsetArea):
|
||||
def __init__(self, obj):
|
||||
OffsetArea.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self, obj):
|
||||
OffsetArea.setProperties(self, obj)
|
||||
self.Type = obj.Type = "ProhibitedArea"
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored."""
|
||||
self.setProperties(obj)
|
||||
|
||||
|
||||
class ViewProviderForbiddenArea(_ViewProviderArea):
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon '''
|
||||
return str(os.path.join(DirIcons, "area_forbidden.svg"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
return children
|
||||
|
||||
|
||||
''' PV Area: '''
|
||||
|
||||
|
||||
def makePVSubplant():
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "PVSubplant")
|
||||
PVSubplant(obj)
|
||||
ViewProviderPVSubplant(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
|
||||
class PVSubplant:
|
||||
def __init__(self, obj):
|
||||
self.setProperties(obj)
|
||||
self.Type = None
|
||||
self.obj = None
|
||||
|
||||
def setProperties(self, obj):
|
||||
pl = obj.PropertiesList
|
||||
|
||||
if not "Setup" in pl:
|
||||
obj.addProperty("App::PropertyEnumeration",
|
||||
"Setup",
|
||||
"PVSubplant",
|
||||
"The facemaker type to use to build the profile of this object"
|
||||
).Setup = ["String Inverter", "Central Inverter"]
|
||||
|
||||
if not ("Frames" in pl):
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"Frames",
|
||||
"PVSubplant",
|
||||
"List of frames"
|
||||
)
|
||||
|
||||
if not ("Inverters" in pl):
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"Inverters",
|
||||
"PVSubplant",
|
||||
"List of Inverters"
|
||||
)
|
||||
|
||||
if not ("Cables" in pl):
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"Cables",
|
||||
"PVSubplant",
|
||||
"List of Cables"
|
||||
)
|
||||
|
||||
if not "TotalPVModules" in pl:
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"TotalPVModules",
|
||||
"PVSubplant",
|
||||
"The facemaker type to use to build the profile of this object"
|
||||
)
|
||||
|
||||
if not "TotalPowerDC" in pl:
|
||||
obj.addProperty("App::PropertyQuantity",
|
||||
"TotalPowerDC",
|
||||
"PVSubplant",
|
||||
"The facemaker type to use to build the profile of this object"
|
||||
)
|
||||
|
||||
if not "Color" in pl:
|
||||
obj.addProperty("App::PropertyColor",
|
||||
"Color",
|
||||
"PVSubplant",
|
||||
"Color"
|
||||
)
|
||||
|
||||
if not "Type" in pl:
|
||||
obj.addProperty("App::PropertyString",
|
||||
"Type",
|
||||
"Base",
|
||||
"The facemaker type to use to build the profile of this object"
|
||||
).Type = "PVSubplant"
|
||||
obj.setEditorMode("Type", 1)
|
||||
|
||||
self.Type = obj.Type
|
||||
self.obj = obj
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""Method run when the document is restored."""
|
||||
self.setProperties(obj)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "Color":
|
||||
obj.ViewObject.LineColor = obj.Color
|
||||
obj.ViewObject.PointColor = obj.Color
|
||||
|
||||
if prop == "Setup":
|
||||
if obj.Setup == "Central Inverter":
|
||||
if not ("StringBoxes" in obj.PropertiesList):
|
||||
obj.addProperty("App::PropertyLinkList",
|
||||
"StringBoxes",
|
||||
"PVSubplant",
|
||||
"List of String-Boxes"
|
||||
)
|
||||
else:
|
||||
if hasattr(obj, "StringBoxes"):
|
||||
obj.removeProperty("StringBoxes")
|
||||
|
||||
if prop == "Frames":
|
||||
import numpy as np
|
||||
# 1. Dibujar contorno:
|
||||
maxdist = 6000
|
||||
if len(obj.Frames) > 0:
|
||||
onlyframes = []
|
||||
for object in obj.Frames:
|
||||
if object.Name.startswith("Tracker"):
|
||||
onlyframes.append(object)
|
||||
obj.Frames = onlyframes
|
||||
|
||||
pts = []
|
||||
for frame in obj.Frames:
|
||||
for panel in frame.Shape.SubShapes[0].SubShapes[0].SubShapes:
|
||||
zm = panel.BoundBox.ZMax
|
||||
for i in range(8):
|
||||
pt = panel.BoundBox.getPoint(i)
|
||||
if pt.z == zm:
|
||||
pts.append(pt)
|
||||
import MeshTools.Triangulation as Triangulation
|
||||
import MeshTools.MeshGetBoundary as mgb
|
||||
m = Triangulation.Triangulate(np.array(pts), MaxlengthLE=maxdist, use3d=False)
|
||||
b = mgb.get_boundary(m)
|
||||
obj.Shape = b
|
||||
|
||||
# 2. rellenar información
|
||||
power = 0
|
||||
modulenum = 0
|
||||
for frame in obj.Frames:
|
||||
modules = frame.Setup.ModuleColumns * frame.Setup.ModuleRows
|
||||
power += frame.Setup.ModulePower.Value * modules
|
||||
modulenum += modules
|
||||
obj.TotalPowerDC = power
|
||||
obj.TotalPVModules = modulenum
|
||||
obj.ViewObject.LineWidth = 5
|
||||
|
||||
def execute(self, obj):
|
||||
''' '''
|
||||
pass
|
||||
|
||||
|
||||
class ViewProviderPVSubplant:
|
||||
def __init__(self, vobj):
|
||||
''' Set view properties. '''
|
||||
self.Object = None
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
''' Create Object visuals in 3D view. '''
|
||||
self.Object = vobj.Object
|
||||
return
|
||||
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon. '''
|
||||
return str(os.path.join(DirIcons, "subplant.svg"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Frames:
|
||||
children.extend(self.Object.Frames)
|
||||
return children
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
'''def onDelete(self, feature, subelements):
|
||||
try:
|
||||
for obj in self.claimChildren():
|
||||
obj.ViewObject.show()
|
||||
except Exception as err:
|
||||
FreeCAD.Console.PrintError("Error in onDelete: " + str(err))
|
||||
return True
|
||||
|
||||
def canDragObjects(self):
|
||||
return True
|
||||
|
||||
def canDropObjects(self):
|
||||
return True
|
||||
|
||||
def canDragObject(self, dragged_object):
|
||||
return True
|
||||
|
||||
def canDropObject(self, incoming_object):
|
||||
return hasattr(incoming_object, 'Shape')
|
||||
|
||||
def dragObject(self, selfvp, dragged_object):
|
||||
objs = self.Object.Objects
|
||||
objs.remove(dragged_object)
|
||||
self.Object.Objects = objs
|
||||
|
||||
def dropObject(self, selfvp, incoming_object):
|
||||
self.Object.Objects = self.Object.Objects + [incoming_object]
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Enable edit
|
||||
"""
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
"""
|
||||
Disable edit
|
||||
"""
|
||||
return False
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
"""
|
||||
Detect double click
|
||||
"""
|
||||
pass
|
||||
|
||||
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'''
|
||||
|
||||
# Comandos: -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class CommandDivideArea:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "area.svg")),
|
||||
'Accel': "A, D",
|
||||
'MenuText': "Divide Area",
|
||||
'ToolTip': "Allowed Area"}
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()[0]
|
||||
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CommandBoundary:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "area.svg")),
|
||||
'Accel': "A, B",
|
||||
'MenuText': "Area",
|
||||
'ToolTip': "Allowed Area"}
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()[0]
|
||||
obj = makeArea([ver.Point for ver in sel.Shape.Vertexes])
|
||||
#taskd = _PVPlantPlacementTaskPanel()
|
||||
#FreeCADGui.Control.showDialog(taskd)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CommandFrameArea:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "FrameArea.svg")),
|
||||
'Accel': "A, F",
|
||||
'MenuText': "Frame Area",
|
||||
'ToolTip': "Frame Area"}
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
makeFramedArea(None, sel)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CommandProhibitedArea:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "area_forbidden.svg")),
|
||||
'Accel': "A, F",
|
||||
'MenuText': "Prohibited Area",
|
||||
'ToolTip': "Prohibited Area"}
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
makeProhibitedArea(sel[0])
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CommandPVSubplant:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "subplant.svg")),
|
||||
'Accel': "A, P",
|
||||
'MenuText': "PV Subplant",
|
||||
'ToolTip': "PV Subplant"}
|
||||
|
||||
def Activated(self):
|
||||
area = makePVSubplant()
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
for obj in sel:
|
||||
if obj.Name[:7] == "Tracker":
|
||||
frame_list = area.Frames
|
||||
frame_list.append(obj)
|
||||
area.Frames = frame_list
|
||||
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CommandOffsetArea:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "offset.svg")),
|
||||
'Accel': "A, O",
|
||||
'MenuText': "OffsetArea",
|
||||
'ToolTip': "OffsetArea"}
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
base = None
|
||||
if sel:
|
||||
base = sel[0]
|
||||
obj = makeOffsetArea(base)
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandAreaGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple([#'Area',
|
||||
'FrameArea',
|
||||
'ForbiddenArea',
|
||||
'PVSubplant',
|
||||
'OffsetArea'
|
||||
])
|
||||
|
||||
def GetResources(self):
|
||||
return {'MenuText': 'Areas',
|
||||
'ToolTip': 'Areas'
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
#FreeCADGui.addCommand('Area', CommandBoundary())
|
||||
FreeCADGui.addCommand('FrameArea', CommandFrameArea())
|
||||
FreeCADGui.addCommand('ForbiddenArea', CommandProhibitedArea())
|
||||
FreeCADGui.addCommand('PVSubplant', CommandPVSubplant())
|
||||
FreeCADGui.addCommand('OffsetArea', CommandOffsetArea())
|
||||
FreeCADGui.addCommand('PVPlantAreas', CommandAreaGroup())
|
||||
167
Project/Area/PVPlantAreaUtils.py
Normal file
167
Project/Area/PVPlantAreaUtils.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Area Utils"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
|
||||
|
||||
def splitArea(area, tool):
|
||||
if (not area) or (not tool):
|
||||
return None
|
||||
|
||||
import Part, TechDraw
|
||||
import BOPTools.SplitAPI as splitter
|
||||
tool = tool.Shape
|
||||
if tool.BoundBox.ZMax != tool.BoundBox.ZMin:
|
||||
tool = TechDraw.projectEx(tool, FreeCAD.Vector(0, 0, 1))[0]
|
||||
tool = tool.extrude(FreeCAD.Vector(0, 0, 1000))
|
||||
tool.Placement.Base.z -= 500
|
||||
|
||||
shape = area.Shape
|
||||
if shape.BoundBox.ZMax != shape.BoundBox.ZMin:
|
||||
shape = TechDraw.projectEx(shape, FreeCAD.Vector(0, 0, 1))[0]
|
||||
face = Part.Face(Part.Wire(shape.Edges))
|
||||
|
||||
return splitter.slice(face, [tool, ], "Split")
|
||||
|
||||
|
||||
class splitAreaTaskPanel:
|
||||
def __init__(self):
|
||||
self.area = None
|
||||
self.tool = None
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(PVPlantResources.__dir__, "Project", "Area", "PVPlantSplitArea.ui"))
|
||||
self.form.buttonAreaSel.clicked.connect(self.addArea)
|
||||
self.form.buttonToolSel.clicked.connect(self.addTool)
|
||||
|
||||
#self.view = FreeCADGui.ActiveDocument.ActiveView
|
||||
#self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
|
||||
def addArea(self):
|
||||
self.area = FreeCADGui.Selection.getSelection()[0]
|
||||
self.form.lineArea.setText(self.area.Name)
|
||||
|
||||
def addTool(self):
|
||||
self.tool = FreeCADGui.Selection.getSelection()[0]
|
||||
self.form.lineTool.setText(self.tool.Name)
|
||||
|
||||
def accept(self):
|
||||
import Part
|
||||
self.closeForm()
|
||||
results = splitArea(self.area, self.tool)
|
||||
if isinstance(results, Part.Compound):
|
||||
for face in results.Faces:
|
||||
Part.show(face.Wire, self.area.Label + "-split")
|
||||
elif isinstance(results, list):
|
||||
for face in results:
|
||||
Part.show(face.Wire, self.area.Label + "-split")
|
||||
else:
|
||||
Part.show(results)
|
||||
|
||||
|
||||
if self.form.checkBoxDeleteTool.isChecked():
|
||||
FreeCAD.ActiveDocument.removeObject(self.tool.Name)
|
||||
if self.form.checkBoxDeleteArea.isChecked():
|
||||
FreeCAD.ActiveDocument.removeObject(self.area.Name)
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
print(" .. Rejecting .. ")
|
||||
if self.new:
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def closeForm(self):
|
||||
print(" .. Closing .. ")
|
||||
#self.view.removeEventCallback("SoEvent", self.call)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
def joinAreas(areas):
|
||||
if len(areas) == 0:
|
||||
return None
|
||||
|
||||
import TechDraw
|
||||
shapes = []
|
||||
for area in areas:
|
||||
shape = area.Shape
|
||||
if shape.BoundBox.ZMax != shape.BoundBox.ZMin:
|
||||
shape = TechDraw.projectEx(shape, FreeCAD.Vector(0, 0, 1))[0]
|
||||
shapes.append(shape)
|
||||
shape = shapes.pop()
|
||||
shape.fuse(shapes)
|
||||
return shape
|
||||
|
||||
class CommandSplitArea:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "split_area.svg")),
|
||||
'Accel': "A, S",
|
||||
'MenuText': "Split Area",
|
||||
'ToolTip': "Split Area"}
|
||||
|
||||
def IsActive(self):
|
||||
return (not FreeCAD.ActiveDocument is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="ProhibitedArea") is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="OffsetArea") is None)
|
||||
def Activated(self):
|
||||
self.TaskPanel = splitAreaTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
class CommandJoinAreas:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "split_area.svg")),
|
||||
'Accel': "A, J",
|
||||
'MenuText': "Join Areas",
|
||||
'ToolTip': "Join Areas"}
|
||||
|
||||
def IsActive(self):
|
||||
return (not FreeCAD.ActiveDocument is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="ProhibitedArea") is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="OffsetArea") is None)
|
||||
def Activated(self):
|
||||
self.TaskPanel = splitAreaTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('SplitArea', CommandSplitArea())
|
||||
FreeCADGui.addCommand('JoinAreas', CommandJoinAreas())
|
||||
|
||||
|
||||
106
Project/Area/PVPlantSplitArea.ui
Normal file
106
Project/Area/PVPlantSplitArea.ui
Normal file
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formSplitArea</class>
|
||||
<widget class="QWidget" name="formSplitArea">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>313</width>
|
||||
<height>301</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Split Area</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Herramienta de corte</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineTool">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonToolSel">
|
||||
<property name="text">
|
||||
<string>Seleccionar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Area</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLineEdit" name="lineArea">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="buttonAreaSel">
|
||||
<property name="text">
|
||||
<string>Seleccionar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Resultado</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxDeleteTool">
|
||||
<property name="text">
|
||||
<string>Borrar herramienta de corte</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxDeleteArea">
|
||||
<property name="text">
|
||||
<string>Borrar Area inicial</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
163
Project/ProjectSetup.py
Normal file
163
Project/ProjectSetup.py
Normal file
@@ -0,0 +1,163 @@
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtGui, QtCore
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Project Setup"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
class ProjectSetupDialog(QtGui.QWidget):
|
||||
'''The editmode TaskPanel to select what you want to export'''
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QWidget.__init__(self)
|
||||
|
||||
import os
|
||||
# self.form:
|
||||
self.form = FreeCADGui.PySideUic.loadUi(
|
||||
os.path.join(os.path.dirname(os.path.realpath(__file__)), "ProjectSetup.ui"))
|
||||
#self.form.setWindowIcon(QtGui.QIcon(os.path.join(PVPlantResources.DirIcons, "convert.svg")))
|
||||
|
||||
self.bcnf = FreeCADGui.UiLoader().createWidget("Gui::ColorButton")
|
||||
self.bcnf.setProperty('color', QtGui.QColor(255, 126, 126))
|
||||
self.bcsf = FreeCADGui.UiLoader().createWidget("Gui::ColorButton")
|
||||
self.bcsf.setProperty('color', QtGui.QColor(255, 126, 0))
|
||||
gridLayout = self.form.tab1.layout()
|
||||
gridLayout.addWidget(self.bcnf, 2, 1)
|
||||
gridLayout.addWidget(self.bcsf, 2, 2)
|
||||
self.setdefaultvalues()
|
||||
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||
self.layout.addWidget(self.form)
|
||||
|
||||
self.form.buttonAccept.clicked.connect(self.onAcceptClick)
|
||||
self.form.buttonCancel.clicked.connect(self.onCancelClick)
|
||||
|
||||
def setdefaultvalues(self):
|
||||
doc = FreeCAD.ActiveDocument
|
||||
pl = doc.PropertiesList
|
||||
if "MaximumTiltPositive" in pl:
|
||||
self.form.editNFTL.setValue(doc.MaximumTiltPositive)
|
||||
|
||||
if "MaximumTiltPositiveColor" in pl:
|
||||
col = QtGui.QColor()
|
||||
col.setRgbF(doc.MaximumTiltPositiveColor[0], doc.MaximumTiltPositiveColor[1],
|
||||
doc.MaximumTiltPositiveColor[2])
|
||||
self.bcsf.setProperty('color', col)
|
||||
|
||||
if "MaximumTiltNegative" in pl:
|
||||
self.form.editSFTL.setValue(-doc.MaximumTiltNegative)
|
||||
|
||||
if "MaximumTiltNegativeColor" in pl:
|
||||
col = QtGui.QColor()
|
||||
col.setRgbF(doc.MaximumTiltNegativeColor[0], doc.MaximumTiltNegativeColor[1],
|
||||
doc.MaximumTiltNegativeColor[2])
|
||||
self.bcnf.setProperty('color', col)
|
||||
|
||||
if "MaximumWestEastSlope" in pl:
|
||||
self.form.editWETL.setValue(doc.MaximumWestEastSlope)
|
||||
|
||||
|
||||
def onAcceptClick(self):
|
||||
doc = FreeCAD.ActiveDocument
|
||||
pl = doc.PropertiesList
|
||||
if not ("FramesChecking" in pl):
|
||||
doc.addProperty("App::PropertyBool",
|
||||
"FramesChecking",
|
||||
"PVPlantProject",
|
||||
"All the frames inside this area."
|
||||
).FramesChecking = False
|
||||
doc.setEditorMode("FramesChecking", 1) # no editable
|
||||
doc.setEditorMode("FramesChecking", 2) # no visible
|
||||
|
||||
if not ("MaximumTiltPositive" in pl):
|
||||
doc.addProperty("App::PropertyAngle",
|
||||
"MaximumTiltPositive",
|
||||
"PVPlantProject",
|
||||
"All the frames inside this area."
|
||||
)
|
||||
|
||||
if not ("MaximumTiltPositiveColor" in pl):
|
||||
doc.addProperty("App::PropertyColor",
|
||||
"MaximumTiltPositiveColor",
|
||||
"PVPlantProject",
|
||||
"All the frames inside this area."
|
||||
)
|
||||
|
||||
if not ("MaximumTiltNegative" in pl):
|
||||
doc.addProperty("App::PropertyAngle",
|
||||
"MaximumTiltNegative",
|
||||
"PVPlantProject",
|
||||
"All the frames inside this area."
|
||||
)
|
||||
|
||||
if not ("MaximumTiltNegativeColor" in pl):
|
||||
doc.addProperty("App::PropertyColor",
|
||||
"MaximumTiltNegativeColor",
|
||||
"PVPlantProject",
|
||||
"All the frames inside this area."
|
||||
)
|
||||
|
||||
if not ("MaximumWestEastSlope" in pl):
|
||||
doc.addProperty("App::PropertyAngle",
|
||||
"MaximumWestEastSlope",
|
||||
"PVPlantProject",
|
||||
"All the frames inside this area."
|
||||
)
|
||||
|
||||
doc.MaximumTiltPositive = self.form.editNFTL.value()
|
||||
col = self.bcsf.property('color')
|
||||
doc.MaximumTiltPositiveColor = (col.redF(), col.greenF(), col.blueF())
|
||||
|
||||
doc.MaximumTiltNegative = -self.form.editSFTL.value()
|
||||
col = self.bcnf.property('color')
|
||||
doc.MaximumTiltNegativeColor = (col.redF(), col.greenF(), col.blueF())
|
||||
|
||||
doc.MaximumWestEastSlope = self.form.editWETL.value()
|
||||
|
||||
self.closeForm()
|
||||
|
||||
def onCancelClick(self):
|
||||
self.closeForm()
|
||||
|
||||
def closeForm(self):
|
||||
self.close()
|
||||
|
||||
class CommandProjectSetup:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "flash.svg")),
|
||||
'Accel': "P, S",
|
||||
'MenuText': "Project Setup",
|
||||
'ToolTip': "Setup all the variable for this project"}
|
||||
|
||||
def Activated(self):
|
||||
taskd = ProjectSetupDialog()
|
||||
taskd.setParent(FreeCADGui.getMainWindow())
|
||||
taskd.setWindowFlags(QtCore.Qt.Window)
|
||||
taskd.show()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('ProjectSetup', CommandProjectSetup())
|
||||
|
||||
201
Project/ProjectSetup.ui
Normal file
201
Project/ProjectSetup.ui
Normal file
@@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formProjectSetup</class>
|
||||
<widget class="QDialog" name="formProjectSetup">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>485</width>
|
||||
<height>384</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export to PVSyst</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab1">
|
||||
<attribute name="title">
|
||||
<string>Frame Tolerances</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Maximum north-south slope:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Frame coloring:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Maximum west-east slope:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editWETL">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> º</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>8.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDoubleSpinBox" name="editSFTL">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> º</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2.800000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QWidget" name="widget_2" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>South facing</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="editNFTL">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> º</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>North Facing</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab2">
|
||||
<attribute name="title">
|
||||
<string>tab2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab3">
|
||||
<attribute name="title">
|
||||
<string>Page</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAccept">
|
||||
<property name="text">
|
||||
<string>Aceptar</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Accept">
|
||||
<normaloff>../../../../../.designer/backup</normaloff>../../../../../.designer/backup</iconset>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonCancel">
|
||||
<property name="text">
|
||||
<string>Cancelar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
108
Project/utils/renamer.py
Normal file
108
Project/utils/renamer.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui, os
|
||||
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
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
|
||||
|
||||
def rename(objects, mask, mode=0):
|
||||
'''
|
||||
mode = 0/1/2/3
|
||||
0: izquierda a derecha - arriba a abajo
|
||||
1: arriba a abajo - izquierda a derecha
|
||||
'''
|
||||
|
||||
# sort:
|
||||
tmp = sorted(objects, key=lambda x: (x.Placement.Base.x,
|
||||
x.Placement.Base.y))
|
||||
|
||||
for idx, obj in tmp:
|
||||
obj.Name = name
|
||||
|
||||
class renamerTaskPanel:
|
||||
def __init__(self, obj=None):
|
||||
self.obj = obj
|
||||
|
||||
# -------------------------------------------------------------------------------------------------------------
|
||||
# Module widget form
|
||||
# -------------------------------------------------------------------------------------------------------------
|
||||
self.formRack = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantFrame.ui")
|
||||
self.formRack.widgetTracker.setVisible(False)
|
||||
self.formRack.comboFrameType.currentIndexChanged.connect(self.selectionchange)
|
||||
|
||||
self.formPiling = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantRackFixedPiling.ui")
|
||||
self.formPiling.editBreadthwaysNumOfPost.valueChanged.connect(self.editBreadthwaysNumOfPostChange)
|
||||
self.formPiling.editAlongNumOfPost.valueChanged.connect(self.editAlongNumOfPostChange)
|
||||
|
||||
self.form = [self.formRack, self.formPiling]
|
||||
|
||||
def accept(self):
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
self.closeForm()
|
||||
return False
|
||||
|
||||
def closeForm(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
|
||||
class _CommandRenamer:
|
||||
"the Arch Building command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "trackersetup.svg")),
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PVPlantTracker", "TrackerSetup"),
|
||||
'Accel': "R, F",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PVPlanTracker",
|
||||
"Creates a TrackerSetup object from setup dialog.")}
|
||||
|
||||
def IsActive(self):
|
||||
return (not FreeCAD.ActiveDocument is None and
|
||||
not FreeCAD.ActiveDocument.getObject("Site") is None)
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = renamerTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
90
Project/utils/renamer.ui
Normal file
90
Project/utils/renamer.ui
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formRack</class>
|
||||
<widget class="QDialog" name="formRack">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>255</width>
|
||||
<height>337</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fixed Frame:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Renombrar por sub-planta</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>GroupBox</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>New Item</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>New Item</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>New Item</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>New Item</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Leyenda</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,820 @@
|
||||
<?xml version='1.0' standalone='yes' ?>
|
||||
<LVData xmlns="http://www.ni.com/LVData">
|
||||
<Version>12.0f3</Version>
|
||||
<Cluster>
|
||||
<Name>Cable Data</Name>
|
||||
<NumElts>11</NumElts>
|
||||
<Cluster>
|
||||
<Name>General</Name>
|
||||
<NumElts>9</NumElts>
|
||||
<String>
|
||||
<Name>Title</Name>
|
||||
<Val>0.5mm2 Cu_Single core, 1kV V-90 insulated (unsheathed)</Val>
|
||||
</String>
|
||||
<String>
|
||||
<Name>Description</Name>
|
||||
<Val>To AS/NZS 5000.1</Val>
|
||||
</String>
|
||||
<Path>
|
||||
<Name>Path</Name>
|
||||
<Val>C:\Users\User\Desktop\Cables\Olex LV Handbook\PVC Insulated\0.5mm2 Cu_Single core, 1kV V-90 insulated (unsheathed).xml</Val>
|
||||
</Path>
|
||||
<DBL>
|
||||
<Name>Frequency (Hz)</Name>
|
||||
<Val>50.00000000000000</Val>
|
||||
</DBL>
|
||||
<EL>
|
||||
<Name>Phases</Name>
|
||||
<Choice>DC</Choice>
|
||||
<Choice>Single phase</Choice>
|
||||
<Choice>Three phase</Choice>
|
||||
<Val>2</Val>
|
||||
</EL>
|
||||
<EL>
|
||||
<Name>Cores</Name>
|
||||
<Choice>Single core</Choice>
|
||||
<Choice>Multicore</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<DBL>
|
||||
<Name>Voltage, U (phase to phase)</Name>
|
||||
<Val>1000.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Daily load factor, L</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Conductor temperature, theta (deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor</Name>
|
||||
<NumElts>10</NumElts>
|
||||
<EW>
|
||||
<Name>Conductor size (mm2)</Name>
|
||||
<Choice>0.5 mm2</Choice>
|
||||
<Choice>0.75 mm2</Choice>
|
||||
<Choice>1 mm2</Choice>
|
||||
<Choice>1.5 mm2</Choice>
|
||||
<Choice>2.5 mm2</Choice>
|
||||
<Choice>4 mm2</Choice>
|
||||
<Choice>6 mm2</Choice>
|
||||
<Choice>10 mm2</Choice>
|
||||
<Choice>16 mm2</Choice>
|
||||
<Choice>25 mm2</Choice>
|
||||
<Choice>35 mm2</Choice>
|
||||
<Choice>50 mm2</Choice>
|
||||
<Choice>70 mm2</Choice>
|
||||
<Choice>95 mm2</Choice>
|
||||
<Choice>120 mm2</Choice>
|
||||
<Choice>150 mm2</Choice>
|
||||
<Choice>185 mm2</Choice>
|
||||
<Choice>240 mm2</Choice>
|
||||
<Choice>300 mm2</Choice>
|
||||
<Choice>400 mm2</Choice>
|
||||
<Choice>500 mm2</Choice>
|
||||
<Choice>630 mm2</Choice>
|
||||
<Choice>800 mm2</Choice>
|
||||
<Choice>1000 mm2</Choice>
|
||||
<Choice>1200 mm2</Choice>
|
||||
<Choice>1600 mm2</Choice>
|
||||
<Choice>1800 mm2</Choice>
|
||||
<Choice>2000 mm2</Choice>
|
||||
<Choice>2500 mm2</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Conductor class</Name>
|
||||
<Choice>Class 1 solid conductors for single or multicore cables</Choice>
|
||||
<Choice>Class 2 stranded conductors for single or multicore cables</Choice>
|
||||
<Choice>Class 5 flexible copper conductors for single or multicore cables</Choice>
|
||||
<Choice>Class 6 flexible copper conductors for single or multicore cables</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Conductor material</Name>
|
||||
<Choice>Copper, plain wires</Choice>
|
||||
<Choice>Copper, metal-coated wires</Choice>
|
||||
<Choice>Aluminium wires</Choice>
|
||||
<Choice>Aluminium alloy wires</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Boolean>
|
||||
<Name>Hard-drawn Cu? (aerial cable)</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EW>
|
||||
<Name>Conductor Type</Name>
|
||||
<Choice>Copper_Round, stranded_Dried & impregnated</Choice>
|
||||
<Choice>Copper_Round, stranded_Not dried & impregnated</Choice>
|
||||
<Choice>Copper_Round, 4 segment</Choice>
|
||||
<Choice>Copper_Hollow, helical stranded_Dried and impregnated</Choice>
|
||||
<Choice>Copper_Sector-shaped_Dried and impregnated</Choice>
|
||||
<Choice>Copper_Sector-shaped_Not dried and impregnated</Choice>
|
||||
<Choice>Aluminium_Round, stranded</Choice>
|
||||
<Choice>Aluminium_Round, 4 segment</Choice>
|
||||
<Choice>Aluminium_Round, 5 segment</Choice>
|
||||
<Choice>Aluminium_Round, 6 segment</Choice>
|
||||
<Choice>Aluminium, Segmental with peripheral strands</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Conductor shape (self inductance)</Name>
|
||||
<Choice>Circular</Choice>
|
||||
<Choice>Circular compacted</Choice>
|
||||
<Choice>Shaped</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<DBL>
|
||||
<Name>External diameter of cable, De (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<Cluster>
|
||||
<Name>DC resistance</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Standards</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>DC resistance calculation based on:</Name>
|
||||
<Choice>Insulation max. operating temperature, Theta (deg.C)</Choice>
|
||||
<Choice>Conductor operating temperature (deg.C)</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<DBL>
|
||||
<Name>Conductor operating temperature (deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<EW>
|
||||
<Name>Standards</Name>
|
||||
<Choice>IEC 60228:2004</Choice>
|
||||
<Choice>AS/NZS 1125:2001</Choice>
|
||||
<Val>1</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>3.60000000000000E-2</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>3.93000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor No. of Wires</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<EL>
|
||||
<Name>Mode</Name>
|
||||
<Choice>Based on conductor size (mm2) and IEC 60228</Choice>
|
||||
<Choice>Specify no. of conductors</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<I32>
|
||||
<Name>No. of conductor wires</Name>
|
||||
<Val>0</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor diameter</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<EL>
|
||||
<Name>Mode</Name>
|
||||
<Choice>Based on conductor size (mm2)</Choice>
|
||||
<Choice>Specify conductor diameter</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<DBL>
|
||||
<Name>Nominal conductor diameter, dc (m)</Name>
|
||||
<Val>8.00000000000000E-4</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor shield</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Boolean>
|
||||
<Name>Conductor shield?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>3.60000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Insulation</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<EW>
|
||||
<Name>Type of cable insulation</Name>
|
||||
<Choice>Impregnated paper_Solid type, fully- pre- or mass-impregnated non-draining</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 36kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 87kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 160kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 220kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-pressure pipe-type</Choice>
|
||||
<Choice>Impregnated paper_External gas pressure</Choice>
|
||||
<Choice>Impregnated paper_Internal gas pressure</Choice>
|
||||
<Choice>Butyl rubber</Choice>
|
||||
<Choice>EPR_up to and including 18/30 (36) kV</Choice>
|
||||
<Choice>EPR_greater than 18/30 (36) kV</Choice>
|
||||
<Choice>PVC</Choice>
|
||||
<Choice>PE (HD and LD)</Choice>
|
||||
<Choice>XLPE_Unfilled_up to and including 18/30 (36) kV</Choice>
|
||||
<Choice>XLPE_Unfilled_greater than 18/30 (36) kV</Choice>
|
||||
<Choice>XLPE_Filled_greater than 18/30 (36) kV</Choice>
|
||||
<Choice>PPL_equal to or greater than 63/110 kV</Choice>
|
||||
<Val>11</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Epsilon</Name>
|
||||
<Val>8.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Tandelta</Name>
|
||||
<Val>0.10000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>8.00000000000000E-4</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>2.40000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<I32>
|
||||
<Name>Insulation. Max. operating temp., Theta (deg.C)</Name>
|
||||
<Val>90</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Insulation screen</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<Boolean>
|
||||
<Name>Insulation screen?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Single core</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Semi-conductor screen</Choice>
|
||||
<Choice>Copper screen tape</Choice>
|
||||
<Choice>Aluminium screen tape</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Multi-core</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Belted (unscreened)-Multicore</Choice>
|
||||
<Choice>Semi-conductor screen</Choice>
|
||||
<Choice>Copper screen tape</Choice>
|
||||
<Choice>Aluminium screen tape</Choice>
|
||||
<Val>1</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Sheath</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<Boolean>
|
||||
<Name>Cable sheath?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EL>
|
||||
<Name>Multicore</Name>
|
||||
<Choice>Common</Choice>
|
||||
<Choice>Sheath per phase</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<Cluster>
|
||||
<Name>Type of sheath</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>Type of sheath</Name>
|
||||
<Choice>Aluminium</Choice>
|
||||
<Choice>Lead</Choice>
|
||||
<Choice>Lead with reinforcing tape</Choice>
|
||||
<Choice>Copper</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Construction and dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<EW>
|
||||
<Name>Construction</Name>
|
||||
<Choice>Non-corrugated</Choice>
|
||||
<Choice>Corrugated</Choice>
|
||||
<Choice>Longitudinally corrugated</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<Cluster>
|
||||
<Name>Non-corrugated</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Corrugated</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness of corrugated sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Inner diameter of corrugated sheath (m)</Name>
|
||||
<Val>2.40000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Outer diameter of corrugated sheath (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Longitudinally corrugated</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Corrugation height</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Inner radius of corrugated sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Outer radius of corrugated sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<Cluster>
|
||||
<Name>Tape</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<DBL>
|
||||
<Name>Overlap (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Width (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Accumulation factor</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<Cluster>
|
||||
<Name>Calculated properties</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Diameter over sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>DC resistance at 25 deg.C. (Ohm/m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Sheath reinforcing tape</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<Boolean>
|
||||
<Name>Sheath reinforcing tape?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Material</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Copper</Choice>
|
||||
<Choice>Brass/bronze</Choice>
|
||||
<Choice>Zinc</Choice>
|
||||
<Choice>Stainless steel</Choice>
|
||||
<Choice>Steel</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Width (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of tapes</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Concentric neutral</Name>
|
||||
<NumElts>6</NumElts>
|
||||
<Boolean>
|
||||
<Name>Concentric neutral?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EL>
|
||||
<Name>Multicore</Name>
|
||||
<Choice>Common</Choice>
|
||||
<Choice>Around each core</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Custom</Choice>
|
||||
<Choice>Copper</Choice>
|
||||
<Choice>Brass/bronze</Choice>
|
||||
<Choice>Zinc</Choice>
|
||||
<Choice>Stainless steel</Choice>
|
||||
<Val>1</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Construction</Name>
|
||||
<Choice>Round wires</Choice>
|
||||
<Choice>Flat straps</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Electrical and magnetic material properties</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<Cluster>
|
||||
<Name>Electrical resistivity and temp. coefficient</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>1.72410000000000E-8</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>3.93000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Round Wire</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of wires</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Flat straps</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Strap length (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of straps</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Bedding</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<Boolean>
|
||||
<Name>Armour bedding?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Compounded jute and fibrous materials</Choice>
|
||||
<Choice>Rubber sandwich protection</Choice>
|
||||
<Choice>Polychloroprene</Choice>
|
||||
<Choice>PVC up to and including 35 kV</Choice>
|
||||
<Choice>PVC greater than 35 kV</Choice>
|
||||
<Choice>PVC/bitumen on corrugated aluminium sheaths</Choice>
|
||||
<Choice>PE</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<DBL>
|
||||
<Name>Thermal resistivity, rhoT (Cm/W)</Name>
|
||||
<Val>6.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>0.99880000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>2.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Armour/reinforcing tape</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<Boolean>
|
||||
<Name>Armour/reinforcing tape?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Material</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Custom_non-magnetic tape</Choice>
|
||||
<Choice>Steel tape reinforcement</Choice>
|
||||
<Choice>Custom_non-magnetic wires</Choice>
|
||||
<Choice>Custom_magnetic wires</Choice>
|
||||
<Choice>Steel wires_touching</Choice>
|
||||
<Choice>Steel wires_not touching</Choice>
|
||||
<Choice>Copper armour wires</Choice>
|
||||
<Choice>Stainless steel wires</Choice>
|
||||
<Choice>TECK armour</Choice>
|
||||
<Val>4</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Electrical and magnetic material properties</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Cluster>
|
||||
<Name>Electrical resistivity and temp. coefficient</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>1.38000000000000E-7</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>4.50000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Magnetic properties (if applicable)</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<EL>
|
||||
<Name>Magnetic properties</Name>
|
||||
<Choice>Standard</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<DBL>
|
||||
<Name>Longitudinal relative permeability, Mue-e</Name>
|
||||
<Val>10.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Traverse relative permeability, Mue-t</Name>
|
||||
<Val>45.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Gamma angle (degrees)</Name>
|
||||
<Val>45.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Wire</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of wires</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Tape</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Cross-sectional area of tape armour (m2)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<EW>
|
||||
<Name>Lay of tapes (reinforcement resistance)</Name>
|
||||
<Choice>Very long lay (longitudinal tapes)</Choice>
|
||||
<Choice>Wound at approximately 54 degrees</Choice>
|
||||
<Choice>Wound in very short lay (circumferential tapes)</Choice>
|
||||
<Choice>Layers of tapes in contact with each other having a very short lay</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Jacket/Serving</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<Boolean>
|
||||
<Name>Jacket/Serving?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Compounded jute and fibrous materials</Choice>
|
||||
<Choice>Rubber sandwich</Choice>
|
||||
<Choice>Polychropropene</Choice>
|
||||
<Choice>PVC up to and including 35 kV</Choice>
|
||||
<Choice>PVC above 35 kV</Choice>
|
||||
<Choice>Butyl rubber</Choice>
|
||||
<Choice>Coal tar wrapping</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<DBL>
|
||||
<Name>Thermal resistivity, rhoT (Cm/W)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.80000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</LVData>
|
||||
@@ -0,0 +1,820 @@
|
||||
<?xml version='1.0' standalone='yes' ?>
|
||||
<LVData xmlns="http://www.ni.com/LVData">
|
||||
<Version>12.0f3</Version>
|
||||
<Cluster>
|
||||
<Name>Cable Data</Name>
|
||||
<NumElts>11</NumElts>
|
||||
<Cluster>
|
||||
<Name>General</Name>
|
||||
<NumElts>9</NumElts>
|
||||
<String>
|
||||
<Name>Title</Name>
|
||||
<Val>1.5mm2 Cu_Single core, 1kV V-90 insulated (unsheathed)</Val>
|
||||
</String>
|
||||
<String>
|
||||
<Name>Description</Name>
|
||||
<Val>To AS/NZS 5000.1</Val>
|
||||
</String>
|
||||
<Path>
|
||||
<Name>Path</Name>
|
||||
<Val>C:\Users\User\Desktop\Cables\Olex LV Handbook\PVC Insulated\1.5mm2 Cu_Single core, 1kV V-90 insulated (unsheathed).xml</Val>
|
||||
</Path>
|
||||
<DBL>
|
||||
<Name>Frequency (Hz)</Name>
|
||||
<Val>50.00000000000000</Val>
|
||||
</DBL>
|
||||
<EL>
|
||||
<Name>Phases</Name>
|
||||
<Choice>DC</Choice>
|
||||
<Choice>Single phase</Choice>
|
||||
<Choice>Three phase</Choice>
|
||||
<Val>2</Val>
|
||||
</EL>
|
||||
<EL>
|
||||
<Name>Cores</Name>
|
||||
<Choice>Single core</Choice>
|
||||
<Choice>Multicore</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<DBL>
|
||||
<Name>Voltage, U (phase to phase)</Name>
|
||||
<Val>1000.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Daily load factor, L</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Conductor temperature, theta (deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor</Name>
|
||||
<NumElts>10</NumElts>
|
||||
<EW>
|
||||
<Name>Conductor size (mm2)</Name>
|
||||
<Choice>0.5 mm2</Choice>
|
||||
<Choice>0.75 mm2</Choice>
|
||||
<Choice>1 mm2</Choice>
|
||||
<Choice>1.5 mm2</Choice>
|
||||
<Choice>2.5 mm2</Choice>
|
||||
<Choice>4 mm2</Choice>
|
||||
<Choice>6 mm2</Choice>
|
||||
<Choice>10 mm2</Choice>
|
||||
<Choice>16 mm2</Choice>
|
||||
<Choice>25 mm2</Choice>
|
||||
<Choice>35 mm2</Choice>
|
||||
<Choice>50 mm2</Choice>
|
||||
<Choice>70 mm2</Choice>
|
||||
<Choice>95 mm2</Choice>
|
||||
<Choice>120 mm2</Choice>
|
||||
<Choice>150 mm2</Choice>
|
||||
<Choice>185 mm2</Choice>
|
||||
<Choice>240 mm2</Choice>
|
||||
<Choice>300 mm2</Choice>
|
||||
<Choice>400 mm2</Choice>
|
||||
<Choice>500 mm2</Choice>
|
||||
<Choice>630 mm2</Choice>
|
||||
<Choice>800 mm2</Choice>
|
||||
<Choice>1000 mm2</Choice>
|
||||
<Choice>1200 mm2</Choice>
|
||||
<Choice>1600 mm2</Choice>
|
||||
<Choice>1800 mm2</Choice>
|
||||
<Choice>2000 mm2</Choice>
|
||||
<Choice>2500 mm2</Choice>
|
||||
<Val>3</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Conductor class</Name>
|
||||
<Choice>Class 1 solid conductors for single or multicore cables</Choice>
|
||||
<Choice>Class 2 stranded conductors for single or multicore cables</Choice>
|
||||
<Choice>Class 5 flexible copper conductors for single or multicore cables</Choice>
|
||||
<Choice>Class 6 flexible copper conductors for single or multicore cables</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Conductor material</Name>
|
||||
<Choice>Copper, plain wires</Choice>
|
||||
<Choice>Copper, metal-coated wires</Choice>
|
||||
<Choice>Aluminium wires</Choice>
|
||||
<Choice>Aluminium alloy wires</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Boolean>
|
||||
<Name>Hard-drawn Cu? (aerial cable)</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EW>
|
||||
<Name>Conductor Type</Name>
|
||||
<Choice>Copper_Round, stranded_Dried & impregnated</Choice>
|
||||
<Choice>Copper_Round, stranded_Not dried & impregnated</Choice>
|
||||
<Choice>Copper_Round, 4 segment</Choice>
|
||||
<Choice>Copper_Hollow, helical stranded_Dried and impregnated</Choice>
|
||||
<Choice>Copper_Sector-shaped_Dried and impregnated</Choice>
|
||||
<Choice>Copper_Sector-shaped_Not dried and impregnated</Choice>
|
||||
<Choice>Aluminium_Round, stranded</Choice>
|
||||
<Choice>Aluminium_Round, 4 segment</Choice>
|
||||
<Choice>Aluminium_Round, 5 segment</Choice>
|
||||
<Choice>Aluminium_Round, 6 segment</Choice>
|
||||
<Choice>Aluminium, Segmental with peripheral strands</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Conductor shape (self inductance)</Name>
|
||||
<Choice>Circular</Choice>
|
||||
<Choice>Circular compacted</Choice>
|
||||
<Choice>Shaped</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<DBL>
|
||||
<Name>External diameter of cable, De (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<Cluster>
|
||||
<Name>DC resistance</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Standards</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>DC resistance calculation based on:</Name>
|
||||
<Choice>Insulation max. operating temperature, Theta (deg.C)</Choice>
|
||||
<Choice>Conductor operating temperature (deg.C)</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<DBL>
|
||||
<Name>Conductor operating temperature (deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<EW>
|
||||
<Name>Standards</Name>
|
||||
<Choice>IEC 60228:2004</Choice>
|
||||
<Choice>AS/NZS 1125:2001</Choice>
|
||||
<Val>1</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>1.21000000000000E-2</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>3.93000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor No. of Wires</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<EL>
|
||||
<Name>Mode</Name>
|
||||
<Choice>Based on conductor size (mm2) and IEC 60228</Choice>
|
||||
<Choice>Specify no. of conductors</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<I32>
|
||||
<Name>No. of conductor wires</Name>
|
||||
<Val>0</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor diameter</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<EL>
|
||||
<Name>Mode</Name>
|
||||
<Choice>Based on conductor size (mm2)</Choice>
|
||||
<Choice>Specify conductor diameter</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<DBL>
|
||||
<Name>Nominal conductor diameter, dc (m)</Name>
|
||||
<Val>1.50000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Conductor shield</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Boolean>
|
||||
<Name>Conductor shield?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>3.25000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Insulation</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<EW>
|
||||
<Name>Type of cable insulation</Name>
|
||||
<Choice>Impregnated paper_Solid type, fully- pre- or mass-impregnated non-draining</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 36kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 87kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 160kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-filled, self-contained_up to Uo = 220kV</Choice>
|
||||
<Choice>Impregnated paper_Oil-pressure pipe-type</Choice>
|
||||
<Choice>Impregnated paper_External gas pressure</Choice>
|
||||
<Choice>Impregnated paper_Internal gas pressure</Choice>
|
||||
<Choice>Butyl rubber</Choice>
|
||||
<Choice>EPR_up to and including 18/30 (36) kV</Choice>
|
||||
<Choice>EPR_greater than 18/30 (36) kV</Choice>
|
||||
<Choice>PVC</Choice>
|
||||
<Choice>PE (HD and LD)</Choice>
|
||||
<Choice>XLPE_Unfilled_up to and including 18/30 (36) kV</Choice>
|
||||
<Choice>XLPE_Unfilled_greater than 18/30 (36) kV</Choice>
|
||||
<Choice>XLPE_Filled_greater than 18/30 (36) kV</Choice>
|
||||
<Choice>PPL_equal to or greater than 63/110 kV</Choice>
|
||||
<Val>11</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Epsilon</Name>
|
||||
<Val>8.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Tandelta</Name>
|
||||
<Val>0.10000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>8.00000000000000E-4</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>3.10000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<I32>
|
||||
<Name>Insulation. Max. operating temp., Theta (deg.C)</Name>
|
||||
<Val>90</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Insulation screen</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<Boolean>
|
||||
<Name>Insulation screen?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Single core</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Semi-conductor screen</Choice>
|
||||
<Choice>Copper screen tape</Choice>
|
||||
<Choice>Aluminium screen tape</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Multi-core</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Belted (unscreened)-Multicore</Choice>
|
||||
<Choice>Semi-conductor screen</Choice>
|
||||
<Choice>Copper screen tape</Choice>
|
||||
<Choice>Aluminium screen tape</Choice>
|
||||
<Val>1</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Sheath</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<Boolean>
|
||||
<Name>Cable sheath?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EL>
|
||||
<Name>Multicore</Name>
|
||||
<Choice>Common</Choice>
|
||||
<Choice>Sheath per phase</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<Cluster>
|
||||
<Name>Type of sheath</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>Type of sheath</Name>
|
||||
<Choice>Aluminium</Choice>
|
||||
<Choice>Lead</Choice>
|
||||
<Choice>Lead with reinforcing tape</Choice>
|
||||
<Choice>Copper</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Construction and dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<EW>
|
||||
<Name>Construction</Name>
|
||||
<Choice>Non-corrugated</Choice>
|
||||
<Choice>Corrugated</Choice>
|
||||
<Choice>Longitudinally corrugated</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<Cluster>
|
||||
<Name>Non-corrugated</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Corrugated</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness of corrugated sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Inner diameter of corrugated sheath (m)</Name>
|
||||
<Val>3.10000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Outer diameter of corrugated sheath (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Longitudinally corrugated</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Corrugation height</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Inner radius of corrugated sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Outer radius of corrugated sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<Cluster>
|
||||
<Name>Tape</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<DBL>
|
||||
<Name>Overlap (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Width (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Accumulation factor</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<Cluster>
|
||||
<Name>Calculated properties</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Diameter over sheath (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>DC resistance at 25 deg.C. (Ohm/m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Sheath reinforcing tape</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<Boolean>
|
||||
<Name>Sheath reinforcing tape?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Material</Name>
|
||||
<NumElts>3</NumElts>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Copper</Choice>
|
||||
<Choice>Brass/bronze</Choice>
|
||||
<Choice>Zinc</Choice>
|
||||
<Choice>Stainless steel</Choice>
|
||||
<Choice>Steel</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Width (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of tapes</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Concentric neutral</Name>
|
||||
<NumElts>6</NumElts>
|
||||
<Boolean>
|
||||
<Name>Concentric neutral?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EL>
|
||||
<Name>Multicore</Name>
|
||||
<Choice>Common</Choice>
|
||||
<Choice>Around each core</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Custom</Choice>
|
||||
<Choice>Copper</Choice>
|
||||
<Choice>Brass/bronze</Choice>
|
||||
<Choice>Zinc</Choice>
|
||||
<Choice>Stainless steel</Choice>
|
||||
<Val>1</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Construction</Name>
|
||||
<Choice>Round wires</Choice>
|
||||
<Choice>Flat straps</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Electrical and magnetic material properties</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<Cluster>
|
||||
<Name>Electrical resistivity and temp. coefficient</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>1.72410000000000E-8</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>3.93000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Round Wire</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of wires</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Flat straps</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Strap length (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of straps</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Bedding</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<Boolean>
|
||||
<Name>Armour bedding?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Compounded jute and fibrous materials</Choice>
|
||||
<Choice>Rubber sandwich protection</Choice>
|
||||
<Choice>Polychloroprene</Choice>
|
||||
<Choice>PVC up to and including 35 kV</Choice>
|
||||
<Choice>PVC greater than 35 kV</Choice>
|
||||
<Choice>PVC/bitumen on corrugated aluminium sheaths</Choice>
|
||||
<Choice>PE</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<DBL>
|
||||
<Name>Thermal resistivity, rhoT (Cm/W)</Name>
|
||||
<Val>6.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>0.99845000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>2.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Armour/reinforcing tape</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<Boolean>
|
||||
<Name>Armour/reinforcing tape?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<Cluster>
|
||||
<Name>Material</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Custom_non-magnetic tape</Choice>
|
||||
<Choice>Steel tape reinforcement</Choice>
|
||||
<Choice>Custom_non-magnetic wires</Choice>
|
||||
<Choice>Custom_magnetic wires</Choice>
|
||||
<Choice>Steel wires_touching</Choice>
|
||||
<Choice>Steel wires_not touching</Choice>
|
||||
<Choice>Copper armour wires</Choice>
|
||||
<Choice>Stainless steel wires</Choice>
|
||||
<Choice>TECK armour</Choice>
|
||||
<Val>4</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Electrical and magnetic material properties</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Cluster>
|
||||
<Name>Electrical resistivity and temp. coefficient</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Resistivity (Rho) ohm.m at 20 deg.C.</Name>
|
||||
<Val>1.38000000000000E-7</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Electrical temp. coeff. of metal, a20 (per K at 20 deg.C)</Name>
|
||||
<Val>4.50000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Magnetic properties (if applicable)</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<EL>
|
||||
<Name>Magnetic properties</Name>
|
||||
<Choice>Standard</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EL>
|
||||
<DBL>
|
||||
<Name>Longitudinal relative permeability, Mue-e</Name>
|
||||
<Val>10.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Traverse relative permeability, Mue-t</Name>
|
||||
<Val>45.00000000000000</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Gamma angle (degrees)</Name>
|
||||
<Val>45.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Wire</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Length of lay (m)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<I32>
|
||||
<Name>No. of wires</Name>
|
||||
<Val>1</Val>
|
||||
</I32>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions_Tape</Name>
|
||||
<NumElts>4</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Cross-sectional area of tape armour (m2)</Name>
|
||||
<Val>1.00000000000000</Val>
|
||||
</DBL>
|
||||
<EW>
|
||||
<Name>Lay of tapes (reinforcement resistance)</Name>
|
||||
<Choice>Very long lay (longitudinal tapes)</Choice>
|
||||
<Choice>Wound at approximately 54 degrees</Choice>
|
||||
<Choice>Wound in very short lay (circumferential tapes)</Choice>
|
||||
<Choice>Layers of tapes in contact with each other having a very short lay</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Jacket/Serving</Name>
|
||||
<NumElts>5</NumElts>
|
||||
<Boolean>
|
||||
<Name>Jacket/Serving?</Name>
|
||||
<Val>0</Val>
|
||||
</Boolean>
|
||||
<EW>
|
||||
<Name>Material</Name>
|
||||
<Choice>Compounded jute and fibrous materials</Choice>
|
||||
<Choice>Rubber sandwich</Choice>
|
||||
<Choice>Polychropropene</Choice>
|
||||
<Choice>PVC up to and including 35 kV</Choice>
|
||||
<Choice>PVC above 35 kV</Choice>
|
||||
<Choice>Butyl rubber</Choice>
|
||||
<Choice>Coal tar wrapping</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<EW>
|
||||
<Name>Calculation mode:</Name>
|
||||
<Choice>Standards</Choice>
|
||||
<Choice>Custom</Choice>
|
||||
<Val>0</Val>
|
||||
</EW>
|
||||
<Cluster>
|
||||
<Name>Custom</Name>
|
||||
<NumElts>1</NumElts>
|
||||
<DBL>
|
||||
<Name>Thermal resistivity, rhoT (Cm/W)</Name>
|
||||
<Val>0.00000000000000</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
<Cluster>
|
||||
<Name>Dimensions</Name>
|
||||
<NumElts>2</NumElts>
|
||||
<DBL>
|
||||
<Name>Thickness (m)</Name>
|
||||
<Val>2.45000000000000E-3</Val>
|
||||
</DBL>
|
||||
<DBL>
|
||||
<Name>Diameter (m)</Name>
|
||||
<Val>8.00000000000000E-3</Val>
|
||||
</DBL>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</Cluster>
|
||||
</LVData>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user