| | | Gut zu wissen: Hilfreiche Tipps und Tricks aus der Praxis prägnant, und auf den Punkt gebracht für Autodesk Produkte |
Autor
|
Thema: Bogen mit Richtungsvektor erzeugen (2010 mal gelesen)
|
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 26. Okt. 2009 11:04 <-- editieren / zitieren --> Unities abgeben:
Hallo, ich möchte mit vb.net einen Befehl erstellen, der mir einen Bogen unter Angabe des Start- und Endpunktes und des Startwinkels (oder Richtungsvektor) zeichnet. In Autocad selbst gibt es zwar so einen Befehl schon (Startp Endp Richtung), aber ich möchte mit dem neuen Befehl einen Bogen an eine vorhandene Linie oder Bogen an einem beliebigen Punkt tangential ansetzen können. Im angehängten Bild sind alle gegebenen Werte blau, Hilfs- und Konstruktionslinien grün und das erwünschte Objekt rot dargestellt. Wie kann ich mit den gegebenen Werten in vb.net möglichst einfach einen Bogen erstellen? Mit z.b CircularArc3d kann ich einen Bogen mithilfe von 3 Punkten erstellen, oder mit Zentrum, Radius, Startwinkel und Endwinkel. 3 Punkte habe ich aber nicht und den Radius und das Zentrum müsste ich mir erst berechnen. Den Zentrumspunkt würde ich mir aus dem Schnittpunkt der Linie "R" und der Winkelhalbierenden "WH" berechnen. Gibt es einen einfacheren Weg? Wenn nein: Ich komme bei der Berechnung des Schnittpunktes mit den Objekttypen nicht ganz klar. Ich habe mit "line", "line3d" und "vector3d" herumexperimentiert, aber immer fehlt mir in irgendeinem Objekttyp eine Eigenschaft (z.B. getperpendicularvector oder intersectwith). Außerdem lassen sich Schnittpunkte nur in einer 2D-Ebene berechnen? ------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 26. Okt. 2009 11:38 <-- editieren / zitieren -->
Hi, >> In Autocad selbst gibt es zwar so einen Befehl schon (Startp Endp Richtung) >> aber ich möchte mit dem neuen Befehl einen Bogen an eine vorhandene Linie >> oder Bogen an einem beliebigen Punkt tangential ansetzen können. Und aus welchem Grund verwendest Du den AutoCAD-Befehl dann nicht? _ARC<ENTER> _nea<ENTER> <Punkt auf Linie zeigen> _e<ENTER> <Bogenendpunkt zeigen> _d<ENTER> _nea<ENTER> (alternativ auch mit Spur die Verlängerung der Linie zeigen) <Punkt auf Linie zeigen, damit Tangentialrichtung festgelegt wird> >> ... den Radius und das Zentrum müsste ich mir erst berechnen um diese Unzulänglichkeiten wirst Du in der Programmierung nie umhinkommen Und vorweg zu allem anderen: sprichst Du von 3D oder von 2D?
- alfred -
------------------ www.hollaus.at |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 26. Okt. 2009 12:23 <-- editieren / zitieren --> Unities abgeben:
Hallo Alfred, Zitat: Und aus welchem Grund verwendest Du den AutoCAD-Befehl dann nicht?
Bei einer vorhandenen Linie kann man einen Bogen tangential nach der von dir beschriebenen Methode ansetzen, aber nicht an einen Bogen. Dafür müsste man sich dann erst wieder eine Hilfslinie konstruieren. Da ich diese Funktionalität oft benötige, will ich außerdem, falls der Bogen nicht am Endpunkt sondern an einem beliebigem Punkt ansetzt, das Ursprungsobjekt passend Stutzen. Zitat: Und vorweg zu allem anderen: sprichst Du von 3D oder von 2D?
Eigentlich benötige ich diesen Befehl nur im 2D. Falls es sich aber auch (einfach) so programmieren lässt, das es auch 3D funktioniert... Was mir im Moment noch Kopfzerbrechen bereitet ist, wie ich an den Schnittpunkt von "R" und "WH" komme. Hier mein bisheriger Code: Code:
Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.Geometry Imports Autodesk.AutoCADPublic Class TestClass <CommandMethod("B3")> _ Sub Testbogen() Dim StartP As New Point3d(0, 0, 0) Dim EndP As New Point3d(5, 5, 0) Dim Richtung As New Vector3d(0, 1, 0) Dim R As New Line3d(StartP, Richtung.GetPerpendicularVector) Dim Sehne As New Line3d(StartP, EndP) Dim WH As New Line3d(StartP.Add(StartP.GetVectorTo(EndP) * 0.5), Sehne.Direction.GetPerpendicularVector) End Sub End Class
------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 26. Okt. 2009 14:23 <-- editieren / zitieren -->
Hi Markus, sorry für die Verzögerung (Mittag war und Feiertag haben wir auch ) Anbei mal ein Ansatz (nicht wirklich getestet, also unterschiedliche Fälle durchprobieren), lass mich wissen, ob Dir das hilft und die Kommentare ausreichend für's verstehen sind. Zitat: Dim tAcadDoc As ApplicationServices.Document = Nothing Dim tDocLock As ApplicationServices.DocumentLock = Nothing Dim tTrAct As DatabaseServices.Transaction = Nothing Try tAcadDoc = ApplicationServices.Application.DocumentManager.MdiActiveDocument tDocLock = tAcadDoc.LockDocument tTrAct = tAcadDoc.TransactionManager.StartTransaction Dim tBlTab As DatabaseServices.BlockTable = CType(tTrAct.GetObject(tAcadDoc.Database.BlockTableId, DatabaseServices.OpenMode.ForRead, True, True), DatabaseServices.BlockTable) Dim tModSp As DatabaseServices.BlockTableRecord = CType(tTrAct.GetObject(tBlTab.Item("*Model_Space"), DatabaseServices.OpenMode.ForWrite, True, True), DatabaseServices.BlockTableRecord) Dim tPnt1 As Geometry.Point3d = New Geometry.Point3d(0, 0, 0) 'Startpunkt Bogen Dim tPnt2 As Geometry.Point3d = New Geometry.Point3d(10, 20, 0) 'Endpunkt Bogen Dim tTangAng As Double = Math.PI / 4.0 'Tangentenrichtung des Bogens (PI/4 = 45°) 'der Winkel von Startpunkt Richtung Zentrum (senkrecht auf Tangente) Dim tAng1 As Double = tTangAng + (Math.PI / 2.0) 'der Winkel zwischen Pkt1 und Pkt2 (bzw. der Sehne) Dim tAngS As Double = tPnt1.GetVectorTo(tPnt2).AngleOnPlane(New Geometry.Plane) 'der rechte Winkel zwischen Sehne und Zentrum Dim tAngS90 As Double = tAngS + (Math.PI / 2.0) 'der Winkel zwischen Pkt2 und Zentrum Dim tAng2 As Double = tAng1 + 2 * (tAngS90 - tAng1) 'temporaerer Punkt auf Strecke zwischen Pkt1 und Zentrum Dim tPnt1T As Geometry.Point3d = New Geometry.Point3d(tPnt1.X + Math.Cos(tAng1), tPnt1.Y + Math.Sin(tAng1), tPnt1.Z) 'temporaere Linie dazu Dim tLine1T As DatabaseServices.Line = New DatabaseServices.Line(tPnt1, tPnt1T) 'temporaerer Punkt auf Strecke zwischen Pkt2 und Zentrum Dim tPnt2T As Geometry.Point3d = New Geometry.Point3d(tPnt2.X + Math.Cos(tAng2), tPnt2.Y + Math.Sin(tAng2), tPnt2.Z) 'temporaere Linie dazu Dim tLine2T As DatabaseServices.Line = New DatabaseServices.Line(tPnt2, tPnt2T) 'und der Schnittpunkt aus obigen Linien ist der Mittelpunkt Dim tIntPnts As Geometry.Point3dCollection = New Geometry.Point3dCollection Call tLine1T.IntersectWith(tLine2T, DatabaseServices.Intersect.ExtendBoth, tIntPnts, 0, 0) If (tIntPnts Is Nothing) OrElse (tIntPnts.Count = 0) OrElse (tIntPnts.Count > 1) Then Call MsgBox("Bogenmittelpunkt ist nicht zu errechnen") Else Dim tPntZ As Geometry.Point3d = tIntPnts(0) Dim tArc As DatabaseServices.Arc = New DatabaseServices.Arc(tPntZ, tPntZ.DistanceTo(tPnt1), tPntZ.GetVectorTo(tPnt1).AngleOnPlane(New Geometry.Plane), tPntZ.GetVectorTo(tPnt2).AngleOnPlane(New Geometry.Plane)) tModSp.AppendEntity(tArc) tTrAct.AddNewlyCreatedDBObject(tArc, True) End If 'und noch bereinigen If tLine1T IsNot Nothing Then tLine1T.Dispose() If tLine2T IsNot Nothing Then tLine2T.Dispose()
HTH, - alfred - ------------------ www.hollaus.at [Diese Nachricht wurde von a.n. am 26. Okt. 2009 editiert.] |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 26. Okt. 2009 14:48 <-- editieren / zitieren --> Unities abgeben:
Vielen Dank Alfred, für so eine ausführliche Antwort gönne ich dir gerne dein Mittagessen An dieser Stelle möchte ich dir mal allgemein ein großes Lob für deine hervorragenden Hilfestellungen in dieser Forensparte aussprechen. Weiter so! Deinen Vorschlag schaue ich mir mal an und melde mich dann wieder. Schönen Feiertag noch! ------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006 ACAD 13 bis 2012 Accurender4 IMOS 9 Rhinoceros 4&5beta Mastercam X5
|
erstellt am: 27. Okt. 2009 00:15 <-- editieren / zitieren --> Unities abgeben:
Hallo nochmal, dein Code funktioniert soweit Alfred (bis auf das fehlende "Catch" und "End Try"). Nocheinmal Danke dafür. Allerdings glaube ich, das wegen der vielen Winkelberechnungen am Ende die Genauigkeit darunter leidet (wenn auch erst nach der x-ten Nachkommastelle). Deshalb habe ich ein bischen im Internet gestöbert und meine Kenntnisse in Bezug auf Vektorrechnung ein bischen aufgefrischt. Herausgekommen ist dabei eine Klasse zur Berechnung des Schnittpunktes von 2 Linien. Zusätzlich kann man angeben, ob die beiden Linien zur Ermittlung des Schnittpunktes verlängert werden sollen (gedachter Schnittpunkt) und die Klasse merkt, wenn die Linien parallel zueinander sind. Wen es interessiert - hier der Code der Klasse: Code:
Public Class LineIntersection Dim locIntersects As Boolean = False Dim locIntersectionPoint As Point2d Dim locResultMessage As String Sub New(ByVal StartpointLine1 As Vector2d, ByVal Direction1 As Vector2d, _ ByVal StartpointLine2 As Vector2d, ByVal Direction2 As Vector2d, ByVal ExtendLines As Boolean) Calculate(StartpointLine1, Direction1, StartpointLine2, Direction2, ExtendLines) End Sub Private Sub Calculate(ByVal SPL1 As Vector2d, ByVal Dir1 As Vector2d, _ ByVal SPL2 As Vector2d, ByVal Dir2 As Vector2d, ByVal ExtendLines As Boolean) 'Die Determinante D berechnen Dim D As Double = Dir1.Y * Dir2.X - Dir1.X * Dir2.Y 'Wenn D null ist, sind die Linien parallel. If D < 0.0000001 And D > -0.0000001 Then locIntersects = False locResultMessage = "Die Linien sind parallel zueinander und schneiden sich daher nicht." Exit Sub End If Dim Ds As Double = (SPL2.Y - SPL1.Y) * Dir2.X - (SPL2.X - SPL1.X) * Dir2.Y 's ist Faktor um Linie1 bis zum Schnittpunkt zu verlängern Dim s As Double = Ds / D Dim Dt As Double = (SPL2.Y - SPL1.Y) * Dir1.X - (SPL2.X - SPL1.X) * Dir1.Y 't ist Faktor um Linie2 bis zum Schnittpunkt zu verlängern Dim t As Double = Dt / D 'Prüfen, ob die Linien für einen Schnittpunkt verlängert werden müssten If ExtendLines = False Then If s < 0 OrElse s > 1 OrElse t < 0 OrElse t > 1 Then locIntersects = False locResultMessage = "Die Linien schneiden sich nicht." Exit Sub End If End If 'Die Linien schneiden sich Dim SPVector As Vector2d = SPL1.Add(s * Dir1) locIntersectionPoint = New Point2d(SPVector.X, SPVector.Y) locIntersects = True locResultMessage = "Schnittpunkt: " & locIntersectionPoint.ToString End Sub Public ReadOnly Property IntersectionPoint() As Point2d Get Return locIntersectionPoint End Get End Property Public ReadOnly Property Intersects() As Boolean Get Return locIntersects End Get End Property Public ReadOnly Property ResultMessage() As String Get Return locResultMessage End Get End Property End Class
------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 27. Okt. 2009 00:36 <-- editieren / zitieren -->
Hi Markus, >> dein Code funktioniert soweit Alfred ... bis auf das fehlende "Catch" und "End Try" Ich hab auch nicht den ganzen Teil darunter mitkopiert, denn da waren bei mir auch noch Debug-Draw's drunter, die hätten den wesentlichen Teil des Codes aber nicht verständlicher gemacht. Und das Wissen um TransAction.Commit sowie dass 'Try' mit 'Catch' 'Finally' (optional) und 'End Try' zu ergänzen ist, habe ich (richtigerweise ) vorausgesetzt. >> Allerdings glaube ich, das wegen der vielen Winkelberechnungen am Ende die Genauigkeit darunter leidet
Die Winkel werden mit DoublePrecission gerechnet, und am End der Funktion werden diese aus den ermittelten Punkten nochmals zurückgerechnet, also sehe ich da wenig Probleme, oder kannst Du mir da ein (begründetes) Beispiel übermitteln, wo mehr Fehler ersichtlich wäre, als AutoCAD bei Bögen/Splines/Ellipsen/Winkel sowieso drin hat? >> eine Klasse zur Berechnung des Schnittpunktes von 2 Linien
Die Schnittpunktberechnung von AutoCAD hat zwar ihre Macken (im hohen Koordinatenbereich, oder in einzelnen Fällen für die Angabe, dass Elemente NICHT verlängert werden sollen), aber das trifft hier alles nicht zu, damit ersparst Du Dir zwar meine temporäre Linienerzeugung (im Speicher, nicht in der DWG-Datenbank), aber nicht mehr! Wäre interessant, jetzt mal 100.000 Elemente durchrechnen zu lassen, was schneller ist. Und Vorsicht: mit If D < 0.0000001 And D > -0.0000001 hast Du auch schon Deine Rundungsfehler eingebaut. Auch sehe ich hier nicht, dass Du um die Berechnung der Winkel herumkommst. Aber gelernt ist gelernt und das hast Du ja jetzt, also hat's jedenfalls sein gutes
Schöne Restnacht, - alfred -
------------------ www.hollaus.at |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 27. Okt. 2009 09:16 <-- editieren / zitieren --> Unities abgeben:
Hallo Alfred, wirst du eigentlich von deinem Computer geweckt, wenn wieder neue Forenbeiträge vorhanden sind? Zitat: >> Allerdings glaube ich, das wegen der vielen Winkelberechnungen am Ende die Genauigkeit darunter leidetDie Winkel werden mit DoublePrecission gerechnet, und am End der Funktion werden diese aus den ermittelten Punkten nochmals zurückgerechnet, also sehe ich da wenig Probleme, oder kannst Du mir da ein (begründetes) Beispiel übermitteln, wo mehr Fehler ersichtlich wäre, als AutoCAD bei Bögen/Splines/Ellipsen/Winkel sowieso drin hat?
Mathematisch beweisen kann ich es nicht. Meine These ist aber, dass je mehr Berechnungen mit einem Wert gemacht werden, umso ungenauer wird das Ergebnis. Da Sinus- und Cosinusberechnungen meines Wissens nach Funktionen sind und deshalb im Hintergrund noch deutlich mehr Berechnungen stattfinden, als bei normalen Rechenoperationen (wie z.B. Addition), gehe ich von einer größeren Ungenauigkeit beim Endergebnis aus. Und weil es mir beim Zeichnen im Autocad schon öfters passiert, dass bei Objektkoordinaten z.B. ein X-Wert von 0.00000005 steht, möchte ich solchen Ungenauigkeiten lieber vorbeugen. Zitat: Und Vorsicht: mit If D < 0.0000001 And D > -0.0000001 hast Du auch schon Deine Rundungsfehler eingebaut.
Bei diesem Vergleich geht es ja nur darum, herauszufinden, ob die Linien parallel sind (D=0). Bei einem Wert von D=0.00000001 (eine Nachkommastelle mehr) macht eine Berechnung des Schnittpunktes eh nicht mehr viel Sinn, weil der Schnittpunkt dann meilenweit von den Linien entfernt wäre. Zitat: Wäre interessant, jetzt mal 100.000 Elemente durchrechnen zu lassen, was schneller ist.
Vielleicht finde ich das ja noch heraus: Ich will die Klasse nämlich in einen Jig einbauen (Bogen aktualisiert sich beim bewegen der Maus ständig). Da bin ich auch mal gespannt, ob sich da Verzögerungen bemerkbar machen. Falls ja, geb ich hier mal ein Feedback dazu. ------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 27. Okt. 2009 09:24 <-- editieren / zitieren -->
Hi, >> wirst du eigentlich von deinem Computer geweckt, >> wenn wieder neue Forenbeiträge vorhanden sind? Eine ÜberwachungsSW gibt es schon bei mir, aber die weckt mich nicht >> Da Sinus- und Cosinusberechnungen meines Wissens nach Funktionen sind >> und deshalb im Hintergrund noch deutlich mehr Berechnungen stattfinden
OK, da geb ich Dir ganz sicher recht, 'rechten Winkel' kann man auch anders rechnen. >> Ich will die Klasse nämlich in einen Jig einbauen
Uuiii, viel Vergnügen, mit der kämpft man schon mal ein paar Sekunden Hiezu einen Tip (aus leidiger eigener Erfahrung), probier das immer auch aus, wenn Du eine langsame Graphikkarte hast und eher überdurchschnittlich viel Geometrie darunter, da kann das aus der Sicht des Anwenders schon langsam werden/wirken. Viel Erfolg, - alfred -
------------------ www.hollaus.at |
Jonapap Mitglied
Beiträge: 206 Registriert: 18.08.2006
|
erstellt am: 29. Okt. 2009 20:21 <-- editieren / zitieren --> Unities abgeben:
Hallo Alfred, danke für die Tipps. Der Befehl zur Erzeugung eines tangentialen Bogens und die Punktauswahl inkl. der Anzeige des Jiggs funktionieren jetzt. Der Aufruf einer Prozedur oder einer Funktion aus der WorldDraw-Funktion des Jiggs ist aber nicht möglich (wohl wegen der Absturzgefahr), deshalb musste ich die Berechnung der Bogenkoordinaten direkt in diese Funktion einbauen. Seit meinem Umstieg von VBA auf VB.NET bin ich ja immer wieder von dem Geschwindigkeitszuwachs begeistert: Mein Laptop schafft in 1 Sekunde 900.000!!! komplette Durchläufe zur Berechnung aller Bogenkoordinaten wie in der obigen Klasse. Und mein 3Jahre alterBüro-PC schafft immerhin noch 500.000 Durchgänge. Damit dürften die Berechnungen wohl nicht zur Bremse bei der Jig-Darstellung werden. ------------------ Gruß Markus Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 29. Okt. 2009 20:57 <-- editieren / zitieren -->
Hi Markus, >> Der Aufruf einer Prozedur oder einer Funktion aus der WorldDraw-Funktion des Jiggs Mit 2010 kannst Du sogar das .Draw überschreiben, also wüsste ich mal nicht, wieso 'eine Prozedur' nicht aufrufbar wäre. Vielleicht hängt es von Parametertypen oder anderem ab, aber ich hätte das mal nicht als 'geht grundsätzlich nicht' gesehen. >> Damit dürften die Berechnungen wohl nicht zur Bremse bei der Jig-Darstellung werden
Nee, die Berechnungen, sprich die reine Mathematik ist es nicht, es ist das Dragging am Monitor, wirklich der Pixelaufbau. Lass Dich aber nicht abschrecken durch meine zuer Vorsicht mahnenden Tips, ich gehe da wohl oft von zu kritischen Situtionen aus, wo ich dieses hatte. - alfred - ------------------ www.hollaus.at |
| Anzeige.:
Anzeige: (Infos zum Werbeplatz >>)
|