Author Topic: AU 2005 code - Part 9 "Gettin' Jiggy With It"  (Read 10323 times)

0 Members and 1 Guest are viewing this topic.

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
AU 2005 code - Part 9 "Gettin' Jiggy With It"
« on: December 28, 2005, 03:39:56 PM »
I debated on whether or not to post this one because it's not quite ready for production.  But then I said to myself, "What the heck, you only live once". :)

This example takes the previous Jig example to the next logical level.  It allows you to pass in an array of ObjectId's and allows you to drag them around the screen and reports back the displacement matrix of the drag operation.  The test driver defines a method that drags them around and creates a copy, "DragCopy". 

**WARNING**
Don't use the test driver on block inserts with attributes.  The EntityDragger class works just fine with them.

**WARNING II**
This code requires the 2.0 version of the .NET framework.  Although with a very small change this can be made compatible with the 1.1 version.  Simply change all instances of the generic List<T> to an ArrayList.

EntityDragger class
Code: [Select]
//Code not in the handout!
using System;
using System.Collections;
using System.Collections.Generic;

using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;



namespace AU2005.AcadApi
{
   //TODO: Handle the pointer moving out of the Acad window
//TODO: Determine how/if to handle non database resident entities
//TODO: Add UseBasePoint option
public class EntityDragger : DrawJig
{
#region Private member fields

private Point3d m_basePoint;
private Point3d m_previousCursorPosition;
private Point3d m_currentCursorPosition;
private Matrix3d m_displacementMatrix = Matrix3d.Identity;
private List<Entity> m_entitiesToDrag;

#endregion


#region Public members

/// <summary>
/// Drag entities on screen with cursor.
/// </summary>
/// <param name="basePoint">The base point of the drag</param>
/// <param name="entitiesToDrag">ObjectId's to drag.</param>
/// <returns>The PromptResult of the Drag operation</returns>
public virtual PromptResult StartDrag (Point3d basePoint, params ObjectId[] entitiesToDrag)
{
m_basePoint = TransformPointToCurrentUcs(basePoint);

//Prepare for initial transformation
m_previousCursorPosition = m_basePoint;

m_entitiesToDrag = CloneEntitiesToDrag(entitiesToDrag);

//Start dragging loop
return Application.DocumentManager.MdiActiveDocument.Editor.Drag(this);
}

/// <summary>
/// WCS displacement matrix from the basepoint to the final selected point.
/// </summary>
public virtual Matrix3d DisplacementMatrix
{
get
{
Vector3d displacementVector = m_currentCursorPosition.GetVectorTo(m_basePoint);

return Matrix3d.Displacement(TransformVectorToWcs(displacementVector));
}
}
#endregion


#region protected members

protected override SamplerStatus Sampler(JigPrompts prompts)
{
//Track cursor position
PromptPointResult userFeedback = prompts.AcquirePoint();
m_currentCursorPosition = userFeedback.Value;

if (CursorHasMoved())
{
//Get the vector of the move
Vector3d displacementVector = m_currentCursorPosition.GetVectorTo(m_previousCursorPosition);

//Save a displacement matrix for the move
m_displacementMatrix = Matrix3d.Displacement(displacementVector);

//Save the cursor position
m_previousCursorPosition = m_currentCursorPosition;

return SamplerStatus.OK;
}
else
{
return SamplerStatus.NoChange;
}
}


protected override bool WorldDraw(WorldDraw draw)
{
Matrix3d displacementMatrix = m_displacementMatrix;

foreach (Entity draggingEntity in m_entitiesToDrag)
{
draggingEntity.TransformBy(displacementMatrix);
draw.Geometry.Draw(draggingEntity);
}
return true;
}
#endregion


#region private members

private List<Entity> CloneEntitiesToDrag (IList entities)
{
List<Entity> entitiesToDrag = new List<Entity>(entities.Count);

using (Transaction dragTrans = Application.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction())
{
foreach (ObjectId entityId in entities)
{
Entity drawableEntity = (Entity)dragTrans.GetObject(entityId, OpenMode.ForRead);

entitiesToDrag.Add((Entity)drawableEntity.Clone());
}
}
return entitiesToDrag;
}


private bool CursorHasMoved ()
{
return m_currentCursorPosition != m_previousCursorPosition;
}


private Vector3d TransformVectorToWcs (Vector3d vector)
{
return vector.TransformBy(Matrix3d.Identity);
}


private Point3d TransformPointToCurrentUcs (Point3d basePoint)
{
Matrix3d currentUcs = Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;

return basePoint.TransformBy(currentUcs);
}
#endregion

}
}


