# -*- coding: utf-8 -*- """ /*************************************************************************** GemeindeMessdatenImport A QGIS plugin Importiert Messdaten im TXT-Format in die Gemeindeeigene Messdaten-Datenbank. ------------------- begin : 2024-02-01 git sha : $Format:%H$ copyright : (C) 2024 by Sebastian Pertl email : sebastian.pertl@fridolfing.bayern.de ***************************************************************************/ /*************************************************************************** * * * This program 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. * * * ***************************************************************************/ """ from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtWidgets import QAction, QComboBox from qgis.PyQt import uic from qgis.PyQt import QtWidgets from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox, QInputDialog, QLineEdit #from qgis.core import QgsVectorLayer, QgsVectorFileWriter, QgsProviderRegistry #from qgis.core import QgsProject, QgsFeature from qgis.core import * from qgis.utils import iface import qgis.core import toml # Initialize Qt resources from file resources.py # from .resources import * # Import the code for the dialog #from .gdeMessdatenImport_dialog import GemeindeMessdatenImportDialog import os import os.path import ezdxf import pandas as pd import numpy as np import networkx as nx import math import scipy import sqlite3 import subprocess import win32com.client from http.server import BaseHTTPRequestHandler, HTTPServer import time hostName = "localhost" serverPort = 8080 file_path = "D:/Daten/nc/Ingenieurbüro/98-CAD-Daten/Tools-QGIS/ibpTools/" with open(file_path + 'config.toml', 'r') as f: CFG = toml.load(f) class MyServer(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(bytes("
Request: %s
" % self.path, "utf-8")) self.wfile.write(bytes("", "utf-8")) self.wfile.write(bytes("This is an example web server.
", "utf-8")) self.wfile.write(bytes("", "utf-8")) basepath = os.path.dirname(os.path.realpath(__file__)) TEIGHA_PATH = basepath.replace("\\","/") + "/Teigha File Converter 4.3.2/TeighaFileConverter.exe" tmp_folder = r"C:/tmp" class ibpTools: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # Declare instance attributes # Eintrag Menüband Oben self.actions = [] self.menu = u'&IBP: Kanalplanung-Tools' # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads self.first_start = None inp_file = 'D:/Daten/nc/Ingenieurbüro/20 Projekte/Kanalplanung/kanalplanung.gpkg' self.md = QgsProviderRegistry.instance().providerMetadata("ogr") self.gpkg_con = self.md.createConnection( inp_file, {}) self.doc = False def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" # self.toolBar = self.iface.addToolBar("IBP: Kanalplanung-Tools") self.actList = [] icon_path = os.path.join(self.plugin_dir, 'icon_filter.png') act = QAction(QIcon(icon_path), u'Setze Projektfilter', self.iface.mainWindow()) act.triggered.connect(self.run_projectFilter) self.actList.append(act) icon_path = os.path.join(self.plugin_dir, 'icon_setup.png') act = QAction(QIcon(icon_path), u'Initialisiere BricsCAD', self.iface.mainWindow()) act.triggered.connect(self.run_setup) self.actList.append(act) icon_path = os.path.join(self.plugin_dir, 'icon_import.png') act = QAction(QIcon(icon_path), u'Importiere von BricsCAD', self.iface.mainWindow()) act.triggered.connect(self.run_import_from_bricscad) self.actList.append(act) icon_path = os.path.join(self.plugin_dir, 'icon_export.png') act = QAction(QIcon(icon_path), u'Übertrag in BricsCAD', self.iface.mainWindow()) act.triggered.connect(self.run_export_to_bricscad) self.actList.append(act) for i in self.actList: self.toolBar.addAction(i) self.iface.addPluginToMenu(self.menu, i) self.first_start = True def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu(u'&IBP: Kanalplanung-Tools', action) self.iface.removeToolBarIcon(action) def run_projectFilter(self): qid = QInputDialog() filter, ok = QInputDialog.getText( qid, "Projektfilter", "Projektnummmer", QLineEdit.Normal, "") self.gpkg_con.executeSql("UPDATE projekt SET aktiv = 0;") if filter != "": self.gpkg_con.executeSql("UPDATE projekt SET aktiv = 1 WHERE nr='{}';".format(filter)) #for i in self.iface.mapCanvas().layers(): for i in QgsProject.instance().mapLayers().values(): if type(i) == type(QgsVectorLayer()): idx = i.fields().indexFromName('ibpprj') if idx >= 0: i.setSubsetString("ibpprj LIKE '%"+filter+"%'") else: row.setSubsetString("") def run_setup(self): self.acad = win32com.client.Dispatch("BricscadApp.AcadApplication") self.doc = self.acad.ActiveDocument self.model = self.doc.ModelSpace QMessageBox.information(None, "Information", "BricsCAD gestartet und Datei gewählt: "+self.doc.name) def run_import_from_bricscad(self): """ Lädt alle Layer von BricsCAD in QGIS die mit "_IBP_QIN_" beginnen. """ if self.doc == False: QMessageBox.warning(None, "Warnung", "Verbindung noch nicht initialisiert!") else: self.doc.save() ibp_dwg_to_dxf(self.doc.name, self.doc.path.replace("\\","/")) file_path = self.doc.path.replace("\\","/")+self.doc.name.replace(".dwg",".dxf") print(file_path) s_doc = ezdxf.readfile(file_path) s_msp = s_doc.modelspace() # QGIS-Daten laylist = {} laylist['cad_punkt'] = {"qgis_handle":[], "add_new":[], "qgis_lay": None} laylist['cad_linie'] = {"qgis_handle":[], "add_new":[], "qgis_lay": None} #@todo: Wenn Layer nicht existiert soll er neu angelegt werden for key, val in laylist.items(): val['qgis_lay'] = QgsProject.instance().mapLayersByName(key)[0] val['qgis_lay'].startEditing() for i in val['qgis_lay'].getFeatures(): if i['doc'] == self.doc.name: val['qgis_handle'].append(i['handle']) # Übertrage alle Elemente des Bricscad Layer "_IBP_QIN_..." in QGIS cad_qgis_obj = [] for i in s_msp.query('*[layer?"{}.*"]'.format(CFG['qgs_cad']['import_layer_prefix'])): cad_qgis_obj.append(i) #print(cad_qgis_obj) for i in cad_qgis_obj: layer = "" if i.dxftype() in ["INSERT","POINT","CIRCLE"]: layer = "cad_punkt" elif i.dxftype() in ["LINE","LWPOLYLINE"]: layer = "cad_linie" else: continue new_feat = False if i.dxf.handle not in laylist[layer]['qgis_handle']: new_feat = True feature = QgsFeature(laylist[layer]['qgis_lay'].fields()) feature['layer'] = i.dxf.layer feature['handle'] = i.dxf.handle feature['doc'] = self.doc.name feature['type'] = i.dxftype() else: for j in laylist[layer]['qgis_lay'].getFeatures(): if j['handle'] == i.dxf.handle and j['doc'] == self.doc.name: feature = j if i.dxftype() == "LINE": geom = QgsGeometry.fromPolylineXY([QgsPointXY(i.dxf.start[0],i.dxf.start[1]), QgsPointXY(i.dxf.end[0],i.dxf.end[1])]) elif i.dxftype() == "INSERT": geom = QgsGeometry.fromPointXY(QgsPointXY(i.dxf.insert[0],i.dxf.insert[1])) feature['block_name'] = i.dxf.name elif i.dxftype() == "LWPOLYLINE": pts = [] for j in i.vertices(): pts.append(QgsPointXY(j[0],j[1])) ##Kontrolle ob geschlossen if i.dxf.flags == 1: geom = QgsGeometry.fromPolygonXY([pts]) else: geom = QgsGeometry.fromPolylineXY(pts) elif i.dxftype() == "POINT": geom = QgsGeometry.fromPointXY(QgsPointXY(i.dxf.location[0],i.dxf.location[1])) elif i.dxftype() == "CIRCLE": geom = QgsGeometry.fromPointXY(QgsPointXY(i.dxf.center[0],i.dxf.center[1])) if new_feat: feature.setGeometry(geom) laylist[layer]['add_new'].append(feature) else: laylist[layer]['qgis_lay'].updateFeature(feature) laylist[layer]['qgis_lay'].changeGeometry(feature.id(), geom) for key, val in laylist.items(): val['qgis_lay'].commitChanges() val['qgis_lay'].dataProvider().addFeatures(val['add_new']) self.iface.mapCanvas().refreshAllLayers() def run_export_to_bricscad(self): if self.doc == False: QMessageBox.warning(None, "Warnung", "Verbindung noch nicht initialisiert!") else: lgp_file = self.doc.path.replace("\\","/")+self.doc.name.replace(".dwg","_Lageplan.dxf") try: ibp_dwg_to_dxf(lgp_file.split("/")[-1].replace(".dxf",".dwg"),lgp_file.replace(lgp_file.split("/")[-1],"")) lgp_doc = ezdxf.readfile(lgp_file) except: lgp_doc = ezdxf.readfile('C:/Daten/nc/Ingenieurbüro/99-Vorlagen/ezdxf_vorl.dxf') lgp_msp = lgp_doc.modelspace() lay = QgsProject.instance().mapLayersByName('schacht')[0] lay.startEditing() for i in lay.getFeatures(): if i['schacht_dn'] > 0: rad = i['schacht_dn']/1000/2 else: if i['fallrohr'] > 0: rad = i['fallrohr']/1000/2 else: rad = 0.05 if len(lgp_msp.query().filter(lambda e: "QGIS:schacht:symb:{}".format(i['fid']) in e.get_hyperlink())) == 1: # Element vorhanden #ent_symb = lgp_msp.query('*[handle=="'+i['cad_out_handle_symb']+'"]')[0] ent_symb = lgp_msp.query().filter(lambda e: "QGIS:schacht:symb:{}".format(i['fid']) in e.get_hyperlink())[0] else: # Element anlegen ent_symb = lgp_msp.add_circle((0,0), 1) ent_symb.dxf.layer = '_IBP_QO_EW_{}_SCH'.format(i['art']) ent_symb.dxf.center = (i.geometry().asPoint().x(), i.geometry().asPoint().y()) ent_symb.dxf.radius = rad if len(lgp_msp.query().filter(lambda e: "QGIS:schacht:txt1:{}".format(i['fid']) in e.get_hyperlink())) == 1: # Element vorhanden # ent_txt = lgp_msp.query('*[handle=="{}"]'.format(i['cad_out_handle_txt']))[0] ent_txt = lgp_msp.query().filter(lambda e: "QGIS:schacht:txt1:{}".format(i['fid']) in e.get_hyperlink())[0] else: # Element anlegen ent_txt = lgp_msp.add_mtext("abc") ent_txt.dxf.insert = ent_symb.dxf.center ent_txt.dxf.layer = '_IBP_QO_EW_{}_SCH_Txt'.format(i['art']) ent_txt.dxf.char_height = 0.25 ent_txt.dxf.style = 'IBP_Norm' ent_txt.text = "{}".format(i['name']) if i['schacht_dn'] != NULL: ent_txt.text+="\nDN{:.0f}".format(i['schacht_dn']) if i['dh'] != NULL: ent_txt.text+="\nDH: {:.2f}".format(i['dh']) if i['sh'] != NULL: ent_txt.text+="\nSH: {:.2f}".format(i['sh']) #i['cad_out_handle_symb'] = ent_symb.dxf.handle #i['cad_out_handle_txt'] = ent_txt.dxf.handle ent_symb.set_hyperlink("QGIS:schacht:symb:{}".format(i['fid'])) ent_txt.set_hyperlink("QGIS:schacht:txt1:{}".format(i['fid'])) #lay.commitChanges() lay = QgsProject.instance().mapLayersByName('haltung')[0] lay.startEditing() for i in lay.getFeatures(): points = [] for j in i.geometry().vertices(): points.append((j.x(),j.y())) qry = lgp_msp.query().filter(lambda e: "QGIS:haltung:symb:{}".format(i['fid']) in e.get_hyperlink()) if len(qry) == 1: # Element vorhanden #ent_symb = lgp_msp.query('*[handle=="{}"]'.format(i['cad_out_handle_symb']))[0] ent_symb = qry[0] else: # Element anlegen ent_symb = lgp_msp.add_lwpolyline(points) ent_symb.dxf.layer = '_IBP_QO_EW_{}_Lei'.format(i['art']) #i['cad_out_handle_symb'] = ent_symb.dxf.handle ent_symb.set_hyperlink("QGIS:haltung:symb:{}".format(i['fid'])) mid_point = i.geometry().interpolate(i.geometry().length()/2) mid_point_c = [mid_point.asPoint().x(), mid_point.asPoint().y()] mid_angle = i.geometry().interpolateAngle(i.geometry().length()/2) mid_angle_deg = 90-mid_angle/math.pi*180 if mid_angle_deg < 0: mid_angle_deg+= 360 if mid_angle_deg > 90 and mid_angle_deg < 270: mid_angle_deg-= 180 qry = lgp_msp.query().filter(lambda e: "QGIS:haltung:txt1:{}".format(i['fid']) in e.get_hyperlink()) if len(qry) == 1: # Element vorhanden #ent_txt = lgp_msp.query('*[handle=="{}"]'.format(i['cad_out_handle_txt']))[0] ent_txt = qry[0] else: # Element anlegen ent_txt = lgp_msp.add_mtext("abc") ent_txt.dxf.insert = [mid_point_c[0]+math.cos((mid_angle_deg+90)/180*math.pi)*.1, mid_point_c[1]+math.sin((mid_angle_deg+90)/180*math.pi)*.1] ent_txt.dxf.layer = '_IBP_QO_EW_{}_Lei_Txt'.format(i['art']) ent_txt.dxf.rotation = mid_angle_deg ent_txt.dxf.attachment_point = ezdxf.lldxf.const.MTEXT_BOTTOM_CENTER ent_txt.dxf.char_height = 0.25 ent_txt.dxf.style = 'IBP_Norm' ent_txt.text = "{}".format(i['mat']) #i['cad_out_handle_txt'] = ent_txt.dxf.handle ent_txt.set_hyperlink("QGIS:haltung:txt1:{}".format(i['fid'])) qry = lgp_msp.query().filter(lambda e: "QGIS:haltung:txt2:{}".format(i['fid']) in e.get_hyperlink()) if len(qry) == 1: # Element vorhanden #ent_txt = lgp_msp.query('*[handle=="{}"]'.format(i['cad_out_handle_txt2']))[0] ent_txt = qry[0] else: # Element anlegen ent_txt = lgp_msp.add_mtext("abc") ent_txt.dxf.insert = [mid_point_c[0]-math.cos((mid_angle_deg+90)/180*math.pi)*.1, mid_point_c[1]-math.sin((mid_angle_deg+90)/180*math.pi)*.1] ent_txt.dxf.layer = '_IBP_QO_EW_{}_Lei_Txt'.format(i['art']) ent_txt.dxf.rotation = mid_angle_deg ent_txt.dxf.attachment_point = ezdxf.lldxf.const.MTEXT_TOP_CENTER ent_txt.dxf.char_height = 0.25 ent_txt.dxf.style = 'IBP_Norm' if i['gefaelle'] == qgis.core.NULL: ent_txt.text = '{:.2f}m'.format(i['c_laenge']) else: ent_txt.text = '{:.2f}‰; {:.2f}m'.format(i['gefaelle'], i['c_laenge']) #i['cad_out_handle_txt2'] = ent_txt.dxf.handle ent_txt.set_hyperlink("QGIS:haltung:txt2:{}".format(i['fid'])) #lay.updateFeature(i) #Update-QGIS-Layer lay.commitChanges() lgp_doc.saveas(lgp_file) ibp_dxf_to_dwg(lgp_file.split("/")[-1],lgp_file.replace(lgp_file.split("/")[-1],"")) def run_init(self): # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started if self.first_start == True: self.first_start = False self.dlg = ibpToolsDialog() # PARAMS: # Input folder # Output folder # Output version: ACAD9, ACAD10, ACAD12, ACAD14, ACAD2000, ACAD2004, ACAD2007, ACAD20010, ACAD2013, ACAD2018 # Output file type: DWG, DXF, DXB # Recurse Input Folder: 0, 1 # Audit each file: 0, 1 # (Optional) Input files filter: *.DWG, *.DXF def ibp_dwg_to_dxf(file, INPUT_FOLDER = tmp_folder, OUTPUT_FOLDER = tmp_folder, RECURSIVE = "0", AUDIT = "1"): if INPUT_FOLDER != tmp_folder and OUTPUT_FOLDER == tmp_folder: OUTPUT_FOLDER = INPUT_FOLDER OUTVER = "ACAD2018" OUTFORMAT = "DXF" # Command to run cmd = [TEIGHA_PATH, INPUT_FOLDER, OUTPUT_FOLDER, OUTVER, OUTFORMAT, RECURSIVE, AUDIT, file] # Run subprocess.run(cmd, shell=True) def ibp_dxf_to_dwg(file, INPUT_FOLDER = tmp_folder, OUTPUT_FOLDER = tmp_folder, RECURSIVE = "0", AUDIT = "1"): if INPUT_FOLDER != tmp_folder and OUTPUT_FOLDER == tmp_folder: OUTPUT_FOLDER = INPUT_FOLDER OUTVER = "ACAD2018" OUTFORMAT = "DWG" # Command to run cmd = [TEIGHA_PATH, INPUT_FOLDER, OUTPUT_FOLDER, OUTVER, OUTFORMAT, RECURSIVE, AUDIT, file] # Run subprocess.run(cmd, shell=True)