I am trying use the Entity zig for rotation but I am getting error
Entity zig code:
namespace palet.Jig
{
public sealed class mod__BlockRotating : EntityJig
{
#region Fields
public int mCurJigFactorNumber = 1;
private double mRotation = 0.0; // Factor #1
#endregion
#region Constructors
public mod__BlockRotating(Entity ent)
: base(ent)
{
}
#endregion
#region Overrides
protected override bool Update()
{
switch (mCurJigFactorNumber)
{
case 1:
(Entity as BlockReference).Rotation = mRotation;
break;
default:
return false;
}
return true;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
switch (mCurJigFactorNumber)
{
case 1:
JigPromptAngleOptions prOptions1 = new JigPromptAngleOptions("\nBlock rotation angle:");
prOptions1.BasePoint = (Entity as BlockReference).Position;
prOptions1.UseBasePoint = true;
prOptions1.Cursor = CursorType.RubberBand;
PromptDoubleResult prResult1 = prompts.AcquireAngle(prOptions1);
if (prResult1.Status == PromptStatus.Cancel) return SamplerStatus.Cancel;
if (prResult1.Value.Equals(mRotation))
{
return SamplerStatus.NoChange;
}
else
{
mRotation = prResult1.Value;
return SamplerStatus.OK;
}
default:
break;
}
return SamplerStatus.OK;
}
#endregion
#region Method to Call
public static bool Jig(BlockReference ent)
{
try
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
mod__BlockRotating jigger = new mod__BlockRotating(ent);
PromptResult pr;
do
{
pr = ed.Drag(jigger);
jigger.mCurJigFactorNumber++;
} while (pr.Status != PromptStatus.Cancel &&
pr.Status != PromptStatus.Error &&
pr.Status != PromptStatus.Keyword &&
jigger.mCurJigFactorNumber <= 1);
return pr.Status == PromptStatus.OK;
}
catch
{
return false;
}
}
#endregion
}
}
Error That I am getting when I use the function to call jig
System.InvalidCastException: 'Unable to cast COM object of type 'System.__ComObject' to class type 'Autodesk.AutoCAD.DatabaseServices.BlockReference'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.'
Then I realized that I am using
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
AcadBlock a_BlkObj = default(AcadBlock);
AcadBlockReference a_BlockRefObj1 = default(AcadBlockReference);
AcadBlockReference a_BlockRefObj2 = default(AcadBlockReference);
mod__BlockRotating.Jig((Autodesk.AutoCAD.DatabaseServices.BlockReference)a_BlockRefObj1);
Then I realized that I am using Autodesk.AutoCAD.Interop.Common to add the Block.. due to which its throwing error.
Now I have ported most of my code to Autodesk.AutoCAD.Interop.Common and I want to use the Entity jig to rotate some of by blocks.
Is there any resolution for this?
Firstly, why do you want to use COM API to create a block reference in .NET API code? It does not make much sense in most, if not all, cases.
Secondly, even you insist to create a COM API's AcadBlockReference and then pass it to .NET API's Jig, your code is still wrong: an instance of AcadBlockReference object cannot be created with default<T>. It can only be created by calling AcadBlock.InsertBlock() method. Once the InsertBlock() call is done, you can convert it to .NET BlockReference by DBObject.FromAcadObject() method. However, at this moment, the block reference has already been added into the database. So, if you want to jig it, you should use DrawJig, instead of EntityJig.
Again, I simply see no reason to create an AcadBlockReference via COM API before calling an EntityJig. You can simply:
using (BlockReference blockRef=new BlockReference(Point3d.Origin, [blockdefinitionId]))
{
if (mod_BlockRotating.Jig(blockRef))
{
// add the blockRef to database
}
}
Norman Yuan
The resolution is to not use the COM API unless you are exposing your API to lisp or some other automation client.
If you must use ActiveX, note:
AcadBlockReference is not a BlockReference
Look at these for casting
DBObject.FromAcadObject and DBObject.AcadObject
The Project already was developed with com APIs.. now I need to Add this new functionality to existing one.. moving all code to new will be big task .. So looking for quick solution..
Is there any sample code that I can study which I can refer with COM API I can use the Jig Functionality.. As I need to move, Draw and rotated the Blocks. In below video I am not able to rotate block with cursor movement.
Well, even your .NET plugin somehow developed mostly using COM API for very odd reasons (it is .NET API plugin, isn't it? Or you would not try to do jig and post here), it does not prevent you from adding JIG using .NET API's Entity class (in your case, it is BlockReference class). So, when you only adding this jig features to your existing project, you should have no issue to do it with PURE .NET API.
As for your video showing the jig not working, since there is no all related code posted, all I can say is that the code of doing it is wrong.
Norman Yuan
Hi ,
Below is code that I am trying after placing the block I need to Rotate the Block, Move the Block, or Draw Circle , Squre using Jig
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Interop.Common;
using Autodesk.AutoCAD.Interop;
using System.Linq.Expressions;
using System.Windows.Forms;
using Application = Autodesk.AutoCAD.ApplicationServices.Application;
using palet.Startup;
using palet.DC;
using System.Runtime.InteropServices;
using palet.Startup.Microdesk;
namespace palet.TESTCODES
{
public class Commands
{
/*public static extern int SetFocusAPI(int hwnd);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]*/
public static double[] dbl_Origin = new double[3];
public static double dbl_DC_ScaleFactor = 64;
[CommandMethod("ROTATEBLOCK")]
public void RotateBlockCommand()
{
String s_FileName = @"XXX.dwg";
String s_InsPrompt = "Specify insertion point of form part mark";
AcadBlock a_BlkObj = default(AcadBlock);
AcadBlockReference a_BlockRefObj1 = default(AcadBlockReference);
AcadBlockReference a_BlockRefObj2 = default(AcadBlockReference);
AcadLayer a_CurLayer = default(AcadLayer);
m_ThisDrawing.acd_DocumentManager = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
m_ThisDrawing.acd_AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication as AcadApplication;
m_ThisDrawing.ThisDrawing = m_ThisDrawing.acd_AcadApplication.ActiveDocument;
string cst_TempBlockName = "_Temporary";
a_BlkObj = null;
try
{
a_BlkObj = m_ThisDrawing.ThisDrawing.Blocks.Add(dbl_Origin, cst_TempBlockName);
a_BlockRefObj2 = a_BlkObj.InsertBlock(dbl_Origin, s_FileName, 1, 1, 1, 0);
a_BlockRefObj1 = m_ThisDrawing.ThisDrawing.ModelSpace.InsertBlock(dbl_Origin, a_BlkObj.Name, 1, 1, 1, fnc_dbl_UCSRotation());
a_BlockRefObj1.ScaleEntity(dbl_Origin, dbl_DC_ScaleFactor);
m_ThisDrawing.ThisDrawing.Utility.InitializeUserInput(1, "Undo");
bool IsKeyword = false;
dynamic v_IPnt = null;
bool bln_IsManualOn = true;
m_ThisDrawing.ThisDrawing.Utility.InitializeUserInput(1, "Auto");
v_IPnt = GetPoint(Type.Missing, "\r\n" + s_InsPrompt + " or [Auto gap on]: ", ref IsKeyword);
a_BlockRefObj1.InsertionPoint = v_IPnt;
a_BlockRefObj1.Update();
/*
* Till here Block is placed in the Drawing now further not sure how to proceed
* I need to Rotate the Block, Move the Block, Draw Circle , Squre using Jig
*/
//RotateBlockJig(v_IPnt);
/* Rotaton Jig, should happen here
* Should take angle of rotaion and rotate the block accordingly
* This is place where I am not able to proceed..
*/
}
catch {
}
}
public static dynamic GetPoint(object Point, object Prompt, ref bool IsKeyword)
{
object Ret = null;
try
{
if (ReferenceEquals(Point, null))
{
Point = Type.Missing;
}
Ret = m_ThisDrawing.ThisDrawing.Utility.GetPoint(Point, Prompt);
}
catch (COMException ComEx)
{
if (ComEx.Message.IndexOf("User input is a keyword", StringComparison.InvariantCultureIgnoreCase) != -1)
{
IsKeyword = true;
}
else
{
Ret = null;
if (ComEx.HResult == -2147352567)
{
}
else
{
}
}
}
catch (System.Exception ex)
{
Ret = null;
}
return Ret;
}
public static double fnc_dbl_UCSRotation()
{
object v_XVector = null;
double d_UCSRotation = 0;
try
{
v_XVector = m_ThisDrawing.ThisDrawing.GetVariable("UCSXDIR");
d_UCSRotation = System.Convert.ToDouble(m_ThisDrawing.ThisDrawing.Utility.AngleFromXAxis(dbl_Origin, v_XVector));
}
catch (System.Exception)
{
d_UCSRotation = 0;
}
return d_UCSRotation;
}
}
public class RotateBlockJig : EntityJig
{
private Point3d _center;
private double _angle;
public RotateBlockJig(Point3d center)
: base(new BlockReference(center, ObjectId.Null))
{
_center = center;
_angle = 0.0;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
JigPromptAngleOptions angleOptions = new JigPromptAngleOptions("\nSelect rotation angle:");
angleOptions.DefaultValue = _angle;
PromptDoubleResult angleResult = prompts.AcquireAngle(angleOptions);
if (angleResult.Status == PromptStatus.OK)
{
_angle = angleResult.Value;
return SamplerStatus.OK;
}
return SamplerStatus.Cancel;
}
protected override bool Update()
{
// Rotate the block reference
((BlockReference)Entity).TransformBy(Matrix3d.Rotation(_angle, Vector3d.ZAxis, _center));
return true;
}
}
public class m_ThisDrawing
{
public static DocumentCollection acd_DocumentManager;
public static AcadApplication acd_AcadApplication;
public static AcadDocument ThisDrawing;
}
}
Which IDE you use to write the code? VisualStudio? Dosen't Visual Studio prompt code error with red underline, does it? The code certainly cannot be compiled.
Just to begin with:
a_BlkObj = m_ThisDrawing.ThisDrawing.Blocks.Add(dbl_Origin, cst_TempBlockName);
a_BlockRefObj2 = a_BlkObj.InsertBlock(dbl_Origin, s_FileName, 1, 1, 1, 0);
a_BlockRefObj1 = m_ThisDrawing.ThisDrawing.ModelSpace.InsertBlock(dbl_Origin, a_BlkObj.Name, 1, 1, 1, fnc_dbl_UCSRotation());
The first line is completely wrong: ThisDrawing in your code is an .NET API Document, not an AcadDocument in COM API.
In your previous post, you mention that the .NET plugin mainly uses COM API. However, if the code shown here is for that plugin, I do not see why stick with COM API (a VBA porting project, maybe?) and I'd restart/learn from scratch with real .NET API plugin. It would be waste of time rewrite COM API code in .NET API plugin.
I'd strongly suggest you start with learning basic AutoCAD .NET APIs. I also strongly suggest that you REMOVE the reference to COM API interop assembly and do/learn writing code with AutoCAD .NET API, so that you can do thing correctly.
If you still insist in using COM API to insert a block, you need to learn how to obtain an AcadApplication/AcadDocument from .NET Application/Document:
AcadApplicatio comApp=(AcadDocument)Application.AcadApplication;
AcadDocument comDoc=(AcadDocument)Application.DocumentManager.MdiActiveDocument.GetAcadDocument();
Then you can go on with COM API operation. Again, in most cases, it is not necessary, and probably bad move.
Norman Yuan
m_ThisDrawing is the class at end of code which refers for AcadDocument using Autodesk.AutoCAD.Interop;
your suggesion seems good to move to new .net API.. but as I already said its big application which need this change. Moving all code to .net compatible API is not possible.
public class m_ThisDrawing
{
public static DocumentCollection acd_DocumentManager;
public static AcadApplication acd_AcadApplication;
public static AcadDocument ThisDrawing;
}
OK, I overlooked. But still, the code would not work: it added a block definition with no entities in it. So, when the AcadModelSpace.InsertBlock() is called, there is nothing can be seen/scaled/rotated as AcadBlockReference - it is an empty block reference.
Let's put this aside, assuming the code is only meant to show how an AcadBlockReference is created. Then you want to jig-rotate an EXISTING block reference. so, here is what you can do:
1. You should use DrawJig, instead of EntityJig. Because EntityJig is meant to jig an new Entity (not database-residing yet). In case the user cancels the jig, the entity should be disposed and only when the jig is Oked, the entity is then added into the database. For DrawJig, you pass an Entity opened for writing in a transaction to the jig. If the jig is OKed, the jig calling code comitted the transaction; if cancelled, the calling code abort the transaction. Technically, you can use Entity jig for existing entity, but it is not EntityJig intended for;
2. For jigging an existing AcadBlockReference, you could do something like:
private void JigAcdBlockReference(AcadBlockReference acadBlkRef)
{
using (var tran = [database].TransactionManager.StartTransaction())
{
BlockReference blkref=DBObject.FromAcadObject(acadBlkRef) as BlockReference
if (blkRef==null)
{
throw new ArgumentException("Wrong AcadObject!");
}
if (!blkRef.IsWriteEnabled)
{
blkRef.UpgradeOpen();
}
var ok = mod_BlockRotating.Jig(blkRef);
if (ok)
tran.Commit()
else
tran.Abort();
}
}
public class mod_BlockRotatingJig : DrawJig
{
private readonly BlockReference _blk;
public mod_RlockRotaingJig(BlockReference blk):base()
{
_blk= blk;
}
// implement virtual methods here
}
Norman Yuan
Can't find what you're looking for? Ask the community or share your knowledge.