Author Topic: equivelent of lisp Osnap function in .net?  (Read 8922 times)

0 Members and 1 Guest are viewing this topic.

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
equivelent of lisp Osnap function in .net?
« on: April 11, 2006, 05:52:44 PM »
I use the osnap function a lot in lisp.  It fills a critical need for picking nested entities.
If I want to get the ends of, say, a nested line, I would do this:
(SETQ PT (CADR (ENTSEL "Pick the Line")))
(SETQ SP (OSNAP PT "qui,end")
          MP (OSNAP PT "qui,mid")
          EP (POLAR MP (ANGLE SP MP) (DISTANCE SP MP))
)

Now, this might seem junky, but its actually super efficient and dependable, rather than deal with getting actual data, then translating by xref rotation, scale, mirror and so on.
Is there a function on .net to do this?
I looked in the object browser but did not see anything for it.  It may be right in front of me though...
thanks
James Maeding

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: equivelent of lisp Osnap function in .net?
« Reply #1 on: April 11, 2006, 06:11:46 PM »
Have a look at GetObjectSnapPoints() in the managed arx reference help, all drawn autocad entities have this property and using this api you have direct access to them.
hth.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: equivelent of lisp Osnap function in .net?
« Reply #2 on: April 11, 2006, 07:01:56 PM »
ah, exactly the info I wanted - the answer and how to research it next time, thanks a bunch
James Maeding

Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #3 on: November 14, 2007, 03:28:31 PM »
Have a look at GetObjectSnapPoints() in the managed arx reference help, all drawn autocad entities have this property and using this api you have direct access to them.
hth.

Mick,

Would you happen to have an example for GetObjectSnapPoints(). I'm having a little trouble understanding how to implement this API.

Thanks
Jeff

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: equivelent of lisp Osnap function in .net?
« Reply #4 on: November 14, 2007, 08:24:53 PM »
Sorry Jeff, I don't but James may have coded something up he can share.

In the mean time I would suggest looking into the ARX ref.-> AcDb -> AcDbEntity-> getOsnapPoints() method which explains how and what the parameters are used for (the managed method simply wraps this so it should be very similar).
While the managed help does list all/most methods available they have little help in the way of using them and I guess they expect you to be able to understand the C/C++ help already available.

cheers.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #5 on: November 14, 2007, 10:04:52 PM »
Sorry Jeff, I don't but James may have coded something up he can share.

In the mean time I would suggest looking into the ARX ref.-> AcDb -> AcDbEntity-> getOsnapPoints() method which explains how and what the parameters are used for (the managed method simply wraps this so it should be very similar).
While the managed help does list all/most methods available they have little help in the way of using them and I guess they expect you to be able to understand the C/C++ help already available.

cheers.

Thanks Mick,

I did find an example from someone in the .net discussion group in which the person was having a problem. When I tried the example I keep getting an error.
the example:  ent.GetObjectSnapPoints(ObjectSnapModes.ModeMid, 0, pickPt, pickPt, Matrix3d.Identity, snapPts, geomIds);
I believe my problem was with the Matrix3d.Identy part. But I'm not sure.

Thanks for you help though, I did look into the c++ code and found it a little more helpful, but I'm not quite there yet.
Jeff



Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #6 on: November 14, 2007, 10:07:47 PM »
Sorry Jeff, I don't but James may have coded something up he can share.

cheers.

James,

If your there! I would like to know if you had any luck!

