Author Topic: Toggling CustomObjectSnapMode  (Read 6998 times)

0 Members and 1 Guest are viewing this topic.

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Toggling CustomObjectSnapMode
« on: March 07, 2015, 11:45:14 AM »
I've added a new CustomObjectSnapMode to my app, thanks to the help by the excellent examples from gile and n.yuan. It works well except for a few minor issues.

Issue #1, which I don't think has a solution but thought I'd ask anyway: My Osnap shows itself in the status bar Osnap toggles icon, but not in the context menu used when wanting to set a temporary osnap override. Is there any way to add to this menu?

Issue #2: This is actually kind of serious. I have a Transparent command setup in order to toggle the Osnap on/off, which works just fine, however it does not trigger the item in the status bar osnap menu to toggle with it. Which means the 2 settings can be out of sync. If it get toggled on via the menu, then toggled off via my command toggle, it still displays as being on in the menu. Then when I toggle it off in the menu it actually toggles it on. This is obviously undesirable behavior. Any ideas on how to solve this?

Here is what I'm using to toggle it:
Code - C#: [Select]
  1.         internal static void SetCustomOsnap(int cosmode)
  2.         {
  3.             if (!CustomObjectSnapMode.IsActive("Perp2d") && cosmode == 1)
  4.                 CustomObjectSnapMode.Activate("Perp2d");
  5.             else if (CustomObjectSnapMode.IsActive("Perp2d") && cosmode == 0)
  6.                 CustomObjectSnapMode.Deactivate("Perp2d");
  7.         }
  8.  
  9.         [CommandMethod("Perp2d", CommandFlags.Transparent)]
  10.         public void perp2dcommand()
  11.         {    
  12.             //this is just a toggle to turn on/off
  13.             m_cosmode.Value = m_cosmode.Value == 0 ? 1 : 0;
  14.             SetCustomOsnap(m_cosmode.Value);
  15.         }
  16.  

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #1 on: March 07, 2015, 03:44:55 PM »
Another question about the CustomObjectSnaps. Trying to get the Temporary override to work like the base Osnaps, where it is valid for the next pick only. So far, I'm coming up empty in my searches on this. Anyone ever try to do this and get it to work?

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Toggling CustomObjectSnapMode
« Reply #2 on: March 07, 2015, 11:45:12 PM »
just a shot in the dark while passing, do you need to set any snap environment variables as well for them to take affect with the UI (i.e. get/setvar). That is, perhaps you are changing a state during a command but to make the change stick you might need to set the system var??
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Toggling CustomObjectSnapMode
« Reply #3 on: March 08, 2015, 06:37:06 AM »
Hi Jeff,

I'm not sure to understand your issues, but I agree with MickD, using a system variable makes the things easier.

You can try the following little example which seems to work fine for me. Temporary override works without adding anything to the code and the 'ToggleFith' command seems to work fine too.

A .reg file to register a system variable. Change the key path to your suit (AutoCAD Vanilla French 2014 here)
Code: [Select]
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R19.1\ACAD-D001:40C\Variables\FITH_CUSTOSMODE]
@="0"
"LowerBound"=dword:00000000
"PrimaryType"=dword:0000138b
"StorageType"=dword:00000002
"UpperBound"=dword:00000001

