.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Mirroring attribute values

4 REPLIES 4
SOLVED
Reply
Message 1 of 5
js75CAD
491 Views, 4 Replies

Mirroring attribute values

Hi all,

 

A simple task (or so you would think), but I am trying to mirror a group of blocks. When I insert each one I am appending them to a group and then iterating that group to modify certain aspects. One of which is mirroring...

 

Now when I use the standard mirror command, the attribute values all look right. If I do it programmatically, well, here we are:

 

I have set the system variable MIRRTEXT to 0, but to no avail. Nothing changes, but my code for whatever reason simply won't work. Is there a simple answer to this or am I required to go through and determine each attribute? If so, how on earth do you make it go back when it technically isn't "backwards"?

 

Any and all help is appreciated.

   <CommandMethod("UDC_ConduitFlip180")> Public Sub UDC_ConduitFlip180()
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor

        Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("MIRRTEXT", 0)

        Using tr As Transaction = doc.TransactionManager.StartTransaction()
            Dim UCS As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
            Dim ulDir As String = String.Empty
            Dim peo As New PromptEntityOptions(vbLf & "Select Entity: ")
            peo.SetRejectMessage(vbLf & "Must be block reference...")
            peo.AddAllowedClass(GetType(BlockReference), True)
            Dim per As PromptEntityResult = ed.GetEntity(peo)

            If Not per.Status = PromptStatus.OK Then Return
            Dim br As BlockReference = CType(tr.GetObject(per.ObjectId, 0), BlockReference)

            Dim acBlkTblRec As BlockTableRecord
            If br.IsDynamicBlock Then
                acBlkTblRec = TryCast(tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead, False, forceOpenOnLockedLayer:=True), BlockTableRecord)
            Else
                acBlkTblRec = TryCast(tr.GetObject(br.BlockTableRecord, OpenMode.ForRead, False, True), BlockTableRecord)
            End If

            If acBlkTblRec.IsFromExternalReference = True Or acBlkTblRec.IsLayout = True Then Return
            If UCase(acBlkTblRec.Name).EndsWith("R") Then ulDir = "L" Else ulDir = "R"
            Dim bName As String = String.Empty
            Select Case ulDir
                Case "L" : bName = "TRENCH_VIEW-L"
                Case "R" : bName = "TRENCH_VIEW-R"
            End Select

            Dim bRot As Double = br.Rotation
            Dim bPos As Point3d = br.Position
 
' So here is the mirror component, as you can see I find the simple block with text and mirror it back on its own axis no stress, but the attribute blocks all place the text in a bacward style... yet when I click on it, it does not say backward....

            For Each id In idCol
                Dim oChkEnt = TryCast(tr.GetObject(id, OpenMode.ForWrite), Entity)
                oChkEnt.TransformBy(Matrix3d.Mirroring(acLine3d))

                If TypeOf oChkEnt Is BlockReference Then
                    Dim chkbr As BlockReference = CType(tr.GetObject(id, 0), BlockReference)
                    Dim acPtTo2 As Point3d = Polar(chkbr.Position, chkbr.Rotation + funcGetRads(90), 1)
                    Dim acLine3d2 As Line3d = New Line3d(chkbr.Position, acPtTo2)
                    If chkbr.Name.Contains("Comm") Then chkbr.TransformBy(Matrix3d.Mirroring(acLine3d2))
                End If

            Next
            tr.Commit()
        End Using

    End Sub
4 REPLIES 4
Message 2 of 5
_gile
in reply to: js75CAD

Hi,

You could use these extension methods.

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

using System;
using System.Runtime.InteropServices;

namespace MirroringSample
{
    // inspired by: https://adndevblog.typepad.com/autocad/2013/10/mirroring-a-dbtext-entity.html
    public static class MirroringExtension
    {
        [DllImport("accore.dll", CharSet = CharSet.Unicode,
            CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTextBox")]
        static extern System.IntPtr acedTextBox(IntPtr rb, double[] point1, double[] point2);

        /// <summary>
        /// Gets the WCS points of the text bounding box.
        /// </summary>
        /// <param name="dbText">Instance of DBText the method applies to.</param>
        /// <returns>The bounding box points in counterclockwise sense.</returns>
        public static Point3d[] GetTextBoxCorners(this DBText dbText)
        {
            if (dbText == null)
                throw new ArgumentNullException("dbText");

            int mirrored = dbText.IsMirroredInX ? 2 : 0;
            mirrored |= dbText.IsMirroredInY ? 4 : 0;
            var rb = new ResultBuffer(
                    new TypedValue(1, dbText.TextString),
                    new TypedValue(40, dbText.Height),
                    new TypedValue(41, dbText.WidthFactor),
                    new TypedValue(51, dbText.Oblique),
                    new TypedValue(7, dbText.TextStyleName),
                    new TypedValue(71, mirrored),
                    new TypedValue(72, (int)dbText.HorizontalMode),
                    new TypedValue(73, (int)dbText.VerticalMode));

            var point1 = new double[3];
            var point2 = new double[3];

            acedTextBox(rb.UnmanagedObject, point1, point2);

            var xform =
                Matrix3d.Displacement(dbText.Position.GetAsVector()) *
                Matrix3d.Rotation(dbText.Rotation, dbText.Normal, Point3d.Origin) *
                Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, dbText.Normal));

            return new[]
            {
                new Point3d(point1).TransformBy(xform),
                new Point3d(point2[0], point1[1], 0.0).TransformBy(xform),
                new Point3d(point2).TransformBy(xform),
                new Point3d(point1[0], point2[1], 0.0).TransformBy(xform)
            };
        }

