明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
123
返回列表 发新帖

[Kean专集] Kean专题(9)—Object_Properties

   关闭 [复制链接]
 楼主| 发表于 2009-8-18 11:37:00 | 显示全部楼层
二、更改动态块属性
March 06, 2009
Painting properties between dynamic AutoCAD blocks using .NET
In the last post we looked at some code that essentially dumped out the dynamic properties of dynamic blocks to the command-line. In this post we take it a step further and capture the properties from one dynamic block reference and attempt to apply them to another.
We're going to apply slightly different logic, depending on the situation...
If the block references refer to the same dynamic block definition (i.e. their DynamicBlockTableRecord property contains the same ObjectId) then we'll assume they have the same dynamic properties in the same order. So we'll go through and attempt to copy the property value from the first to the second. This may be a flawed approach, I don't know enough to say whether there are situations where dynamic blocks might have different sets of properties or properties in a different order... if it proves to be a problem, it'd be a simple matter to remove this clause and rely on the second approach for all dynamic block references.
If the block references refer to different dynamic block definitions (i.e. their DynamicBlockTableRecord property contains different ObjectIds) then we use a slightly more elaborate approach: we go through the dynamic properties of the "source" dynamic block reference and store them in a dictionary. We then go through the dynamic properties of the "target" dynamic block reference, and if we find a value in the list we then attempt to apply it to this reference. In this way we should be able to paint properties across blocks - as long as they have the same name - even if they don't have the same overall make-up.
Here's the C# code:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System.Collections.Generic;
  7. namespace DynamicBlocks2
  8. {
  9.   public class Commands
  10.   {
  11.     [CommandMethod("ADBP")]
  12.     static public void ApplyDynamicBlockProps()
  13.     {
  14.       Document doc =
  15.         Application.DocumentManager.MdiActiveDocument;
  16.       Database db = doc.Database;
  17.       Editor ed = doc.Editor;
  18.       // Select the source and target block references
  19.       PromptEntityOptions peo =
  20.         new PromptEntityOptions(
  21.           "\nSelect source dynamic block reference: "
  22.         );
  23.       peo.SetRejectMessage("\nEntity is not a block.");
  24.       peo.AddAllowedClass(typeof(BlockReference), false);
  25.       PromptEntityResult per =
  26.         ed.GetEntity(peo);
  27.       if (per.Status != PromptStatus.OK)
  28.         return;
  29.       ObjectId sourceId = per.ObjectId;
  30.       peo.Message =
  31.         "\nSelect target dynamic block reference: ";
  32.       per = ed.GetEntity(peo);
  33.       if (per.Status != PromptStatus.OK)
  34.         return;
  35.       ObjectId targetId = per.ObjectId;
  36.       Transaction tr =
  37.         db.TransactionManager.StartTransaction();
  38.       using (tr)
  39.       {
  40.         // Open our block references: the source (br1)
  41.         // for read and the target (br2) for write
  42.         BlockReference br1 =
  43.           (BlockReference)tr.GetObject(
  44.             sourceId,
  45.             OpenMode.ForRead
  46.           );
  47.         BlockReference br2 =
  48.           (BlockReference)tr.GetObject(
  49.             targetId,
  50.             OpenMode.ForWrite
  51.           );
  52.         // They must both be dynamic block references
  53.         if (br1 != null && br1.IsDynamicBlock &&
  54.             br2 != null && br2.IsDynamicBlock)
  55.         {
  56.           if (br1.DynamicBlockTableRecord ==
  57.               br2.DynamicBlockTableRecord)
  58.           {
  59.             // They use the same block definition - let's assume
  60.             // the properties are in the same order
  61.             DynamicBlockReferencePropertyCollection pc1 =
  62.               br1.DynamicBlockReferencePropertyCollection;
  63.             DynamicBlockReferencePropertyCollection pc2 =
  64.               br2.DynamicBlockReferencePropertyCollection;
  65.             if (pc1.Count == pc2.Count)
  66.             {
  67.               for (int i = 0; i < pc1.Count; i++)
  68.               {
  69.                 // Get each property. If they have the same
  70.                 // name and are not read-only, attempt to
  71.                 // copy the value from the source (prop1)
  72.                 // to the target (prop2)
  73.                 DynamicBlockReferenceProperty prop1 = pc1[i],
  74.                                               prop2 = pc2[i];
  75.                 if (prop1.PropertyName == prop2.PropertyName &&
  76.                     !prop1.ReadOnly && !prop2.ReadOnly)
  77.                 {
  78.                   prop2.Value = prop1.Value;
  79.                 }
  80.               }
  81.             }
  82.           }
  83.           else
  84.           {
  85.             // If the block references refer to different
  86.             // dynamic block definitions, let's collect the
  87.             // properties for the first in a dictionary and
  88.             // attempt to apply them to the second
  89.             DynamicBlockReferencePropertyCollection pc1 =
  90.               br1.DynamicBlockReferencePropertyCollection;
  91.             // Create and populate our dictionary
  92.             Dictionary<string, DynamicBlockReferenceProperty> dict =
  93.               new
  94.               Dictionary<string, DynamicBlockReferenceProperty>();
  95.             foreach (DynamicBlockReferenceProperty prop in pc1)
  96.             {
  97.               if (!prop.ReadOnly &&
  98.                   !dict.ContainsKey(prop.PropertyName))
  99.                 dict.Add(prop.PropertyName, prop);
  100.             }
  101.             // Try to copy them to the target block reference's
  102.             // dynamic properties
  103.             DynamicBlockReferencePropertyCollection pc2 =
  104.               br2.DynamicBlockReferencePropertyCollection;
  105.             foreach (DynamicBlockReferenceProperty prop2 in pc2)
  106.             {
  107.               if (!prop2.ReadOnly &&
  108.                   dict.ContainsKey(prop2.PropertyName))
  109.               {
  110.                 try
  111.                 {
  112.                   DynamicBlockReferenceProperty prop1;
  113.                   if (dict.TryGetValue(
  114.                         prop2.PropertyName, out prop1
  115.                     )
  116.                   )
  117.                   {
  118.                     if (prop2.PropertyTypeCode ==
  119.                         prop1.PropertyTypeCode)
  120.                     {
  121.                       prop2.Value = prop1.Value;
  122.                     }
  123.                   }
  124.                 }
  125.                 // Expand if you want to diagnose specific issues
  126.                 catch { }
  127.               }
  128.             }
  129.           }
  130.         }
  131.         else
  132.         {
  133.           ed.WriteMessage(
  134.             "\nYou need to select two dynamic bock references."
  135.           );
  136.         }
  137.         tr.Commit();
  138.       }
  139.     }
  140.   }
  141. }
Let's see what happens when we put our ADBP command through its paces. Here's our initial state - we have two differently-sized instances of the same dynamic block, plus one instance of a different dynamic block (which shares parameters - the left-hand block is a "Hex Socket Bolt (Side)" while the right-hand block is a "Hex Nut" - both these blocks are available in the "Mechanical - Metric.dwg" sample file in the Samples\Dynamic Blocks folder of your AutoCAD installation).

Dynamic block references
Here's where we are when we run our ADBP command and select the block reference at the top followed by the block reference at the bottom-left:

Dynamic block references - after paint from top to bottom elevation view
So we see it works on references of the same dynamic block definition. Now let's try it, selecting one of the left-hand elevation views on the bolt, followed by the plan view of the nut on the right:

Dynamic block references - after paint from elevation to plan view
Because they share a dynamic property ("Size", which went from "M10" to "M14"), we were able to "paint" from one to the other.
With AutoCAD 2010 you'll be able to create constraints between geometry - which is a much simpler and more powerful approach - but what we've seen in this post should be of use to people working with dynamic blocks today.
By the way - for those of you with ADN website access - I used this DevNote as inspiration for how to modify properties in a dynamic block reference: How to programmatically insert a dynamic block with attributes containing dynamic parameters? (requires login.) Thanks to Fernando for pointing me to it (at that point in my research I had not quite gotten as far as checking the ADN website... ahem), as well as for suggesting this topic in the first place.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
 楼主| 发表于 2009-9-6 19:31:00 | 显示全部楼层
uly 15, 2009
Adding a dynamic distance property to an AutoCAD object using .NET
Back in these previous posts, we introduced an ObjectARX module that exposed AutoCAD’s Property Palette to .NET (thanks again to Cyrille Fauvel for his work on this :-). In this post we’re going to build on this work to demonstrate how to integrate properties with more advanced editing controls into the Property Palette.
[Note: this sample does not deal with persisting the data with an object. If you want to store your data with a particular object, I suggest taking a look at this previous post which demonstrates how to use Xdata to do so.]
This code is being built on top of the sample project provided with the OPM .NET implementation, which I’ve posted previously for AutoCAD 2007-2009 and for AutoCAD 2010. It defines a custom dynamic property – much like the original CustomProp, an integer property – but this one implements a new interface, IAcPiPropertyDisplay. This special interface allows you to – among other things – specify a custom editing control, which gets instantiated by the Property Palette and is then used to allow editing of the property.
The ObjectARX documentation contains this information on the main method we’re interested in implementing, GetCustomPropertyCtrl():
    Supplies a custom ActiveX control for property display/edit on a per-property basis.
    Before attempting to pick one of the ACPEX stock custom ActiveX controls for property display/edit, the Property Inspector calls this method to see if the object/command wishes to supply its own custom ActiveX control. This method is called on a per-property basis (both static and dynamic) for an object/command whose properties are active for display in the Property Inspector.
    The supplied custom control must implement IPropertyEditCtrl to be displayed for property value display/edit. The Property Inspector releases the output BSTR pointer after its use.
We want to enable this interface for use from .NET. In the previous cases we’ve had to do some extra work to expose or enable our Property Palette interfaces for use from .NET, but luckily this work has already been done for AutoCAD’s Tool Palette implementation. We can now simply add an assembly reference to AcTcMgd.dll and include the Autodesk.AutoCAD.Windows.ToolPalette namespace in our code.
[Note: I found this assembly in the inc-win32 folder of the ObjectARX SDK for AutoCAD 2010 (I’m running AutoCAD 2010 on Vista 32-bit), and it’s not clear to me when exactly we delivered this implementation - whether it was done for AutoCAD 2010 or beforehand. If AcTcMgd.dll is not available for your version of AutoCAD, it is still an option to expose this interface for use from .NET yourself, following the examples shown when we originally introduced the OPM .NET implementation.]
When we implement our GetCustomPropertyCtrl() method, we then need to set the string output argument to the ProgId of the editing control we wish to use. To decide an appropriate ProgId, I looked into the Registry, to identify the candidates:

Various AcPEXCtl ProgIds in the Registry
It’s also possible to implement your own truly custom editing control exposing the IPropertyEditCtrl interface, but that’s way beyond the scope of this post. :-)
For our custom distance property, we’re going to use a (standard) custom control that allows the user to select two points in the drawing; the distance between them then gets set as our dynamic property’s value. The ProgId for this control is “AcPEXCtl.AcPePick2PointsCtrl.16”.
Otherwise the methods of IAcPiPropertyDisplay should be fairly straightforward to understand, although perhaps IsFullView() requires a little explanation: the “visible” parameter actually indicates whether the control should take up the whole of the row – obscuring the property name – which is why we set it to false.
One final note: I’ve remapped the GUID for the property, to prevent it from conflicting with the previous CustomProp implementation.
Here’s the C# code for our custom distance property:
  1. using Autodesk.AutoCAD.Runtime;
  2. using Autodesk.AutoCAD.Windows.OPM;
  3. using Autodesk.AutoCAD.Windows.ToolPalette;
  4. using System;
  5. using System.Reflection;
  6. using System.Runtime.InteropServices;
  7. namespace OPMNetSample
  8. {
  9.   #region Our Custom Distance Property
  10.   [
  11.     Guid("78286EBD-7380-4bb5-9EA6-1742677FA2E3"),
  12.     ProgId("OPMNetSample.DistanceProperty.1"),
  13.     ClassInterface(ClassInterfaceType.None),
  14.     ComDefaultInterface(typeof(IDynamicProperty2)),
  15.     ComVisible(true)
  16.   ]
  17.   public class DistanceProp : IDynamicProperty2, IAcPiPropertyDisplay
  18.   {
  19.     private IDynamicPropertyNotify2 _pSink = null;
  20.     private double _value = 0.0;
  21.     #region IDynamicProperty2 methods
  22.     // Unique property ID
  23.     public void GetGUID(out Guid propGUID)
  24.     {
  25.       propGUID =
  26.         new Guid("78286EBD-7380-4bb5-9EA6-1742677FA2E3");
  27.     }
  28.     // Property display name
  29.     public void GetDisplayName(out string szName)
  30.     {
  31.       szName = "Distance";
  32.     }
  33.     // Show/Hide property in the OPM, for this object instance
  34.     public void IsPropertyEnabled(object pUnk, out int bEnabled)
  35.     {
  36.       bEnabled = 1;
  37.     }
  38.     // Is property showing but disabled
  39.     public void IsPropertyReadOnly(out int bReadonly)
  40.     {
  41.       bReadonly = 0;
  42.     }
  43.     // Get the property description string
  44.     public void GetDescription(out string szName)
  45.     {
  46.       szName =
  47.         "This distance property is from picking two points";
  48.     }
  49.     // OPM will typically display these in an edit field
  50.     // optional: meta data representing property type name,
  51.     // ex. ACAD_ANGLE
  52.     public void GetCurrentValueName(out string szName)
  53.     {
  54.       throw new System.NotImplementedException();
  55.     }
  56.     // What is the property type, ex. VT_R8
  57.     public void GetCurrentValueType(out ushort varType)
  58.     {
  59.       // The Property Inspector supports the following data
  60.       // types for dynamic properties:
  61.       // VT_I2 (2), VT_I4 (3), VT_R4 (4), VT_R8 (5),
  62.       // VT_BSTR (8), VT_BOOL (11), and VT_USERDEFINED (29).
  63.       varType = 4; // VT_R4
  64.     }
  65.     // Get the property value, passes the specific object
  66.     // we need the property value for.
  67.     public void GetCurrentValueData(object pUnk, ref object pVarData)
  68.     {
  69.       pVarData = _value;
  70.     }
  71.     // Set the property value, passes the specific object we
  72.     // want to set the property value for
  73.     public void SetCurrentValueData(object pUnk, object varData)
  74.     {
  75.       _value = (double)varData;
  76.     }
  77.     // OPM passes its implementation of IDynamicPropertyNotify, you
  78.     // cache it and call it to inform OPM your property has changed
  79.     public void Connect(object pSink)
  80.     {
  81.       _pSink = (IDynamicPropertyNotify2)pSink;
  82.     }
  83.     public void Disconnect() {
  84.       _pSink = null;
  85.     }
  86.     #endregion
  87.     #region IAcPiPropertyDisplay methods
  88.     public void GetCustomPropertyCtrl(
  89.       object id, uint lcid, out string progId
  90.     )
  91.     {
  92.       progId = "AcPEXCtl.AcPePick2PointsCtrl.16";
  93.     }
  94.     public void GetPropertyWeight(object id, out int propertyWeight)
  95.     {
  96.       propertyWeight = 0;
  97.     }
  98.     public void GetPropertyIcon(object id, out object icon)
  99.     {
  100.       icon = null;
  101.     }
  102.     public void GetPropTextColor(object id, out uint textColor)
  103.     {
  104.       textColor = 0;
  105.     }
  106.     public void IsFullView(
  107.       object id, out bool visible, out uint integralHeight
  108.     )
  109.     {
  110.       visible = false;
  111.       integralHeight = 1;
  112.     }
  113.     #endregion
  114.   }
  115.   #endregion
  116.   #region Application Entry Point
  117.   public class MyEntryPoint : IExtensionApplication
  118.   {
  119.     protected internal DistanceProp distProp = null;
  120.     public void Initialize()
  121.     {
  122.       Assembly.LoadFrom("asdkOPMNetExt.dll");
  123.       // Add the Dynamic Property
  124.       Dictionary classDict = SystemObjects.ClassDictionary;
  125.       RXClass lineDesc = (RXClass)classDict.At("AcDbLine");
  126.       IPropertyManager2 pPropMan =
  127.         (IPropertyManager2)xOPM.xGET_OPMPROPERTY_MANAGER(lineDesc);
  128.       distProp = new DistanceProp();
  129.       pPropMan.AddProperty((object)distProp);
  130.     }
  131.     public void Terminate()
  132.     {
  133.       // Remove the Dynamic Property
  134.       Dictionary classDict = SystemObjects.ClassDictionary;
  135.       RXClass lineDesc = (RXClass)classDict.At("AcDbLine");
  136.       IPropertyManager2 pPropMan =
  137.         (IPropertyManager2)xOPM.xGET_OPMPROPERTY_MANAGER(lineDesc);
  138.       pPropMan.RemoveProperty((object)distProp);
  139.       distProp = null;
  140.     }
  141.   }
  142.   #endregion
  143. }