TestEntityDragger class
Defines the "DragCopy" command
Code: [Select]
using System;

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

using AU2005.AcadApi;

namespace AU2005.AcadApi
{
public class TestEntityDragger
{
[CommandMethod("DragCopy")]
public void DragAndCopyEntities ()
{
Editor currentEditor = Application.DocumentManager.MdiActiveDocument.Editor;

//Create a new selection set options object
PromptSelectionOptions ssOptions = new PromptSelectionOptions();
ssOptions.AllowDuplicates = true;
ssOptions.MessageForAdding = "Select objects to copy: ";

//Get a selection from the user
PromptSelectionResult ssResult = currentEditor.GetSelection(ssOptions);

//Get a point from the user
PromptPointResult pointResult = currentEditor.GetPoint("\nSelect Base Point: ");

bool userPromptsOk = (ssResult.Status == PromptStatus.OK) && (pointResult.Status == PromptStatus.OK);

if (userPromptsOk)
{
EntityDragger dragger = new EntityDragger();
PromptResult dragResult = dragger.StartDrag(pointResult.Value, ssResult.Value.GetObjectIds());

if (dragResult.Status == PromptStatus.OK)
{
CreateTransformedCopy(dragger.DisplacementMatrix, ssResult.Value.GetObjectIds());
}
}
}


/// <summary>
/// Creates a transformed copy of the provided entities in the current space.
/// </summary>
/// <param name="transformationMatrix">The Matrix3d to apply to the entities.</param>
/// <param name="entitiesToCopy">A list of ObjectId's to copy and transform</param>
private void CreateTransformedCopy(Matrix3d transformationMatrix, params ObjectId[] entitiesToCopy)
//TODO: Handle blocks with attributes
{
Editor currentEditor = Application.DocumentManager.MdiActiveDocument.Editor;

using (Transaction trans = currentEditor.Document.TransactionManager.StartTransaction())
{
ObjectIdCollection entityCollection = new ObjectIdCollection(entitiesToCopy);

Database currentDb = currentEditor.Document.Database;

IdMapping idMap = currentDb.DeepCloneObjects(entityCollection, currentDb.CurrentSpaceId, false);

foreach (IdPair pair in idMap)
{
Entity clonedEntity = (Entity)trans.GetObject(pair.Value, OpenMode.ForWrite);
clonedEntity.TransformBy(transformationMatrix);
}

trans.Commit();
}
}
}
}
« Last Edit: December 28, 2005, 04:19:50 PM by Bobby C. Jones »
Bobby C. Jones

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #1 on: December 28, 2005, 06:08:45 PM »
Thanks immensely for posting these 9 Examples Bobby.


I'm sure that they will become an invaluable resource as more people delve into C# and NET generally.


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.

Draftek

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #2 on: December 29, 2005, 08:04:40 AM »
agreed.

Very nice Bobby..

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #3 on: December 29, 2005, 11:00:21 AM »
Thanks immensely for posting these 9 Examples Bobby.


I'm sure that they will become an invaluable resource as more people delve into C# and NET generally.

Thanks guys, and you're welcome.