A little C# snippet to define a custom osnap to the fith of a curve length.
Code - C#: [Select]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Geometry;
  3. using Autodesk.AutoCAD.GraphicsInterface;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System;
  6.  
  7. [assembly: ExtensionApplication(typeof(CustOsmodeSample.CustomOsnap))]
  8.  
  9. namespace CustOsmodeSample
  10. {
  11.     public class CustomOsnap : IExtensionApplication
  12.     {
  13.         private static Variable cosmode;
  14.  
  15.         public void Initialize()
  16.         {
  17.             cosmode = SystemObjects.Variables["FITH_CUSTOSMODE"];
  18.             cosmode.Changed += cosmode_Changed;
  19.  
  20.             FithGlyph glyph = new FithGlyph();
  21.  
  22.             CustomObjectSnapMode fthOsmode = new CustomObjectSnapMode("FTH", "FTH", "Fith", glyph);
  23.             FithOsnapInfo fthInfo = new FithOsnapInfo();
  24.             fthOsmode.ApplyToEntityType(
  25.                 RXClass.GetClass(typeof(Curve)), fthInfo.FithSnapInfoCurve);
  26.             fthOsmode.ApplyToEntityType(
  27.                 RXClass.GetClass(typeof(Entity)), fthInfo.FithSnapInfoEntity);
  28.  
  29.             SetCustomOsnap((short)cosmode.Value);
  30.         }
  31.  
  32.         public void Terminate()  { }
  33.  
  34.         void cosmode_Changed(object sender, VariableChangedEventArgs e)
  35.         {
  36.             SetCustomOsnap((short)e.NewValue);
  37.         }
  38.  
  39.         private void SetCustomOsnap(int value)
  40.         {
  41.             if (value == 1 && !CustomObjectSnapMode.IsActive("FTH"))
  42.                 CustomObjectSnapMode.Activate("FTH");
  43.             else if (value == 0 && CustomObjectSnapMode.IsActive("FTH"))
  44.                 CustomObjectSnapMode.Deactivate("FTH");
  45.         }
  46.  
  47.         [CommandMethod("ToggleFith", CommandFlags.Transparent)]
  48.         public static void ToggleFith()
  49.         {
  50.             cosmode.Value = (short)((short)cosmode.Value ^ 1);
  51.         }
  52.     }
  53.  
  54.     class FithGlyph : Glyph
  55.     {
  56.         private Point3d point;
  57.  
  58.         public override void SetLocation(Point3d point)
  59.         {
  60.             this.point = point;
  61.         }
  62.  
  63.         protected override void SubViewportDraw(ViewportDraw vd)
  64.         {
  65.             int glyphPixels = CustomObjectSnapMode.GlyphSize;
  66.             Point2d glyphSize = vd.Viewport.GetNumPixelsInUnitSquare(point);
  67.             double dist = (glyphPixels / glyphSize.Y) * 0.8;
  68.             Matrix3d e2w = vd.Viewport.EyeToWorldTransform;
  69.             double angle = Math.PI / 2.0;
  70.             double  incr = 2.0 * Math.PI / 5.0;
  71.             Point3d[] points =
  72.             {
  73.                 Polar(point, angle, dist),
  74.                 Polar(point, angle + incr, dist),
  75.                 Polar(point, angle + 2 * incr, dist),
  76.                 Polar(point, angle + 3 * incr, dist),
  77.                 Polar(point, angle + 4 * incr, dist)
  78.             };
  79.             vd.SubEntityTraits.LineWeight = LineWeight.LineWeight030;
  80.             vd.Geometry.Polygon(new Point3dCollection(points));
  81.         }
  82.  
  83.         private Point3d Polar(Point3d point, double angle, double distance)
  84.         {
  85.             return new Point3d(
  86.                 point.X + distance * Math.Cos(angle),
  87.                 point.Y + distance * Math.Sin(angle),
  88.                 point.Z);
  89.         }
  90.     }
  91.  
  92.     class FithOsnapInfo
  93.     {
  94.         public void FithSnapInfoCurve(ObjectSnapContext context, ObjectSnapInfo result)
  95.         {
  96.             Curve curve = context.PickedObject as Curve;
  97.             if (curve == null || curve is Xline || curve is Ray || curve is Spline)
  98.                 return;
  99.             double len = curve.GetDistanceAtParameter(curve.EndParam);
  100.             double dist = len / 5.0;
  101.             result.SnapPoints.Add(curve.GetPointAtDist(dist));
  102.             result.SnapPoints.Add(curve.GetPointAtDist(dist * 2.0));
  103.             result.SnapPoints.Add(curve.GetPointAtDist(dist * 3.0));
  104.             result.SnapPoints.Add(curve.GetPointAtDist(dist * 4.0));
  105.         }
  106.  
  107.         public void FithSnapInfoEntity(ObjectSnapContext context, ObjectSnapInfo result) { }
  108.     }
  109. }
  110.  
« Last Edit: March 08, 2015, 06:47:42 AM by gile »
Speaking English as a French Frog

BlackBox

  • King Gator
  • Posts: 3770
Re: Toggling CustomObjectSnapMode
« Reply #4 on: March 08, 2015, 10:44:38 AM »
FWIW -

In 2015+, no .REG file (or code to interface with Registry class) is needed if using Autoloader, as PackageContents.xml now supports custom System Variables,etc:

http://knowledge.autodesk.com/support/autocad/downloads/caas/CloudHelp/cloudhelp/2015/ENU/AutoCAD-Customization/files/GUID-3C25E517-8660-4BB7-9447-2310462EF06F-htm.html