Here’s what we see when we NETLOAD the asdkOPMNetExt.dll and our OPMNetSample.dll, and then select a standard line:

Our new dynamic distance property on the line object
When we select the property we see we get a custom editing icon:

Our new dynamic distance property with its pick two points function
When we click that button, we get prompted to select two points in the drawing:
Pick a start point in the drawing:
Pick an end point in the drawing:
Once we’ve done so, the distance between the two points gets assigned to our property:

Bear in mind that we’re currently storing this value with the property, not with the line itself. So you’ll see the same value irrespective of the line you’ve selected. See the note at the beginning of this post if you wish to go further and attach this data per object.
I’m going to spend some time looking further into the capabilities of the custom control mechanism: in the next post in this series we’ll look at hosting a masked string (as in a password) dynamic property inside the Property Palette. If you have suggestions for additional controls to implement, please let me know (and I’ll see what I can figure out :-).

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
 楼主| 发表于 2009-9-6 19:36:00 | 显示全部楼层
July 20, 2009
Adding a dynamic password property to an AutoCAD object using .NET
In this recent post we looked at adding custom editing capabilities for dynamic properties we’ve added via .NET. In the first example we looked at a “distance” property which provided a button allowing the user to select two points. In this post we’ll look at implementing a masked string property, such as one you would use for a password.
I won’t repeat too much of the background information from the last post in this series: you should refer to that to understand the fundamentals (the fact that we’re basing this implementation on Cyrille Fauvel’s OPM .NET sample, that we’re not dealing with per-object persistence, and that we’re using “stock” ActiveX editing controls we’ve discovered via the Registry). That said, the code we’re providing here stands alone from the code in the last post, even if it’s altogether possible to combine them.
Here is the C# code to implement a simple, masked string dynamic property:
  1. using Autodesk.AutoCAD.Runtime;
  2. using Autodesk.AutoCAD.Windows.OPM;
  3. using Autodesk.AutoCAD.Windows.ToolPalette;
  4. using System;
  5. using System.Reflection;
  6. using System.Runtime.InteropServices;
  7. namespace OPMNetSample
  8. {
  9.   #region Our Custom Password Property
  10.   [
  11.     Guid("B5D9010E-48A2-4bfb-8601-76A7B1007C68"),
  12.     ProgId("OPMNetSample.PasswordProperty.1"),
  13.     ClassInterface(ClassInterfaceType.None),
  14.     ComDefaultInterface(typeof(IDynamicProperty2)),
  15.     ComVisible(true)
  16.   ]
  17.   public class PasswordProp : IDynamicProperty2, IAcPiPropertyDisplay
  18.   {
  19.     private IDynamicPropertyNotify2 _pSink = null;
  20.     private string _password = "";
  21.     #region IDynamicProperty2 methods
  22.     // Unique property ID
  23.     public void GetGUID(out Guid propGUID)
  24.     {
  25.       propGUID =
  26.         new Guid("B5D9010E-48A2-4bfb-8601-76A7B1007C68");
  27.     }
  28.     // Property display name
  29.     public void GetDisplayName(out string szName)
  30.     {
  31.       szName = "Password";
  32.     }
  33.     // Show/Hide property in the OPM, for this object instance
  34.     public void IsPropertyEnabled(object pUnk, out int bEnabled)
  35.     {
  36.       bEnabled = 1;
  37.     }
  38.     // Is property showing but disabled
  39.     public void IsPropertyReadOnly(out int bReadonly)
  40.     {
  41.       bReadonly = 0;
  42.     }
  43.     // Get the property description string
  44.     public void GetDescription(out string szName)
  45.     {
  46.       szName =
  47.         "This masked property is a string";
  48.     }
  49.     // OPM will typically display these in an edit field
  50.     // optional: meta data representing property type name,
  51.     // ex. ACAD_ANGLE
  52.     public void GetCurrentValueName(out string szName)
  53.     {
  54.       throw new System.NotImplementedException();
  55.     }
  56.     // What is the property type, ex. VT_R8
  57.     public void GetCurrentValueType(out ushort varType)
  58.     {
  59.       // The Property Inspector supports the following data
  60.       // types for dynamic properties:
  61.       // VT_I2 (2), VT_I4 (3), VT_R4 (4), VT_R8 (5),
  62.       // VT_BSTR (8), VT_BOOL (11), and VT_USERDEFINED (29).
  63.       varType = 8; // VT_BSTR
  64.     }
  65.     // Get the property value, passes the specific object
  66.     // we need the property value for.
  67.     public void GetCurrentValueData(object pUnk, ref object pVarData)
  68.     {
  69.       pVarData = _password;
  70.     }
  71.     // Set the property value, passes the specific object we
  72.     // want to set the property value for
  73.     public void SetCurrentValueData(object pUnk, object varData)
  74.     {
  75.       _password = varData.ToString();
  76.       System.Windows.Forms.MessageBox.Show(
  77.         "String entered was "" + _password + ""."
  78.       );
  79.     }
  80.     // OPM passes its implementation of IDynamicPropertyNotify, you
  81.     // cache it and call it to inform OPM your property has changed
  82.     public void Connect(object pSink)
  83.     {
  84.       _pSink = (IDynamicPropertyNotify2)pSink;
  85.     }
  86.     public void Disconnect() {
  87.       _pSink = null;
  88.     }
  89.     #endregion
  90.     #region IAcPiPropertyDisplay methods
  91.     public void GetCustomPropertyCtrl(
  92.       object id, uint lcid, out string progId
  93.     )
  94.     {
  95.       progId = "AcPEXCtl.AcPePropertyEditorPwdText.16";
  96.     }
  97.     public void GetPropertyWeight(object id, out int propertyWeight)
  98.     {
  99.       propertyWeight = 0;
  100.     }
  101.     public void GetPropertyIcon(object id, out object icon)
  102.     {
  103.       icon = null;
  104.     }
  105.     public void GetPropTextColor(object id, out uint textColor)
  106.     {
  107.       textColor = 0;
  108.     }
  109.     public void IsFullView(
  110.       object id, out bool visible, out uint integralHeight
  111.     )
  112.     {
  113.       visible = false;
  114.       integralHeight = 1;
  115.     }
  116.     #endregion
  117.   }
  118.   #endregion
  119.   #region Application Entry Point
  120.   public class MyEntryPoint : IExtensionApplication
  121.   {
  122.     protected internal PasswordProp passProp = null;
  123.     public void Initialize()
  124.     {
  125.       Assembly.LoadFrom("asdkOPMNetExt.dll");
  126.       // Add the Dynamic Property
  127.       Dictionary classDict = SystemObjects.ClassDictionary;
  128.       RXClass lineDesc = (RXClass)classDict.At("AcDbLine");
  129.       IPropertyManager2 pPropMan =
  130.         (IPropertyManager2)xOPM.xGET_OPMPROPERTY_MANAGER(lineDesc);
  131.       passProp = new PasswordProp();
  132.       pPropMan.AddProperty((object)passProp);
  133.     }
  134.     public void Terminate()
  135.     {
  136.       // Remove the Dynamic Property
  137.       Dictionary classDict = SystemObjects.ClassDictionary;
  138.       RXClass lineDesc = (RXClass)classDict.At("AcDbLine");
  139.       IPropertyManager2 pPropMan =
  140.         (IPropertyManager2)xOPM.xGET_OPMPROPERTY_MANAGER(lineDesc);
  141.       pPropMan.RemoveProperty((object)passProp);
  142.       passProp = null;
  143.     }
  144.   }
  145.   #endregion
  146. }