I don't know about invaluable, but I hope that they are a resource.  And I sure hope that those out there using VB.NET aren't turned off by the C# code.  These examples should easily translate over to VB.  Of course I say that without trying it first  :-)
Bobby C. Jones

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #4 on: August 18, 2006, 06:49:00 PM »
.......
I don't know about invaluable, but I hope that they are a resource.  .......................

I just found this thread copied to another forum, warts and all, including Bobby'd edit note,
Quote
« Last Edit: 2005-12-29, 06:19:50 by Bobby C. Jones »

... so I'd consider it IS a valid resource  :lol:
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.

DBARANAS

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #5 on: August 18, 2006, 10:07:03 PM »
Another piece of the puzzle!

My thanks too!

Roland Feletic

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #6 on: December 07, 2006, 08:20:49 AM »
Hello,
your code helped me a lot. But now i have the problem that i use AutoCAD 2007 and there the following code does not work.
What do i have to do now?
Code: [Select]
IdMapping idMap = currentDb.DeepCloneObjects(entityCollection, currentDb.CurrentSpaceId, false);I get this error: Error   1   No overload for method 'DeepCloneObjects' takes '3' arguments

I need 4 arguments, but i do not know which IdMapping i have to use.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #7 on: December 07, 2006, 08:49:00 AM »
Roland,
Welcome to the Swamp.
I'm not sure of the requirement for the IdMapping Parameter other than whats in the help file.

You may be able to determine it from the clones.CPP and deepclon.CPP in the SDK

regards
kwb
« Last Edit: December 07, 2006, 09:02:37 AM by Kerry Brown »
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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #8 on: December 07, 2006, 09:03:20 AM »
This may help ..

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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #9 on: December 07, 2006, 09:12:29 AM »
public DeepCloneType DeepCloneContext { get; }

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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #10 on: December 07, 2006, 09:15:32 AM »
public Database DestinationDatabase { get; set; }


///--------------------------------------------------

public DuplicateRecordCloning DuplicateRecordCloning { get; }
« Last Edit: December 07, 2006, 09:19:26 AM by Kerry Brown »
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.

Roland Feletic

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #11 on: December 07, 2006, 11:52:41 AM »
I think that i need more time to look at cloning objects, i've never done it before. Thank you for your help. Will see if i understand all this stuff  :lol:

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #12 on: December 07, 2006, 12:12:56 PM »
Hello,
your code helped me a lot. But now i have the problem that i use AutoCAD 2007 and there the following code does not work.
What do i have to do now?
Code: [Select]
IdMapping idMap = currentDb.DeepCloneObjects(entityCollection, currentDb.CurrentSpaceId, false);I get this error: Error   1   No overload for method 'DeepCloneObjects' takes '3' arguments

I need 4 arguments, but i do not know which IdMapping i have to use.

Hey Roland,
If you're using 2007 and are just trying to mimic the code from that post, have a look here http://www.theswamp.org/index.php?topic=11340.0

The examples shown there are the prefered way to drag a selection set in 2007 and a different approach to cloning entities is shown.
Bobby C. Jones

Roland Feletic

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #13 on: December 07, 2006, 12:54:51 PM »
Sorry, but i do not understand it. I tried it now with following code and it also doesn't work.
Code: [Select]
                IdMapping idMap = new IdMapping();

                currentDb.DeepCloneObjects(entityCollection, currentDb.CurrentSpaceId, idMap, false);
OK, i will leave it now because i will be out of office for a few days, will be back on Tuesday.
Will try a little bit more next week.

Roland

Roland Feletic

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #14 on: December 07, 2006, 12:56:46 PM »
Again sorry, Bobby i've seen your post after writing the last one, will have a look at it next week.
Thanks

Roland