Separately, Gile - just wanted to say thanks for the work you do, and so willingly offer here. I wonder how long it will take Autodesk to incorporate your work into AutoCAD as a 'new feature'?

 :-D
"How we think determines what we do, and what we do determines what we get."

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Toggling CustomObjectSnapMode
« Reply #5 on: March 08, 2015, 01:00:59 PM »
Thanks BlackBox.

Autodesk listened for me (almost one time).
When I was publishing OsnapPalette on Exchange Apps store (during August 2013), I had to build my own MSI because the Autodesk standard  installer for Exhange Apps do not allow to register the system variables the application needs (similar to the one shown upper). So, i suggested them to add this feature to the Autoloader mechanism, what thet finally did in 2015...

Anyway, for those who do not use AutoCAD 2015 and/or the Autoloader, they can also register system variables using the litlle helpers shown here. The following code (compiled as .exe) register the FITH_CUSTOSMODE system variable for all AutoCAD 2012 or later installed.

Code - C#: [Select]
  1. using Gile.AutocadRegistryServices;
  2.  
  3. namespace RegisterSysVar
  4. {
  5.     class Program
  6.     {
  7.         static void Main()
  8.         {
  9.             foreach (ProductKey key in AcadReg.GetProductKeysSince("R18.1"))
  10.             {
  11.                 key.RegisterSystemVariable(
  12.                     "FITH_CUSTOSMODE",
  13.                     SysVar.StorageType.PerUser,
  14.                     SysVar.PrimaryType.Short,
  15.                     SysVar.SecondaryType.Boolean,
  16.                     0,
  17.                     1);
  18.             }
  19.         }
  20.     }
  21. }

Speaking English as a French Frog

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #6 on: March 08, 2015, 01:30:30 PM »
Gile, thank you for that. Unfortunately, I am seeing the exact same behavior with your example as I am with mine. Note the status in the Osnap status bar form below. I had just toggled the Fith on, verified it is on by invoking the Line command and seeing the glyph's for this osnap. Yet the status is showing it as Off. If I then check that to be on, then invoke the Line command and trying to snap to another line, the osnap is no longer enabled. Also, I could only get the 'temporary override' to activate by issuing the 'togglefith transparent command. When I selected the point, the fith osnap was still active, meaning it wasn't temporary.

Blackbox, thanks for the reminder on the PackageContents.xml

FWIW, I was using a method to save/restore the setting in my Application's section of the registry. I think it is essentially the same as using the Custom System Variable except for the user being able to edit the value with the setvar command.



gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Toggling CustomObjectSnapMode
« Reply #7 on: March 08, 2015, 03:42:33 PM »
Hi,

To temporary override the FTH osnap (if not already activated), just type FTH at the prompt for a point.
The TOGGLEFITH command works fine for me either transparently or not.
See this video.
Speaking English as a French Frog

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #8 on: March 08, 2015, 06:04:20 PM »
Thanks again, Gile. First, you are absolutely correct about the osnap override...it's been so long since I actually typed in the override that I had been trying to use it like so: 'fth, which, of course, doesn't work. After I saw your video I had a DOH! moment, typed it correctly, and it works fine. Although I did learn that you cannot have a numeric character in the CustomObjsectSnap name, else this still doesn't work.

As for the toggle vs the osnap status...I tested again in 2014 and it works just as you show. I was using 2015 for my coding and it does not work the same as previous versions. SO I'm still stuck getting this working correctly for the newer version(s).

BlackBox

  • King Gator
  • Posts: 3770
Re: Toggling CustomObjectSnapMode
« Reply #9 on: March 08, 2015, 09:41:27 PM »
Thanks BlackBox.

Autodesk listened for me (almost one time).
When I was publishing OsnapPalette on Exchange Apps store (during August 2013), I had to build my own MSI because the Autodesk standard  installer for Exhange Apps do not allow to register the system variables the application needs (similar to the one shown upper). So, i suggested them to add this feature to the Autoloader mechanism, what thet finally did in 2015...

Well, for what it's worth, I too am a strong advocate for your custom OSNAP work, and made sure to point others in your direction recently.

I cannot comment further, due to NDA, unfortunately... Perhaps following this year's release, this will make more sense.

