| | | Gut zu wissen: Hilfreiche Tipps und Tricks aus der Praxis prägnant, und auf den Punkt gebracht für Autodesk Produkte |
Autor
|
Thema: langsames Lesen von Blöcken (3127 mal gelesen)
|
bennyboss Mitglied
Beiträge: 15 Registriert: 07.11.2005 ThinkPad 60, OS: Vista Business, CPU: 1,86 Core 2 Duo, RAM: 2GB, AutoCAD: 2008, VisualStudio2005
|
erstellt am: 12. Apr. 2007 15:33 <-- editieren / zitieren --> Unities abgeben:
Hallo, ich brauche wieder ein kleines Tipp von euch, das Problem: ich möchte in meinem C# Programm alle Blöcke einer Zeichnung zählen... das macht mein Programm richting nur sehr sehr langsam, da manche Blöcke andere Blöcken enthalten können, benutzte ich um sie alle zu finden eine Rekurrenz-Funktion, dann zähle ich entsprechend alles was ich gefunden habe irgendwie benutzt AutoCAD immer 50% von der CPU Leistung (Core 2 Duo) (XPro, AutoCAD2007) während diese Rekurrenz-Funktion ausgeführt wird... obwohl sie oft nicht mehr als 50 Mal hintereinader gerufen wird wenn ein Block komplizierter ist auf das laufende AutoCAD Instanz greife ich von C# mit Marshal.GetActiveObject("AutoCAD.Application.17") zu ist es möglich diese Rekurrenz-Funktion zu beschleunigen? wenn ja dann wie? und eine ausweichende Lösung die mir so eingefallen ist: ich dachte man könnte sie zB in ein ARX-Programm reinpacken und sie dann extern von meinem Programm wenn nötig ausführen?... da ich aber mit ARXen noch nicht gearbeitet habe weiss ich nicht ob es sich der Aufwand loht... ginge so was? [Diese Nachricht wurde von bennyboss am 12. Apr. 2007 editiert.] Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 16. Apr. 2007 18:19 <-- editieren / zitieren --> Unities abgeben: Nur für bennyboss
Hallo bennyboss, wenn ich dich richtig verstanden habe, dann bindest du dein Programm nicht als dll in Acad ein sondern greifst mit einem exe-Programm auf die aktuelle Sitzung zu. Das Problem hierbei ist, das Zugriffe auf die Datenbank von Acad über ein externes Programm wesentlich langsamer ablaufen (um Faktor 80x langsamer) als wenn die Funktion direkt in Acad eingebunden ist. Lösung: Funktion als dll einbinden (C#.Net-Dll mit "netload" einbinden), mit dem internen VBA arbeiten oder das ganze als Lisp-Programm laufen lassen. Falls du die Blöcke über ein Selectionset-Object suchst: Das müsste über einen direkten Zugriff auf die Datenbank viel schneller gehen. Document.Blocks.count dürfte dir dabei behilflich sein.
------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
bennyboss Mitglied
Beiträge: 15 Registriert: 07.11.2005 ThinkPad 60, OS: Vista Business, CPU: 1,86 Core 2 Duo, RAM: 2GB, AutoCAD: 2008, VisualStudio2005
|
erstellt am: 21. Apr. 2007 12:19 <-- editieren / zitieren --> Unities abgeben:
Hi Jonapap, vielen Dank für deine Antwort, nach alldem was ich noch gefunden habe bin ich noch mehr verwirrt, also eine ARX-Datei ist eine DLL nur die Endung ist anders, aber das ist nicht das gleiche wie eine DLL erstellt mit C# und mit DLL-Endung denn das wird mit netload geladen und lässt sich nicht debugen usw. dagegen mit ARXen kann man fast alles machen auf der Website von Autodesk steht: "The ObjectARX® programming environment provides object-oriented C++, C# and VB .NET application programming interfaces for developers to use, customize, and extend AutoCAD® software..." warum ist es denn nur so schwer etwas über ARXen in C# zu finden? in der Dokumentation konnte ich auch nichts vernünftiges finden... manche Webseiten bechaupten man müsse COM benutzten wenn man ARX in C# schreiben will, leider sagt keine von denen ob so eine ARX-Datein dann genau so schnell ist wie Lisp oder VBA [Diese Nachricht wurde von bennyboss am 21. Apr. 2007 editiert.] Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 21. Apr. 2007 14:33 <-- editieren / zitieren --> Unities abgeben: Nur für bennyboss
Hallo bennyboss, 1. Eine Arx-Datei ist eine mit Visual C++ kompilierte dll-Datei 2. Man kann nur mit Visual C++ auf die Objekt-ARX-Klasse zugreifen. 3. Mit C# oder Visual-Basic kann man über die COM-Schnittstelle Autocad steuern. Auf COM basierte dll's können jedoch soweit ich weiß nur über Autocad-VBA angesprochen werden. Haben dann jedoch kaum Nachteile bei der Performance. 4. Mit .Net (vb.Net,C#.Net ...) kann man über die sogenannten wrapped Classes Autocad steuern. Die so erzeugten dll's lassen sich ohne Tricks (http://discussion.autodesk.com/thread.jspa?messageID=4531456) nur mittels Netload in Autocad laden. 5.Dll's die auf Objekt-ARX oder wrapped Classes basieren können nur direkt in Autocad eingebunden werden. Eine Steuerung aus externen Programmen ist nur über die COM-Schnittstelle möglich und ist dann deutlich langsamer, als wenn die dll's direkt in Acad eingebunden werden. Mögliche Lösung für dein Problem: Die in Autocad eingebundene dll greift selbst auf deine Datenbank zu und speichert dort die Daten die du brauchst ------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
bennyboss Mitglied
Beiträge: 15 Registriert: 07.11.2005 ThinkPad 60, OS: Vista Business, CPU: 1,86 Core 2 Duo, RAM: 2GB, AutoCAD: 2008, VisualStudio2005
|
erstellt am: 22. Apr. 2007 20:36 <-- editieren / zitieren --> Unities abgeben:
ich muss mich noch mal bei Dir für die ausführliche Erklärung bedanken wie ich sehe ist das ganze so kompliziert und verwirrend dass es wohl einfacher wäre wenn ich mich mit C++ und MFC und VC++ beschäftige um ObjectARX Programme zu schreiben als sich den Kopf mit dieser ganzen noch unsinnigen Implementation von wrapped Classes für .NET zu zerbrechen das aller schlimmste daran ist dass man bei jeder Änderung AutoCAD neustarten muss... es ist doch unmöglich beim ersten Mal ein fehlerfreies dll-Programm zu schreiben bis ich soweit mit C++ bin schreibe ich diese BlockCount-Funktion einfach in VBA um ------------------ ( ... bennyboss ... ) Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 23. Apr. 2007 07:30 <-- editieren / zitieren --> Unities abgeben: Nur für bennyboss
Zitat: Original erstellt von bennyboss: das aller schlimmste daran ist dass man bei jeder Änderung AutoCAD neustarten muss... es ist doch unmöglich beim ersten Mal ein fehlerfreies dll-Programm zu schreiben [/i]
In .Net gibt es die Möglichkeit beim debuggen "Edit and Continue" zu verwenden. Solange du nur innerhalb der Subs oder Functions editierst und noch keine Formulare benutzt, kannst du also bei gestartetem Acad deinen Code editieren und anschließend sofort in Acad testen Bei Objekt-Arx gibt's dass bestimmt auch. Blöd ist allerdings die äußerst dürftige Dokumentation (Acad SDK) zu wrapped Classes und zu ObjektArx. Viele Infos dazu findet man nur in englischsprachigen Foren (z.B. http://discussion.autodesk.com/index2.jspa?categoryID=8)------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
bennyboss Mitglied
Beiträge: 15 Registriert: 07.11.2005 ThinkPad 60, OS: Vista Business, CPU: 1,86 Core 2 Duo, RAM: 2GB, AutoCAD: 2008, VisualStudio2005
|
erstellt am: 23. Apr. 2007 10:12 <-- editieren / zitieren --> Unities abgeben:
|
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 23. Apr. 2007 10:36 <-- editieren / zitieren --> Unities abgeben: Nur für bennyboss
Netload automatisieren: 1.Debug-Pfad der dll-Datei mit bei den Supportpfaden von Acad eintragen 2.(command "Netload" "Testprojekt") z.B. in die acaddoc.lsp eintragen Vorlagedatei laden: In VS unter Debug bei "Command Line Args" folgendes eintragen: /p "Testprofil" /t "C:\Test.dwg" ------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
bennyboss Mitglied
Beiträge: 15 Registriert: 07.11.2005 ThinkPad 60, OS: Vista Business, CPU: 1,86 Core 2 Duo, RAM: 2GB, AutoCAD: 2008, VisualStudio2005
|
erstellt am: 23. Apr. 2007 11:00 <-- editieren / zitieren --> Unities abgeben:
super! funktioniert wunderbar, danke! (ich muss mal AutoCAD User Guide lesen, ich hab garnicht gewusst (und erwartet) dass AC so viele "Command line switches" hat) und jetzt an die Arbeit, BlockCount als eine DLL-Datei, das wird interresant ------------------ ( ... MfG, benjamin ... ) Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
bennyboss Mitglied
Beiträge: 15 Registriert: 07.11.2005 ThinkPad 60, OS: Vista Business, CPU: 1,86 Core 2 Duo, RAM: 2GB, AutoCAD: 2008, VisualStudio2005
|
erstellt am: 23. Apr. 2007 17:20 <-- editieren / zitieren --> Unities abgeben:
klasse! ich muss sagen ich bin begeistert, jetzt braucht die DLL weniger als eine Sekunde um alle Blöcke zu zählen, dagegen die alte die über die COM-Schnitstelle auf AutoCAD zugriff hatte, brauchte jedes mal mehr als eine Minute, manchmal sogar 6 und mehr! das ist der Haput-Code der nach Blöcken in einer Zeichnung sucht und macht davon eine Liste mit deren Inhalt, es gibt noch mehr Code aber dann wäre das Prinzip unübersichtlich denke ich, also wenn jemand das ganze Funktion braucht dann bitte bei mir melden vielleicht nutzt der Code jemandem: Code:
public class BlockCounter { private Transaction tr; private BlockTable bt; [Autodesk.AutoCAD.Runtime.CommandMethod("nblocks")] public void HelloCommand() { Document doc = acadApp.DocumentManager.MdiActiveDocument; Database db = doc.Database; tr = doc.TransactionManager.StartTransaction(); bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); // zu erst suche ich alle BlockDefinitions um zu wissen wie viele das sind um myBlocks-Array mit fester Größe initiieren zu können #region get blockNames ArrayList blockNames = new ArrayList(); BlockTableRecord btr; foreach (ObjectId tmpBlockId in bt) { btr = (BlockTableRecord)tr.GetObject(tmpBlockId, OpenMode.ForRead, false); if (btr.IsLayout == false) { blockNames.Add(btr.Name); } } #endregion object[,] myBlocks = new object[blockNames.Count, 2]; // block counters int i0 = 0; ArrayList blockItems; // block contents BlockTableRecord blockDef; foreach (ObjectId tmpBlockId in bt) // noch mal eine Schleiffe über alle Blöcke { blockDef = (BlockTableRecord)tr.GetObject(tmpBlockId, OpenMode.ForRead, false); if (blockDef.IsLayout == false) // wir wollen keine von den drei default-Blocks { blockItems = new ArrayList(); // der Inhalt eines Blocks (wird später benötigt) myBlocks[i0, 0] = blockDef.Name; Entity ent; BlockReference blockRef; foreach (ObjectId blockItem in blockDef) { ent = (Entity)tr.GetObject(blockItem, OpenMode.ForRead, false); // wenn ein Object in dem Block ein BlockRef ist dann such das BlockDef nach mehr if (string.Compare(ent.GetType().Name, "BlockReference") == 0) { blockRef = (BlockReference)ent; blockItems.Add(blockRef.Name); GoDeeper(bt[blockRef.Name], ref blockItems); myBlocks[i0, 1] = blockItems; } } i0 = i0 + 1; } } tr.Commit(); acadApp.DocumentManager.MdiActiveDocument.Editor.WriteMessage("fertig!"); acadApp.UpdateScreen(); }
und die Regkurenz-Funktion Code:
private void GoDeeper(ObjectId blockDefId, ref ArrayList blockItems) { BlockTableRecord blockDef = (BlockTableRecord)tr.GetObject(blockDefId, OpenMode.ForRead, false); Entity ent; BlockReference blockRef; foreach (ObjectId blockItem in blockDef) { ent = (Entity)tr.GetObject(blockItem, OpenMode.ForRead, false); if (string.Compare(ent.GetType().Name, "BlockReference") == 0) { blockRef = (BlockReference)ent; blockItems.Add(blockRef.Name); GoDeeper(bt[blockRef.Name], ref blockItems); } } } } // Class-Ende
------------------ ( ... MfG, benjamin ... ) [Diese Nachricht wurde von bennyboss am 23. Apr. 2007 editiert.] Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
RoSiNiNo Mitglied Konstrukteur
Beiträge: 1126 Registriert: 09.10.2002 Revit Structure 2011 Acad 2011-deutsch, Express Tools 3ds Max 2011 Win 7-Professional HP Workstation Z400, 6GB GeForce GTX 470
|
erstellt am: 08. Mai. 2007 11:33 <-- editieren / zitieren --> Unities abgeben: Nur für bennyboss
Hier vielleicht ein etwas anderer Lösungsansatz, hier muss man allerdings noch alle unnötigen Blöcke ausschließen (Bemaßungen, anonyme Blöcke, etc.). Code: [CommandMethod("TestBlockCount")] static public void BlockCountTest() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; int i = 0; try { using (Transaction tr = doc.TransactionManager.StartTransaction()) using (BlockTable bt = (BlockTable)tr.GetObject(doc.Database.BlockTableId, OpenMode.ForRead, false)) { foreach (ObjectId blockId in bt) { using (BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead, false)) { if (btr.IsLayout == false) { ObjectIdCollection IDColl = btr.GetBlockReferenceIds(false, false); i += IDColl.Count; } } } tr.Commit(); } ed.WriteMessage(System.String.Format("\nAnzahl der Blöcke in der Zeichnung: {0}!", i.ToString())); } catch { //Mach etwas } finally { //Mach nix } }
------------------ Roland Feletic PAUSER ZT-GMBH Acad 2008-deutsch, Express Tools 3ds Max 9 WinXP-Professional HP Workstation xw4400, 3GB Quadro FX1500 Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
| Anzeige.:
Anzeige: (Infos zum Werbeplatz >>)
|