LE

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #15 on: December 07, 2006, 01:28:51 PM »
Hello,
your code helped me a lot. But now i have the problem that i use AutoCAD 2007 and there the following code does not work.
What do i have to do now?
Code: [Select]
IdMapping idMap = currentDb.DeepCloneObjects(entityCollection, currentDb.CurrentSpaceId, false);I get this error: Error   1   No overload for method 'DeepCloneObjects' takes '3' arguments

I need 4 arguments, but i do not know which IdMapping i have to use.

Welcome to TheSwamp Roland;

I think this is a way to do it:

Code: [Select]
        [CommandMethod("DeepClone")]
        public void deepclone()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            IdMapping mapping = new IdMapping();
            ObjectIdCollection identifiers = new ObjectIdCollection();
            db.DeepCloneObjects(identifiers, db.CurrentSpaceId, mapping, true);
            foreach (ObjectId id in identifiers)
            {
                //...
            }
        }

HTH

LE

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #16 on: December 07, 2006, 02:37:24 PM »
Ignore my previous post, it was the first tryout, see if this one helps you, I used a selection set, but it will be easier to adapt it for your needs.

Code: [Select]
        [CommandMethod("DeepClone")]
        public void deepclone()
        {
        Document doc = acadApp.DocumentManager.MdiActiveDocument;
        Editor ed = doc.Editor;
        Database db = doc.Database;
        IdMapping mapping = new IdMapping();
        ObjectIdCollection identifiers = new ObjectIdCollection();

        PromptSelectionOptions prOpts = new PromptSelectionOptions();
        prOpts.MessageForAdding = "\nSelect objects: ";
        PromptSelectionResult res = ed.GetSelection(prOpts);
        if (res.Status != PromptStatus.OK) return;

        ObjectId[] ids = res.Value.GetObjectIds();
        foreach (ObjectId id in ids)
            identifiers.Add(id);

        db.DeepCloneObjects(identifiers, db.CurrentSpaceId, mapping, false);
        using (Transaction tr = db.TransactionManager.StartTransaction())
        {
            foreach (IdPair id in mapping)
            {
                DBObject obj = (DBObject)tr.GetObject(id.Value, OpenMode.ForWrite, false);
                Entity ent = obj as Entity;
            }
            tr.Commit();
        }
        }

HTH

Roland Feletic

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #17 on: February 12, 2007, 11:29:15 AM »
Now i changed the code that it works for my use. The only problem is that it does not work with blocks. Now i changed the TransformSelectionSet to TransformSelectionSet2. There i use DeepCloneObjects and all works good. But if i want to transform blocks i get an error. Every other object works correctly. What do i have to do that i can transform a block?

Code: [Select]
#region Using directives
using System;
using System.Collections;
using System.Collections.Generic;

using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;

using RSNNAcadApp.ExtendedCommands;
#endregion

[assembly: CommandClass(typeof(RSNNAcadApp.ExtendedCommands.Copy))]
namespace RSNNAcadApp.ExtendedCommands
{
    class Copy
    {
        private Matrix3d UcsMatrix;
        private Point3d m_basePoint;
        private Point3d m_destinationPoint;
        private Curve BaseCurve;
        private Matrix3d transMat;

        private Vector3d xAxisFrom, yAxisFrom, zAxisFrom;
        private Vector3d xAxisTo, yAxisTo, zAxisTo;
       
