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
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Solved by _gile. Go to Solution.
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;
}
}
}
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.
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;
}
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.