Cheers
"How we think determines what we do, and what we do determines what we get."

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #10 on: March 08, 2015, 10:15:05 PM »
I gave up, for now, trying to get this to work correctly. And since I need it to work in the 2013 & 2014 products, and a host of other negatives that entails (registry related) I decided to try an OsnapOverrule instead. This actually works quite well and can persist between sessions using my app's registry read/write tools. I will post the code tomorrow if anyone is interested.

BlackBox

  • King Gator
  • Posts: 3770
Re: Toggling CustomObjectSnapMode
« Reply #11 on: March 09, 2015, 01:30:28 PM »
"How we think determines what we do, and what we do determines what we get."

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #12 on: March 09, 2015, 02:09:35 PM »
Here is my condensed example code to override the Perpendicular ObjectSnap. The default behavior for this Osnap, when used with 3d linework, is to snap in a 3d direction. This is not desirable for surveyors and engineers who work in 2d with elevations, so I was asked if something like this could be done. As noted in the first section of this thread, I had originally intended to create a new CustomObjectSnap, which worked well enough, but the troubles I was having with it made it not the ideal solution.

So I took my first venture into Overrides and have found them to be not as scary as I had imagined. Based upon the example by n.yuan (also available via the link in my first post), I was able to put this together and have it working as I had anticipated. My app is a bit more robust, in that it saves/restores the current state, adds an icon to the Tray to visibly show the user which state is current and is also used to toggle the state.

Code - C#: [Select]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Geometry;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System;
  5.  
  6. namespace CustomOsnapTest
  7. {
  8.     public class PerpOverruleTest : OsnapOverrule
  9.     {
  10.         private bool _overruling;
  11.  
  12.         public PerpOverruleTest()
  13.         {
  14.             _overruling = Overruling;
  15.             Overruling = true;
  16.             Overrule.AddOverrule(RXClass.GetClass(typeof(Curve)), this, false);
  17.         }
  18.  
  19.         public void Terminate()
  20.         {
  21.             Overrule.RemoveOverrule(RXClass.GetClass(typeof(Curve)), this);
  22.             Overruling = _overruling;
  23.         }
  24.  
  25.         public override void GetObjectSnapPoints(
  26.         Entity entity, ObjectSnapModes snapMode, IntPtr gsSelectionMark,
  27.         Point3d pickPoint, Point3d lastPoint, Matrix3d viewTransform,
  28.         Point3dCollection snapPoints, IntegerCollection geometryIds)
  29.         {
  30.             Curve curve = entity as Curve;
  31.  
  32.             snapPoints.Clear();
  33.             snapMode = ObjectSnapModes.ModePerpendicular;
  34.  
  35.             var cv2d = curve.GetOrthoProjectedCurve(new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis));
  36.             var pt = new Point3d(lastPoint.X, lastPoint.Y, 0);
  37.             var perppt = cv2d.GetClosestPointTo(pt, true);
  38.             snapPoints.Add(perppt);
  39.         }
  40.    
  41.     }
  42.  
  43.     public class OverrideTest
  44.     {
  45.         PerpOverruleTest perpover;
  46.         [CommandMethod("perptesttoggle")]
  47.         public void perptestcommand()
  48.         {
  49.             if (perpover == null)
  50.             {
  51.                 perpover = new PerpOverruleTest();
  52.                 Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n***Perpendicular set to 2d snapping only!***");
  53.             }
  54.             else
  55.             {
  56.                 perpover.Terminate();
  57.                 Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n***Perpendicular set to default of 3d snapping!***");
  58.                 perpover = null;
  59.             }
  60.         }
  61.     }
  62. }
  63.  
  64.  
« Last Edit: March 09, 2015, 02:18:02 PM by Jeff_M »

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #13 on: March 07, 2016, 08:03:39 PM »
Dredging up another old post, this time one of my own since my solution then doesn't work. Here's is some updated code which is working, for the most part. It is not working when the user wants/needs to use the Tangent Osnap with the first pick point...and example of needing this is using the TTR Circle creation command and selecting a point on a line. Without my overrule running, the normal Tangent glyph is displayed and the user can pick a point, however, with the overrule running no glyph is shown and no pick is allowed. I have no idea why...

