AutoCAD .NET API provides two concrete Jig classes for us to jig different entities in different circumstances, EntityJig and DrawJig. EntityJig is to jig a specific entity as its name indicates and the DrawJig is to jig anything that has graphics to draw, which can be a single entity, a group of entities, or something that is not available natively in AutoCAD.
We have demonstrated jigging a block (BlockReference in the API term and INSERT in the AutoCAD usage term) in various ways such as by its position point, its rotation angle, and both, but the block reference/insert should be already created into the database for those block jiggers.
A reader, Indrawan, proposed a good idea about block rotating jig, detecting the mouse wheel actions (up or down) as the rotation angle increment or decrement of 90 degree for example when a block (with the API name BlockReference and AutoCAD term INSERT) is being rotated by a jig.
It’s definitely possible to use the Windows message filger. In this article, let us see how to achieve the goal. Here is the test command for increasing/decreasing rotation angles by 90 degree with mouse wheeling during a block rotatation jigging:
[CommandMethod("TestJigWithMouseWheelSupport")]
public static void TestJigWithMouseWheelSupport_Method()
{
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
Database db = HostApplicationServices.WorkingDatabase;
PromptEntityResult selRes = ed.GetEntity("Pick a block to rotate (mouse wheel up/down for 90 degree increment/decrement:");
if (selRes.Status == PromptStatus.OK)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockReference ent = tr.GetObject(selRes.ObjectId, OpenMode.ForWrite) as BlockReference;
if (ent != null)
{
using (Transaction tr1 = db.TransactionManager.StartTransaction())
{
ent.Highlight();
tr1.Commit();
}
if (BlockRotating2.Jig(ent))
tr.Commit();
else
tr.Abort();
}
}
}
}
Here was how the block rotating jig behaved when the moust wheel was being rolled up or down:
As can be noticed, the jig already honored UCS. But the block (BlockTableReference/INSERT) attributes were not taken into account for the purpose of mouse wheel support. In fact, a few posts have already talked about how to move, rotate, or scale those block attributes along with its host block reference using the EntityJig technology. Please refer to early posts if interested.
Here is the enhanced BlockRotating jig class along with the mouse wheel (both up and down) message filtering and hookup code.
#region Namespaces
using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Windows;
using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;
#endregion
namespace AcadNetAddinWizard_Namespace
{
class MouseWheelMsgFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x20a && m.WParam != IntPtr.Zero && BlockRotating2.jigger != null) //WM_MOUSEWHEEL
{
Int32 highword = HighWord((Int32)m.WParam);
if ( highword > 0) // Scoll up or down?
{
BlockRotating2.jigger.mRotation += BlockRotating2.anglePerScroll;
}
else
{
BlockRotating2.jigger.mRotation -= BlockRotating2.anglePerScroll;
}
BlockRotating2.jigger.mRotation = (int)(BlockRotating2.jigger.mRotation / (Math.PI / 2)) * Math.PI / 2;
BlockRotating2.jigger.UpdateRotation();
return true;
}
return false;
}
public static Int32 HighWord(Int32 word)
{
return word >> 16;
}
}
public class BlockRotating2 : EntityJig
{
#region Constants
public const double anglePerScroll = 90; //Change it if necessary.
#endregion
#region Fields
public int mCurJigFactorNumber = 1;
public double mRotation = 0.0; // Factor #1
private double mAngleOffset;
MouseWheelMsgFilter mMsgFilter;
#endregion
#region Constructors/Deconstructors
public BlockRotating2(Entity ent)
: base(ent)
{
mMsgFilter = new MouseWheelMsgFilter();
System.Windows.Forms.Application.AddMessageFilter(mMsgFilter);
mAngleOffset = (ent as BlockReference).Rotation;
}
~BlockRotating2()
{
System.Windows.Forms.Application.RemoveMessageFilter(mMsgFilter);
}
#endregion
public void UpdateRotation()
{
Entity.Rotation = mAngleOffset + mRotation;
Entity.Draw();
//TODO: Move the current cursor to a good position.
}
#region Overrides
public new BlockReference Entity
{
get
{
return (base.Entity as BlockReference);
}
}
protected override bool Update()
{
switch (mCurJigFactorNumber)
{
case 1:
Entity.Rotation = mAngleOffset + 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.Position;
prOptions1.UseBasePoint = true;
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 BlockRotating2 jigger;
public static bool Jig(BlockReference ent)
{
try
{
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
jigger = new BlockRotating2(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
}
}
A few highlights about the code may be helpful:
• An entity type needs to be specified in the EntityJig derivative, as BlockReference here.
• The Sampler() override is to acquire input for the position and the rotation angle in a certain order.
• If the input is the same as the stored variable, we’d better return SamplerStatus.NoChange to avoid unnecessary flashing; if not, return SamplerStatus.OK.
• Please do not forget to handle the cancel/escape circumstance as demonstrated.
• The Update() override is to update the position and the rotation angle properties of the BlockReference in the same order as set in the Sampler().
• The Editor.Draw() is the power to fire the jig.
• Only after the jig succeeds should the BlockReference be updated to avoid entity messy.
• The Windows Forms IMessageFilter interface needs to be implemented to provide the mouse wheel message filtering support.
• The MOUSEWHEEL message has a specific value and parameter to indicate whether the mouse wheel has been rolled up or down. Detailed information can be got from the MSDN documentation about those Windows API.
• When the mouse wheel up or down messge happens, we need to update the block/insert rotation angle properly according and get its graphics refreshed. Another new approach is introduced here.
• The existing Update() mechanism may be used for the graphics refresh purpose as well, but it needs some redesign for the whole jig class. I would like to leave it as is at this point.
As commented out, still some tiny things need to be tidied up. The major one may be with updating the current cursor position accordingly after the rotation angle has been updated by the mouse wheel so that the block/INSERT could be updated properly right after the mouse wheel action. Otherwise, the block rotation angle will be overridden by the following mouse click. If interested, please go ahead and implement it as an exercise. A future post may also address this issue. Please stay tuned.
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides a coder, Entity Jigger, to help us create entity jig code automatically, quickly and reliably.
Hello,
How is the PreFilterMessage method utilized? I don't see a call to the method.
Thanks,
John H.
Posted by: John Herman | 09/07/2014 at 10:31 PM
It's called automatically by the message filter system after the filter class being registered.
Posted by: Spiderinnet1 | 09/08/2014 at 12:43 AM