        /// <summary>
        /// Moves blockreferences along a Curve with a given distance
        /// </summary>
        [CommandMethod("KOPIERENENTLANGMITBASIS", CommandFlags.UsePickSet)]
        public void CopyAlongCurve()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            //Transaction myT = db.TransactionManager.StartTransaction();
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            try
            {

                PromptSelectionOptions ssOptions = new PromptSelectionOptions();
                ssOptions.MessageForAdding = "\nObjekte wählen: ";
                ssOptions.MessageForRemoval = "\nObjekte entfernen: ";
                ssOptions.AllowDuplicates = true;


                PromptSelectionResult ssResult = ed.GetSelection(ssOptions);
                if (ssResult.Status != PromptStatus.OK)
                    return;
                if (ssResult.Value.Count == 0)
                    return;

                PromptEntityOptions entOptions = new PromptEntityOptions("\nBezugslinie wählen, entlang der kopiert werden soll");
                entOptions.SetRejectMessage("\nNur Kurven können gewählt werden.");
                entOptions.AddAllowedClass(typeof(Curve), false);
                PromptEntityResult entResult = ed.GetEntity(entOptions);
                if (entResult.Status != PromptStatus.OK)
                    return;
                ObjectId BaseCurveId = entResult.ObjectId;
                //Get a base point from the user
                PromptPointResult pointResult = ed.GetPoint("\nBasispunkt: ");
                if (pointResult.Status != PromptStatus.OK)
                    return;
                UcsMatrix = ed.CurrentUserCoordinateSystem;
                m_basePoint = pointResult.Value.TransformBy(UcsMatrix);

                do
                {
                    using (Transaction myT = db.TransactionManager.StartTransaction())
                    {
                        BaseCurve = (Curve)myT.GetObject(BaseCurveId, OpenMode.ForRead);
                        if (BaseCurve == null)
                            return;

                        Point3d tmpbasePoint = BaseCurve.GetClosestPointTo(m_basePoint, false);

                        xAxisFrom = BaseCurve.GetFirstDerivative(tmpbasePoint).GetNormal();
                        yAxisFrom = BaseCurve.GetSecondDerivative(tmpbasePoint).GetNormal();
                        if (yAxisFrom.IsZeroLength() || !yAxisFrom.IsPerpendicularTo(xAxisFrom))
                        {
                            if (BaseCurve.IsPlanar)
                                yAxisFrom = BaseCurve.GetPlane().Normal.CrossProduct(xAxisFrom.GetNormal()).GetNormal();
                            else
                                yAxisFrom = xAxisFrom.GetPerpendicularVector().GetNormal();
                        }
                        zAxisFrom = xAxisFrom.CrossProduct(yAxisFrom).GetNormal();

                        //Initiate the drag callback delegate
                        DragCallback dragCallbackDelegate = this.FollowCursor;

                        //Start the drag operation
                        PromptDragOptions dragOptions = new PromptDragOptions(ssResult.Value, "\nZweiter Punkt angeben oder", dragCallbackDelegate);
                        string kwDefault = "Beenden";
                        dragOptions.Keywords.Add(kwDefault);
                        dragOptions.Keywords.Default = kwDefault;
                        PromptPointResult destinationPointResult = ed.Drag(dragOptions);
                        if (destinationPointResult.Status != PromptStatus.OK)
                            return;

                        m_destinationPoint = destinationPointResult.Value.TransformBy(UcsMatrix);
                        //m_destinationPoint = destinationPointResult.Value;
                        Point3d tmpdestinationPoint = BaseCurve.GetClosestPointTo(m_destinationPoint, false);

                        xAxisTo = BaseCurve.GetFirstDerivative(tmpdestinationPoint).GetNormal();
                        yAxisTo = BaseCurve.GetSecondDerivative(tmpdestinationPoint).GetNormal();
                        if (yAxisTo.IsZeroLength() || !yAxisTo.IsPerpendicularTo(xAxisTo))
                        {
                            if (BaseCurve.IsPlanar)
                                yAxisTo = BaseCurve.GetPlane().Normal.CrossProduct(xAxisTo.GetNormal()).GetNormal();
                            else
                                yAxisTo = xAxisTo.GetPerpendicularVector().GetNormal();
                        }
                        zAxisTo = xAxisTo.CrossProduct(yAxisTo).GetNormal();

                        //Determine the final displacement matrix
                        transMat = Matrix3d.AlignCoordinateSystem(
                            m_basePoint, xAxisFrom, yAxisFrom, zAxisFrom,
                            m_destinationPoint, xAxisTo, yAxisTo, zAxisTo);

                        myT.Commit();
                    }

                    //transform the ss to the new location
                    this.TransformSelectionSet2(ssResult.Value, transMat);
                } while (true);
           
            }
            finally
            {
                //myT.Dispose();
            }

        }