Let’s see what happens when we NETLOAD the asdkOPMNetExt.dll and our OPMNetSample.dll, and then select a standard line:

Once we start entering a string inside our dynamic password property, we see it displayed as a masked string:

And once we finish entering our string, we can see that our code has the unmasked data available to it – here’s a MessageBox we throw up to display the contents:

If we really wanted to store this securely – to avoid any determined application from snooping the underlying data – then we would really need to encrypt it before assigning it to our object (whether in Xdata or an Xrecord stored in the extension dictionary of an object). Beyond that we might even want to take measures to make sure the variable – as stored in memory, not just persisted with the object – isn’t readable by external applications. But again, this is beyond the scope of this post, which is really just to introduce another property editing control available inside AutoCAD.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
 楼主| 发表于 2009-9-9 08:01:00 | 显示全部楼层
创建尺寸式样替代
September 07, 2009
Creating and overriding AutoCAD dimension styles using .NET
A request came in by email during last week’s vacation:
    I have been looking around to find a way about creating Dimension Style Overrides, but have not really had any success at anything yet. I have created program in which I do create several dimension styles, but I just keep getting lost with the overrides.
This seemed like a really good topic to cover, so this post contains some simple code that to create a dimension style and two nearly-identical linear dimensions: both use our newly-created dimension style but the second of the two also contains some Dimension Style Overrides, which we attach to the dimension via External Entity Data (XData).
Here’s the C# code:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. namespace DimStyleOverrideTest
  7. {
  8.   public class Commands
  9.   {
  10.     [CommandMethod("ODS")]
  11.     public void OverrideDimensionStyle()
  12.     {
  13.       Database db =
  14.         HostApplicationServices.WorkingDatabase;
  15.       Transaction tr =
  16.         db.TransactionManager.StartTransaction();
  17.       using (tr)
  18.       {
  19.         // Open our dimension style table to add our
  20.         // new dimension style
  21.         DimStyleTable dst =
  22.           (DimStyleTable)tr.GetObject(
  23.             db.DimStyleTableId, OpenMode.ForWrite
  24.           );
  25.         // Create our new dimension style
  26.         DimStyleTableRecord dstr =
  27.           new DimStyleTableRecord();
  28.         dstr.Dimtad = 2;
  29.         dstr.Dimgap = 0.3;
  30.         dstr.Name = "MyStyle";
  31.         // Add it to the dimension style table
  32.         ObjectId dsId = dst.Add(dstr);
  33.         tr.AddNewlyCreatedDBObject(dstr, true);
  34.         // Now create two identical dimensions, one
  35.         // next to the other, using our dimension
  36.         // style
  37.         AlignedDimension ad1 =
  38.           new AlignedDimension(
  39.             Point3d.Origin,
  40.             new Point3d(5.0, 0.0, 0.0),
  41.             new Point3d(2.5, 2.0, 0.0),
  42.             "Standard dimension",
  43.             dsId
  44.           );
  45.         // The only thing we change is the text string
  46.         AlignedDimension ad2 =
  47.           new AlignedDimension(
  48.             new Point3d(5.0, 0.0, 0.0),
  49.             new Point3d(10.0, 0.0, 0.0),
  50.             new Point3d(7.5, 2.0, 0.0),
  51.             "Overridden dimension",
  52.             dsId
  53.           );
  54.         /*
  55.         Now we'll add dimension overrides for DIMTAD
  56.         and DIMGAP via XData
  57.         Dimension variable group codes are:
  58.           DIMPOST     3
  59.           DIMAPOST    4
  60.           DIMSCALE   40
  61.           DIMASZ     41
  62.           DIMEXO     42
  63.           DIMDLI     43
  64.           DIMEXE     44
  65.           DIMRND     45
  66.           DIMDLE     46
  67.           DIMTP      47
  68.           DIMTM      48
  69.           DIMTOL     71
  70.           DIMLIM     72
  71.           DIMTIH     73
  72.           DIMTOH     74
  73.           DIMSE1     75
  74.           DIMSE2     76
  75.           DIMTAD     77
  76.           DIMZIN     78
  77.           DIMAZIN    79
  78.           DIMTXT    140
  79.           DIMCEN    141
  80.           DIMTSZ    142
  81.           DIMALTF   143
  82.           DIMLFAC   144
  83.           DIMTVP    145
  84.           DIMTFAC   146
  85.           DIMGAP    147
  86.           DIMALTRND 148
  87.           DIMALT    170
  88.           DIMALTD   171
  89.           DIMTOFL   172
  90.           DIMSAH    173
  91.           DIMTIX    174
  92.           DIMSOXD   175
  93.           DIMCLRD   176
  94.           DIMCLRE   177
  95.           DIMCLRT   178
  96.           DIMADEC   179
  97.           DIMDEC    271
  98.           DIMTDEC   272
  99.           DIMALTU   273
  100.           DIMALTTD  274
  101.           DIMAUNIT  275
  102.           DIMFRAC   276
  103.           DIMLUNIT  277
  104.           DIMDSEP   278
  105.           DIMATMOVE 279
  106.           DIMJUST   280
  107.           DIMSD1    281
  108.           DIMSD2    282
  109.           DIMTOLJ   283
  110.           DIMTZIN   284
  111.           DIMALTZ   285
  112.           DIMALTTZ  286
  113.           DIMUPT    288
  114.           DIMATFIT  289
  115.           DIMTXSTY  340
  116.           DIMLDRBLK 341
  117.           DIMBLK    342
  118.           DIMBLK1   343
  119.           DIMBLK2   344
  120.           DIMLWD    371
  121.           DIMLWE    372
  122.         Variables have different types: these can be found in
  123.         the ObjectARX Reference - search for "Dimension Style
  124.         Overrides"
  125.         */
  126.         ResultBuffer rb =
  127.           new ResultBuffer(
  128.             new TypedValue[8]{
  129.               new TypedValue(
  130.                 (int)DxfCode.ExtendedDataRegAppName, "ACAD"
  131.               ),
  132.               new TypedValue(
  133.                 (int)DxfCode.ExtendedDataAsciiString, "DSTYLE"
  134.               ),
  135.               new TypedValue(
  136.                 (int)DxfCode.ExtendedDataControlString, "{"
  137.               ),
  138.               new TypedValue(
  139.                 (int)DxfCode.ExtendedDataInteger16, 77  // DIMTAD
  140.               ),
  141.               new TypedValue(
  142.                 (int)DxfCode.ExtendedDataInteger16, 4   // Below
  143.               ),
  144.               new TypedValue(
  145.                 (int)DxfCode.ExtendedDataInteger16, 147 // DIMGAP
  146.               ),
  147.               new TypedValue(
  148.                 (int)DxfCode.ExtendedDataReal, 0.5      // Larger
  149.               ),
  150.               new TypedValue(
  151.                 (int)DxfCode.ExtendedDataControlString, "}"
  152.               )
  153.             }
  154.           );
  155.         // Set the XData on our object
  156.         ad2.XData = rb;
  157.         rb.Dispose();
  158.         // Now let's open the current space and add our two
  159.         // dimensions
  160.         BlockTableRecord btr =
  161.           (BlockTableRecord)tr.GetObject(
  162.             db.CurrentSpaceId,
  163.             OpenMode.ForWrite
  164.           );
  165.         btr.AppendEntity(ad1);
  166.         btr.AppendEntity(ad2);
  167.         tr.AddNewlyCreatedDBObject(ad1, true);
  168.         tr.AddNewlyCreatedDBObject(ad2, true);
  169.         // And commit the transaction, of course
  170.         tr.Commit();
  171.       }
  172.     }
  173.   }
  174. }