Thanks
Jeff

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: equivelent of lisp Osnap function in .net?
« Reply #7 on: November 14, 2007, 10:18:07 PM »
it looks like you are passing in the matrix identity 'property', you need to pass it a matrix set to the current view matrix but if you are not in a custom view (ie. you're working in 2d in wcs plan view), setting your matrix to identity should be fine.

Matrix3d mat = new Matrix3d();
mat = Matrix3d.Identity();
ent.GetObjectSnapPoints(ObjectSnapModes.ModeMid, 0, pickPt, pickPt, mat, snapPts, geomIds);

or something like that, it's been a while :)
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #8 on: November 14, 2007, 10:52:47 PM »
Matrix3d mat = new Matrix3d();
mat = Matrix3d.Identity();
ent.GetObjectSnapPoints(ObjectSnapModes.ModeMid, 0, pickPt, pickPt, mat, snapPts, geomIds);

I gave it a try, and I'm still getting an error. It says "eInvalidInput", but it doesn't tell me what input is Invalid!


Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #9 on: November 14, 2007, 11:01:03 PM »
I figured it out!
I used a 1 instead of a 0
ent.GetObjectSnapPoints(ObjectSnapModes.ModeMid, 0, pickPt, pickPt, mat, snapPts, geomIds);
changed to
ent.GetObjectSnapPoints(ObjectSnapModes.ModeMid, 1, pickPt, pickPt, mat, snapPts, geomIds);

MickD

  • King Gator
  • Posts: 3637
  • (x-in)->[process]->(y-out) ... simples!
Re: equivelent of lisp Osnap function in .net?
« Reply #10 on: November 14, 2007, 11:03:15 PM »
could you post the section of code (ie the whole method) to have a look at, someone will be able to spot something a bit quicker that way, thanks.

good news!
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: equivelent of lisp Osnap function in .net?
« Reply #11 on: November 14, 2007, 11:59:20 PM »
James, Jeff.

Any code and explanation notes you are able post will be a great help for anyone following this thread (now and in the future)


ps:
Welcome to theSwamp Jeff !
Great to see another adventurer posting here.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #12 on: November 15, 2007, 08:17:12 AM »
ps:
Welcome to theSwamp Jeff !
Great to see another adventurer posting here.

Thanks for the nice welcome Kerry,

I'm a independent consultant for Architects and Structural Engineers. I've written many lisp programs over the years and wanted to expand my level of experience to learning .net using C#. I thought the best way I could get a good start would be to convert my lisp programs to C#.

The lisp to .net program I'm working on is one for Structural where you add text(beam size) to a line (beam). The line can be just about anything that can accept a mid point snap and an end  point snap. ie: polyline, block, xref, arc, etc.

Here are both my lisp and my C# in progress:

Lisp Code:
Code: [Select]
(defun Initialize ()
(setq NewLayer "ANNO-NOTE")
(if (null (tblsearch "LAYER" NewLayer))
    (command "._layer" "new" NewLayer "s" NewLayer "C" "2" NewLayer "")
);End if

(command "._layer" "s" "ANNO-NOTE" "")
(command "COLOR" "BYLAYER")
 
(setq OldSnapMode (getvar "OSMODE"))
(SETVAR "OSMODE" 0)
 
(setq DwgScale (/ 1.0 (getvar "CANNOSCALEVALUE")))
 
(setq Entity (nentsel))
(setq EndPoint (osnap (cadr Entity) "End"))
(setq MidPoint (osnap (cadr Entity) "mid"))
 
(setq LineAngle (rtd (angle EndPoint MidPoint)))

;Adjust Angle for proper text orientation
(if
  (and
  (> LineAngle 90.1)
  (< LineAngle 270.1)
  )
  (setq LineAngle (- LineAngle 180))
 );end if
 
);END DEFUN
 

(defun c:BMX (/ NewLayer OldSnapMode Entity EndPoint MidPoint LineAngle DwgScale TextPoint)
(Initialize)
(setq TextPoint (Polar MidPoint (dtr (+ LineAngle 90)) (* 0.03125 DwgScale)))
(initdia)
(command "._MText" TextPoint "J" "BC" "R" LineAngle "W" "0")
(SETVAR "OSMODE" OldSnapMode)
);End defun

(defun c:UBMX (/ NewLayer OldSnapMode Entity EndPoint MidPoint LineAngle DwgScale TextPoint)
(Initialize)
(setq TextPoint (Polar MidPoint (dtr (+ LineAngle 270)) (* 0.03125 DwgScale)))
(initdia)
(command "._MText" TextPoint "J" "TC" "R" LineAngle "W" "0")
(SETVAR "OSMODE" OldSnapMode)
);End defun

C# code:
Code: [Select]
        [CommandMethod("BeaMtext")]
        public void AddBeamText()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Database db = HostApplicationServices.WorkingDatabase;
            Transaction tr = db.TransactionManager.StartTransaction();

            PromptEntityResult selectionRes = ed.GetEntity("Select Entity ");

            if (selectionRes.Status == PromptStatus.OK)   
            {
                try
                {
                    ObjectId objId = selectionRes.ObjectId;
                    Entity ent = (Entity)tr.GetObject(objId, OpenMode.ForRead);

                    Point3d pickPt = selectionRes.PickedPoint;
                    Matrix3d mat = new Matrix3d();
                    mat = Matrix3d.Identity;
                    Point3dCollection snapPts = new Point3dCollection();
                    IntegerCollection geomIds = new IntegerCollection();
                    geomIds.Add(0);

                    ent.GetObjectSnapPoints(ObjectSnapModes.ModeMid, 1, pickPt, pickPt, mat, snapPts, geomIds);
                    ed.WriteMessage("\nYour selected point is:" + pickPt.ToString());
                    ent.Dispose();
                }
                catch (Autodesk.AutoCAD.Runtime.Exception ex)
                {
                    ed.WriteMessage(ex.Message);
                    tr.Abort();
                }
               
            }//end if
        }//end function

Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #13 on: November 17, 2007, 05:40:49 AM »
I finally stumbled on what I wanted all along, and it's a lot less complex than I thought.
I believe the equivalent code for this lisp:

(setq Entity (entsel))
(setq MidPoint (osnap (cadr Entity) "mid"))

is

PromptEntityResult selectionRes = ed.GetEntity("Select Entity ");
Point3d pickPt = selectionRes.PickedPoint;
Point3d snapPt = ed.Snap("midpoint", pickPt);


sinc

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #14 on: November 17, 2007, 10:40:06 AM »
Just be aware that is really risky code.

All you are doing is mimicking what happens when the user clicks on that point, and has the MID osnap turned on.

If entities overlap at that point, you may not get the midpoint of the previously-selected entity.  You may get the midpoint of a different entity.

LE

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #15 on: November 17, 2007, 01:59:30 PM »
I finally stumbled on what I wanted all along, and it's a lot less complex than I thought.
I believe the equivalent code for this lisp:

(setq Entity (entsel))
(setq MidPoint (osnap (cadr Entity) "mid"))

is

PromptEntityResult selectionRes = ed.GetEntity("Select Entity ");
Point3d pickPt = selectionRes.PickedPoint;
Point3d snapPt = ed.Snap("midpoint", pickPt);



If is not there and cannot be P/Invoke - you can make your own, here is a start, that might help [includes the midpoint and endpoint only]:

Code: [Select]
static public void getosnap(string mode)
{
    Database db = HostApplicationServices.WorkingDatabase;
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;

    PromptEntityResult res = ed.GetEntity("\nSelect entity: ");
    if (res.Status != PromptStatus.OK)
        return;
   
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Curve obj = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
        if (obj is Curve)
        {
            Point3d pickPoint = res.PickedPoint;
            Point3d oPoint = obj.GetClosestPointTo(pickPoint, ed.GetCurrentView().ViewDirection, false);

            Point3d sp = obj.StartPoint;
            Point3d ep = obj.EndPoint;
            Point3d pt = new Point3d(); // point to return

            double dx = obj.GetDistAtPoint(oPoint);
            double param = obj.GetParameterAtPoint(oPoint); //where is that point selected?
           
            double sparam = obj.GetParameterAtPoint(sp);
            double eparam = obj.GetParameterAtPoint(ep);

            double xparam = param - sparam;
            double yparam = param - eparam;

            double ds = obj.GetDistanceAtParameter(Math.Abs(xparam));
            double de = obj.GetDistanceAtParameter(Math.Abs(yparam));

            switch (mode.ToUpper())
            {
                case "MIDP":
                    double totlen = obj.GetDistanceAtParameter(obj.EndParam);
                    pt = obj.GetPointAtDist(totlen / 2.0);
                    break;
                case "ENDP":
                    if (ds > de)
                        pt = ep;
                    else
                        pt = sp;
                    break;
            }

            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            DBPoint point = new DBPoint(pt);
            point.ColorIndex = 1;
            btr.AppendEntity(point);
            tr.AddNewlyCreatedDBObject(point, true);

        }

        tr.Commit();
    }
}

[CommandMethod("GETOSNAP")]
static public void testosnap()
{
    getosnap("MIDP"); // test
    getosnap("ENDP"); // test
}

Then, you can use the above code to have a function to return the osnap point

Code: [Select]
static public Point3d getosnap(Curve obj, string mode)
{

return pt;
}

Jeff Moran

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #16 on: November 17, 2007, 05:46:09 PM »
Just be aware that is really risky code.

All you are doing is mimicking what happens when the user clicks on that point, and has the MID osnap turned on.

If entities overlap at that point, you may not get the midpoint of the previously-selected entity.  You may get the midpoint of a different entity.

Thanks for your advice!

Being new to C#, I thought it would be a good idea to try to writing code in which I am familiar with, as in something I've done in Lisp. Does that make sense? In a previous post I've included both the finished lisp code and the beginning of C# code for this particular program. I would appreciate any suggestion on how I may improve on that particular code as try writing a version in C#.

Thanks again!
Jeff




sinc

  • Guest
Re: equivelent of lisp Osnap function in .net?
« Reply #17 on: November 18, 2007, 07:58:48 PM »
Here's something that may prove useful.

