Author Topic: RevCloud AutoLisp routine ported to C#  (Read 4277 times)

0 Members and 1 Guest are viewing this topic.

LE3

  • Guest
RevCloud AutoLisp routine ported to C#
« on: October 25, 2010, 08:52:19 PM »
In case anyone might found this class useful, here it is (I did it as an example for a friend):

RevCloud - Based on the original Code, idea and concept by David Harrington (from one of the earlier autolisp versions).

Note: it does not save the arc length value for next use.

Code: [Select]
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

//
// Based on the original Code, idea and concept by David Harrington
//
// Code ported to C# by LE OCT.24.2010.
//

namespace RevCloudNET
{
    public class RevCloudCommand
    {
        // ARX: int acedGrRead(int track, int * type, struct resbuf * result);
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int acedGrRead(int track, out int display, IntPtr result);
       
        // ARX: int acedCmd(const struct resbuf * rbp);
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)]
        extern static int acedCmd(IntPtr rbp);

        const int RTNORM = 5100;
        const int RTCAN = -5002;
        const short RTSTR = 5005;
        const int RT3DPOINT = 5009;
        const int RTREAL = 5001;

        public static void drawCloud()
        {
            if (AcadApp.DocumentManager.IsApplicationContext) return;

            Database db = HostApplicationServices.WorkingDatabase;
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            int status = 0;
            double incAngle = 110.0;
            double arcDist = 0.0;

            if (Convert.ToInt32(AcadApp.GetSystemVariable("DIMSCALE")) == 0)
                arcDist = 0.375;
            else
                arcDist = 0.375 * Convert.ToInt32(AcadApp.GetSystemVariable("DIMSCALE"));

            PromptPointResult res = ed.GetPoint("\nPick cloud start point: ");
            if (res.Status != PromptStatus.OK) return; ...
Below it is the full source code attached, hope that helps - provided as-is

kaefer

  • Guest
Re: RevCloud AutoLisp routine ported to C#
« Reply #1 on: November 02, 2010, 01:20:20 PM »
In case anyone might found this class useful, here it is (I did it as an example for a friend):

RevCloud - Based on the original Code, idea and concept by David Harrington (from one of the earlier autolisp versions).

Note: it does not save the arc length value for next use.
Hi Luis,

I couldn't resist doing the whole thing all over again, this time in F# (as usual). Three approaches for pure .NET appeared viable:
1. PointMonitor (Transient graphics, needs a second prompt to run inside)
2. DrawJig (GraphicsInterface.Polyline wouldn't cut it - no bulges, so that means Transients as in 1.)
3. EntityJig (runs into trouble as there's out-of-band messaging involved between sampler and updater,  when the Polyline should be closed. The upside would be ortho mode support)

BTW, what does your code if snap-to-grid is on and you are moving the cursor back to the start point? When the distance between the last two points is greater then the arc length, it doesn't matter any more that the next point is identical to the start point and the polyline would not be closed. That was just another issue I ran into.

Here's the PointMonitor solution:
Code: [Select]
// Based on the original Code, idea and concept by David Harrington
//
// Code ported to C# by LE OCT.24.2010.
//
// Rewritten for PointMonitor in F# by kaefer 2010-11-02

module RevCloudNET

open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime
open Autodesk.AutoCAD.Colors

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

type acGiTm =  Autodesk.AutoCAD.GraphicsInterface.TransientManager
type acGiTdm =  Autodesk.AutoCAD.GraphicsInterface.TransientDrawingMode

[<CommandMethod "REVCLOUDNET">]
let drawCloud() =
    let db = HostApplicationServices.WorkingDatabase
    let doc = acApp.DocumentManager.MdiActiveDocument
    let ed = doc.Editor

    let p2d (p: Point3d) = new Point2d(p.X, p.Y)

    let incBulge = 0.5205670506 // = tan (110° / 4)
    let dimScale = acApp.GetSystemVariable "DIMSCALE" |> unbox<float>
    let arcDist =
        if  dimScale = 0. then 0.375
        else 0.375 * dimScale

    let ppr = ed.GetPoint "\nStart point: "
    if ppr.Status = PromptStatus.OK then
       
        let startp = p2d ppr.Value
        let lastp = ref startp
        let v = ref 0 // Number of segments

        use pl = new Polyline()
        pl.AddVertexAt(0, !lastp, incBulge, 0., 0.)
        pl.Color <- Color.FromColorIndex(ColorMethod.ByAci, 3s)
        acGiTm.CurrentTransientManager.AddTransient(
            pl, acGiTdm.DirectShortTerm, 128, new IntegerCollection() )
        |> ignore

        let pointMonitor =
            ed.PointMonitor
            |> Observable.subscribe
                (fun e ->
                    if not pl.Closed then
                        let nextp = p2d e.Context.ComputedPoint
                        let dist = nextp.GetDistanceTo !lastp
                        if dist > startp.GetDistanceTo nextp then
                            incr v
                            pl.Closed <- true
                         elif dist > arcDist then
                            incr v
                            pl.AddVertexAt(!v, nextp, incBulge, 0., 0.)
                            lastp := nextp
                        acGiTm.CurrentTransientManager.UpdateTransient(
                            pl, new IntegerCollection() ) )

        let ppr1 =
            new PromptPointOptions("\nAccept/End point: ", AllowNone = true)
            |> ed.GetPoint
        pointMonitor.Dispose()
        acGiTm.CurrentTransientManager.EraseTransient(
            pl, new IntegerCollection() ) |> ignore

        if ppr1.Status <> PromptStatus.Cancel then
            if ppr1.Status = PromptStatus.OK && not pl.Closed then
                incr v
                pl.AddVertexAt(!v, p2d ppr1.Value, incBulge, 0., 0.)

            use tr = db.TransactionManager.StartTransaction()
            let btr =
                tr.GetObject(
                    db.CurrentSpaceId, OpenMode.ForWrite ) :?> BlockTableRecord
            pl.Color <- db.Cecolor
            btr.AppendEntity pl |> ignore
            tr.AddNewlyCreatedDBObject(pl, true)
            tr.Commit()

            ed.WriteMessage("\n{0} segments created. ", !v)
Cheers, Thorsten

LE3

  • Guest
Re: RevCloud AutoLisp routine ported to C#
« Reply #2 on: November 02, 2010, 01:48:29 PM »
Hi Thorsten,

I see what you mean, even the built-in (arx) from AutoCAD 2011 - does the closing but shows the below error:

Quote
Revision cloud finished.
Command:
Unknown command "845821027655,-420.9446385533047,0.000000000000000".  Press F1
for help.

Interesting, to bad I do not have an idea about F#....  :-(

What I did was just a mickey mouse porting :)