        /// <summary>
        /// Gets the WCS points of the mtext bounding box.
        /// </summary>
        /// <param name="mtext">Instance of MText the method applies to.</param>
        /// <returns>The bounding box points in counterclockwise sense.</returns>
        public static Point3d[] GetMTextBoxCorners(this MText mtext)
        {
            double width = mtext.ActualWidth;
            double height = mtext.ActualHeight;
            Point3d point1, point2;
            switch (mtext.Attachment)
            {
                case AttachmentPoint.TopLeft:
                default:
                    point1 = new Point3d(0.0, -height, 0.0);
                    point2 = new Point3d(width, 0.0, 0.0);
                    break;
                case AttachmentPoint.TopCenter:
                    point1 = new Point3d(-width * 0.5, -height, 0.0);
                    point2 = new Point3d(width * 0.5, 0.0, 0.0);
                    break;
                case AttachmentPoint.TopRight:
                    point1 = new Point3d(-width, -height, 0.0);
                    point2 = new Point3d(0.0, 0.0, 0.0);
                    break;
                case AttachmentPoint.MiddleLeft:
                    point1 = new Point3d(0.0, -height * 0.5, 0.0);
                    point2 = new Point3d(width, height * 0.5, 0.0);
                    break;
                case AttachmentPoint.MiddleCenter:
                    point1 = new Point3d(-width * 0.5, -height * 0.5, 0.0);
                    point2 = new Point3d(width * 0.5, height * 0.5, 0.0);
                    break;
                case AttachmentPoint.MiddleRight:
                    point1 = new Point3d(-width, -height * 0.5, 0.0);
                    point2 = new Point3d(0.0, height * 0.5, 0.0);
                    break;
                case AttachmentPoint.BottomLeft:
                    point1 = new Point3d(0.0, 0.0, 0.0);
                    point2 = new Point3d(width, height, 0.0);
                    break;
                case AttachmentPoint.BottomCenter:
                    point1 = new Point3d(-width * 0.5, 0.0, 0.0);
                    point2 = new Point3d(width * 0.5, height, 0.0);
                    break;
                case AttachmentPoint.BottomRight:
                    point1 = new Point3d(-width, 0.0, 0.0);
                    point2 = new Point3d(0.0, height, 0.0);
                    break;
            }

            var xform =
                Matrix3d.Displacement(mtext.Location.GetAsVector()) *
                Matrix3d.Rotation(mtext.Rotation, mtext.Normal, Point3d.Origin) *
                Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, mtext.Normal));

            return new[]
            {
                point1.TransformBy(xform),
                new Point3d(point2.X, point1.Y, 0.0).TransformBy(xform),
                point2.TransformBy(xform),
                new Point3d(point1.X, point2.Y, 0.0).TransformBy(xform)
            };
        }

        /// <summary>
        /// Mirrors the entity (honoring the value of MIRRTEXT system variable).
        /// </summary>
        /// <param name="source">Instance of DBText the method applies to.</param>
        /// <param name="axis">Mirror symmetry line.</param>
        /// <param name="eraseSource">Value indicating if the source object have to be erased</param>
        public static Entity Mirror(this Entity source, Line3d axis, bool eraseSource)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            if (axis == null)
                throw new ArgumentNullException("axis");

            var db = source.Database;
            var tr = db.TransactionManager.TopTransaction;
            if (tr == null)
                throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);

            Entity mirrored;
            if (eraseSource)
            {
                mirrored = source;
                if (!mirrored.IsWriteEnabled)
                {
                    tr.GetObject(mirrored.ObjectId, OpenMode.ForWrite);
                }
            }
            else
            {
                var ids = new ObjectIdCollection(new[] { source.ObjectId });
                var mapping = new IdMapping();
                db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, false);
                mirrored = (Entity)tr.GetObject(mapping[source.ObjectId].Value, OpenMode.ForWrite);
            }
            mirrored.TransformBy(Matrix3d.Mirroring(axis));

            // Honoring the MIRRTEXT sysvar with DBText, MText and AttributeReference.
            if ((short)Application.GetSystemVariable("MIRRTEXT") == 0)
            {
                void MirrorText(Entity entity, Point3d[] points)
                {
                    var cen = new LineSegment3d(points[0], points[2]).MidPoint;
                    var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ?
                        points[0].GetVectorTo(points[3]) :
                        points[0].GetVectorTo(points[1]);
                    entity.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen));
                }

                if (mirrored is DBText text)
                {
                    var pts = text.GetTextBoxCorners();
                    MirrorText(text, pts);
                }
                else if (mirrored is MText mtext)
                {
                    var pts = mtext.GetMTextBoxCorners();
                    MirrorText(mtext, pts);
                }
                else if (mirrored is BlockReference br)
                {
                    foreach (ObjectId id in br.AttributeCollection)
                    {
                        var attRef = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                        var pts = attRef.GetTextBoxCorners();
                        MirrorText(attRef, pts);
                    }
                }
            }
            return mirrored;
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 5
js75CAD
in reply to: _gile