When we NETLOAD our application and run the ODS command, we see that two dimensions are created in the current space:

I won’t spend time on the specifics of the various dimension variables you can override using this mechanism – I’m sure many (if not most) of you know much more about AutoCAD’s dimension mechanism than I – but I have included the list of the various dimension variables’ group codes in a comment in the above code. For more information regarding the specific types of these variables – and their ranges, if applicable – I suggest searching for “Dimension Style Override” in the ObjectARX Reference.
Update
OK, I missed the obvious on this one (as does happen from time-to-time, as regular readers will by now be aware). Rather than setting the overrides directly via XData, there are handy properties belonging to the dimension’s managed interface that do this for you. Very cool. So we can reduce the code to the following:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. namespace DimStyleOverrideTest
  7. {
  8.   public class Commands
  9.   {
  10.     [CommandMethod("ODS")]
  11.     public void OverrideDimensionStyle()
  12.     {
  13.       Database db =
  14.         HostApplicationServices.WorkingDatabase;
  15.       Transaction tr =
  16.         db.TransactionManager.StartTransaction();
  17.       using (tr)
  18.       {
  19.         // Open our dimension style table to add our
  20.         // new dimension style
  21.         DimStyleTable dst =
  22.           (DimStyleTable)tr.GetObject(
  23.             db.DimStyleTableId, OpenMode.ForWrite
  24.           );
  25.         // Create our new dimension style
  26.         DimStyleTableRecord dstr =
  27.           new DimStyleTableRecord();
  28.         dstr.Dimtad = 2;
  29.         dstr.Dimgap = 0.3;
  30.         dstr.Name = "MyStyle";
  31.         // Add it to the dimension style table
  32.         ObjectId dsId = dst.Add(dstr);
  33.         tr.AddNewlyCreatedDBObject(dstr, true);
  34.         // Now create two identical dimensions, one
  35.         // next to the other, using our dimension
  36.         // style
  37.         AlignedDimension ad1 =
  38.           new AlignedDimension(
  39.             Point3d.Origin,
  40.             new Point3d(5.0, 0.0, 0.0),
  41.             new Point3d(2.5, 2.0, 0.0),
  42.             "Standard dimension",
  43.             dsId
  44.           );
  45.         // The only thing we change is the text string
  46.         AlignedDimension ad2 =
  47.           new AlignedDimension(
  48.             new Point3d(5.0, 0.0, 0.0),
  49.             new Point3d(10.0, 0.0, 0.0),
  50.             new Point3d(7.5, 2.0, 0.0),
  51.             "Overridden dimension",
  52.             dsId
  53.           );
  54.         // Isn't this easier?
  55.         ad2.Dimtad = 4;
  56.         ad2.Dimgap = 0.5;
  57.         // Now let's open the current space and add our two
  58.         // dimensions
  59.         BlockTableRecord btr =
  60.           (BlockTableRecord)tr.GetObject(
  61.             db.CurrentSpaceId,
  62.             OpenMode.ForWrite
  63.           );
  64.         btr.AppendEntity(ad1);
  65.         btr.AppendEntity(ad2);
  66.         tr.AddNewlyCreatedDBObject(ad1, true);
  67.         tr.AddNewlyCreatedDBObject(ad2, true);
  68.         // And commit the transaction, of course
  69.         tr.Commit();
  70.       }
  71.     }
  72.   }
  73. }
I managed to forget to name the style in the previous example, so I’ve gone ahead and fixed that in both sets of code.
And it turns out that the original question may actually have been about something different, so I’m now going to go away and look at that (and will create a new post, as needed).

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
 楼主| 发表于 2009-9-14 16:42:00 | 显示全部楼层
十六、操纵新创建填充的绘图顺序
March 30, 2007
Manipulating the draw order of a newly created AutoCAD hatch using .NET
This question came in from Limin as a comment in this previous post:
    Is there .Net interface for autocad command "DrawOrder"? For example: after solid-hatch a polyline, need to reorder polyline and hatch, how to make it happen using .NET?
