Hi,
Here is a link that I personally find useful in converting code from C# to VB.Net and vice-versa.
Some basic things will need to be fixed if you get some compile errors.
http://www.developerfusion.com/tools/convert/csharp-to-vb/
<CommandMethod("FilletLines", "FLT", CommandFlags.UsePickSet Or CommandFlags.Redraw)> _ |
Public Shared Sub FilletLines() |
Dim db As Database = HostApplicationServices.WorkingDatabase |
Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument |
Dim ed As Editor = doc.Editor |
Dim tr As Transaction = db.TransactionManager.StartTransaction() |
Using tr |
Try |
' Prompt for the fillet radius |
Dim pdo As New PromptDoubleOptions(vbLf & "Enter the fillet radius: ") |
pdo.AllowZero = False |
pdo.AllowNegative = False |
pdo.AllowNone = False |
Dim pdr As PromptDoubleResult = ed.GetDouble(pdo) |
If pdr.Status <> PromptStatus.OK Then |
Return |
End If |
Dim rad As Double = pdr.Value |
' Prompt for the lines to be filleted |
Dim peo As New PromptEntityOptions(vbLf & "Select first line:") |
Dim per As PromptEntityResult = ed.GetEntity(peo) |
If per.Status <> PromptStatus.OK Then |
Return |
End If |
Dim fid As ObjectId = per.ObjectId |
peo.Message = vbLf & "Select second line:" |
per = ed.GetEntity(peo) |
If per.Status <> PromptStatus.OK Then |
Return |
End If |
Dim sid As ObjectId = per.ObjectId |
' get entities |
Dim ent1 As Entity = TryCast(tr.GetObject(fid, OpenMode.ForRead), Entity) |
Dim ent2 As Entity = TryCast(tr.GetObject(sid, OpenMode.ForRead), Entity) |
' cast entites as lines |
Dim line1 As Line = TryCast(ent1, Line) |
Dim line2 As Line = TryCast(ent2, Line) |
Dim intpts As New Point3dCollection() |
' get intersection between lines |
line1.IntersectWith(line2, Intersect.OnBothOperands, intpts, 0, 0) |
If intpts.Count <> 1 Then |
Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("Lines are colinear or does not intersects") |
Return |
End If |
Dim ip As Point3d = intpts(0) |
Dim midp1 As Point3d |
Dim midp2 As Point3d |
' compare points |
If Not (line1.StartPoint.Equals(ip)) Then |
line1.UpgradeOpen() |
line1.EndPoint = line1.StartPoint |
line1.StartPoint = ip |
End If |
midp1 = line1.GetPointAtDist(rad) |
If Not (line2.StartPoint.Equals(ip)) Then |
line2.UpgradeOpen() |
line2.EndPoint = line2.StartPoint |
line2.StartPoint = ip |
End If |
midp2 = line2.GetPointAtDist(rad) |
' get point on bisector |
Dim midp As New Point3d((midp1.X + midp2.X) / 2.0, (midp1.Y + midp2.Y) / 2.0, (midp1.Z + midp2.Z) / 2.0) |
' get angles along lines from intersection |
Dim ang1 As Double = AngleFromX(ip, midp1) |
Dim ang2 As Double = AngleFromX(ip, midp2) |
' get bisector angle |
Dim ang As Double = AngleFromX(ip, midp) |
' calculate angle between lines |
Dim angc As Double = Math.Abs(ang2 - ang1) |
' get a half of them |
Dim bis As Double = angc / 2.0 |
' calculate hypotenuse |
Dim hyp As Double = rad / Math.Sin(bis) |
' calculate center point of filleting arc |
Dim cp As Point3d = PolarPoint(ip, ang, hyp) |
' calculate another leg of a triangle |
Dim cat As Double = Math.Sqrt((Math.Pow(hyp, 2)) - (Math.Pow(rad, 2))) |
' calculate center point on arc |
Dim pa As Point3d = PolarPoint(ip, ang, hyp - rad) |
' calculate start point of arc |
Dim ps As Point3d = PolarPoint(ip, ang1, cat) |
' calculate end point of arc |
Dim pe As Point3d = PolarPoint(ip, ang2, cat) |
' define arc |
Dim arc As New Arc() |
' check on direction of points |
If isLeft(midp2, ip, midp1) Then |
arc = New Arc(cp, rad, AngleFromX(cp, pe), AngleFromX(cp, ps)) |
Else |
arc = New Arc(cp, rad, AngleFromX(cp, ps), AngleFromX(cp, pe)) |
End If |
' trim lines by arc |
line1.UpgradeOpen() |
line1.StartPoint = ps |
line2.UpgradeOpen() |
line2.StartPoint = pe |
Dim btr As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord) |
' add arc to space |
btr.AppendEntity(arc) |
tr.AddNewlyCreatedDBObject(arc, True) |
tr.Commit() |
Catch ex As Autodesk.AutoCAD.Runtime.Exception |
Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(ex.Message) |
End Try |
End Using 'dispose transaction |
End Sub |
thx Hallex.
'///
'/// Polar point // credit to Tony Tanzillo
'///
Public Shared Function PolarPoint(ByVal basepoint As Point3d, ByVal angle As Double, ByVal distance As Double) As Point3d
Return New Point3d(basepoint.X + (distance * Math.Cos(angle)), basepoint.Y + (distance * Math.Sin(angle)), basepoint.Z)
End Function
'///
'///
Public Shared Function AngleFromX(ByVal pt1 As Point3d, ByVal pt2 As Point3d) As Double
Dim ang As Double
Dim vec As Vector3d
Dim ucsplane As Plane
ucsplane = New Plane(New Point3d(0, 0, 0), New Vector3d(0, 0, 1))
vec = pt2 - pt1
ang = vec.AngleOnPlane(ucsplane)
Return ang
End Function
'///
'/// isleft function (edited) // credit to Bryco
'///
Public Shared Function isLeft(ByVal spt As Point3d, ByVal ept As Point3d, ByVal apt As Point3d) As Boolean
Dim Ans As Double
Dim result As Boolean
result = False
Ans = ((ept.X - spt.X) * (apt.Y - spt.Y) - (apt.X - spt.X) * (ept.Y - spt.Y))
If (Ans > 0) Then
result = True
Else
result = False
End If
Return result
End Function
Hi,
What about when we have line in 3D? Have you any idea? above code not work when one of the line is vertical.
Hi,
Here's a 3d working example.
using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using static System.Math; using AcAp = Autodesk.AutoCAD.ApplicationServices.Application; [assembly: CommandClass(typeof(Fillet3D.Commands))] namespace Fillet3D { public class Commands { double radius = 0.0; [CommandMethod("TEST")] public void Test() { var doc = AcAp.DocumentManager.MdiActiveDocument; var db = doc.Database; var ed = doc.Editor; var pdo = new PromptDistanceOptions("\nEnter the fillet radius: "); pdo.DefaultValue = radius; pdo.AllowNegative = false; pdo.AllowNone = true; pdo.UseDefaultValue = true; var pdr = ed.GetDistance(pdo); if (pdr.Status != PromptStatus.OK) return; radius = pdr.Value; var peo = new PromptEntityOptions("\nSelect the first line: "); peo.SetRejectMessage("\nSelected object is not a line."); peo.AddAllowedClass(typeof(Line), true); var per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; var id1 = per.ObjectId; var pp1 = ed.Snap("_near", per.PickedPoint).TransformBy(ed.CurrentUserCoordinateSystem); peo.Message = "\nSelect the second line: "; per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; var id2 = per.ObjectId; var pp2 = ed.Snap("_near", per.PickedPoint).TransformBy(ed.CurrentUserCoordinateSystem); using (var tr = db.TransactionManager.StartTransaction()) { // open the lines var line1 = (Line)tr.GetObject(id1, OpenMode.ForRead); var line2 = (Line)tr.GetObject(id2, OpenMode.ForRead); // get the intersection var pts = new Point3dCollection(); line1.IntersectWith(line2, Intersect.ExtendBoth, pts, IntPtr.Zero, IntPtr.Zero); if (pts.Count != 1) { ed.WriteMessage("\nSelected lines do not intersect."); return; } var inters = pts[0]; var sp1 = line1.StartPoint; var ep1 = line1.EndPoint; var sp2 = line2.StartPoint; var ep2 = line2.EndPoint; // get the farest points from intersection on the picked side of both lines Func<Point3d, Point3d, Point3d, Point3d> getFarest = (sp, ep, pp) => { var dir = inters.GetVectorTo(pp); if (!inters.GetVectorTo(sp).IsCodirectionalTo(dir)) return ep; if (!inters.GetVectorTo(ep).IsCodirectionalTo(dir)) return sp; if (inters.DistanceTo(sp) < inters.DistanceTo(ep)) return ep; return sp; }; var fp1 = getFarest(sp1, ep1, pp1); var fp2 = getFarest(sp2, ep2, pp2); // if radius == 0, just trim/extend the lines if (radius == 0.0) { line1.UpgradeOpen(); if (sp1.IsEqualTo(line1.StartPoint)) line1.EndPoint = inters; else line1.StartPoint = inters; line2.UpgradeOpen(); if (sp2.IsEqualTo(line2.StartPoint)) line2.EndPoint = inters; else line2.StartPoint = inters; } // compute the fillet else { // 2D work in the plane defined by the two lines var normal = (fp1 - inters).CrossProduct(fp2 - inters); var plane = new Plane(inters, normal); var v1 = fp1.Convert2d(plane).GetAsVector(); var v2 = fp2.Convert2d(plane).GetAsVector(); double angle = v1.GetAngleTo(v2) / 2.0; var dist = radius / Tan(angle); if (v1.Length <= dist || v2.Length <= dist) { ed.WriteMessage("\nRadius too large to fillet the selected lines."); return; } double hyp = radius / Sin(angle); var center = new Point2d(hyp * Cos(angle + v1.Angle), hyp * Sin(angle + v1.Angle)); var p1 = Point2d.Origin + v1.GetNormal() * dist; var p2 = Point2d.Origin + v2.GetNormal() * dist; var a1 = center.GetVectorTo(p1).Angle; var a2 = center.GetVectorTo(p2).Angle; // back to 3D Func<Point2d, Point3d> convert3d = (pt) => new Point3d(pt.X, pt.Y, 0.0).TransformBy(Matrix3d.PlaneToWorld(plane)); var arc = new Arc(new Point3d(center.X, center.Y, 0.0), radius, a2, a1); arc.TransformBy(Matrix3d.PlaneToWorld(plane)); var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); curSpace.AppendEntity(arc); tr.AddNewlyCreatedDBObject(arc, true); line1.UpgradeOpen(); line1.StartPoint = convert3d(p1); line1.EndPoint = fp1; line2.UpgradeOpen(); line2.StartPoint = fp2; line2.EndPoint = convert3d(p2); } tr.Commit(); } } } }
_gile wrote:
Hi,
Here's a 3d working example.
Hi Gilles, @_gile
Nice example of using Delegates !
Regards and thanks for all your hard work.
Kerry
// Called Kerry in my other life.
Everything will work just as you expect it to, unless your expectations are incorrect.
class keyThumper<T> : Lazy<T>; another Swamper
KerryBrown a écrit :
Hi Gilles, @_gile
Nice example of using Delegates !
Regards and thanks for all your hard work.
Kerry
Thanks Kerry, @kdub_nz
Delegates are an alternative to local functions which are coming with the C# 7 as tuples and pattern matching.
C# get closer to F# at each new version...
F# code
namespace Fillet3d open System open Autodesk.AutoCAD.DatabaseServices open Autodesk.AutoCAD.EditorInput open Autodesk.AutoCAD.Geometry open Autodesk.AutoCAD.Runtime type AcAp = Autodesk.AutoCAD.ApplicationServices.Application type Command () = let mutable radius = 0.0 [<CommandMethod("Test")>] member x.test () = let doc = AcAp.DocumentManager.MdiActiveDocument let db = doc.Database let ed = doc.Editor let pdo = PromptDistanceOptions("\nSpecify the radius: ") pdo.DefaultValue <- radius pdo.UseDefaultValue <- true pdo.AllowNegative <- false let pdr = ed.GetDistance(pdo) if (pdr.Status = PromptStatus.OK) then radius <- pdr.Value ed.WriteMessage("\nRadius = {0}", radius) let peo = PromptEntityOptions("\nSelect the first line: ") peo.SetRejectMessage("\nSelected object is not a line.") peo.AddAllowedClass(typeof<Line>, true) let per = ed.GetEntity(peo) if (per.Status = PromptStatus.OK) then let id1 = per.ObjectId let pp1 = ed.Snap("_near", per.PickedPoint).TransformBy(ed.CurrentUserCoordinateSystem) peo.Message <- "\nSelect the second line: " let per = ed.GetEntity(peo) if (per.Status = PromptStatus.OK) then let id2 = per.ObjectId let pp2 = ed.Snap("_near", per.PickedPoint).TransformBy(ed.CurrentUserCoordinateSystem) use tr = db.TransactionManager.StartTransaction() // open the lines let line1 = tr.GetObject(id1, OpenMode.ForRead) :?> Line let line2 = tr.GetObject(id2, OpenMode.ForRead) :?> Line // get the intersection let pts = new Point3dCollection() line1.IntersectWith(line2, Intersect.ExtendBoth, pts, IntPtr.Zero, IntPtr.Zero) if (pts.Count = 0) then ed.WriteMessage("\nSelected lines do not intersect.") else let inters = pts.[0] // get the farest points from intersection on the picked side of both lines let getFarest sp ep pp = let dir = pp - inters if not ((sp - inters).IsCodirectionalTo(dir)) then ep elif not ((ep - inters).IsCodirectionalTo(dir)) then sp elif inters.DistanceTo(sp) < inters.DistanceTo(ep) then ep else sp let fp1 = getFarest line1.StartPoint line1.EndPoint pp1 let fp2 = getFarest line2.StartPoint line2.EndPoint pp2 // if radius equals 0.0, just trim or extend the lines if radius = 0.0 then let trimExtend (line: Line) fp = line.UpgradeOpen() if line.StartPoint.IsEqualTo(fp) then line.EndPoint <- inters else line.StartPoint <- inters trimExtend line1 fp1 trimExtend line2 fp2 else // compute the fillet // 2D work in the plane defined by the 2 lines let norm = (fp1 - inters).CrossProduct(fp2 - inters) let plane = new Plane(inters, norm) let v1 = fp1.Convert2d(plane).GetAsVector() let v2 = fp2.Convert2d(plane).GetAsVector() let ang = v1.GetAngleTo(v2) / 2. let dist = radius / tan ang if (v1.Length <= radius || v2.Length <= radius) then ed.WriteMessage("\nRadius too large too fillet the lines.") else let hyp = radius / sin ang let cen = Point2d(hyp * cos (ang + v1.Angle), hyp * sin (ang + v1.Angle)) let pointAngle (v : Vector2d) = let p = Point2d.Origin + v.GetNormal() * dist (p, (p - cen).Angle) let (p1, a1) = pointAngle v1 let (p2, a2) = pointAngle v2 // back to 3D let arc = new Arc(Point3d(cen.X, cen.Y, 0.0), radius, a2, a1) arc.TransformBy(Matrix3d.PlaneToWorld(plane)) let space = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord space.AppendEntity(arc) |> ignore tr.AddNewlyCreatedDBObject(arc, true) let convert3d (pt : Point2d) = Point3d(pt.X, pt.Y, 0.0).TransformBy(Matrix3d.PlaneToWorld(plane)) let trimExtend (line : Line) fp p = line.UpgradeOpen() if line.StartPoint.IsEqualTo(fp) then line.EndPoint <- convert3d p else line.StartPoint <- convert3d p trimExtend line1 fp1 p1 trimExtend line2 fp2 p2 tr.Commit()