        //DragCallback Delegate
        public SamplerStatus FollowCursor(Point3d currentPoint, ref Matrix3d transMat)
        {
            Point3d tmpcurrentPoint = BaseCurve.GetClosestPointTo(currentPoint.TransformBy(UcsMatrix), false);
            xAxisTo = BaseCurve.GetFirstDerivative(tmpcurrentPoint).GetNormal();
            yAxisTo = BaseCurve.GetSecondDerivative(tmpcurrentPoint).GetNormal();
            if (yAxisTo.IsZeroLength() || !yAxisTo.IsPerpendicularTo(xAxisTo))
            {
                if (BaseCurve.IsPlanar)
                    yAxisTo = BaseCurve.GetPlane().Normal.CrossProduct(xAxisTo.GetNormal()).GetNormal();
                else
                    yAxisTo = xAxisTo.GetPerpendicularVector().GetNormal();
            }
            zAxisTo = xAxisTo.CrossProduct(yAxisTo).GetNormal();

            //Determine the final displacement matrix
            transMat = Matrix3d.AlignCoordinateSystem(
                m_basePoint, xAxisFrom, yAxisFrom, zAxisFrom,
                currentPoint.TransformBy(UcsMatrix), xAxisTo, yAxisTo, zAxisTo);

            return SamplerStatus.OK;
        }


        private void TransformSelectionSet(SelectionSet ss, Matrix3d transMat)
        {
            if (ss.Count == 0)
            {
                return;
            }
           
            Database targetDatabase = ss[0].ObjectId.Database;

            using (Transaction trans = targetDatabase.TransactionManager.StartTransaction())
            {
                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(targetDatabase.CurrentSpaceId, OpenMode.ForWrite);

                foreach (SelectedObject selectedObj in ss)
                {
                    Entity selectedEntity = (Entity)trans.GetObject(selectedObj.ObjectId, OpenMode.ForRead);

                    Entity transformedEntity = selectedEntity.GetTransformedCopy(transMat);

                    currentSpace.AppendEntity(transformedEntity);

                    trans.AddNewlyCreatedDBObject(transformedEntity, true);
                }

                trans.Commit();
            }
        }

        private void TransformSelectionSet2(SelectionSet ss, Matrix3d transMatrix)
        {
            if (ss.Count == 0)
            {
                return;
            }

            Database targetDatabase = ss[0].ObjectId.Database;

            using (Transaction trans = targetDatabase.TransactionManager.StartTransaction())
            {
                ObjectIdCollection entityCollection = new ObjectIdCollection(ss.GetObjectIds());
                IdMapping idMap = new IdMapping();
                targetDatabase.DeepCloneObjects(entityCollection, targetDatabase.CurrentSpaceId, idMap, false);

                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(targetDatabase.CurrentSpaceId, OpenMode.ForWrite);
             
                foreach (IdPair pair in idMap)
                {
                    Entity clonedEntity = (Entity)trans.GetObject(pair.Value, OpenMode.ForWrite);

                    clonedEntity.TransformBy(transMatrix);
                }
               
                trans.Commit();
            }
        }


    }
}

Roland Feletic

  • Guest
Re: AU 2005 code - Part 9 "Gettin' Jiggy With It"
« Reply #18 on: February 27, 2007, 08:17:53 AM »
If someone had the same problem, here is the working code. Many thanks to Kean Walmsley from the ADN-Team.
Code: [Select]
#region Using directives
using System;
using System.Collections;
using System.Collections.Generic;

using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;

using RSNNAcadApp.ExtendedCommands;
#endregion