I've put together some C# code to demonstrate how to do this:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. namespace HatchDrawOrder
  6. {
  7.   public class Commands
  8.   {
  9.     [CommandMethod("HDO")]
  10.     static public void HatchDrawOrder()
  11.     {
  12.       Document doc =
  13.         Application.DocumentManager.MdiActiveDocument;
  14.       Editor ed = doc.Editor;
  15.       // Ask the user to select a hatch boundary
  16.       PromptEntityOptions opt =
  17.         new PromptEntityOptions(
  18.           "\nSelect boundary: "
  19.         );
  20.       opt.SetRejectMessage("\nObject must be a curve.");
  21.       opt.AddAllowedClass(typeof(Curve), false);
  22.       PromptEntityResult res =
  23.         ed.GetEntity(opt);
  24.       if (res.Status == PromptStatus.OK)
  25.       {
  26.         Transaction tr =
  27.           doc.TransactionManager.StartTransaction();
  28.         using (tr)
  29.         {
  30.           // Check the entity is a closed curve
  31.           DBObject obj =
  32.             tr.GetObject(
  33.               res.ObjectId,
  34.               OpenMode.ForRead
  35.             );
  36.           Curve cur = obj as Curve;
  37.           if (cur != null && cur.Closed == false)
  38.           {
  39.             ed.WriteMessage("\nLoop must be a closed curve.");
  40.           }
  41.           else
  42.           {
  43.             // Add the hatch to the model space
  44.             BlockTable bt =
  45.               (BlockTable)tr.GetObject(
  46.                 doc.Database.BlockTableId,
  47.                 OpenMode.ForRead
  48.               );
  49.             BlockTableRecord btr =
  50.               (BlockTableRecord)tr.GetObject(
  51.                 bt[BlockTableRecord.ModelSpace],
  52.                 OpenMode.ForWrite
  53.               );
  54.             Hatch hat = new Hatch();
  55.             hat.SetDatabaseDefaults();
  56.             hat.SetHatchPattern(
  57.               HatchPatternType.PreDefined,
  58.               "SOLID"
  59.             );
  60.             ObjectId hatId = btr.AppendEntity(hat);
  61.             tr.AddNewlyCreatedDBObject(hat, true);
  62.             // Add the hatch loop and complete the hatch
  63.             ObjectIdCollection ids =
  64.               new ObjectIdCollection();
  65.             ids.Add(res.ObjectId);
  66.             hat.Associative = true;
  67.             hat.AppendLoop(
  68.               HatchLoopTypes.Default,
  69.               ids
  70.             );
  71.             hat.EvaluateHatch(true);
  72.             // Change the draworder of both hatch and loop
  73.             btr.DowngradeOpen();
  74.             ids.Add(hatId);
  75.             DrawOrderTable dot =
  76.               (DrawOrderTable)tr.GetObject(
  77.                 btr.DrawOrderTableId,
  78.                 OpenMode.ForWrite
  79.               );
  80.             dot.MoveToBottom(ids);
  81.             tr.Commit();
  82.           }
  83.         }
  84.       }
  85.     }
  86.   }
  87. }
The code to manipulate the draw order of these two entities is very simple - we have to open the DrawOrderTable for the space containing the entities we care about, and use it to change the order in which the entities are drawn. In this case I chose to send them both to the back of the draw order stack, but you might also manipulate their draw order relative to other entities in the drawing.
On a personal note, my family and I have arrived safely in Beijing - we're all a bit jet-lagged, but very happy to be here. The journey was thankfully uneventful, and with two young children that's really as much as you can hope for. :-)

 楼主| 发表于 2010-2-3 23:05:00 | 显示全部楼层
十七、创建非矩形的视口
December 14, 2009
Creating non-rectangular paperspace viewports in AutoCAD using .NET
Thanks to Philippe Leefsma, from DevTech in Europe, for the ObjectARX code that inspired this post.
In AutoCAD it’s possible to create non-rectangular viewports in paperspace using a variety of closed curve objects: circles, polylines (2D, 3D and lightweight), ellipses, regions, splines and faces. In this post we’re going to see some code that creates four new viewports in the paperspace of the active drawing using a subset of these objects: an Ellipse, a Circle, a closed Spline and a closed Polyline.
Here’s the C# code:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.EditorInput;
  5. using Autodesk.AutoCAD.Geometry;
  6. namespace ViewportCreation
  7. {
  8.   public class Commands
  9.   {
  10.     [CommandMethod("NRVPS")]
  11.     static public void CreateNonRectangularViewports()
  12.     {
  13.       Document doc =
  14.         Application.DocumentManager.MdiActiveDocument;
  15.       Database db = doc.Database;
  16.       Editor ed = doc.Editor;
  17.       // We're accessing drawing objects, so we need a transaction
  18.       Transaction tr = db.TransactionManager.StartTransaction();
  19.       using (tr)
  20.       {
  21.         // Get the primary paperspace from the block table
  22.         BlockTable bt =
  23.           (BlockTable)tr.GetObject(
  24.             db.BlockTableId,
  25.             OpenMode.ForRead
  26.           );
  27.         BlockTableRecord ps =
  28.           (BlockTableRecord)tr.GetObject(
  29.             bt[BlockTableRecord.PaperSpace],
  30.             OpenMode.ForWrite
  31.           );
  32.         // Create a variety of objects for our clip boundaries
  33.         DBObjectCollection objs = new DBObjectCollection();
  34.         // An ellipse...
  35.         Ellipse el =
  36.           new Ellipse(
  37.             new Point3d(3.5, 4.7, 0),
  38.             Vector3d.ZAxis,
  39.             new Vector3d(1.4, 0.03, 0),
  40.             0.35, 0, 0
  41.           );
  42.         objs.Add(el);
  43.         // A circle...
  44.         Circle cir =
  45.           new Circle(
  46.             new Point3d(3.4, 1.9, 0),
  47.             Vector3d.ZAxis,
  48.             0.9
  49.           );
  50.         objs.Add(cir);
  51.         // A closed polyline...
  52.         Polyline pl =
  53.           new Polyline(6);
  54.         pl.AddVertexAt(0, new Point2d(4.92, 5.29), 0, 0, 0);
  55.         pl.AddVertexAt(1, new Point2d(5.16, 6.02), 0, 0, 0);
  56.         pl.AddVertexAt(2, new Point2d(6.12, 6.49), 0, 0, 0);
  57.         pl.AddVertexAt(3, new Point2d(7.29, 6.26), -0.27, 0, 0);
  58.         pl.AddVertexAt(4, new Point2d(8.11, 5.53), -0.47, 0, 0);
  59.         pl.AddVertexAt(5, new Point2d(7.75, 5.41), 0, 0, 0);
  60.         pl.Closed = true;
  61.         objs.Add(pl);
  62.         // A closed spline...
  63.         Point3dCollection pts =
  64.           new Point3dCollection(
  65.             new Point3d[] {
  66.               new Point3d (5.5, 2.06, 0),
  67.               new Point3d (5.26, 2.62, 0),
  68.               new Point3d (5.66, 4.16, 0),
  69.               new Point3d (8.56, 4.21, 0),
  70.               new Point3d (7.2, 0.86, 0),
  71.               new Point3d (6.44, 2.85, 0),
  72.               new Point3d (5.62, 1.8, 0),
  73.               new Point3d (5.5, 2.06, 0)
  74.             }
  75.           );
  76.         Spline sp = new Spline(pts, 2, 0.5);
  77.         objs.Add(sp);
  78.         // Add each to the paperspace blocktablerecord
  79.         // and create/add an associated viewport object
  80.         foreach (DBObject obj in objs)
  81.         {
  82.           Entity ent = obj as Entity;
  83.           if (ent != null)
  84.           {
  85.             // Add our boundary to paperspace and the
  86.             // transaction
  87.             ObjectId id = ps.AppendEntity(ent);
  88.             tr.AddNewlyCreatedDBObject(obj, true);
  89.             // Create our viewport, adding that also
  90.             Viewport vp = new Viewport();
  91.             ps.AppendEntity(vp);
  92.             tr.AddNewlyCreatedDBObject(vp, true);
  93.             // Set the boundary entity and turn the
  94.             // viewport/clipping on
  95.             vp.NonRectClipEntityId = id;
  96.             vp.NonRectClipOn = true;
  97.             vp.On = true;
  98.           }
  99.         }
  100.         tr.Commit();
  101.       }
  102.       // Let's take a look at the results in paperspace
  103.       db.TileMode = false;
  104.     }
  105.   }
  106. }