Here is the code, hopefully someone can point me to what I've done wrong.
Code - C#: [Select]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Geometry;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.Civil.DatabaseServices;
  5. using System;
  6. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  7.  
  8. namespace Quux.SincpacC3D.ObjectSnaps
  9. {
  10.     public class PerpOverrule : OsnapOverrule
  11.     {
  12.         private bool _overruling;
  13.         private ObjectId _entId = ObjectId.Null;
  14.  
  15.         public PerpOverrule()
  16.         {
  17.             _overruling = Overruling;
  18.             Overruling = true;
  19.             Overrule.AddOverrule(RXClass.GetClass(typeof(Curve)), this, true);
  20.         }
  21.  
  22.         public void Terminate()
  23.         {
  24.             Overrule.RemoveOverrule(RXClass.GetClass(typeof(Curve)), this);
  25.             Overruling = _overruling;
  26.         }
  27.  
  28.         public override void GetObjectSnapPoints(AcDb.Entity entity, ObjectSnapModes snapMode, IntPtr gsSelectionMark,
  29.             Point3d pickPoint, Point3d lastPoint, Matrix3d viewTransform, Point3dCollection snapPoints, IntegerCollection geometryIds)
  30.         {
  31.             if (snapMode == ObjectSnapModes.ModePerpendicular)
  32.             {
  33.                 Point3d pt1 = new Point3d(pickPoint.X, pickPoint.Y, 0);
  34.                 Point3d pt2 = new Point3d(lastPoint.X, lastPoint.Y, 0);
  35.  
  36.                     Curve poly = (Curve)entity;
  37.                     Curve flattenedpoly = (Curve)poly.GetOrthoProjectedCurve(new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis));
  38.                     //some C3D objects derive from Curve but do not support the following line.
  39.                     try
  40.                     {
  41.                         base.GetObjectSnapPoints(flattenedpoly, snapMode, gsSelectionMark, pt1, pt2, viewTransform, snapPoints, geometryIds);
  42.                     }
  43.                     catch { }
  44.                
  45.             }
  46.             else //it's any snapmode other than perpendicular
  47.             {
  48.                 try
  49.                 {
  50.                     base.GetObjectSnapPoints(entity, snapMode, gsSelectionMark, pickPoint, lastPoint, viewTransform, snapPoints, geometryIds);
  51.                 }
  52.                 catch { }
  53.             }
  54.         }
  55.  
  56.     }
  57.  
  58.     public class PerpOverrideToggle
  59.     {
  60.         public static PerpOverrule perpoverride = null;
  61.  
  62.         [CommandMethod("Perp2dtoggle", CommandFlags.Transparent)]
  63.         public void perptestcommand()
  64.         {
  65.             if (perpoverride == null)
  66.             {
  67.                 perpoverride = new PerpOverrule();
  68.                 Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n***Perpendicular set to 2d snapping only!***");
  69.             }
  70.             else
  71.             {
  72.                 perpoverride.Terminate();
  73.                 Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n***Perpendicular set to default of 3d snapping!***");
  74.                 perpoverride = null;
  75.             }
  76.         }
  77.     }
  78. }
  79.  
  80.  

BlackBox

  • King Gator
  • Posts: 3770
Re: Toggling CustomObjectSnapMode
« Reply #14 on: March 07, 2016, 09:30:18 PM »
Not sure if this is what you need, but have you tried adding a companion GeometryOverrule?

I'll have to find the code I did last year for an informal app I did, that allowed me to disable/reenable snap points for entities on locked layers - something inspired by SincPac's ParcelOffset Command, so I could limit the available snap points, using my current OSMODE, to only those layers which were unlocked.

In any event, to account for non-literal snap points, I found that I had to also implement a GeometryOverrule.

http://through-the-interface.typepad.com/through_the_interface/2013/12/disabling-snapping-to-specific-autocad-objects-using-net-part-2.html


HTH
"How we think determines what we do, and what we do determines what we get."

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Toggling CustomObjectSnapMode
« Reply #15 on: March 16, 2016, 12:59:49 PM »
FYI, I posted about the Deferred Osnap issue on the Autodesk .NET forum. No responses until today, and it looks like it's stumping the ADN guy as well. We'll see if they can come up with a solution.

BlackBox

  • King Gator
  • Posts: 3770
Re: Toggling CustomObjectSnapMode
« Reply #16 on: March 16, 2016, 02:25:13 PM »
FYI, I posted about the Deferred Osnap issue on the Autodesk .NET forum. No responses until today, and it looks like it's stumping the ADN guy as well. We'll see if they can come up with a solution.

Thanks for sharing, Jeff -

That info may also help with this Idea Station thread.

Cheers
"How we think determines what we do, and what we do determines what we get."