[assembly: CommandClass(typeof(RSNNAcadApp.ExtendedCommands.Copy))]
namespace RSNNAcadApp.ExtendedCommands
{
    class Copy
    {
        private Matrix3d UcsMatrix;
        private Point3d m_basePoint;
        private Point3d m_destinationPoint;
        private Curve BaseCurve;
        private Matrix3d transMat;

        private Vector3d xAxisFrom, yAxisFrom, zAxisFrom;
        private Vector3d xAxisTo, yAxisTo, zAxisTo;
       
        /// <summary>
        /// Moves blockreferences along a Curve with a given distance
        /// </summary>
        [CommandMethod("KOPIERENENTLANGMITBASIS", CommandFlags.UsePickSet)]
        public void CopyAlongCurve()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            //Transaction myT = db.TransactionManager.StartTransaction();
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            try
            {

                PromptSelectionOptions ssOptions = new PromptSelectionOptions();
                ssOptions.MessageForAdding = "\nObjekte wählen: ";
                ssOptions.MessageForRemoval = "\nObjekte entfernen: ";
                ssOptions.AllowDuplicates = true;


                PromptSelectionResult ssResult = ed.GetSelection(ssOptions);
                if (ssResult.Status != PromptStatus.OK)
                    return;
                if (ssResult.Value.Count == 0)
                    return;

                PromptEntityOptions entOptions = new PromptEntityOptions("\nBezugslinie wählen, entlang der kopiert werden soll");
                entOptions.SetRejectMessage("\nNur Kurven können gewählt werden.");
                entOptions.AddAllowedClass(typeof(Curve), false);
                PromptEntityResult entResult = ed.GetEntity(entOptions);
                if (entResult.Status != PromptStatus.OK)
                    return;
                ObjectId BaseCurveId = entResult.ObjectId;
                //Get a base point from the user
                PromptPointResult pointResult = ed.GetPoint("\nBasispunkt: ");
                if (pointResult.Status != PromptStatus.OK)
                    return;
                UcsMatrix = ed.CurrentUserCoordinateSystem;
                m_basePoint = pointResult.Value.TransformBy(UcsMatrix);

                do
                {
                    using (Transaction myT = db.TransactionManager.StartTransaction())
                    {
                        BaseCurve = (Curve)myT.GetObject(BaseCurveId, OpenMode.ForRead);
                        if (BaseCurve == null)
                            return;

                        Point3d tmpbasePoint = BaseCurve.GetClosestPointTo(m_basePoint, false);

                        xAxisFrom = BaseCurve.GetFirstDerivative(tmpbasePoint).GetNormal();
                        yAxisFrom = BaseCurve.GetSecondDerivative(tmpbasePoint).GetNormal();
                        if (yAxisFrom.IsZeroLength() || !yAxisFrom.IsPerpendicularTo(xAxisFrom))
                        {
                            if (BaseCurve.IsPlanar)
                                yAxisFrom = BaseCurve.GetPlane().Normal.CrossProduct(xAxisFrom.GetNormal()).GetNormal();
                            else
                                yAxisFrom = xAxisFrom.GetPerpendicularVector().GetNormal();
                        }
                        zAxisFrom = xAxisFrom.CrossProduct(yAxisFrom).GetNormal();

                        //Initiate the drag callback delegate
                        DragCallback dragCallbackDelegate = this.FollowCursor;

                        //Start the drag operation
                        PromptDragOptions dragOptions = new PromptDragOptions(ssResult.Value, "\nZweiter Punkt angeben oder", dragCallbackDelegate);
                        string kwDefault = "Beenden";
                        dragOptions.Keywords.Add(kwDefault);
                        dragOptions.Keywords.Default = kwDefault;
                        PromptPointResult destinationPointResult = ed.Drag(dragOptions);
                        if (destinationPointResult.Status != PromptStatus.OK)
                            return;

                        m_destinationPoint = destinationPointResult.Value.TransformBy(UcsMatrix);
                        //m_destinationPoint = destinationPointResult.Value;
                        Point3d tmpdestinationPoint = BaseCurve.GetClosestPointTo(m_destinationPoint, false);

                        xAxisTo = BaseCurve.GetFirstDerivative(tmpdestinationPoint).GetNormal();
                        yAxisTo = BaseCurve.GetSecondDerivative(tmpdestinationPoint).GetNormal();
                        if (yAxisTo.IsZeroLength() || !yAxisTo.IsPerpendicularTo(xAxisTo))
                        {
                            if (BaseCurve.IsPlanar)
                                yAxisTo = BaseCurve.GetPlane().Normal.CrossProduct(xAxisTo.GetNormal()).GetNormal();
                            else
                                yAxisTo = xAxisTo.GetPerpendicularVector().GetNormal();
                        }
                        zAxisTo = xAxisTo.CrossProduct(yAxisTo).GetNormal();

                        //Determine the final displacement matrix
                        transMat = Matrix3d.AlignCoordinateSystem(
                            m_basePoint, xAxisFrom, yAxisFrom, zAxisFrom,
                            m_destinationPoint, xAxisTo, yAxisTo, zAxisTo);

                        myT.Commit();
                    }

                    //transform the ss to the new location
                    this.TransformSelectionSet(ssResult.Value, transMat);
                } while (true);
           
            }
            finally
            {
                //myT.Dispose();
            }

        }