Here’s what happens when we draw some geometry in modelspace:

And then call the NRVPS command to create our non-rectangular viewports

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
发表于 2010-2-4 09:43:00 | 显示全部楼层

[转帖]直线延长-Extending a set of AutoCAD lines

A nice little one to start the week. We’re going to ask the user to select a bunch of lines and we’ll then go through and edit each one, extending it in both directions by a quarter of its original length.
The code shows a couple of interesting techniques: aside from extending the lines themselves we also use a SelectionFilter in combination with a PromptSelectionOptions object to restrict the selection process from selecting anything but lines (and to give a customized experience by changing the selection prompt).
我也不明白KEN要写这个实例,但对于初学者来说:这也算是个不错的例子:
1>过滤选择直线对象
2>如何延长直线的长度
C#代码如下:
  1.         [CommandMethod("EXL")]
  2.         public void ExtendLines()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Database db = doc.Database;
  6.             Editor ed = doc.Editor;
  7.             //使用一个选择对象,指定我们想选择的直线
  8.             PromptSelectionOptions pso = new PromptSelectionOptions();
  9.             pso.MessageForAdding = "\nSelect lines: ";
  10.             TypedValue[] tvs = new TypedValue[1] { new TypedValue((int)DxfCode.Start, "LINE") };
  11.             SelectionFilter sf = new SelectionFilter(tvs);
  12.             //选择对象
  13.             PromptSelectionResult psr = ed.GetSelection(pso, sf);
  14.             if (psr.Status != PromptStatus.OK)
  15.             {
  16.                 return;
  17.             }
  18.             //当选择集不为空时
  19.             if (psr.Value.Count > 0)
  20.             {
  21.                 //打开事务
  22.                 Transaction tr = db.TransactionManager.StartTransaction();
  23.                 using (tr)
  24.                 {
  25.                     //编辑选定的每一条直线
  26.                     foreach (SelectedObject so in psr.Value)
  27.                     {
  28.                         //我们假定只有线的选择集
  29.                         //也可以使用更多的判断办法,
  30.                         //使用动态转换(Line ln = xxx as Line;)
  31.                         Line ln = (Line)tr.GetObject(so.ObjectId, OpenMode.ForWrite);
  32.                         //我们将直线两个方向比现在延长多四分之一
  33.                         Vector3d ext = ln.Delta / 4;
  34.                         // 直线起点
  35.                         ln.Extend(true, ln.StartPoint - ext);
  36.                         // 直线终点
  37.                         ln.Extend(false, ln.EndPoint + ext);
  38.                     }
  39.                     //别忘记提示事务
  40.                     tr.Commit();
  41.                 }
  42.             }
  43.         }


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1威望 +1 明经币 +1 收起 理由
雪山飞狐_lzh + 1 + 1 【好评】好文章

查看全部评分

 楼主| 发表于 2010-11-29 15:29:14 | 显示全部楼层
本帖最后由 lzh741206 于 2010-11-29 15:39 编辑

十八、块参照的剪裁Adding a 2D spatial filter to perform a simple xclip on an external reference in AutoCAD using .NET
I’ve now checked in for my flight to Las Vegas – and, thanks to Jeremy Tammik’s recent troubles, I luckily renewed my  ESTA – so I’m pretty much all set for my trip to AU 2010, at least from a travel perspective. I’m just keeping my fingers crossed that the gastric 'flu my kids seem to have come down with doesn’t hit me before I leave (or once I’m at AU… what a grim thought).

I was going to keep today’s post light, just like the last one, but then decided to dip into my email folder of externally contributed posts. This little nugget from Jamie Robertson shows how to add a simple 2D spatial filter to an external reference, effectively duplicating the XCLIP command (although this basic sample doesn’t handle non-World UCSs, block rotation/scaling, etc.).

At some point I may look at implementing a more complete version of this command, but even as it stands I have no doubt it’ll be of use to many of you. Many thanks for contributing this code, Jamie!

Here’s the C# code, with minor modifications to fit this blog:
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.AutoCAD.Geometry;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.DatabaseServices.Filters;
  6. using Autodesk.AutoCAD.Runtime;
  7. using System;


  8. namespace SpatialFiltering
  9. {
  10.   public class ClipBlock
  11.   {
  12.     const string filterDictName = "ACAD_FILTER";
  13.     const string spatialName = "SPATIAL";

  14.     [CommandMethod("2DXCLIP")]
  15.     public static void clipBlockTest()
  16.     {
  17.       Document doc =
  18.         Application.DocumentManager.MdiActiveDocument;
  19.       Database db = doc.Database;
  20.       Editor ed = doc.Editor;

  21.       // Select a block to clip
  22.       PromptEntityOptions peo =
  23.         new PromptEntityOptions(
  24.           "\nSelect a block reference to clip:"
  25.         );

  26.       peo.AllowNone = false;
  27.       peo.SetRejectMessage("\nNot a block reference.");
  28.       peo.AddAllowedClass(typeof(BlockReference), false);
  29.       PromptEntityResult per = ed.GetEntity(peo);
  30.       if (per.Status != PromptStatus.OK)
  31.         return;

  32.       // Select rectangle to clip
  33.       PromptPointOptions ppo =
  34.         new PromptPointOptions(
  35.           "\nSelect first clip corner: "
  36.         );

  37.       ppo.AllowNone = false;
  38.       PromptPointResult ppr = ed.GetPoint(ppo);
  39.       if (ppr.Status != PromptStatus.OK)
  40.         return;
  41.       Point3d pt1 = ppr.Value;

  42.       PromptCornerOptions pco =
  43.         new PromptCornerOptions(
  44.           "\nSelect second clip corner: ", pt1
  45.         );

  46.       ppr = ed.GetCorner(pco);
  47.       if (ppr.Status != PromptStatus.OK)
  48.         return;
  49.       Point3d pt2 = ppr.Value;

  50.       Transaction tr = db.TransactionManager.StartTransaction();
  51.       using (tr)
  52.       {
  53.         // Transform and re-order points
  54.         BlockReference br =
  55.           (BlockReference)tr.GetObject(
  56.             per.ObjectId, OpenMode.ForRead
  57.           );

  58.         pt1 = pt1.TransformBy(br.BlockTransform.Inverse());
  59.         pt2 = pt2.TransformBy(br.BlockTransform.Inverse());
  60.         Point2d rectMin =
  61.           new Point2d(
  62.             Math.Min(pt1.X, pt2.X),
  63.             Math.Min(pt1.Y, pt2.Y)
  64.           );

  65.         Point2d rectMax =
  66.           new Point2d(
  67.             Math.Max(pt1.X, pt2.X),
  68.             Math.Max(pt1.Y, pt2.Y)
  69.           );

  70.         Point2dCollection pts =
  71.           new Point2dCollection(2){ rectMin, rectMax };
  72.         // Create spatial filter
  73.         // Just zeroes for the elevation and clip depths
  74.         SpatialFilterDefinition sfd =
  75.           new SpatialFilterDefinition(
  76.             pts, Vector3d.ZAxis, 0.0, 0.0, 0.0, true
  77.           );
  78.         SpatialFilter sf = new SpatialFilter();
  79.         sf.Definition = sfd;

  80.         // Create extension dictionary if doesn't exist
  81.         if (br.ExtensionDictionary == ObjectId.Null)
  82.         {
  83.           br.UpgradeOpen();
  84.           br.CreateExtensionDictionary();
  85.           br.DowngradeOpen();
  86.         }

  87.         // Add spatial filter to extension dictionary
  88.         DBDictionary xDict =
  89.           (DBDictionary)tr.GetObject(
  90.             br.ExtensionDictionary, OpenMode.ForWrite
  91.           );
  92.         if (xDict.Contains(filterDictName))
  93.         {
  94.           DBDictionary fDict =
  95.             (DBDictionary)tr.GetObject(
  96.               xDict.GetAt(filterDictName), OpenMode.ForWrite
  97.             );
  98.           if (fDict.Contains(spatialName))
  99.             fDict.Remove(spatialName);
  100.           fDict.SetAt(spatialName, sf);
  101.         }
  102.         else
  103.         {
  104.           DBDictionary fDict = new DBDictionary();
  105.           xDict.SetAt(filterDictName, fDict);
  106.           tr.AddNewlyCreatedDBObject(fDict, true);
  107.           fDict.SetAt(spatialName, sf);
  108.         }
  109.         tr.AddNewlyCreatedDBObject(sf, true);
  110.         tr.Commit();
  111.       }
  112.       ed.Regen();
  113.     }
  114.   }
  115. }