This is a command in the soon-to-be-released SincpacC3D v1.0.  It lets you select a bunch of objects, and then change them to match the rotation of another selected object.  If the object to match is a linear object such as a polyline or an arc (or Civil-3D Feature Line or Parcel Line), then the routine uses the direction of the linear object at the point that is closest to the user's pick point.

This code uses other code that already exists in the SincpacC3D, so if you want to actually run it, you will need to add this code to the SincpacC3D source code, which can be downloaded from here.

In the very near future, I plan to release a super-improved version of the SincpacC3D, with more than twice as many useful commands as the current version, as well as new-and-improved versions of existing routines, and also integrated Help for all functions.  It provides quick'n'easy solutions to many of the problems people have been complaining about on Autodesk's discussion groups, so I've been trying to get it ready for release as quickly as possible.  It's getting close to being ready, and I hope to have it available within the next few weeks.  But here's a sneak-peak of one of the simpler (but still very useful) routines:

Code: [Select]
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AECC.Interop.Land;
using AutocadUtilities;
using Civil3DUtilities;

namespace SincpacC3D.RotateObjects
{
    public class RotationMatch
    {
        [CommandMethod("ROTATIONMATCH", CommandFlags.UsePickSet)]
        public void RotationMatchCommand()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            C3DUtil c3dUtil = new C3DUtil();
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            PromptSelectionOptions sPrmpt = new PromptSelectionOptions();
            sPrmpt.MessageForAdding = "\nSelect objects to rotate: ";
            sPrmpt.MessageForRemoval = "\nSelect objects to remove: ";
            PromptSelectionResult ssResult;
            ssResult = ed.GetSelection(sPrmpt);
            if (ssResult.Status == PromptStatus.OK)
            {
                PromptEntityOptions entityOps = new PromptEntityOptions("\nSelect object to match: ");
                PromptEntityResult entityRes = ed.GetEntity(entityOps);
                if (entityRes.Status == PromptStatus.OK)
                {
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        ObjectId[] objIds = ssResult.Value.GetObjectIds();
                        Entity matchEntity = tr.GetObject(entityRes.ObjectId, OpenMode.ForRead, false) as Entity;
                        double rot = 0;
                        int errorCount = 0;
                        Curve crv = matchEntity as Curve;
                        if (crv != null)
                        {
                            Point3d pickPt = entityRes.PickedPoint;
                            Point3d pointOnCurve = crv.GetClosestPointTo(pickPt, false);
                            rot = CurveUtil.AzimuthAtParam(crv, crv.GetParameterAtPoint(pointOnCurve));
                        }
                        else
                        {
                            try
                            {
                                rot = (double)matchEntity.GetType().GetProperty("Rotation").GetValue(matchEntity, null);
                            }
                            catch
                            {
                                AeccPoint p = matchEntity.AcadObject as AeccPoint;
                                if (p != null)
                                {
                                    rot = p.Rotation;
                                }
                                else
                                {
                                    ed.WriteMessage("\nCould not get rotation for selected object...");
                                }
                            }
                        }

                        foreach (ObjectId oId in objIds)
                        {
                            Entity ent = tr.GetObject(oId, OpenMode.ForWrite, false) as Entity;
                            try
                            {
                                ent.GetType().GetProperty("Rotation").SetValue(ent, rot, null);
                            }
                            catch
                            {
                                Line line = ent as Line;
                                if (line != null)
                                {
                                    LineSegment2d calcLine = new LineSegment2d(line.StartPoint.Convert2d(CurveUtil.PlaneXY), line.EndPoint.Convert2d(CurveUtil.PlaneXY));
                                    double dist = line.Length / 2;
                                    double dX = Math.Cos(rot) * dist;
                                    double dY = Math.Sin(rot) * dist;
                                    Point2d midpoint = calcLine.MidPoint;
                                    Point3d newStart = new Point3d(midpoint.X - dX, midpoint.Y - dY, line.StartPoint.Z);
                                    Point3d newEnd = new Point3d(midpoint.X + dX, midpoint.Y + dY, line.EndPoint.Z);
                                    line.StartPoint = newStart;
                                    line.EndPoint = newEnd;
                                }
                                else
                                {
                                    AeccPoint p = ent.AcadObject as AeccPoint;
                                    if (p != null) p.Rotation = rot;
                                    else ++errorCount;
                                }
                            }
                        }
                        if (errorCount > 0)
                            ed.WriteMessage("\nCould not rotate {0} object(s).", errorCount);
                        tr.Commit();
                    }
                }
            }
        }
    }
}
« Last Edit: November 18, 2007, 08:00:07 PM by sinc »