        //DragCallback Delegate
        public SamplerStatus FollowCursor(Point3d currentPoint, ref Matrix3d transMat)
        {
            Point3d tmpcurrentPoint = BaseCurve.GetClosestPointTo(currentPoint.TransformBy(UcsMatrix), false);
            xAxisTo = BaseCurve.GetFirstDerivative(tmpcurrentPoint).GetNormal();
            yAxisTo = BaseCurve.GetSecondDerivative(tmpcurrentPoint).GetNormal();
            if (yAxisTo.IsZeroLength() || !yAxisTo.IsPerpendicularTo(xAxisTo))
            {
                if (BaseCurve.IsPlanar)
                    yAxisTo = BaseCurve.GetPlane().Normal.CrossProduct(xAxisTo.GetNormal()).GetNormal();
                else
                    yAxisTo = xAxisTo.GetPerpendicularVector().GetNormal();
            }
            zAxisTo = xAxisTo.CrossProduct(yAxisTo).GetNormal();

            //Determine the final displacement matrix
            transMat = Matrix3d.AlignCoordinateSystem(
                m_basePoint, xAxisFrom, yAxisFrom, zAxisFrom,
                currentPoint.TransformBy(UcsMatrix), xAxisTo, yAxisTo, zAxisTo);

            return SamplerStatus.OK;
        }


        private void TransformSelectionSet(SelectionSet ss, Matrix3d transMatrix)
        {
            if (ss.Count == 0)
                return;

            Database targetDatabase = ss[0].ObjectId.Database;

            using (Transaction trans = targetDatabase.TransactionManager.StartTransaction())
            {
                ObjectIdCollection entityCollection = new ObjectIdCollection(ss.GetObjectIds());
                IdMapping idMap = new IdMapping();
                targetDatabase.DeepCloneObjects(entityCollection, targetDatabase.CurrentSpaceId, idMap, false);

                foreach (IdPair pair in idMap)
                {
                    Entity clonedEntity = trans.GetObject(pair.Value, OpenMode.ForRead) as Entity;
                    if (clonedEntity != null)
                    {
                        Type et = clonedEntity.GetType();
                        if (typeof(SequenceEnd) != et && typeof(AttributeReference) != et)
                        {
                            clonedEntity.UpgradeOpen();
                            clonedEntity.TransformBy(transMatrix);
                            clonedEntity.DowngradeOpen();
                        }
                    }
                }
                trans.Commit();
            }
        }
    }
}