mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-20 07:14:13 +02:00
Compare commits
14 Commits
e7e2864641
...
c71839a291
| Author | SHA1 | Date | |
|---|---|---|---|
| c71839a291 | |||
| d9a2539702 | |||
| 22c1ec9321 | |||
| 4300a655bc | |||
| 2ed85f6fc7 | |||
| e62d43d024 | |||
| 4a83521306 | |||
| a7f406cd44 | |||
| dad6206386 | |||
| 0920e82188 | |||
| eba258f6cd | |||
| abd5e8978a | |||
| 9bfe18807f | |||
| 00e75604b0 |
@@ -109,6 +109,22 @@ if(QT_VERSION_MAJOR GREATER_EQUAL 6)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# JavaScript scripting (bugtracker #162: `--run script.js`, and later a
|
||||
# "Run Script..." menu action) needs QJSEngine, in the Qml module. As with
|
||||
# QtPdf above, this is not fatal when missing: some minimal Qt6 packagings
|
||||
# may not ship it, and scripting is optional functionality nothing else in
|
||||
# the application depends on. When it's missing the feature is silently
|
||||
# disabled - see the QET_HAS_SCRIPTING guard in qetscripting.*.
|
||||
set(QET_HAS_SCRIPTING FALSE)
|
||||
find_package(Qt${QT_VERSION_MAJOR} QUIET COMPONENTS Qml)
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Qml)
|
||||
set(QET_HAS_SCRIPTING TRUE)
|
||||
list(APPEND QET_PRIVATE_LIBRARIES Qt::Qml)
|
||||
add_compile_definitions(QET_HAS_SCRIPTING)
|
||||
else()
|
||||
message(STATUS "Qt Qml module not available: JavaScript scripting (--run) disabled")
|
||||
endif()
|
||||
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
# CMake < 4.3 only creates the SQLite::SQLite3 target (no SQLite3::SQLite3
|
||||
|
||||
@@ -851,6 +851,20 @@ if(QT_VERSION_MAJOR GREATER_EQUAL 6)
|
||||
)
|
||||
endif()
|
||||
|
||||
# JavaScript scripting (bugtracker #162). Unconditionally in the source
|
||||
# list, like the QtPdf files above: this file is included before the
|
||||
# QET_HAS_SCRIPTING probe runs in the top-level CMakeLists.txt, so the
|
||||
# variable isn't set yet here. Same pattern as QtPdf: always compiled, the
|
||||
# actual Qt::Qml dependent code is behind #ifdef QET_HAS_SCRIPTING inside
|
||||
# qetscripting.cpp/qetscriptapi.cpp themselves, compiling to a harmless
|
||||
# stub when the module wasn't found.
|
||||
list(APPEND QET_SRC_FILES
|
||||
${QET_DIR}/sources/scripting/qetscriptapi.cpp
|
||||
${QET_DIR}/sources/scripting/qetscriptapi.h
|
||||
${QET_DIR}/sources/scripting/qetscripting.cpp
|
||||
${QET_DIR}/sources/scripting/qetscripting.h
|
||||
)
|
||||
|
||||
set(TS_FILES
|
||||
${QET_DIR}/lang/qet_ar.ts
|
||||
${QET_DIR}/lang/qet_ca.ts
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "cli_export.h"
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
#include "scripting/qetscripting.h"
|
||||
#endif
|
||||
#include "logging/eventloopwatchdog.h"
|
||||
#include "logging/qetlogger.h"
|
||||
#include "machine_info.h"
|
||||
@@ -135,6 +138,17 @@ QGuiApplication::setHighDpiScaleFactorRoundingPolicy(QetSettings::hdpiScaleFacto
|
||||
QET::QetMessageBox::setNonInteractive(true);
|
||||
return CLIExport::run(export_app.arguments());
|
||||
}
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
// Headless scripting: --run <script.js> <project.qet> (bugtracker
|
||||
// #162). Same reasoning as the export branch above for running
|
||||
// before SingleApplication and answering message boxes headlessly.
|
||||
if (QetScripting::isRunRequest(raw_args)) {
|
||||
QApplication script_app(argc, argv);
|
||||
QETProject::setBackupEnabled(false);
|
||||
QET::QetMessageBox::setNonInteractive(true);
|
||||
return QetScripting::run(script_app.arguments());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Resolve the logger's state (log directory, session filename, open
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetdiagrameditor.h"
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
#include "scripting/qetscripting.h"
|
||||
#endif
|
||||
#include <QCoreApplication>
|
||||
#include "ElementsCollection/elementscollectionwidget.h"
|
||||
#include "QWidgetAnimation/qwidgetanimation.h"
|
||||
@@ -558,6 +561,15 @@ void QETDiagramEditor::setUpActions()
|
||||
" sans avoir à fermer et rouvrir le projet (action non annulable)"));
|
||||
connect(m_reload_element_drawings, &QAction::triggered, this, &QETDiagramEditor::slot_reloadElementDrawings);
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
// Run a JavaScript macro against the current project (bugtracker #162).
|
||||
m_run_script = new QAction(tr("Exécuter un script..."), this);
|
||||
m_run_script->setStatusTip(
|
||||
tr("Exécute un script JavaScript sur le projet courant (voir qet.*"
|
||||
" dans le script pour l'API disponible)"));
|
||||
connect(m_run_script, &QAction::triggered, this, &QETDiagramEditor::slot_runScript);
|
||||
#endif
|
||||
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this);
|
||||
connect(m_export_project_db, &QAction::triggered, [this]() {
|
||||
@@ -1012,6 +1024,9 @@ void QETDiagramEditor::setUpMenu()
|
||||
menu_project -> addAction(m_project_wiring_list_view);
|
||||
menu_project -> addAction(m_terminal_numbering);
|
||||
menu_project -> addAction(m_reload_element_drawings);
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
menu_project -> addAction(m_run_script);
|
||||
#endif
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
menu_project -> addSeparator();
|
||||
menu_project -> addAction(m_export_project_db);
|
||||
@@ -1867,6 +1882,9 @@ void QETDiagramEditor::slot_updateActions()
|
||||
m_project_wiring_list_view -> setEnabled(opened_project);
|
||||
m_terminal_numbering -> setEnabled(editable_project);
|
||||
m_reload_element_drawings -> setEnabled(opened_project);
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
m_run_script -> setEnabled(opened_project);
|
||||
#endif
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db -> setEnabled(editable_project);
|
||||
#endif
|
||||
@@ -3075,3 +3093,29 @@ void QETDiagramEditor::slot_reloadElementDrawings() {
|
||||
box.setDetailedText(geometry_changed.join(QLatin1Char('\n')));
|
||||
box.exec();
|
||||
}
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
/**
|
||||
@brief QETDiagramEditor::slot_runScript
|
||||
Run a JavaScript macro against the current project (bugtracker #162).
|
||||
See QetScriptApi for what a script can do -- read-mostly: folio/element/
|
||||
conductor counts and the same export operations the --export-* CLI
|
||||
flags provide. Export/save calls inside the script act on this
|
||||
project's file on disk, so unsaved edits in the open editor are not
|
||||
visible to the script; save first if that matters.
|
||||
*/
|
||||
void QETDiagramEditor::slot_runScript() {
|
||||
QETProject *project = currentProject();
|
||||
if (!project) return;
|
||||
|
||||
const QString script_path = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr("Exécuter un script"),
|
||||
QString(),
|
||||
tr("Scripts JavaScript (*.js);;Tous les fichiers (*)")
|
||||
);
|
||||
if (script_path.isEmpty()) return;
|
||||
|
||||
QetScripting::runOnProject(script_path, project, currentDiagramView());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -137,6 +137,9 @@ class QETDiagramEditor : public QETMainWindow
|
||||
void editProjectProperties(QETProject *);
|
||||
void slot_terminalNumbering();
|
||||
void slot_reloadElementDrawings();
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
void slot_runScript();
|
||||
#endif
|
||||
void editDiagramProperties(DiagramView *);
|
||||
void editDiagramProperties(Diagram *);
|
||||
void addDiagramToProject(QETProject *);
|
||||
@@ -213,6 +216,9 @@ class QETDiagramEditor : public QETMainWindow
|
||||
*m_project_wiring_list_view, ///< Action to show the wiring list read from the project database
|
||||
*m_terminal_numbering, ///< Action to launch terminal numbering
|
||||
*m_reload_element_drawings, ///< Action to redraw every placed element from its current definition
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
*m_run_script, ///< Action to run a JavaScript macro against the current project
|
||||
#endif
|
||||
*m_export_project_db, ///Export to file the internal database of the current project
|
||||
*m_tile_window, ///< Show MDI subwindows as tile
|
||||
*m_cascade_window, ///< Show MDI subwindows as cascade
|
||||
|
||||
@@ -407,20 +407,48 @@ void Conductor::generateConductorPath(const QPointF &p1, Qet::Orientation o1, co
|
||||
|
||||
// commence le vrai trajet
|
||||
// starts the real path
|
||||
//
|
||||
// Each cas "3"/"4" below inserts a two-point bridge along one axis, at a
|
||||
// coordinate on the OTHER axis computed as a midpoint and then snapped
|
||||
// to the grid by a loop that walks it strictly downward until it
|
||||
// divides evenly. Whenever depart and arrivee already agree on the axis
|
||||
// the bridge would run along, that bridge is unneeded -- the midpoint
|
||||
// starts on the correct value already, but the snap can still walk it
|
||||
// off, or, if it happens to already be on-grid, the two bridge points
|
||||
// just duplicate depart and arrivee outright. Either way the result is
|
||||
// a short out-and-back excursion, or a longer looping detour, at a join
|
||||
// that needed no bridge in the first place (bugtracker #734). Skip the
|
||||
// bridge in exactly that case; depart and arrivee already form the
|
||||
// direct run. Which axis each cas guards on is noted at each site below
|
||||
// -- descendant and montant are not mirror images of each other here.
|
||||
if (depart.y() < arrivee.y()) {
|
||||
// trajet descendant
|
||||
if ((ori_depart == Qet::North && (ori_arrivee == Qet::South || ori_arrivee == Qet::West)) || (ori_depart == Qet::East && ori_arrivee == Qet::West)) {
|
||||
// cas "3"
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
// cas "3": bridge is vertical, at a shared x between depart.y()
|
||||
// and arrivee.y() -- unnecessary exactly when depart and
|
||||
// arrivee already share an x. Compared qRound()ed, the same
|
||||
// rounding the bridge coordinate itself is computed with below:
|
||||
// an exact != would miss a pair that's already grid-equal after
|
||||
// rounding but off by a sub-pixel remainder, and still route a
|
||||
// degenerate bridge for it.
|
||||
if (qRound(depart.x()) != qRound(arrivee.x())) {
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
}
|
||||
} else if ((ori_depart == Qet::South && (ori_arrivee == Qet::North || ori_arrivee == Qet::East)) || (ori_depart == Qet::West && ori_arrivee == Qet::East)) {
|
||||
// cas "4"
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
// cas "4": bridge is horizontal, at a shared y between
|
||||
// depart.x() and arrivee.x() -- unnecessary exactly when depart
|
||||
// and arrivee already share a y. (Always true in this branch,
|
||||
// since "descendant" requires depart.y() < arrivee.y() strictly
|
||||
// -- kept for symmetry with the "montant" branch below.)
|
||||
if (qRound(depart.y()) != qRound(arrivee.y())) {
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
}
|
||||
} else if ((ori_depart == Qet::North || ori_depart == Qet::East) && (ori_arrivee == Qet::North || ori_arrivee == Qet::East)) {
|
||||
points << QPointF(arrivee.x(), depart.y()); // cas "2"
|
||||
} else {
|
||||
@@ -429,17 +457,28 @@ void Conductor::generateConductorPath(const QPointF &p1, Qet::Orientation o1, co
|
||||
} else {
|
||||
// trajet montant
|
||||
if ((ori_depart == Qet::West && (ori_arrivee == Qet::East || ori_arrivee == Qet::South)) || (ori_depart == Qet::North && ori_arrivee == Qet::South)) {
|
||||
// cas "3"
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
// cas "3": bridge is horizontal, at a shared y between
|
||||
// depart.x() and arrivee.x() -- unnecessary exactly when depart
|
||||
// and arrivee already share a y (the West->East case
|
||||
// diagnosed for #734: two stubs extended onto the same y run
|
||||
// straight into each other, no bridge needed). Compared
|
||||
// qRound()ed, same as the other three guards.
|
||||
if (qRound(depart.y()) != qRound(arrivee.y())) {
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
}
|
||||
} else if ((ori_depart == Qet::East && (ori_arrivee == Qet::West || ori_arrivee == Qet::North)) || (ori_depart == Qet::South && ori_arrivee == Qet::North)) {
|
||||
// cas "4"
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
// cas "4": bridge is vertical, at a shared x between depart.y()
|
||||
// and arrivee.y() -- unnecessary exactly when depart and
|
||||
// arrivee already share an x.
|
||||
if (qRound(depart.x()) != qRound(arrivee.x())) {
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
}
|
||||
} else if ((ori_depart == Qet::West || ori_depart == Qet::North) && (ori_arrivee == Qet::West || ori_arrivee == Qet::North)) {
|
||||
points << QPointF(depart.x(), arrivee.y()); // cas "2"
|
||||
} else {
|
||||
|
||||
@@ -764,6 +764,8 @@ QVariant DynamicElementTextItem::itemChange(QGraphicsItem::GraphicsItemChange ch
|
||||
if(m_parent_element.data()->linkType() == Element::Slave)
|
||||
{
|
||||
connect(m_parent_element.data(), &Element::linkedElementChanged, this, &DynamicElementTextItem::masterChanged);
|
||||
if(m_parent_element.data()->diagram())
|
||||
connect(m_parent_element.data()->diagram()->project(), &QETProject::XRefPropertiesChanged, this, &DynamicElementTextItem::updateXref);
|
||||
//The parent is already linked, wa call master changed for init the connection
|
||||
if(!m_parent_element.data()->linkedElements().isEmpty())
|
||||
masterChanged();
|
||||
@@ -1468,11 +1470,12 @@ void DynamicElementTextItem::updateXref()
|
||||
m_Xref_item = nullptr;
|
||||
}
|
||||
|
||||
m_update_slave_Xref_connection.clear();
|
||||
|
||||
if(m_slave_Xref_item)
|
||||
{
|
||||
delete m_slave_Xref_item;
|
||||
m_slave_Xref_item = nullptr;
|
||||
m_update_slave_Xref_connection.clear();
|
||||
|
||||
//If position changed to Champ de texte, store xref in element info
|
||||
if(m_parent_element->linkType() == Element::Slave &&
|
||||
@@ -1497,6 +1500,19 @@ void DynamicElementTextItem::updateXref()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove stale "xref" from elementInformations when no longer needed
|
||||
if(m_parent_element->linkType() == Element::Slave &&
|
||||
m_text_from == ElementInfo && m_info_name == "xref" &&
|
||||
!parentGroup())
|
||||
{
|
||||
DiagramContext dc = m_parent_element->elementInformations();
|
||||
if(!dc.value("xref").toString().isEmpty())
|
||||
{
|
||||
dc.remove("xref");
|
||||
m_parent_element->setElementInformations(dc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicElementTextItem::setPlainText(const QString &text)
|
||||
|
||||
@@ -59,6 +59,11 @@ ElementTextItemGroup::ElementTextItemGroup(const QString &name,
|
||||
&Element::linkedElementChanged,
|
||||
this,
|
||||
&ElementTextItemGroup::updateXref);
|
||||
if(parent->diagram())
|
||||
connect(parent->diagram()->project(),
|
||||
&QETProject::XRefPropertiesChanged,
|
||||
this,
|
||||
&ElementTextItemGroup::updateXref);
|
||||
}
|
||||
|
||||
ElementTextItemGroup::~ElementTextItemGroup()
|
||||
@@ -868,11 +873,12 @@ void ElementTextItemGroup::updateXref()
|
||||
delete m_Xref_item;
|
||||
m_Xref_item = nullptr;
|
||||
}
|
||||
m_update_slave_Xref_connection.clear();
|
||||
|
||||
if(m_slave_Xref_item)
|
||||
{
|
||||
delete m_slave_Xref_item;
|
||||
m_slave_Xref_item = nullptr;
|
||||
m_update_slave_Xref_connection.clear();
|
||||
|
||||
//If position changed to Champ de texte, store xref in element info
|
||||
if(m_parent_element->linkType() == Element::Slave &&
|
||||
@@ -898,6 +904,25 @@ void ElementTextItemGroup::updateXref()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove stale "xref" from elementInformations when no longer needed
|
||||
if(m_parent_element->linkType() == Element::Slave &&
|
||||
m_parent_element->diagram())
|
||||
{
|
||||
for(DynamicElementTextItem *deti : texts())
|
||||
{
|
||||
if(deti->textFrom() == DynamicElementTextItem::ElementInfo && deti->infoName() == "xref")
|
||||
{
|
||||
DiagramContext dc = m_parent_element->elementInformations();
|
||||
if(!dc.value("xref").toString().isEmpty())
|
||||
{
|
||||
dc.remove("xref");
|
||||
m_parent_element->setElementInformations(dc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElementTextItemGroup::adjustSlaveXrefPos(int slave_offset)
|
||||
|
||||
@@ -111,6 +111,7 @@ void MasterElement::unlinkElement(Element *elmt)
|
||||
ctx.remove(QETInformation::ELMT_PLC_COMMENT);
|
||||
ctx.remove(QETInformation::ELMT_PLC_CROSSREF);
|
||||
ctx.remove(QETInformation::ELMT_LABEL);
|
||||
ctx.remove(QETInformation::ELMT_XREF);
|
||||
elmt->setElementInformations(ctx);
|
||||
|
||||
setGroupIndexForElement(elmt, -1);
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetscriptapi.h"
|
||||
|
||||
#include "../ElementsCollection/elementslocation.h"
|
||||
#include "../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../cli_export.h"
|
||||
#include "../diagram.h"
|
||||
#include "../diagramcontent.h"
|
||||
#include "../diagramview.h"
|
||||
#include "../factory/elementfactory.h"
|
||||
#include "../qet.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../qetmessagebox.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../qetresult.h"
|
||||
#include "../undocommand/addgraphicsobjectcommand.h"
|
||||
#include "../undocommand/deleteqgraphicsitemcommand.h"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QUndoCommand>
|
||||
|
||||
QetScriptApi::QetScriptApi(QETProject *project, DiagramView *view, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_project(project),
|
||||
m_view(view)
|
||||
{
|
||||
}
|
||||
|
||||
QString QetScriptApi::projectTitle() const
|
||||
{
|
||||
return m_project ? m_project->title() : QString();
|
||||
}
|
||||
|
||||
QString QetScriptApi::filePath() const
|
||||
{
|
||||
return m_project ? m_project->filePath() : QString();
|
||||
}
|
||||
|
||||
int QetScriptApi::folioCount() const
|
||||
{
|
||||
return m_project ? m_project->diagrams().count() : 0;
|
||||
}
|
||||
|
||||
QString QetScriptApi::folioTitle(int index) const
|
||||
{
|
||||
if (!m_project) return QString();
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (index < 0 || index >= diagrams.count()) return QString();
|
||||
return diagrams.at(index)->title();
|
||||
}
|
||||
|
||||
int QetScriptApi::elementCount(int folioIndex) const
|
||||
{
|
||||
if (!m_project) return 0;
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return 0;
|
||||
DiagramContent content(diagrams.at(folioIndex), false);
|
||||
return content.m_elements.count();
|
||||
}
|
||||
|
||||
int QetScriptApi::conductorCount(int folioIndex) const
|
||||
{
|
||||
if (!m_project) return 0;
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return 0;
|
||||
DiagramContent content(diagrams.at(folioIndex), false);
|
||||
return content.conductors(DiagramContent::AnyConductor).count();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::runFlag
|
||||
Build a CLIExport::run() argument list from this project's own file
|
||||
path plus @p args, and run it. Reopens the project from disk -- see the
|
||||
class comment for why that trade-off was made.
|
||||
@param flag one of the --export-* / --resave / --set-titleblock flags
|
||||
@param args the flag's own positional arguments (output path, etc.)
|
||||
@return true if CLIExport::run() returned 0 (success)
|
||||
*/
|
||||
bool QetScriptApi::runFlag(const QString &flag, const QStringList &args)
|
||||
{
|
||||
if (!m_project) {
|
||||
log(QStringLiteral("qet.%1: no project").arg(flag));
|
||||
return false;
|
||||
}
|
||||
const QString path = m_project->filePath();
|
||||
if (path.isEmpty()) {
|
||||
log(QStringLiteral("qet.%1: project has no file path -- save it first").arg(flag));
|
||||
return false;
|
||||
}
|
||||
QStringList full_args;
|
||||
full_args << flag << path << args;
|
||||
|
||||
if (m_view)
|
||||
{
|
||||
// Interactive "Run Script...": CLIExport::run() opens a second,
|
||||
// temporary QETProject on the same file the GUI already has open.
|
||||
// Backups are only disabled on the headless --run path (main.cpp);
|
||||
// here that second, short-lived project would otherwise manage its
|
||||
// own KAutoSaveFile for the same path as the user's real, already
|
||||
// open project, racing it and risking a stale-restore prompt next
|
||||
// launch. Disable backups for just this one export and restore
|
||||
// them right after -- the headless path must never see this
|
||||
// change, since it depends on backups staying off for the whole
|
||||
// run (see the crash note next to the other setBackupEnabled(false)
|
||||
// call in main.cpp).
|
||||
QETProject::setBackupEnabled(false);
|
||||
const int result = CLIExport::run(full_args);
|
||||
QETProject::setBackupEnabled(true);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
return CLIExport::run(full_args) == 0;
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportPdf(const QString &output, bool showTerminals)
|
||||
{
|
||||
QStringList args{output};
|
||||
if (showTerminals) args << QStringLiteral("--show-terminals");
|
||||
return runFlag(QStringLiteral("--export-pdf"), args);
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportPng(const QString &outDir, bool showTerminals)
|
||||
{
|
||||
QStringList args{outDir};
|
||||
if (showTerminals) args << QStringLiteral("--show-terminals");
|
||||
return runFlag(QStringLiteral("--export-png"), args);
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportSvg(const QString &outDir, bool showTerminals)
|
||||
{
|
||||
QStringList args{outDir};
|
||||
if (showTerminals) args << QStringLiteral("--show-terminals");
|
||||
return runFlag(QStringLiteral("--export-svg"), args);
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportCables(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-cables"), {output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportWires(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-wires"), {output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportBom(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-bom"), {output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportWiring(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-wiring"), {output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportNets(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-nets"), {output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportLinks(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-links"), {output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportInfo(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--info"), output.isEmpty() ? QStringList{} : QStringList{output});
|
||||
}
|
||||
|
||||
bool QetScriptApi::setTitleBlock(const QString &output, const QStringList &assignments)
|
||||
{
|
||||
QStringList args{output};
|
||||
args << assignments;
|
||||
return runFlag(QStringLiteral("--set-titleblock"), args);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::save
|
||||
Write this project's own current in-memory state -- unlike every export
|
||||
method above, this does NOT go through runFlag()/CLIExport::run(): that
|
||||
reopens the project fresh from its file on disk, which would never see
|
||||
any addElement()/setElementPosition()/moveElement()/deleteElement() this
|
||||
script made, only silently rewrite the file exactly as it already was.
|
||||
Caught by testing this against a script that added an element and
|
||||
called save(): the element counted correctly in memory but the saved
|
||||
file didn't have it, since the old implementation opened an unrelated,
|
||||
unmodified second copy of the project to write.
|
||||
|
||||
With no output path, this goes through QETProject::write() -- the same
|
||||
path "Enregistrer" uses -- so it honours read-only mode the same way,
|
||||
updates saveddate/savedtime, and clears the modified flag. A plain
|
||||
QFile write used to skip all of that and could tear the file on an
|
||||
interruption, where write() goes through QET::writeXmlFile()'s
|
||||
QSaveFile. With an explicit output path this is a save to a different
|
||||
file, so it goes through QET::writeXmlFile() directly without touching
|
||||
the project's own filePath() or read-only state, the same way "Save As"
|
||||
targeting a writable location is allowed even for a project opened
|
||||
read-only.
|
||||
@param output path to write to; the project's own file path if empty
|
||||
@return false if there is no output path to use, or the write failed
|
||||
*/
|
||||
bool QetScriptApi::save(const QString &output)
|
||||
{
|
||||
if (!m_project) return false;
|
||||
|
||||
if (output.isEmpty())
|
||||
{
|
||||
if (m_project->filePath().isEmpty()) {
|
||||
log(QStringLiteral("qet.save: no output path given and the project has none of its own -- pass one"));
|
||||
return false;
|
||||
}
|
||||
const QETResult result = m_project->write();
|
||||
if (!result.isOk()) {
|
||||
log(QStringLiteral("qet.save: %1").arg(result.errorMessage()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QDomDocument xml_doc(m_project->toXml());
|
||||
QString error_message;
|
||||
if (!QET::writeXmlFile(xml_doc, output, &error_message)) {
|
||||
log(QStringLiteral("qet.save: %1").arg(error_message));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QetScriptApi::log(const QString &message)
|
||||
{
|
||||
QTextStream(stderr) << message << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::findElement
|
||||
@param folioIndex
|
||||
@param elementUuid as returned by addElement(), or read from the
|
||||
element's own uuid attribute
|
||||
@return the matching element on that folio, or nullptr
|
||||
*/
|
||||
Element *QetScriptApi::findElement(int folioIndex, const QString &elementUuid) const
|
||||
{
|
||||
if (!m_project) return nullptr;
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return nullptr;
|
||||
DiagramContent content(diagrams.at(folioIndex), false);
|
||||
for (Element *elmt : std::as_const(content.m_elements)) {
|
||||
if (elmt->uuid().toString() == elementUuid)
|
||||
return elmt;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::addElement
|
||||
Place a new element on a folio, through the same AddGraphicsObjectCommand
|
||||
the interactive drag-from-collection-panel path uses (see
|
||||
DiagramEventAddElement::addElement()) -- so Ctrl+Z undoes it exactly as
|
||||
it would a manually dropped element.
|
||||
|
||||
Like that path, the element is first imported into the project's own
|
||||
embedded collection (QETProject::importElement()): building straight
|
||||
from a common://custom:// location without embedding it left the saved
|
||||
.qet referencing a definition outside the project, missing on any
|
||||
machine that doesn't have that same collection installed.
|
||||
|
||||
importElement() can, on a name collision with a different, already
|
||||
embedded element, pop a modal dialog asking the user to choose -- with
|
||||
nobody there to answer it in a script, headless or interactive, that is
|
||||
exactly the hang class this whole API is built to avoid (see the class
|
||||
comment). Detected and refused before it can happen, rather than risked.
|
||||
|
||||
@param folioIndex
|
||||
@param locationPath an element collection path, e.g.
|
||||
"embed://some/path.elmt" or "common://10_electric/...elmt"
|
||||
@param x @param y target position, in the diagram's own coordinates
|
||||
@return the new element's uuid (empty string on failure -- read-only
|
||||
project, bad folio index, an import collision, or the location could
|
||||
not be resolved/built)
|
||||
*/
|
||||
QString QetScriptApi::addElement(int folioIndex, const QString &locationPath, double x, double y)
|
||||
{
|
||||
if (!m_project) return QString();
|
||||
if (m_project->isReadOnly()) {
|
||||
log(QStringLiteral("qet.addElement: project is read-only"));
|
||||
return QString();
|
||||
}
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString();
|
||||
Diagram *diagram = diagrams.at(folioIndex);
|
||||
|
||||
// ElementsLocation::setPath() forces ANY path to embed:// as soon as a
|
||||
// non-null project is given, common://custom:// included -- passing
|
||||
// m_project unconditionally here (as the pre-fix code did) silently
|
||||
// turned every non-embed:: locationPath into a lookup for an embedded
|
||||
// element that was never there. Caught by actually running this
|
||||
// against a common:// path: "does not resolve to an element" even
|
||||
// though the file plainly exists.
|
||||
ElementsLocation location = locationPath.startsWith(QStringLiteral("embed://"))
|
||||
? ElementsLocation(locationPath, m_project)
|
||||
: ElementsLocation(locationPath);
|
||||
if (!location.isElement() || !location.exist()) {
|
||||
log(QStringLiteral("qet.addElement: '%1' does not resolve to an element").arg(locationPath));
|
||||
return QString();
|
||||
}
|
||||
|
||||
ElementsLocation import_location = location;
|
||||
if (!(location.isProject() && location.project() == m_project))
|
||||
{
|
||||
const QString import_path = location.isFileSystem()
|
||||
? QStringLiteral("import/") + location.collectionPath(false)
|
||||
: location.collectionPath(false);
|
||||
const ElementsLocation existing(import_path, m_project);
|
||||
if (existing.exist() && existing.uuid() != location.uuid()) {
|
||||
log(QStringLiteral("qet.addElement: '%1' would collide with a different element "
|
||||
"already embedded under the same name -- refusing rather than "
|
||||
"risk the interactive import-conflict dialog").arg(locationPath));
|
||||
return QString();
|
||||
}
|
||||
|
||||
import_location = m_project->importElement(location);
|
||||
if (!import_location.exist()) {
|
||||
log(QStringLiteral("qet.addElement: could not import '%1' into the project").arg(locationPath));
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
Element *element = ElementFactory::Instance()->createElement(import_location, nullptr, &state);
|
||||
if (state) {
|
||||
delete element;
|
||||
log(QStringLiteral("qet.addElement: could not build element from '%1'").arg(locationPath));
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QPointF pos(x, y);
|
||||
element->setPos(pos);
|
||||
diagram->addItem(element);
|
||||
|
||||
auto *undo_group = new QUndoCommand(QObject::tr("Ajouter %1").arg(element->name()));
|
||||
new AddGraphicsObjectCommand(element, diagram, pos, undo_group);
|
||||
diagram->undoStack().push(undo_group);
|
||||
|
||||
return element->uuid().toString();
|
||||
}
|
||||
|
||||
bool QetScriptApi::setElementPosition(int folioIndex, const QString &elementUuid, double x, double y)
|
||||
{
|
||||
if (m_project && m_project->isReadOnly()) {
|
||||
log(QStringLiteral("qet.setElementPosition: project is read-only"));
|
||||
return false;
|
||||
}
|
||||
Element *element = findElement(folioIndex, elementUuid);
|
||||
if (!element) return false;
|
||||
|
||||
const QVariant old_value = element->pos();
|
||||
const QVariant new_value = QPointF(x, y);
|
||||
if (old_value == new_value) return true; // already there; nothing to push
|
||||
|
||||
auto *cmd = new QPropertyUndoCommand(element, "pos", old_value, new_value);
|
||||
cmd->setText(QObject::tr("Déplacer %1").arg(element->name()));
|
||||
m_project->undoStack()->push(cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QetScriptApi::moveElement(int folioIndex, const QString &elementUuid, double dx, double dy)
|
||||
{
|
||||
Element *element = findElement(folioIndex, elementUuid);
|
||||
if (!element) return false;
|
||||
const QPointF p = element->pos();
|
||||
return setElementPosition(folioIndex, elementUuid, p.x() + dx, p.y() + dy);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::deleteElement
|
||||
Through DeleteQGraphicsItemCommand -- the same command the Delete key
|
||||
uses -- so any conductors attached to the element's terminals are
|
||||
cleaned up the same way, not left dangling.
|
||||
*/
|
||||
bool QetScriptApi::deleteElement(int folioIndex, const QString &elementUuid)
|
||||
{
|
||||
if (!m_project) return false;
|
||||
if (m_project->isReadOnly()) {
|
||||
log(QStringLiteral("qet.deleteElement: project is read-only"));
|
||||
return false;
|
||||
}
|
||||
Element *element = findElement(folioIndex, elementUuid);
|
||||
if (!element) return false;
|
||||
Diagram *diagram = m_project->diagrams().at(folioIndex);
|
||||
|
||||
DiagramContent content;
|
||||
content.m_elements << element;
|
||||
if (DeleteQGraphicsItemCommand::hasNonDeletableTerminal(content)) {
|
||||
log(QStringLiteral("qet.deleteElement: %1 has a non-deletable terminal (linked master/slave?), refusing").arg(elementUuid));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *cmd = new DeleteQGraphicsItemCommand(diagram, content);
|
||||
diagram->undoStack().push(cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QetScriptApi::undo()
|
||||
{
|
||||
if (!m_project || !m_project->undoStack()->canUndo()) return false;
|
||||
m_project->undoStack()->undo();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QetScriptApi::redo()
|
||||
{
|
||||
if (!m_project || !m_project->undoStack()->canRedo()) return false;
|
||||
m_project->undoStack()->redo();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QetScriptApi::canUndo() const
|
||||
{
|
||||
return m_project && m_project->undoStack()->canUndo();
|
||||
}
|
||||
|
||||
bool QetScriptApi::canRedo() const
|
||||
{
|
||||
return m_project && m_project->undoStack()->canRedo();
|
||||
}
|
||||
|
||||
bool QetScriptApi::selectElement(const QString &elementUuid)
|
||||
{
|
||||
if (!m_project) return false;
|
||||
for (Diagram *diagram : m_project->diagrams()) {
|
||||
DiagramContent content(diagram, false);
|
||||
for (Element *elmt : std::as_const(content.m_elements)) {
|
||||
if (elmt->uuid().toString() == elementUuid) {
|
||||
elmt->setSelected(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QetScriptApi::deselectAll(int folioIndex)
|
||||
{
|
||||
if (!m_project) return;
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return;
|
||||
diagrams.at(folioIndex)->clearSelection();
|
||||
}
|
||||
|
||||
bool QetScriptApi::zoomFit()
|
||||
{
|
||||
if (!m_view) return false;
|
||||
m_view->zoomFit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QetScriptApi::zoomToContent()
|
||||
{
|
||||
if (!m_view) return false;
|
||||
m_view->zoomContent();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QetScriptApi::zoomReset()
|
||||
{
|
||||
if (!m_view) return false;
|
||||
m_view->zoomReset();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::showMessage
|
||||
A modal QET::QetMessageBox::information() -- safe to call headless
|
||||
because non-interactive mode is already set for the whole process
|
||||
before any script runs (main.cpp), which is exactly the mechanism
|
||||
that keeps --export-* and --resave from hanging on a warning dialog.
|
||||
Interactively, a real person is there to see and dismiss it.
|
||||
*/
|
||||
void QetScriptApi::showMessage(const QString &text)
|
||||
{
|
||||
QET::QetMessageBox::information(nullptr, QObject::tr("Script"), text);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QET_SCRIPT_API_H
|
||||
#define QET_SCRIPT_API_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class QETProject;
|
||||
class DiagramView;
|
||||
class Element;
|
||||
|
||||
/**
|
||||
@brief The QetScriptApi class
|
||||
The object a script sees as `qet` (bugtracker #162): batch/CI work and
|
||||
human-written macros against an open project.
|
||||
|
||||
@b Scope. Three groups of capability, each added at a different point in
|
||||
the discussion and each drawing its own line:
|
||||
|
||||
- @b Reading the model and @b exporting: folio/element/conductor counts,
|
||||
and the same export operations the `--export-*` CLI flags provide.
|
||||
Every export method is a thin wrapper around CLIExport::run() -- the
|
||||
same, already-tested code path those flags use -- built from the
|
||||
project's own file path rather than the live instance. That keeps this
|
||||
file free of any dependency on cli_export.cpp's internals, at the cost
|
||||
of re-opening the project from disk per call, which means @b none of
|
||||
them ever see edits this script made with the methods below: only
|
||||
save() writes the live instance. A script that edits then exports
|
||||
@b must call save() first, or the export reflects the file as it was
|
||||
before the script ran. Verified the hard way: an early version of this
|
||||
file had save() go through the same reopen-from-disk path as the
|
||||
exports, so it silently wrote back the unmodified original -- an
|
||||
addElement() call counted correctly in memory and then vanished from
|
||||
the saved file.
|
||||
- @b Editing geometry, through the same undo commands the GUI itself
|
||||
uses (AddGraphicsObjectCommand for placement, QPropertyUndoCommand on
|
||||
the standard `pos` property for moves, DeleteQGraphicsItemCommand for
|
||||
removal) -- Ctrl+Z undoes a script's edits exactly as it would the
|
||||
equivalent manual ones, because they are, mechanically, the same
|
||||
commands on the same stack. All four refuse on a read-only project,
|
||||
same as their GUI equivalents check Diagram::isReadOnly() before
|
||||
editing. addElement() also imports the element into the project's
|
||||
own embedded collection first (QETProject::importElement()), same
|
||||
as the drag-from-collection-panel path -- without it, the saved
|
||||
file referenced a definition outside the project and went missing
|
||||
on a machine without that same collection installed. One
|
||||
consequence worth knowing, not a bug:
|
||||
QPropertyUndoCommand merges consecutive commands on the same
|
||||
object+property when their text() also matches
|
||||
(QPropertyUndoCommand::mergeWith(), pre-existing), and
|
||||
setElementPosition()/moveElement() always use the same text for a
|
||||
given element -- so several position changes to the same element in a
|
||||
row collapse into one undo step, the same way dragging an element
|
||||
does, not one step per call. Verified against exactly that: two
|
||||
consecutive calls on one element, then undo/undo/redo/redo, land
|
||||
where a merge predicts, not where two independent steps would.
|
||||
- @b Navigating and @b messaging: select an element, zoom the active
|
||||
view, and show the user a message. Deliberately narrow: selection and
|
||||
messaging work with no view at all (headless `--run`); zoom is a no-op
|
||||
returning false without one, since there is nothing to zoom.
|
||||
|
||||
Explicitly @b not in scope: driving arbitrary GUI actions or dialogs. A
|
||||
script that could invoke any QAction by name could just as easily
|
||||
trigger one that opens a modal QDialog::exec() with nobody there to
|
||||
dismiss it -- exactly the hang class investigated for bugtracker #882.
|
||||
Every method here is either non-blocking by construction or, for
|
||||
messages, safe under QET::QetMessageBox's existing non-interactive mode
|
||||
(already active for headless runs). Nothing here opens a dialog the
|
||||
caller has to wait on -- including addElement(), which detects an
|
||||
import-collision case that would otherwise reach
|
||||
QETProject::importElement()'s own ImportElementDialog::exec() and
|
||||
refuses instead, rather than let a plain QDialog (not routed through
|
||||
QetMessageBox) block a script the same way.
|
||||
*/
|
||||
class QetScriptApi : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
@param project the project this API acts on
|
||||
@param view the active DiagramView, when run interactively via
|
||||
"Run Script..."; nullptr for the headless --run entry point.
|
||||
Only the zoom methods use it -- everything else works either way.
|
||||
*/
|
||||
explicit QetScriptApi(QETProject *project, DiagramView *view = nullptr, QObject *parent = nullptr);
|
||||
|
||||
// -- read the model --
|
||||
Q_INVOKABLE QString projectTitle() const;
|
||||
Q_INVOKABLE QString filePath() const;
|
||||
Q_INVOKABLE int folioCount() const;
|
||||
Q_INVOKABLE QString folioTitle(int index) const;
|
||||
Q_INVOKABLE int elementCount(int folioIndex) const;
|
||||
Q_INVOKABLE int conductorCount(int folioIndex) const;
|
||||
|
||||
// -- export / save: thin wrappers around the --export-* CLI paths --
|
||||
Q_INVOKABLE bool exportPdf(const QString &output, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportPng(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportSvg(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportCables(const QString &output);
|
||||
Q_INVOKABLE bool exportWires(const QString &output);
|
||||
Q_INVOKABLE bool exportBom(const QString &output);
|
||||
Q_INVOKABLE bool exportWiring(const QString &output);
|
||||
Q_INVOKABLE bool exportNets(const QString &output);
|
||||
Q_INVOKABLE bool exportLinks(const QString &output);
|
||||
Q_INVOKABLE bool exportInfo(const QString &output);
|
||||
Q_INVOKABLE bool setTitleBlock(const QString &output, const QStringList &assignments);
|
||||
Q_INVOKABLE bool save(const QString &output);
|
||||
|
||||
// -- edit geometry, through the real undo commands --
|
||||
Q_INVOKABLE QString addElement(int folioIndex, const QString &locationPath, double x, double y);
|
||||
Q_INVOKABLE bool setElementPosition(int folioIndex, const QString &elementUuid, double x, double y);
|
||||
Q_INVOKABLE bool moveElement(int folioIndex, const QString &elementUuid, double dx, double dy);
|
||||
Q_INVOKABLE bool deleteElement(int folioIndex, const QString &elementUuid);
|
||||
Q_INVOKABLE bool undo();
|
||||
Q_INVOKABLE bool redo();
|
||||
Q_INVOKABLE bool canUndo() const;
|
||||
Q_INVOKABLE bool canRedo() const;
|
||||
|
||||
// -- navigate and message --
|
||||
Q_INVOKABLE bool selectElement(const QString &elementUuid);
|
||||
Q_INVOKABLE void deselectAll(int folioIndex);
|
||||
Q_INVOKABLE bool zoomFit();
|
||||
Q_INVOKABLE bool zoomToContent();
|
||||
Q_INVOKABLE bool zoomReset();
|
||||
Q_INVOKABLE void showMessage(const QString &text);
|
||||
|
||||
// -- logging: a script has no console of its own --
|
||||
Q_INVOKABLE void log(const QString &message);
|
||||
|
||||
private:
|
||||
bool runFlag(const QString &flag, const QStringList &args);
|
||||
Element *findElement(int folioIndex, const QString &elementUuid) const;
|
||||
|
||||
QETProject *m_project;
|
||||
DiagramView *m_view;
|
||||
};
|
||||
|
||||
#endif // QET_SCRIPT_API_H
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetscripting.h"
|
||||
|
||||
#include "qetscriptapi.h"
|
||||
#include "../qetmessagebox.h"
|
||||
#include "../qetproject.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QObject>
|
||||
#include <QTextStream>
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
#include <QJSEngine>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
QTextStream out(stdout);
|
||||
QTextStream err(stderr);
|
||||
}
|
||||
|
||||
namespace QetScripting {
|
||||
|
||||
bool isRunRequest(const QStringList &args)
|
||||
{
|
||||
return args.contains(QStringLiteral("--run"));
|
||||
}
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
|
||||
int run(const QStringList &args)
|
||||
{
|
||||
const int idx = args.indexOf(QStringLiteral("--run"));
|
||||
const QString script_path = args.value(idx + 1);
|
||||
const QString project_path = args.value(idx + 2);
|
||||
if (script_path.isEmpty() || project_path.isEmpty()) {
|
||||
err << "Usage: qelectrotech --run <script.js> <project.qet>\n";
|
||||
return 2;
|
||||
}
|
||||
if (!QFileInfo::exists(script_path)) {
|
||||
err << "Script not found: " << script_path << "\n";
|
||||
return 2;
|
||||
}
|
||||
if (!QFileInfo::exists(project_path)) {
|
||||
err << "Project not found: " << project_path << "\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
QETProject project(project_path);
|
||||
if (project.state() != QETProject::Ok) {
|
||||
err << "Failed to open project: " << project_path
|
||||
<< " (state " << project.state() << ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return runOnProject(script_path, &project, nullptr) ? 0 : 1;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A runaway script (an infinite loop, or just a very slow one) would
|
||||
// otherwise freeze the GUI forever, or hang a CI job running --run with
|
||||
// no way out. QJSEngine::setInterrupted() is documented callable from
|
||||
// another thread; the engine polls it during evaluation and returns an
|
||||
// error QJSValue, which the normal error-reporting path below already
|
||||
// handles.
|
||||
constexpr int kScriptTimeoutMs = 30000;
|
||||
}
|
||||
|
||||
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view)
|
||||
{
|
||||
QFile file(scriptPath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
err << "Cannot open script: " << scriptPath << "\n";
|
||||
return false;
|
||||
}
|
||||
const QString source = QString::fromUtf8(file.readAll());
|
||||
file.close();
|
||||
|
||||
QJSEngine engine;
|
||||
auto *api = new QetScriptApi(project, view, &engine);
|
||||
QJSValue qet_value = engine.newQObject(api);
|
||||
// newQObject() takes ownership by default (QJSEngine::JavaScriptOwnership),
|
||||
// which would delete api as soon as the engine's GC decides to -- api's
|
||||
// real owner is the engine itself via the parent-child relationship set
|
||||
// above, so keep the engine, not the GC, in charge of its lifetime.
|
||||
engine.setObjectOwnership(api, QJSEngine::CppOwnership);
|
||||
engine.globalObject().setProperty(QStringLiteral("qet"), qet_value);
|
||||
|
||||
// wait_for(), not sleep_for(): a script that finishes well inside the
|
||||
// timeout must let the watchdog thread wake immediately, not force
|
||||
// every run -- including a fast, successful one -- to block on join()
|
||||
// for the full budget. Caught by testing this against a one-line
|
||||
// script: it took the full 30 seconds to exit before this fix.
|
||||
bool finished = false;
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
std::thread watchdog([&]() {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait_for(lock, std::chrono::milliseconds(kScriptTimeoutMs), [&finished]{ return finished; });
|
||||
if (!finished) {
|
||||
engine.setInterrupted(true);
|
||||
}
|
||||
});
|
||||
|
||||
QJSValue result = engine.evaluate(source, scriptPath);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
finished = true;
|
||||
}
|
||||
cv.notify_one();
|
||||
watchdog.join();
|
||||
|
||||
if (result.isError()) {
|
||||
const QString message = QStringLiteral("Script error: %1:%2: %3")
|
||||
.arg(scriptPath)
|
||||
.arg(result.property(QStringLiteral("lineNumber")).toInt())
|
||||
.arg(result.toString());
|
||||
err << message << "\n";
|
||||
// Interactive "Run Script...": stderr is invisible to a user who
|
||||
// launched the GUI normally (nowhere on Windows, easy to miss
|
||||
// everywhere else). Headless --run has no GUI to show this in, and
|
||||
// no session for it to block.
|
||||
if (view) {
|
||||
QET::QetMessageBox::critical(nullptr, QObject::tr("Script"), message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#else // !QET_HAS_SCRIPTING
|
||||
|
||||
// Qt::Qml was not found at configure time (see the QET_HAS_SCRIPTING probe
|
||||
// in the top-level CMakeLists.txt). Compile to a clear, non-silent failure
|
||||
// rather than omitting these symbols -- the same "always compiled, the
|
||||
// disabled path says why" shape as the QtPdf feature guard.
|
||||
|
||||
int run(const QStringList &)
|
||||
{
|
||||
err << "This build of QElectroTech was compiled without the Qt Qml "
|
||||
"module, so JavaScript scripting (--run) is not available.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool runOnProject(const QString &, QETProject *, DiagramView *)
|
||||
{
|
||||
err << "This build of QElectroTech was compiled without the Qt Qml "
|
||||
"module, so JavaScript scripting is not available.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // QET_HAS_SCRIPTING
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QET_SCRIPTING_H
|
||||
#define QET_SCRIPTING_H
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class QETProject;
|
||||
class DiagramView;
|
||||
|
||||
/**
|
||||
@brief JavaScript scripting entry points (bugtracker #162).
|
||||
|
||||
A script sees a single global, `qet` (see QetScriptApi): reading the
|
||||
model, exporting, editing geometry through the real undo commands, and
|
||||
a narrow set of navigation/messaging calls. See QetScriptApi's class
|
||||
comment for the exact scope and why each group of capability stops
|
||||
where it does.
|
||||
*/
|
||||
namespace QetScripting {
|
||||
|
||||
/**
|
||||
@brief True if @p args is a `--run <script.js> <project.qet>`
|
||||
invocation.
|
||||
*/
|
||||
bool isRunRequest(const QStringList &args);
|
||||
|
||||
/**
|
||||
@brief Run the script named in @p args against the project also
|
||||
named there, headless.
|
||||
Usage: qelectrotech --run <script.js> <project.qet>
|
||||
@return process exit code: 0 on success, 1 if the project failed to
|
||||
open or the script threw, 2 on a usage error.
|
||||
*/
|
||||
int run(const QStringList &args);
|
||||
|
||||
/**
|
||||
@brief Run @p scriptPath against an already-open @p project (the
|
||||
"Run Script..." GUI macro path). Errors go to stderr; there is no
|
||||
modal reporting in this first version.
|
||||
@param view the active DiagramView, so the script's zoom methods
|
||||
have something to act on; nullptr from the headless entry point,
|
||||
where they become no-ops (see QetScriptApi).
|
||||
@return true if the script ran without throwing.
|
||||
*/
|
||||
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view = nullptr);
|
||||
|
||||
}
|
||||
|
||||
#endif // QET_SCRIPTING_H
|
||||
@@ -393,6 +393,20 @@ void PlcLinkWidget::on_m_unlink_pb_clicked()
|
||||
return;
|
||||
|
||||
LinkElementCommand *undo = new LinkElementCommand(m_element);
|
||||
|
||||
// Store the current group index so makeLink() can
|
||||
// restore PLC variables and terminal labels on undo.
|
||||
for (Element *elmt : m_element->linkedElements())
|
||||
{
|
||||
if (elmt->linkType() == Element::Master)
|
||||
{
|
||||
int idx = elmt->groupIndexForElement(m_element);
|
||||
if (idx >= 0)
|
||||
undo->setGroupIndex(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
undo->unlinkAll();
|
||||
m_element->diagram()->undoStack().push(undo);
|
||||
|
||||
|
||||
@@ -254,6 +254,7 @@ void LinkElementCommand::undo()
|
||||
ctx.remove(QETInformation::ELMT_PLC_COMMENT);
|
||||
ctx.remove(QETInformation::ELMT_PLC_CROSSREF);
|
||||
ctx.remove(QETInformation::ELMT_LABEL);
|
||||
ctx.remove(QETInformation::ELMT_XREF);
|
||||
m_element->setElementInformations(ctx);
|
||||
|
||||
foreach(Element *elmt, m_element->linkedElements())
|
||||
@@ -291,6 +292,7 @@ void LinkElementCommand::undo()
|
||||
ctx.remove(QETInformation::ELMT_PLC_COMMENT);
|
||||
ctx.remove(QETInformation::ELMT_PLC_CROSSREF);
|
||||
ctx.remove(QETInformation::ELMT_LABEL);
|
||||
ctx.remove(QETInformation::ELMT_XREF);
|
||||
slave->setElementInformations(ctx);
|
||||
}
|
||||
|
||||
@@ -622,6 +624,7 @@ void LinkElementCommand::makeLink(const QList<Element *> &element_list)
|
||||
ctx.remove(QETInformation::ELMT_PLC_COMMENT);
|
||||
ctx.remove(QETInformation::ELMT_PLC_CROSSREF);
|
||||
ctx.remove(QETInformation::ELMT_LABEL);
|
||||
ctx.remove(QETInformation::ELMT_XREF);
|
||||
slave->setElementInformations(ctx);
|
||||
}
|
||||
m_element->unlinkElement(elmt);
|
||||
|
||||
@@ -129,3 +129,20 @@ add_executable(
|
||||
add_test(NAME tst_menubarkeyboard COMMAND tst_menubarkeyboard)
|
||||
target_include_directories(tst_menubarkeyboard PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_menubarkeyboard PRIVATE Qt::Test Qt::Widgets)
|
||||
|
||||
# Bugtracker #734 regression: exports fixtures/qet_bug_repro_resaved.qet
|
||||
# (the report's own canonical reproduction) via the built qelectrotech
|
||||
# binary's --export-svg and checks no conductor path is self-retracing.
|
||||
# Runs the real binary rather than linking conductor.cpp directly, since
|
||||
# Conductor::generateConductorPath() pulls in the full graphics-item
|
||||
# dependency graph (Diagram, Element, Terminal...) that the other,
|
||||
# deliberately header-only tests above avoid.
|
||||
add_executable(
|
||||
tst_conductorselfretrace
|
||||
tst_conductorselfretrace.cpp)
|
||||
add_test(NAME tst_conductorselfretrace COMMAND tst_conductorselfretrace)
|
||||
add_dependencies(tst_conductorselfretrace qelectrotech)
|
||||
target_include_directories(tst_conductorselfretrace PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_conductorselfretrace PRIVATE Qt::Test)
|
||||
target_compile_definitions(tst_conductorselfretrace PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
|
||||
|
||||
@@ -0,0 +1,999 @@
|
||||
<project title="ENA006 E-101 QET TRIAL V2 - PILOT ARTIFACT" version="0.100.1">
|
||||
<titleblocktemplates>
|
||||
<titleblocktemplate name="ENA006_D">
|
||||
<information>ENA006 SLD probe title block � generated.</information>
|
||||
<logos/>
|
||||
<grid cols="t5%;t9%;t44%;t6%;t12%;t12%;t6%;t6%;" rows="26;26;26;40;34;34;">
|
||||
<field row="0" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="3" valign="center">
|
||||
<value>
|
||||
<translation lang="en">Z</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">REV</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="0" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="4" valign="center">
|
||||
<value>
|
||||
<translation lang="en">2026-08-11</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="0" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="5" valign="center">
|
||||
<value>
|
||||
<translation lang="en">E-110: G4 CLOSED - LEVITON B3277-YB SIDE-MOUNT SPD + 3P 20 A CB-SPD</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="0" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="6" valign="center">
|
||||
<value>
|
||||
<translation lang="en">CC</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">BY</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="0" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="7" valign="center">
|
||||
<value>
|
||||
<translation lang="en">PRELIMINARY</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="0" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="2" valign="center">
|
||||
<value>
|
||||
<translation lang="en">NOT FOR CONSTRUCTION</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="1" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="3" valign="center">
|
||||
<value>
|
||||
<translation lang="en">Y</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">REV</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="1" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="4" valign="center">
|
||||
<value>
|
||||
<translation lang="en">2026-08-11</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="1" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="5" valign="center">
|
||||
<value>
|
||||
<translation lang="en">BREAKER AUX/POSITION DELETED - s60 GOVERNS; G6 CLOSED-DEL; A-5 RETIRED</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="1" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="6" valign="center">
|
||||
<value>
|
||||
<translation lang="en">CC</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">BY</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="1" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="7" valign="center">
|
||||
<value/>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="1" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="2" valign="center">
|
||||
<value/>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="2" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="3" valign="center">
|
||||
<value>
|
||||
<translation lang="en">X</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">REV</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="2" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="4" valign="center">
|
||||
<value>
|
||||
<translation lang="en">2026-08-11</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="2" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="5" valign="center">
|
||||
<value>
|
||||
<translation lang="en">COUNCIL REVIEW - WRAP/REFS/T3/TEE; KEY-2 PAWL; G14 ACCESS; H-OTD</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="2" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="6" valign="center">
|
||||
<value>
|
||||
<translation lang="en">CC</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">BY</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="2" fontsize="8" hadjust="true" displaylabel="true" name="" align="left" col="7" valign="center">
|
||||
<value/>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="2" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="2" valign="center">
|
||||
<value/>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="3" fontsize="12" hadjust="true" displaylabel="true" name="" align="left" col="2" valign="center">
|
||||
<value>
|
||||
<translation lang="en">MEDIUM VOLTAGE POWER ELECTRONICS LABORATORY � UNIVERSITY OF CALGARY, SCHULICH SCHOOL OF ENGINEERING</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="3" fontsize="10" hadjust="true" displaylabel="true" name="" align="left" col="4" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%plant</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">PROJECT NO.</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="3" fontsize="10" hadjust="true" displaylabel="true" name="" align="left" col="5" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%locmach</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">DRAWING NO.</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="3" fontsize="10" hadjust="true" displaylabel="true" name="" align="left" col="6" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%indexrev</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">REV</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="3" fontsize="10" hadjust="true" displaylabel="true" name="" align="left" col="7" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%folio</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">SHEET</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="4" fontsize="11" hadjust="true" displaylabel="true" name="" align="left" col="2" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%title</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">TITLE</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="4" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="4" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%author</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">DRAWN</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="4" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="5" valign="center">
|
||||
<value>
|
||||
<translation lang="en">%date</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">DATE</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="4" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="6" valign="center">
|
||||
<value>
|
||||
<translation lang="en">NTS</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">SCALE</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="4" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="7" valign="center">
|
||||
<value>
|
||||
<translation lang="en">D</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">SIZE</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="5" fontsize="11" hadjust="true" displaylabel="true" name="" align="left" col="2" valign="center">
|
||||
<value>
|
||||
<translation lang="en">ENA006 MV TEST FACILITY � ENG A 006</translation>
|
||||
</value>
|
||||
<label>
|
||||
<translation lang="en">PROJECT</translation>
|
||||
</label>
|
||||
</field>
|
||||
<field row="5" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="4" valign="center">
|
||||
<value>
|
||||
<translation lang="en">PILOT ARTIFACT</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
<field row="5" fontsize="9" hadjust="true" displaylabel="true" name="" align="left" col="5" valign="center">
|
||||
<value>
|
||||
<translation lang="en">NOT A DELIVERABLE</translation>
|
||||
</value>
|
||||
<label/>
|
||||
</field>
|
||||
</grid>
|
||||
</titleblocktemplate>
|
||||
</titleblocktemplates>
|
||||
<properties>
|
||||
<property name="saveddate" show="1">8/12/2026</property>
|
||||
<property name="saveddate-eu" show="1">12-08-2026</property>
|
||||
<property name="saveddate-us" show="1">2026-08-12</property>
|
||||
<property name="savedfilename" show="1">qet_bug_repro</property>
|
||||
<property name="savedfilepath" show="1">C:/Users/phili/.claude/skills/cabinet-drawings/pilot_qet/out/qet_bug_repro.qet</property>
|
||||
<property name="savedtime" show="1">19:09</property>
|
||||
</properties>
|
||||
<usage enabled="true" time_spent="0"/>
|
||||
<newdiagrams>
|
||||
<border cols="17" rows="8" displaycols="true" rowsize="80" colsize="60" displayrows="true"/>
|
||||
<inset date="null" displayAt="bottom" title="" version="" locmach="" plant="" auto_page_num="" folio="%id/%total" filename="" author="" indexrev=""/>
|
||||
<conductors text_color="#000000" bus="" type="multi" conductor_section="" color2="#000000" num="_" cable="" formula="" condsize="1" conductor_color="" displaytext="1" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" horizontal-alignment="AlignBottom" onetextperfolio="1" vertical-alignment="AlignRight" dash-size="1"/>
|
||||
<report label="%f-%l%c"/>
|
||||
<xrefs>
|
||||
<xref offset="0" powerprefix="" type="commutator" slave_label="(%f-%l%c)" xrefpos="" delayprefix="" switchprefix="" showterminalname="true" master_label="%f-%l%c" displayhas="cross" showpowerctc="false" snapto="label"/>
|
||||
<xref offset="0" powerprefix="" type="plc" slave_label="(%f-%l%c)" xrefpos="" delayprefix="" switchprefix="" showterminalname="true" master_label="%f-%l%c" displayhas="cross" showpowerctc="true" snapto="label"/>
|
||||
<xref offset="0" powerprefix="" type="coil" slave_label="(%f-%l%c)" xrefpos="AlignBottom" delayprefix="" switchprefix="" showterminalname="true" master_label="%f-%l%c" displayhas="contacts" showpowerctc="false" snapto="bottom"/>
|
||||
<xref offset="0" powerprefix="" type="protection" slave_label="(%f-%l%c)" xrefpos="AlignBottom" delayprefix="" switchprefix="" showterminalname="true" master_label="%f-%l%c" displayhas="contacts" showpowerctc="false" snapto="label"/>
|
||||
</xrefs>
|
||||
<conductors_autonums freeze_new_conductors="false" auto_break_conductors="false" current_autonum=""/>
|
||||
<folio_autonums/>
|
||||
<element_autonums freeze_new_elements="false" current_autonum=""/>
|
||||
<guides/>
|
||||
</newdiagrams>
|
||||
<diagram freezeNewConductor="false" locmach="ENA006-E-101" titleblocktemplate="ENA006_D" cols="8" version="0.100.1-dev" colsize="405.333" freezeNewElement="false" title="SINGLE LINE DIAGRAM - QET TRIAL V2 LAYOUT ENGINE (PILOT ARTIFACT)" displaycols="true" rowsize="317.444" plant="ENA006" height="1924.66" order="1" displayAt="bottom" folio="%id OF %total" displayrows="true" indexrev="TRIAL2" rows="6" auto_page_num="" titleblocktemplateCollection="embedded" author="CC" date="null" filename="">
|
||||
<defaultconductor text_color="#000000" bus="" type="multi" conductor_section="" color2="#000000" num="_" cable="" formula="" condsize="1" conductor_color="" displaytext="1" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" horizontal-alignment="AlignBottom" onetextperfolio="0" vertical-alignment="AlignRight" dash-size="1"/>
|
||||
<elements>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_busstub_n.elmt" z="10" uuid="{5f92eb56-c4f7-58b0-9bab-214799bb6e7e}" prefix="" y="513" x="353">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-12" x="0" id="0"/>
|
||||
<terminal orientation="3" y="-5" x="4" id="1"/>
|
||||
<terminal orientation="1" y="-5" x="-4" id="2"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{a29619d6-a146-5d01-bcde-c4a6a81b57b1}" y="-30.9" rotation="0" Valignment="AlignTop" x="9.3" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>PANEL A - 480Y/277 V, 3PH, 4W, 225 A BUS</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{7c64eaac-f664-5ae1-a721-928c337105fc}" y="7.5" rotation="0" Valignment="AlignTop" x="9.3" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,7.5,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>175 A MAIN</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_busstub_n.elmt" z="10" uuid="{dc1e8bdf-ce98-5f8e-8e72-8cbe654d0062}" prefix="" y="1131" x="652">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-12" x="0" id="3"/>
|
||||
<terminal orientation="3" y="-5" x="4" id="4"/>
|
||||
<terminal orientation="1" y="-5" x="-4" id="5"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{56a90a13-8ed9-568b-83b7-27fc276992f0}" y="-30.4" rotation="0" Valignment="AlignTop" x="609.1" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>TRANSFER BUS - 200 A, 3W + PE [CABINET C]</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{7f9d5ad8-a301-5d77-8768-2df60792821e}" y="8" rotation="0" Valignment="AlignTop" x="9.9" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,7.5,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>160 A CONT. TEST ENVELOPE</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_transformer_2w_primary-delta_secondary-wye_g.elmt" z="10" uuid="{3e82a25a-b2e8-554e-b726-14279f81ca38}" prefix="" y="383" x="353">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-28.4" x="0" id="6"/>
|
||||
<terminal orientation="2" y="28.4" x="0" id="7"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{cceb7d8e-68a5-5609-a4cf-a327123cf7e3}" y="-29" rotation="0" Valignment="AlignTop" x="-79.7" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>T-MAIN</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{3d038d23-8843-5c24-8a54-e887be8e6492}" y="-16.1" rotation="0" Valignment="AlignTop" x="-159.9" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>112.5 kVA DRY-TYPE</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{fa675a16-6eee-5576-b864-0dc6d79724f8}" y="-3.1" rotation="0" Valignment="AlignTop" x="-147" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>600 V / 480Y-277 V</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{c08d8155-1d1f-5a40-99e0-dd62e15a57c7}" y="9.8" rotation="0" Valignment="AlignTop" x="-178.2" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>SEPARATELY DERIVED</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_circuit_breaker.elmt" z="10" uuid="{d723fac8-9c4d-50d5-9faf-f288341bac82}" prefix="" y="469" x="353">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-17.6" x="0" id="8"/>
|
||||
<terminal orientation="2" y="17.6" x="0" id="9"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{612c44b6-fb6d-5a30-a2e5-5c90600c18d5}" y="-22.2" rotation="0" Valignment="AlignTop" x="-91.2" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>CB-MAIN</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{88aca51f-ce9b-5487-97fb-d8f4d8296ba5}" y="-9.2" rotation="0" Valignment="AlignTop" x="-107.8" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>175 A I-LINE</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{2575990d-7f9a-5b3e-bce3-7afed6143305}" y="3.8" rotation="0" Valignment="AlignTop" x="-89.9" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>MAIN [A]</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_fuse.elmt" z="10" uuid="{38720887-d879-5b09-aa98-919009b0a730}" prefix="" y="886" x="652">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-17.6" x="0" id="10"/>
|
||||
<terminal orientation="2" y="17.6" x="0" id="11"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{e377eab9-5ef0-54ac-906e-6779ea5d4ea6}" y="-22.3" rotation="0" Valignment="AlignTop" x="-73" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>F-VAR</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{07378af4-d36b-5eee-af3d-40786c613279}" y="-9.3" rotation="0" Valignment="AlignTop" x="-116.4" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>40 A OUTPUT</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{231acebe-5726-58e5-887d-cc9e8b84ebaf}" y="3.6" rotation="0" Valignment="AlignTop" x="-100.1" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>FUSES [B]</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_tee_l.elmt" z="10" uuid="{7955ded1-b35b-5c90-b974-c18cb71d64c6}" prefix="" y="949" x="652">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-6" x="0" id="12"/>
|
||||
<terminal orientation="3" y="0" x="-6" id="13"/>
|
||||
<terminal orientation="2" y="6" x="0" id="14"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts/>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_box_h-8_text-UV_w-10_tape.elmt" z="10" uuid="{c4bf7ba7-98c7-5102-95ee-1f13f9cb4a05}" prefix="" y="949" x="620">
|
||||
<terminals>
|
||||
<terminal orientation="1" y="0" x="-4" id="15"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{b334fd8e-f0ee-5bb4-b252-0084b3768b85}" y="-10.5" rotation="0" Valignment="AlignTop" x="-30.3" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,7.5,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>UV</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{518e1dec-7575-5833-ad0e-557efd1d34af}" y="-28" rotation="0" Valignment="AlignTop" x="-84.4" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>R-UV</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{2e342bb8-ac55-5c62-9ebf-dd90208e1437}" y="-15.1" rotation="0" Valignment="AlignTop" x="-160.5" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>3x RM35UA13MW</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{f2e9069b-e9e4-5ca3-9312-eb3449397d5f}" y="-2.1" rotation="0" Valignment="AlignTop" x="-176.1" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>WIPER-UV L-L AT T3</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{edea9c4d-09de-5ccf-a93d-e3774155b95c}" y="10.8" rotation="0" Valignment="AlignTop" x="-160.1" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>FUSE LOAD SIDE</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{c0cd4483-629b-52b6-9e87-d9baa0122c4e}" y="23.8" rotation="0" Valignment="AlignTop" x="-142.3" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>(E-111/E-112-2)</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_overload.elmt" z="10" uuid="{4e742e7e-3ea9-5554-8d60-7a7e4b271b5d}" prefix="" y="1012" x="652">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-17.6" x="0" id="16"/>
|
||||
<terminal orientation="2" y="17.6" x="0" id="17"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{9f36bc48-0f43-5daa-bb6e-3eac08431eaa}" y="-8.9" rotation="0" Valignment="AlignTop" x="-9.9" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,5.25,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>OL</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{50e7912e-5bf6-5db2-8ad3-bee08580c145}" y="-22.3" rotation="0" Valignment="AlignTop" x="-75.4" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>OL-BR</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{358d6c87-6730-51c8-9245-3e11b7aafe62}" y="-9.3" rotation="0" Valignment="AlignTop" x="-138.2" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>3RR2443 BRUSH</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{bed2dfb3-889f-5c3c-89f3-a06d90047855}" y="3.6" rotation="0" Valignment="AlignTop" x="-118.6" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>MONITOR [C]</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element orientation="0" freezeLabel="false" type="embed://import/probe/v2_no_contact.elmt" z="10" uuid="{15e1997c-4eb6-50df-8629-22efc1524f2f}" prefix="" y="1088" x="652">
|
||||
<terminals>
|
||||
<terminal orientation="0" y="-17.6" x="0" id="18"/>
|
||||
<terminal orientation="2" y="17.6" x="0" id="19"/>
|
||||
</terminals>
|
||||
<inputs/>
|
||||
<dynamic_texts>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{5b2149d4-31b6-5078-b88c-0f35725a2ae8}" y="-22.7" rotation="0" Valignment="AlignTop" x="-62.7" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,75,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>Kvar</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{4f702d8c-dba1-59d9-a882-79e637c82963}" y="-9.7" rotation="0" Valignment="AlignTop" x="-90.5" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>LC1D50A</text>
|
||||
</dynamic_elmt_text>
|
||||
<dynamic_elmt_text Halignment="AlignLeft" uuid="{2f7647d6-0815-56bc-9a1c-9dee9987bec2}" y="3.2" rotation="0" Valignment="AlignTop" x="-121.4" frame="false" text_width="-1" rotation_point_center="false" text_from="UserText" font="Arial,9.75,-1,5,50,0,0,0,0,0,Regular" keep_visual_rotation="true">
|
||||
<text>+ MIRROR [C]</text>
|
||||
</dynamic_elmt_text>
|
||||
</dynamic_texts>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
</elements>
|
||||
<conductors>
|
||||
<conductor text_color="#000000" terminalname2="top" freezeLabel="false" terminalname1="bottom" bus="" type="multi" element2_label="" conductor_section="" element2="{d723fac8-9c4d-50d5-9faf-f288341bac82}" color2="#000000" element1="{3e82a25a-b2e8-554e-b726-14279f81ca38}" num="" x="0" cable="" element2_name="v2_circuit_breaker" formula="" conductor_color="" condsize="1" element1_name="v2_transformer_2w_primary-delta_secondary-wye_g" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{1a09bcec-0e22-5e69-a82d-85f20fd2944c}" terminal2="{67a1679e-e95b-581e-a26e-b47ce16e1ca2}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
<conductor text_color="#000000" terminalname2="tap" freezeLabel="false" terminalname1="bottom" bus="" type="multi" element2_label="" conductor_section="" element2="{5f92eb56-c4f7-58b0-9bab-214799bb6e7e}" color2="#000000" element1="{d723fac8-9c4d-50d5-9faf-f288341bac82}" num="" x="0" cable="" element2_name="v2_busstub_n" formula="" conductor_color="" condsize="1" element1_name="v2_circuit_breaker" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{b238d746-e1b0-5bc0-bdf6-690650239460}" terminal2="{515aaabf-a848-5922-8e0e-30b9442a6004}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
<conductor text_color="#000000" terminalname2="t" freezeLabel="false" terminalname1="bottom" bus="" type="multi" element2_label="" conductor_section="" element2="{7955ded1-b35b-5c90-b974-c18cb71d64c6}" color2="#000000" element1="{38720887-d879-5b09-aa98-919009b0a730}" num="" x="0" cable="" element2_name="v2_tee_l" formula="" conductor_color="" condsize="1" element1_name="v2_fuse" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{64651853-d240-5db8-88d9-6adb7340a161}" terminal2="{93dbb9de-6acb-50b2-b2bc-8dc78b7bd469}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
<conductor text_color="#000000" terminalname2="top" freezeLabel="false" terminalname1="l" bus="" type="multi" element2_label="" conductor_section="" element2="{c4bf7ba7-98c7-5102-95ee-1f13f9cb4a05}" color2="#000000" element1="{7955ded1-b35b-5c90-b974-c18cb71d64c6}" num="" x="0" cable="" element2_name="v2_box_h-8_text-UV_w-10_tape" formula="" conductor_color="" condsize="1" element1_name="v2_tee_l" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{be1f5b40-75e4-5797-a01a-0782e7979dde}" terminal2="{42c69da2-a77c-5fcf-92b4-88ae9fbc950b}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
<conductor text_color="#000000" terminalname2="top" freezeLabel="false" terminalname1="b" bus="" type="multi" element2_label="" conductor_section="" element2="{4e742e7e-3ea9-5554-8d60-7a7e4b271b5d}" color2="#000000" element1="{7955ded1-b35b-5c90-b974-c18cb71d64c6}" num="" x="0" cable="" element2_name="v2_overload" formula="" conductor_color="" condsize="1" element1_name="v2_tee_l" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{9d70e09e-c3a2-536f-876a-98bc14839f3d}" terminal2="{d548c004-98ea-5594-9621-ca07f35a11e9}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
<conductor text_color="#000000" terminalname2="top" freezeLabel="false" terminalname1="bottom" bus="" type="multi" element2_label="" conductor_section="" element2="{15e1997c-4eb6-50df-8629-22efc1524f2f}" color2="#000000" element1="{4e742e7e-3ea9-5554-8d60-7a7e4b271b5d}" num="" x="0" cable="" element2_name="v2_no_contact" formula="" conductor_color="" condsize="1" element1_name="v2_overload" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{b6645803-91cb-5b4e-8323-c6ebc88e20a7}" terminal2="{1b663411-841b-50df-94b6-25953716cb9f}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
<conductor text_color="#000000" terminalname2="tap" freezeLabel="false" terminalname1="bottom" bus="" type="multi" element2_label="" conductor_section="" element2="{dc1e8bdf-ce98-5f8e-8e72-8cbe654d0062}" color2="#000000" element1="{15e1997c-4eb6-50df-8629-22efc1524f2f}" num="" x="0" cable="" element2_name="v2_busstub_n" formula="" conductor_color="" condsize="1" element1_name="v2_no_contact" displaytext="0" tension_protocol="" vertirotatetext="270" bicolor="false" numsize="7" function="" horizrotatetext="0" element1_label="" horizontal-alignment="AlignBottom" onetextperfolio="0" terminal1="{c9545907-50fe-500b-a6c7-7e0cd3936950}" terminal2="{515aaabf-a848-5922-8e0e-30b9442a6004}" vertical-alignment="AlignRight" dash-size="1" y="0">
|
||||
<sequentialNumbers/>
|
||||
</conductor>
|
||||
</conductors>
|
||||
</diagram>
|
||||
<collection>
|
||||
<category name="import">
|
||||
<category name="probe">
|
||||
<element name="v2_busstub_n.elmt">
|
||||
<definition width="30" hotspot_y="21" version="0.100.0" type="element" link_type="simple" hotspot_x="15" height="42">
|
||||
<uuid uuid="{df96c31a-3d4c-54eb-93b7-1acf2aef049e}"/>
|
||||
<names>
|
||||
<name lang="en">v2_busstub_n</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0" y2="0" x1="0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-16" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="6" style="line-style:normal;line-weight:normal;filling:black;color:black" antialias="true" y="-3" x="-3"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{515aaabf-a848-5922-8e0e-30b9442a6004}" name="tap" y="-16" x="0"/>
|
||||
<terminal orientation="w" type="Generic" uuid="{311e59cb-6c46-5771-adad-8a92536c7bc3}" name="l" y="-5" x="0"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{a7f2014d-5dfa-531b-af05-b852a70fbbb1}" name="r" y="-5" x="0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_busstub_s.elmt">
|
||||
<definition width="30" hotspot_y="21" version="0.100.0" type="element" link_type="simple" hotspot_x="15" height="42">
|
||||
<uuid uuid="{912d25d2-aebf-5ca0-bf50-9369ce8450d0}"/>
|
||||
<names>
|
||||
<name lang="en">v2_busstub_s</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0" y2="0" x1="0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="16" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="6" style="line-style:normal;line-weight:normal;filling:black;color:black" antialias="true" y="-3" x="-3"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{c857ddef-ca9e-592f-8e78-2e3d9bb81eb2}" name="tap" y="16" x="0"/>
|
||||
<terminal orientation="w" type="Generic" uuid="{824c3447-6b41-5e1a-ad28-152e9d929e32}" name="l" y="-5" x="0"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{b0922151-dd45-5869-8ac9-c3e6be1627b3}" name="r" y="-5" x="0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_utility.elmt">
|
||||
<definition width="22" hotspot_y="34" version="0.100.0" type="element" link_type="simple" hotspot_x="11" height="39">
|
||||
<uuid uuid="{ebc54f89-5896-5c12-82a1-3c7da232dd83}"/>
|
||||
<names>
|
||||
<name lang="en">v2_utility</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-10.1" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-28.8" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="5.8" x4="0.0" x2="-5.8" y2="-10.1" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="0.0" antialias="true" closed="true" y1="0.0" y3="-10.1"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{d5db23a8-edae-5913-878b-fb6774275a6b}" name="top" y="-28.8" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{f6554699-2407-53b9-a55f-7058e13f61e6}" name="bottom" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_disconnect.elmt">
|
||||
<definition width="25" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="17" height="54">
|
||||
<uuid uuid="{942cc615-f1ff-59da-94aa-fcc1453762c4}"/>
|
||||
<names>
|
||||
<name lang="en">v2_disconnect</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-9.7" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="-9.7" x="-2.5"/>
|
||||
<line end2="none" x2="-11.5" y2="5.8" x1="-1.8" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-5.4" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="4.7" x="-2.5"/>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="9.7" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{3bde8f44-4ba9-583c-8d2e-e2d33fbb8355}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{cea02d4e-770c-5661-bc06-58ed4e421587}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_transformer_2w_primary-delta_secondary-wye_g.elmt">
|
||||
<definition width="52" hotspot_y="38" version="0.100.0" type="element" link_type="simple" hotspot_x="18" height="76">
|
||||
<uuid uuid="{2326ecb2-de00-5fcd-93e7-2f1e68cf7a01}"/>
|
||||
<names>
|
||||
<name lang="en">v2_transformer_2w_primary-delta_secondary-wye_g</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<circle diameter="25.9" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-21.3" x="-13.0"/>
|
||||
<circle diameter="25.9" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-4.7" x="-13.0"/>
|
||||
<line end2="none" x2="0.0" y2="-21.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-32.4" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="0.0" y2="32.4" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="21.2" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="4.7" x4="0.0" x2="-4.7" y2="-7.4" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" y4="-15.5" antialias="true" closed="true" y1="-15.5" y3="-7.4"/>
|
||||
<line end2="none" x2="0.0" y2="1.4" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="6.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="-4.7" y2="9.5" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="6.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="4.7" y2="9.5" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="6.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="23.0" y2="8.3" x1="13.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="8.3" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="23.0" y2="14.0" x1="23.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="8.3" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="28.4" y2="14.0" x1="17.6" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="14.0" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="26.3" y2="16.6" x1="19.8" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="16.6" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="24.5" y2="19.1" x1="21.6" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="19.1" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{e2460619-0e0a-5db9-b5e3-1c3e04baeb55}" name="top" y="-32.4" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{1a09bcec-0e22-5e69-a82d-85f20fd2944c}" name="bottom" y="32.4" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_circuit_breaker.elmt">
|
||||
<definition width="26" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="13" height="54">
|
||||
<uuid uuid="{401afc3c-0271-519c-9515-d2d9287616f1}"/>
|
||||
<names>
|
||||
<name lang="en">v2_circuit_breaker</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-7.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="7.2" length1="1.5" length2="1.5"/>
|
||||
<arc width="14.4" start="270" angle="180" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-7.2" x="-7.2" height="14.4"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{67a1679e-e95b-581e-a26e-b47ce16e1ca2}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{b238d746-e1b0-5bc0-bdf6-690650239460}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_tee_l.elmt">
|
||||
<definition width="30" hotspot_y="15" version="0.100.0" type="element" link_type="simple" hotspot_x="15" height="30">
|
||||
<uuid uuid="{286fe5c5-6217-51d3-811a-83060121dca4}"/>
|
||||
<names>
|
||||
<name lang="en">v2_tee_l</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<circle diameter="6" style="line-style:normal;line-weight:normal;filling:black;color:black" antialias="true" y="-3" x="-3"/>
|
||||
<line end2="none" x2="0" y2="10" x1="0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-10" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{93dbb9de-6acb-50b2-b2bc-8dc78b7bd469}" name="t" y="-10" x="0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{9d70e09e-c3a2-536f-876a-98bc14839f3d}" name="b" y="10" x="0"/>
|
||||
<terminal orientation="w" type="Generic" uuid="{be1f5b40-75e4-5797-a01a-0782e7979dde}" name="l" y="0" x="-10"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_spd_lv_tape.elmt">
|
||||
<definition width="40" hotspot_y="5" version="0.100.0" type="element" link_type="simple" hotspot_x="20" height="53">
|
||||
<uuid uuid="{877441ae-9bef-5065-9d9d-1f599b72686c}"/>
|
||||
<names>
|
||||
<name lang="en">v2_spd_lv_tape</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="7.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="0.0" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="14.4" x4="-14.4" x2="14.4" y2="28.8" y5="28.8" x1="-14.4" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="7.2" antialias="true" x5="-14.4" closed="true" y1="28.8" y3="7.2"/>
|
||||
<line end2="none" x2="0.0" y2="34.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="28.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="9.0" y2="34.6" x1="-9.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="34.6" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="5.8" y2="38.5" x1="-5.8" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="38.5" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="2.5" y2="42.5" x1="-2.5" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="42.5" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{e19c76b6-5c57-53ff-a5b8-fa51a5adce05}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-8_text-LS_w-10.elmt">
|
||||
<definition width="46" hotspot_y="20" version="0.100.0" type="element" link_type="simple" hotspot_x="23" height="40">
|
||||
<uuid uuid="{2440327c-529e-55c8-8e69-ac8aab4395ca}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-8_text-LS_w-10</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="18.0" x4="-18.0" x2="18.0" y2="14.4" y5="14.4" x1="-18.0" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-14.4" antialias="true" x5="-18.0" closed="true" y1="14.4" y3="-14.4"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{78a377a5-1507-514d-aa70-83390dc5de01}" name="top" y="-14.4" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{e10499a4-3979-5cdb-8aa8-be9260e5454e}" name="bottom" y="14.4" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_variac.elmt">
|
||||
<definition width="44" hotspot_y="31" version="0.100.0" type="element" link_type="simple" hotspot_x="22" height="62">
|
||||
<uuid uuid="{ff2da9fb-a168-59fc-9e3f-d33f3ceb72bf}"/>
|
||||
<names>
|
||||
<name lang="en">v2_variac</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-16.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-25.2" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="32.4" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-16.2" x="-16.2"/>
|
||||
<line end2="none" x2="9.4" y2="-9.4" x1="-12.2" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="12.2" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="10.1" x4="12.2" x2="4.3" y2="-10.1" x1="12.2" style="line-style:normal;line-weight:normal;filling:black;color:black" y4="-12.2" antialias="true" closed="true" y1="-12.2" y3="-4.3"/>
|
||||
<line end2="none" x2="0.0" y2="25.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="16.2" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{b1ea261f-cf22-55fb-814d-e9fe9b7fdd2e}" name="top" y="-25.2" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{1c865d9a-c587-583f-8e62-82cbc705b697}" name="bottom" y="25.2" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_fuse.elmt">
|
||||
<definition width="22" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="11" height="54">
|
||||
<uuid uuid="{579e40bc-8ee5-53f4-a8e2-515e5c8d7f01}"/>
|
||||
<names>
|
||||
<name lang="en">v2_fuse</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="5.8" x4="-5.8" x2="5.8" y2="12.6" y5="12.6" x1="-5.8" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-12.6" antialias="true" x5="-5.8" closed="true" y1="12.6" y3="-12.6"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{312cffce-9a2d-52ad-9632-8147f6460507}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{64651853-d240-5db8-88d9-6adb7340a161}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-8_text-UV_w-10_tape.elmt">
|
||||
<definition width="46" hotspot_y="20" version="0.100.0" type="element" link_type="simple" hotspot_x="41" height="40">
|
||||
<uuid uuid="{b99557f0-f555-58bc-b009-b268d75e5ed5}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-8_text-UV_w-10_tape</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="0.0" x4="-36.0" x2="0.0" y2="14.4" y5="14.4" x1="-36.0" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-14.4" antialias="true" x5="-36.0" closed="true" y1="14.4" y3="-14.4"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{42c69da2-a77c-5fcf-92b4-88ae9fbc950b}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_overload.elmt">
|
||||
<definition width="28" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="14" height="54">
|
||||
<uuid uuid="{999b9a70-b5a7-59e9-8d3d-9068eff86fa2}"/>
|
||||
<names>
|
||||
<name lang="en">v2_overload</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-10.8" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="9.0" x4="-9.0" x2="9.0" y2="10.8" y5="10.8" x1="-9.0" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-10.8" antialias="true" x5="-9.0" closed="true" y1="10.8" y3="-10.8"/>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="10.8" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{d548c004-98ea-5594-9621-ca07f35a11e9}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{b6645803-91cb-5b4e-8323-c6ebc88e20a7}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_no_contact.elmt">
|
||||
<definition width="21" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="16" height="54">
|
||||
<uuid uuid="{d32835d2-8cc4-57c9-a729-c3d3b51ddc35}"/>
|
||||
<names>
|
||||
<name lang="en">v2_no_contact</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-7.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="-10.1" y2="5.8" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-7.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="7.2" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{1b663411-841b-50df-94b6-25953716cb9f}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{c9545907-50fe-500b-a6c7-7e0cd3936950}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_resistor.elmt">
|
||||
<definition width="22" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="11" height="54">
|
||||
<uuid uuid="{2e9f77ec-9ae3-5532-b671-00e5afd1141c}"/>
|
||||
<names>
|
||||
<name lang="en">v2_resistor</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="-15.1" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<polygon x5="-5.0" closed="false" x1="0.0" x3="-5.0" y8="15.1" x6="5.0" y4="-2.5" x8="0.0" y6="7.6" y1="-15.1" x2="5.0" antialias="true" y2="-12.6" y7="12.6" x4="5.0" y5="2.5" y3="-7.6" x7="-5.0" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="15.1" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{e859bac3-df77-5cd9-b4d7-f154517e3fca}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{298e3cbf-3348-5fc5-9e6e-202a511076c3}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-11_text-ITECH_w-18.elmt">
|
||||
<definition width="76" hotspot_y="25" version="0.100.0" type="element" link_type="simple" hotspot_x="38" height="50">
|
||||
<uuid uuid="{ddb30ced-f3d9-51ac-a311-463bacdeef79}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-11_text-ITECH_w-18</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="32.4" x4="-32.4" x2="32.4" y2="19.8" y5="19.8" x1="-32.4" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-19.8" antialias="true" x5="-32.4" closed="true" y1="19.8" y3="-19.8"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{8fc34f12-ff87-5ef6-ae13-2aba4fa88cf3}" name="top" y="-19.8" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{648b75fb-363e-5683-9cfd-154ff31b8aac}" name="bottom" y="19.8" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_rectifier.elmt">
|
||||
<definition width="62" hotspot_y="31" version="0.100.0" type="element" link_type="simple" hotspot_x="31" height="62">
|
||||
<uuid uuid="{0bf53093-0ffd-57e3-8176-1ce40ff82dc8}"/>
|
||||
<names>
|
||||
<name lang="en">v2_rectifier</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="25.2" x4="-25.2" x2="25.2" y2="25.2" y5="25.2" x1="-25.2" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-25.2" antialias="true" x5="-25.2" closed="true" y1="25.2" y3="-25.2"/>
|
||||
<line end2="none" x2="-25.2" y2="25.2" x1="25.2" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="-25.2" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{f5eb6733-ca45-5c2a-b2fa-c894a4958a7c}" name="top" y="-25.2" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{2f2037de-cb82-5686-8995-63202aac686a}" name="bottom" y="25.2" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_load_arrow.elmt">
|
||||
<definition width="22" hotspot_y="5" version="0.100.0" type="element" link_type="simple" hotspot_x="11" height="39">
|
||||
<uuid uuid="{3f4716d9-e690-5e20-a12f-22ee04663e2e}"/>
|
||||
<names>
|
||||
<name lang="en">v2_load_arrow</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="18.7" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="0.0" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="5.4" x4="0.0" x2="-5.4" y2="18.7" x1="0.0" style="line-style:normal;line-weight:normal;filling:black;color:black" y4="28.8" antialias="true" closed="true" y1="28.8" y3="18.7"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{429c4d81-a73c-59e0-b403-6ed5a242eceb}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-9_text-s60_w-12.elmt">
|
||||
<definition width="54" hotspot_y="22" version="0.100.0" type="element" link_type="simple" hotspot_x="27" height="44">
|
||||
<uuid uuid="{a271cad0-2c9e-5e19-a32f-2aeb4fefc998}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-9_text-s60_w-12</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="21.6" x4="-21.6" x2="21.6" y2="16.2" y5="16.2" x1="-21.6" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-16.2" antialias="true" x5="-21.6" closed="true" y1="16.2" y3="-16.2"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{a1a38578-8eee-59f9-8706-85f507594626}" name="top" y="-16.2" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{0c62b4ef-92b3-561d-9a19-14ae2cb3d253}" name="bottom" y="16.2" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_earth_switch_tape.elmt">
|
||||
<definition width="31" hotspot_y="5" version="0.100.0" type="element" link_type="simple" hotspot_x="17" height="49">
|
||||
<uuid uuid="{93598103-5108-5555-a4b6-f5d5f09ab28c}"/>
|
||||
<names>
|
||||
<name lang="en">v2_earth_switch_tape</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="4.7" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="0.0" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="4.7" x="-2.5"/>
|
||||
<line end2="none" x2="-11.5" y2="20.2" x1="-1.8" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="9.0" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="20.2" x="-2.5"/>
|
||||
<line end2="none" x2="0.0" y2="30.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="25.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="9.0" y2="30.2" x1="-9.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="30.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="5.8" y2="34.2" x1="-5.8" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="34.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="2.5" y2="38.2" x1="-2.5" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="38.2" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{7077f93d-13f7-55a5-b8d9-1a094d5a6849}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_transformer_2w_neutral-out_primary-delta_secondary-wye.elmt">
|
||||
<definition width="55" hotspot_y="38" version="0.100.0" type="element" link_type="simple" hotspot_x="18" height="76">
|
||||
<uuid uuid="{187f5a17-9334-518b-80f7-f38927279a93}"/>
|
||||
<names>
|
||||
<name lang="en">v2_transformer_2w_neutral-out_primary-delta_secondary-wye</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<circle diameter="25.9" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-21.3" x="-13.0"/>
|
||||
<circle diameter="25.9" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-4.7" x="-13.0"/>
|
||||
<line end2="none" x2="0.0" y2="-21.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-32.4" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="0.0" y2="32.4" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="21.2" length1="1.5" length2="1.5"/>
|
||||
<polygon x3="4.7" x4="0.0" x2="-4.7" y2="-7.4" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" y4="-15.5" antialias="true" closed="true" y1="-15.5" y3="-7.4"/>
|
||||
<line end2="none" x2="0.0" y2="1.4" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="6.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="-4.7" y2="9.5" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="6.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="4.7" y2="9.5" x1="0.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="6.8" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="26.6" y2="8.3" x1="13.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="8.3" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="5.8" x="26.7"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{4dfabc6c-a669-5279-9acf-f6230bd01778}" name="neutral" y="8.3" x="31.7"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{69ea8a10-dd86-548f-a83d-a3e9194731f1}" name="top" y="-32.4" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{362a4c97-c89a-5d2b-954a-18cfd0d6b5bd}" name="bottom" y="32.4" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_relay_func-50G-51G.elmt">
|
||||
<definition width="58" hotspot_y="29" version="0.100.0" type="element" link_type="simple" hotspot_x="29" height="58">
|
||||
<uuid uuid="{4f677421-7f77-5214-8610-0847bc6eac85}"/>
|
||||
<names>
|
||||
<name lang="en">v2_relay_func-50G-51G</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<circle diameter="46.3" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-23.2" x="-23.2"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{91149297-5666-5761-9d70-6cb816961f31}" name="top" y="-22.5" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{400d8d37-d581-5c84-b15e-5fa4354b3a62}" name="bottom" y="22.5" x="0.0"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{5ae6572d-a2ce-5f5a-b6a0-1115a16e44d8}" name="left" y="0.0" x="-22.5"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{29122bc9-05c3-5901-bd8b-a1e4fb037d0a}" name="right" y="0.0" x="22.5"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_dashed-True_h-9_text-MVGND_w-15.elmt">
|
||||
<definition width="64" hotspot_y="22" version="0.100.0" type="element" link_type="simple" hotspot_x="32" height="44">
|
||||
<uuid uuid="{65bfd39f-8716-584b-96be-d6afa60c0c4a}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_dashed-True_h-9_text-MVGND_w-15</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="27.0" x4="-27.0" x2="27.0" y2="16.2" y5="16.2" x1="-27.0" style="line-style:dashed;line-weight:thin;filling:none;color:black" y4="-16.2" antialias="true" x5="-27.0" closed="true" y1="16.2" y3="-16.2"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{4ba9f9da-dd94-59df-85e1-3e73e87fe13e}" name="top" y="-16.2" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{5e39c327-6af7-59cb-a312-c164b98a1c31}" name="bottom" y="16.2" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-12_text-DUT_w-20.elmt">
|
||||
<definition width="82" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="41" height="54">
|
||||
<uuid uuid="{25121bf1-49d1-5667-b84d-9eae0cf16d2c}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-12_text-DUT_w-20</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="36.0" x4="-36.0" x2="36.0" y2="21.6" y5="21.6" x1="-36.0" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-21.6" antialias="true" x5="-36.0" closed="true" y1="21.6" y3="-21.6"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{f1d9e05b-632d-5639-be9e-84b059822dca}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{c2ab760f-9b43-5376-825c-dee311b74019}" name="bottom" y="21.6" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-8_text-TF_w-10_tape.elmt">
|
||||
<definition width="46" hotspot_y="20" version="0.100.0" type="element" link_type="simple" hotspot_x="41" height="40">
|
||||
<uuid uuid="{0f275246-d56b-559f-ae8a-153ae0dcb852}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-8_text-TF_w-10_tape</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="0.0" x4="-36.0" x2="0.0" y2="14.4" y5="14.4" x1="-36.0" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-14.4" antialias="true" x5="-36.0" closed="true" y1="14.4" y3="-14.4"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{3fbc81a4-f120-5c14-b47b-92ea67e39d18}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_ct.elmt">
|
||||
<definition width="40" hotspot_y="27" version="0.100.0" type="element" link_type="simple" hotspot_x="15" height="54">
|
||||
<uuid uuid="{4bb6d5d3-6285-5f64-b67c-a1a425ae6f8e}"/>
|
||||
<names>
|
||||
<name lang="en">v2_ct</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="21.6" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="-21.6" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="18.7" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-9.4" x="-9.4"/>
|
||||
<line end2="none" x2="19.8" y2="0.0" x1="9.4" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" end1="none" y1="0.0" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="3.6" style="line-style:normal;line-weight:normal;filling:black;color:black" antialias="true" y="-12.6" x="-7.9"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{dcd46bb2-a7a6-5354-b3cc-e2e435c7f2ef}" name="top" y="-21.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{f1b2e211-545d-5970-aeb7-385c9fd15317}" name="bottom" y="21.6" x="0.0"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{1c0399b8-9331-5eb3-b768-8e7e04eb69a0}" name="sec" y="0.0" x="19.8"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_meter_letter-MFM.elmt">
|
||||
<definition width="40" hotspot_y="20" version="0.100.0" type="element" link_type="simple" hotspot_x="20" height="40">
|
||||
<uuid uuid="{b29bdb1d-8a5e-5631-8507-56b3b7f1fd5d}"/>
|
||||
<names>
|
||||
<name lang="en">v2_meter_letter-MFM</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<circle diameter="28.5" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" y="-14.3" x="-14.3"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{fc97451c-aed9-5e30-9042-acd18402f128}" name="top" y="-12.6" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{f56989af-7ed7-54ef-9941-da5c4f216072}" name="bottom" y="12.6" x="0.0"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{489fd3b1-eb92-5653-93bf-e2e35e9e9006}" name="left" y="0.0" x="-12.6"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{fcc85842-e95a-5e76-95fc-ede8f83f6cf6}" name="right" y="0.0" x="12.6"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-10_text-RCPT_w-18.elmt">
|
||||
<definition width="76" hotspot_y="23" version="0.100.0" type="element" link_type="simple" hotspot_x="38" height="46">
|
||||
<uuid uuid="{fcd3f9a1-9c6c-51d7-93b2-deac226c423a}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-10_text-RCPT_w-18</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="32.4" x4="-32.4" x2="32.4" y2="18.0" y5="18.0" x1="-32.4" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-18.0" antialias="true" x5="-32.4" closed="true" y1="18.0" y3="-18.0"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{eae7d899-17b3-5245-9f2a-cbb1a5919e23}" name="top" y="-18.0" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{35edf270-c9b7-5c66-a6b7-eed22f54f630}" name="bottom" y="18.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_earth_switch.elmt">
|
||||
<definition width="31" hotspot_y="5" version="0.100.0" type="element" link_type="simple" hotspot_x="17" height="49">
|
||||
<uuid uuid="{d0ce1034-213c-5a38-b921-62f51c7bdfdb}"/>
|
||||
<names>
|
||||
<name lang="en">v2_earth_switch</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<line end2="none" x2="0.0" y2="4.7" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="0.0" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="4.7" x="-2.5"/>
|
||||
<line end2="none" x2="-11.5" y2="20.2" x1="-1.8" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="9.0" length1="1.5" length2="1.5"/>
|
||||
<circle diameter="5.0" style="line-style:normal;line-weight:thin;filling:none;color:black" antialias="true" y="20.2" x="-2.5"/>
|
||||
<line end2="none" x2="0.0" y2="30.2" x1="0.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="25.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="9.0" y2="30.2" x1="-9.0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="30.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="5.8" y2="34.2" x1="-5.8" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="34.2" length1="1.5" length2="1.5"/>
|
||||
<line end2="none" x2="2.5" y2="38.2" x1="-2.5" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="true" end1="none" y1="38.2" length1="1.5" length2="1.5"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{67fffc8f-7e79-59d0-97e3-0e6aefa527d5}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-10_text-LVPNL_w-18.elmt">
|
||||
<definition width="76" hotspot_y="23" version="0.100.0" type="element" link_type="simple" hotspot_x="38" height="46">
|
||||
<uuid uuid="{33d0e3bc-adaa-58c2-8176-4003444084d4}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-10_text-LVPNL_w-18</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="32.4" x4="-32.4" x2="32.4" y2="18.0" y5="18.0" x1="-32.4" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-18.0" antialias="true" x5="-32.4" closed="true" y1="18.0" y3="-18.0"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{e8b0e37b-ae0c-59e1-a773-027b9af4e24d}" name="top" y="-18.0" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{83f1dd0e-48fc-5f4b-bcf0-a355902c6f73}" name="bottom" y="18.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_dashed-True_h-9_text-AVT_w-12_tape.elmt">
|
||||
<definition width="54" hotspot_y="22" version="0.100.0" type="element" link_type="simple" hotspot_x="49" height="44">
|
||||
<uuid uuid="{7f6386d4-07ed-501b-ab67-6060234bd3bb}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_dashed-True_h-9_text-AVT_w-12_tape</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="0.0" x4="-43.2" x2="0.0" y2="16.2" y5="16.2" x1="-43.2" style="line-style:dashed;line-weight:thin;filling:none;color:black" y4="-16.2" antialias="true" x5="-43.2" closed="true" y1="16.2" y3="-16.2"/>
|
||||
<terminal orientation="e" type="Generic" uuid="{87e8ccab-af69-57f9-a376-8aa611282d2f}" name="top" y="0.0" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
<element name="v2_box_h-11_text-DUT_w-18.elmt">
|
||||
<definition width="76" hotspot_y="25" version="0.100.0" type="element" link_type="simple" hotspot_x="38" height="50">
|
||||
<uuid uuid="{8268913e-3f82-5876-9766-27b136126ad8}"/>
|
||||
<names>
|
||||
<name lang="en">v2_box_h-11_text-DUT_w-18</name>
|
||||
</names>
|
||||
<kindInformations/>
|
||||
<informations>ENA006 SLD probe element � original NEMA/IEEE-styled geometry. PILOT ARTIFACT.</informations>
|
||||
<description>
|
||||
<polygon x3="32.4" x4="-32.4" x2="32.4" y2="19.8" y5="19.8" x1="-32.4" style="line-style:normal;line-weight:normal;filling:none;color:black" y4="-19.8" antialias="true" x5="-32.4" closed="true" y1="19.8" y3="-19.8"/>
|
||||
<terminal orientation="n" type="Generic" uuid="{b5f577a1-ac22-5d6e-b109-1d9ac351b5f8}" name="top" y="-19.8" x="0.0"/>
|
||||
<terminal orientation="s" type="Generic" uuid="{5b69e1c7-b417-5784-a874-5502eb581c22}" name="bottom" y="19.8" x="0.0"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
</category>
|
||||
</category>
|
||||
</collection>
|
||||
</project>
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <QtTest>
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QRegularExpression>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
namespace {
|
||||
|
||||
struct Point {
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
bool operator==(const Point &other) const { return x == other.x && y == other.y; }
|
||||
};
|
||||
|
||||
// Mirrors count_retraces.py (qelectrotech-docker), which this project's own
|
||||
// regression checks for bugtracker #734 already use: restricted to the
|
||||
// conductor path shape (4-6 points, every segment axis-aligned, not closed)
|
||||
// so legitimate closed element-graphics shapes (rectangles, polygons) are
|
||||
// never mistaken for a self-retracing conductor.
|
||||
QList<Point> parsePoints(const QString &d)
|
||||
{
|
||||
QList<Point> points;
|
||||
static const QRegularExpression re(QStringLiteral("[ML]\\s*(-?\\d+\\.?\\d*)[ ,](-?\\d+\\.?\\d*)"));
|
||||
auto it = re.globalMatch(d);
|
||||
while (it.hasNext()) {
|
||||
const QRegularExpressionMatch m = it.next();
|
||||
points << Point{m.captured(1).toDouble(), m.captured(2).toDouble()};
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
bool isConductorShaped(const QList<Point> &points)
|
||||
{
|
||||
if (points.size() < 4 || points.size() > 6) return false;
|
||||
if (points.first() == points.last()) return false; // closed shape, not a conductor
|
||||
for (int i = 0; i + 1 < points.size(); ++i) {
|
||||
if (points.at(i).x != points.at(i + 1).x && points.at(i).y != points.at(i + 1).y)
|
||||
return false; // not axis-aligned
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isSelfRetracing(const QList<Point> &points)
|
||||
{
|
||||
// (a) skip-one out-and-back: ... A B A ...
|
||||
for (int i = 0; i + 2 < points.size(); ++i) {
|
||||
if (points.at(i) == points.at(i + 2)) return true;
|
||||
}
|
||||
// (b) immediate duplicate vertex: ... A A ...
|
||||
for (int i = 0; i + 1 < points.size(); ++i) {
|
||||
if (points.at(i) == points.at(i + 1)) return true;
|
||||
}
|
||||
// (c) 6-point crossed-stub loop: depart0 == arrivee AND depart == arrivee0
|
||||
if (points.size() == 6 && points.at(0) == points.at(4) && points.at(1) == points.at(5)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Bugtracker #734: Conductor::generateConductorPath()'s cas "3"/"4" grid-
|
||||
// snap bridge used to route an unnecessary out-and-back excursion, or a
|
||||
// small looping detour, when depart and arrivee already shared the axis the
|
||||
// bridge would run along. This fixture (the report's own canonical
|
||||
// reproduction, "qet_bug_repro_resaved.qet") is known to trigger it.
|
||||
class tst_conductorselfretrace : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void noSelfRetracingPaths()
|
||||
{
|
||||
const QString binary = QStringLiteral(QET_TEST_BINARY_PATH);
|
||||
QVERIFY2(QFile::exists(binary), qPrintable(QStringLiteral("qelectrotech binary not found at '%1'").arg(binary)));
|
||||
|
||||
const QString fixture = QFINDTESTDATA("fixtures/qet_bug_repro_resaved.qet");
|
||||
QVERIFY2(!fixture.isEmpty(), "fixture project not found");
|
||||
|
||||
QTemporaryDir out_dir;
|
||||
QVERIFY(out_dir.isValid());
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
|
||||
|
||||
QProcess proc;
|
||||
proc.setProcessEnvironment(env);
|
||||
proc.start(binary, {QStringLiteral("--export-svg"), fixture, out_dir.path()});
|
||||
QVERIFY2(proc.waitForFinished(30000), "export --export-svg timed out or failed to start");
|
||||
QCOMPARE(proc.exitCode(), 0);
|
||||
|
||||
QDir dir(out_dir.path());
|
||||
const QStringList svgs = dir.entryList({QStringLiteral("*.svg")}, QDir::Files);
|
||||
QVERIFY2(!svgs.isEmpty(), "no SVG exported");
|
||||
|
||||
static const QRegularExpression path_re(QStringLiteral("<path[^>]*\\bd=\"([^\"]+)\""));
|
||||
|
||||
int retraces = 0;
|
||||
for (const QString &name : svgs) {
|
||||
QFile file(dir.filePath(name));
|
||||
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
const QString content = QString::fromUtf8(file.readAll());
|
||||
auto it = path_re.globalMatch(content);
|
||||
while (it.hasNext()) {
|
||||
const QRegularExpressionMatch m = it.next();
|
||||
const QList<Point> points = parsePoints(m.captured(1));
|
||||
if (isConductorShaped(points) && isSelfRetracing(points)) {
|
||||
++retraces;
|
||||
}
|
||||
}
|
||||
}
|
||||
QCOMPARE(retraces, 0);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_conductorselfretrace)
|
||||
|
||||
#include "tst_conductorselfretrace.moc"
|
||||
Reference in New Issue
Block a user