Here’s an xrefed drawing – the venerable HVAC Architectural sample drawing, no less:

And here’s the effect of running the 2DXCLIP command, selecting the Xref (the grey geometry) and a window to which to clip:

That’s it until AU – I’m looking forward to catching up with many of you in Las Vegas! :-)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
 楼主| 发表于 2012-7-26 18:50:18 | 显示全部楼层
本帖最后由 雪山飞狐_lzh 于 2012-7-26 18:51 编辑


July 06, 2007
Applying a gradient fill to an AutoCAD hatch using .NET
So, back in the saddle after an eventful week off, back in the UK. Aside from the extremely changeable weather (even by British standards) and the heightened security at UK airports, the week went swimmingly... :-)

It's now Friday night, and disappointingly I've spent nearly two days regaining control of my inbox. I really wanted to make a quick post before the weekend, so rather than diving into the issue I'd planned on tackling (Palettes), I decided to take a shot at a request I'd received by email a few weeks ago: to show how to create a gradient fill using .NET.

I started by reusing the code from this previous post: so much of the code I needed was there already, it had to be easy to adjust the hatch to use a gradient fill, right? Well, no - it took me much longer than I'd expected to work this one out. Maybe I should have stuck with Palettes, after all...

I decided to use a spherical gradient fill of two colours (the default colours used when you create a two-tone gradient fill using the UI), as this shows one of the trickier parts of the API, that of specifying the colours themselves. One other call it took me a while to work out was to set the HatchObjectType property - if you don't do that then you'll get an eAmbiguousOutput exception.

Here's the C# code:

  1. using Autodesk.AutoCAD.ApplicationServices;

  2. using Autodesk.AutoCAD.DatabaseServices;

  3. using Autodesk.AutoCAD.EditorInput;

  4. using Autodesk.AutoCAD.Runtime;

  5. using Autodesk.AutoCAD.Colors;



  6. namespace HatchGradient

  7. {

  8.   public class Commands

  9.   {

  10.     [CommandMethod("GFH")]

  11.     static public void GradientFillHatch()

  12.     {

  13.       Document doc =

  14.         Application.DocumentManager.MdiActiveDocument;

  15.       Editor ed = doc.Editor;



  16.       // Ask the user to select a hatch boundary

  17.       PromptEntityOptions opt =

  18.         new PromptEntityOptions(

  19.           "\nSelect boundary: "

  20.         );

  21.       opt.SetRejectMessage("\nObject must be a curve.");

  22.       opt.AddAllowedClass(typeof(Curve), false);

  23.       PromptEntityResult res =

  24.         ed.GetEntity(opt);



  25.       if (res.Status == PromptStatus.OK)

  26.       {

  27.         Transaction tr =

  28.           doc.TransactionManager.StartTransaction();

  29.         using (tr)

  30.         {

  31.           // Check the entity is a closed curve

  32.           DBObject obj =

  33.             tr.GetObject(

  34.               res.ObjectId,

  35.               OpenMode.ForRead

  36.             );

  37.           Curve cur = obj as Curve;

  38.           if (cur != null && cur.Closed == false)

  39.           {

  40.             ed.WriteMessage("\nLoop must be a closed curve.");

  41.           }

  42.           else

  43.           {

  44.             // We'll add the hatch to the model space

  45.             BlockTable bt =

  46.               (BlockTable)tr.GetObject(

  47.                 doc.Database.BlockTableId,

  48.                 OpenMode.ForRead

  49.               );

  50.             BlockTableRecord btr =

  51.               (BlockTableRecord)tr.GetObject(

  52.                 bt[BlockTableRecord.ModelSpace],

  53.                 OpenMode.ForWrite

  54.               );



  55.             Hatch hat = new Hatch();

  56.             hat.SetDatabaseDefaults();



  57.             // Firstly make it clear we want a gradient fill

  58.             hat.HatchObjectType =

  59.               HatchObjectType.GradientObject;



  60.             // Let's use the pre-defined spherical gradient

  61.             hat.SetGradient(

  62.               GradientPatternType.PreDefinedGradient,

  63.               "SPHERICAL");



  64.             // We're defining two colours

  65.             hat.GradientOneColorMode = false;

  66.             GradientColor[] gcs = new GradientColor[2];

  67.             gcs[0] =

  68.               new GradientColor(

  69.                 Color.FromRgb(0, 0, 255),

  70.                 0 // First colour must have value of 0

  71.               );

  72.             gcs[1] =

  73.               new GradientColor(

  74.                 Color.FromRgb(255, 255, 153),

  75.                 1 // Second colour must have value of 1

  76.               );

  77.             hat.SetGradientColors(gcs);



  78.             // Add the hatch to the model space

  79.             // and the transaction

  80.             ObjectId hatId = btr.AppendEntity(hat);

  81.             tr.AddNewlyCreatedDBObject(hat, true);



  82.             // Add the hatch loop and complete the hatch

  83.             ObjectIdCollection ids =

  84.               new ObjectIdCollection();

  85.             ids.Add(res.ObjectId);

  86.             hat.Associative = true;

  87.             hat.AppendLoop(

  88.               HatchLoopTypes.Default,

  89.               ids

  90.             );



  91.             hat.EvaluateHatch(true);



  92.             tr.Commit();

  93.           }

  94.         }

  95.       }

  96.     }

  97.   }

  98. }


Here's what you get when you run the GFH command and select a polyline boundary you've created previously:



That's it for this week - have a great weekend, all of you.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-25 16:50 , Processed in 0.194130 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表