Hi _gile,

 

Thank you so much, but I am having trouble converting this to vb.net. It has an issue with the following line when converting:

 

''' Cannot convert LocalFunctionStatementSyntax, CONVERSION ERROR: Conversion for LocalFunctionStatement not implemented, please report this issue in 'void MirrorText(Entity enti...' at character 7137

 

I have never seen the void thing before so I have no idea how to convert the Mirror function at this point. 

 

Does anyone know what the Vb conversion for this part is? Is it a function of some sort?? It appears to be  trying to get some points (?) from the entity. 

 

void MirrorText(Entity entity, Point3d[] points)

 

Then the next part is making a 3d line (same as for the mirror transform), then to the best of my understanding, it is checking whether the abs of x is less than y, and if so rotating the entity.

 

But what is the MirrorText function it keeps calling?

 

Knowing you mate, this thing will be killer if I get it going. Thank you very much.

Message 4 of 5
_gile
in reply to: js75CAD

MirrorText is a local function (i.e. a method nested in another method). It seems that this feature is not available with VB.

Here, it's used to avoid repeating three times the same code.

Without local function the Mirror method cna be written:

 

        /// <summary>
        /// Mirrors the entity (honoring the value of MIRRTEXT system variable).
        /// </summary>
        /// <param name="source">Instance of Entity the method applies to.</param>
        /// <param name="axis">Mirror symmetry line.</param>
        /// <param name="eraseSource">Value indicating if the source object have to be erased</param>
        public static Entity Mirror(this Entity source, Line3d axis, bool eraseSource)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            if (axis == null)
                throw new ArgumentNullException("axis");

            var db = source.Database;
            var tr = db.TransactionManager.TopTransaction;
            if (tr == null)
                throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);

            Entity mirrored;
            if (eraseSource)
            {
                mirrored = source;
                if (!mirrored.IsWriteEnabled)
                {
                    tr.GetObject(mirrored.ObjectId, OpenMode.ForWrite);
                }
            }
            else
            {
                var ids = new ObjectIdCollection(new[] { source.ObjectId });
                var mapping = new IdMapping();
                db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, false);
                mirrored = (Entity)tr.GetObject(mapping[source.ObjectId].Value, OpenMode.ForWrite);
            }
            mirrored.TransformBy(Matrix3d.Mirroring(axis));

            // Honoring the MIRRTEXT sysvar with DBText, MText and AttributeReference.
            if ((short)Application.GetSystemVariable("MIRRTEXT") == 0)
            {
                if (mirrored is DBText)
                {
                    var pts = ((DBText)mirrored).GetTextBoxCorners();
                    var cen = new LineSegment3d(pts[0], pts[2]).MidPoint;
                    var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ?
                        pts[0].GetVectorTo(pts[3]) :
                        pts[0].GetVectorTo(pts[1]);
                    mirrored.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen));
                }
                else if (mirrored is MText)
                {
                    var pts = ((MText)mirrored).GetMTextBoxCorners();
                    var cen = new LineSegment3d(pts[0], pts[2]).MidPoint;
                    var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ?
                        pts[0].GetVectorTo(pts[3]) :
                        pts[0].GetVectorTo(pts[1]);
                    mirrored.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen));
                }
                else if (mirrored is BlockReference)
                {
                    foreach (ObjectId id in ((BlockReference)mirrored).AttributeCollection)
                    {
                        var attRef = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                        var pts = attRef.GetTextBoxCorners();
                        var cen = new LineSegment3d(pts[0], pts[2]).MidPoint;
                        var rotAxis = Math.Abs(axis.Direction.Y) > Math.Abs(axis.Direction.X) ?
                            pts[0].GetVectorTo(pts[3]) :
                            pts[0].GetVectorTo(pts[1]);
                        attRef.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen));
                    }
                }
            }
            return mirrored;
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 5
js75CAD
in reply to: _gile

Thanks _gile!

 

I did figure that out late last night, but you confirmed my suspicion so thank you!

 

As always, you are a deadset legend mate.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report