ऑटोकैड के लिए एक "कस्टम" कस्टम ऑब्जेक्ट बनाना जो ऑब्जेक्ट एनब्लर के बिना काम करता है

शुभ दोपहर
जो लोग ऑटोकैड और इसके लिए तीसरे पक्ष के समाधान के साथ सौदा करते हैं, निश्चित रूप से, प्रॉक्सी ऑब्जेक्ट्स की समस्या का सामना करना पड़ा है, उन्हें प्रदर्शित करने या स्थानांतरित करने के लिए आपको पुस्तकालयों को स्थापित करने की आवश्यकता होती है जिसके साथ ये ऑब्जेक्ट्स या तथाकथित ऑब्जेक्ट्स एनबलर्स बनाए गए थे, उसी डेवलपर्स से। यह काफी असुविधाजनक है। उदाहरण के लिए, आपको एक ग्राहक / उपठेकेदार से एक दस्तावेज प्राप्त हुआ और आप केवल वर्ग देखते हैं।

मैं ऑटोकैड के लिए "गैर-पारंपरिक" ऑब्जेक्ट बनाने में अपने व्यक्तिगत अनुभव को आपके साथ साझा करना चाहता हूं। आधार एक अनाम ब्लॉक है। ऑब्जेक्ट गुण अलग से BlockReference में संग्रहीत किए जाते हैं :: Extension हल्के। यह तीसरे पक्ष के अनुप्रयोग या स्क्रिप्ट के लिए उन्हें एक्सेस करने और उन्हें पढ़ने के लिए संभव बनाता है, और यदि वांछित है, तो मूल पुस्तकालयों की उपस्थिति के बिना उन्हें बदल दें। एक ब्लॉक के अंदर प्राथमिकताओं को हमेशा उनके राज्य के अनुसार प्रदान किया जाता है। वैसे भी, ऑटोकैड की स्थिरता बहुत अधिक है। साइड से, सब कुछ सरल दिखता है। लेकिन जब इस तंत्र को लागू करने की कोशिश की गई, तो विभिन्न "नुकसान" की पहचान की गई। क्रम में इस बारे में।


पहले आपको ऑब्जेक्ट बनाने के लिए आवश्यक इनपुट ऑर्डर सेट करने के लिए, EntityJig से विरासत में दिए गए जिग को लागू करने की आवश्यकता है। इसमें, हमें यह निर्धारित करना होगा कि हमें कितने राज्यों की आवश्यकता है, मेरे मामले में यह इस तरह दिखता है:
public enum MyJigState { EnteringBasePoint, EnteringEndPoint, Done } 

इस वर्ग के मुख्य तरीके अपडेट () और नमूना () होंगे, नतीजतन, मुझे यह वर्ग मिला:
 public class MyJig : EntityJig { public enum MyJigState { EnteringBasePoint, EnteringEndPoint, Done } MyJigState _state = MyJigState.EnteringBasePoint; PointSampler _basePoint = new PointSampler(AcGe.Point3d.Origin); PointSampler _endPoint = new PointSampler(new AcGe.Point3d(10, 10, 0)); LevelMark _levelMark; public MyJig(LevelMark levelmark, BlockReference reference) : base(reference) { this._levelMark = levelmark; } protected override bool Update() { try { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; using (DocumentLock dl = doc.LockDocument(DocumentLockMode.ProtectedAutoWrite, null, null, true)) { using (var transaction = Acad.TransactionManager.StartTransaction()) { BlockReference reference = (BlockReference)transaction.GetObject(this.Entity.Id, OpenMode.ForWrite, true); reference.Erase(false); reference.Position = this._levelMark.InsertionPoint; reference.BlockUnit = Acad.Database.Insunits; transaction.Commit(); } this._levelMark.UpdateEntities(); this._levelMark.BlockRecord.UpdateAnonymousBlocks(); } } catch (System.Exception ex) { return false; } return true; } public MyJigState State { get { return this._state; } set { this._state = value; } } protected override SamplerStatus Sampler(JigPrompts prompts) { try { switch (_state) { case MyJigState.EnteringBasePoint: return _basePoint.Acquire(prompts, "\n  :", value => { Matrix3d ucs = Acad.Editor.CurrentUserCoordinateSystem; this._levelMark.InsertionPoint = value }); case MyJigState.EnteringEndPoint: return _endPoint.Acquire(prompts, "\n  :", value => { Matrix3d ucs = Acad.Editor.CurrentUserCoordinateSystem; this._levelMark.EndPoint = value }); default: return SamplerStatus.NoChange; } } catch { return SamplerStatus.NoChange; } } } 


मुझे EntityOverride से ऑब्जेक्ट का मुख्य वर्ग विरासत में मिला है और प्रविष्टियों को फिर से परिभाषित किया है:

 private Lazy<AcDb.Line> line = new Lazy<AcDb.Line>(() => new AcDb.Line(Point3d.Origin, new Point3d(10, 0, 0))); private Lazy<AcDb.Polyline> simbolPoly = new Lazy<AcDb.Polyline>(() => new AcDb.Polyline()); private Lazy<AcDb.Polyline> arrowPoly = new Lazy<AcDb.Polyline>(() => new AcDb.Polyline()); private Lazy<AcDb.MText> text = new Lazy<AcDb.MText>(() => new AcDb.MText()); private Lazy<AcDb.MText> note = new Lazy<AcDb.MText>(() => new AcDb.MText()); public override IEnumerable<AcDb.Entity> Entities { get { yield return line.Value; yield return simbolPoly.Value; yield return arrowPoly.Value; yield return text.Value; yield return note.Value; } } 


जो ब्लॉक में शामिल वस्तुओं को प्रस्तुत करने के बारे में स्नान नहीं करना संभव बनाता है। इस वर्ग में भी, मैंने एक फ़ंक्शन लागू किया, जो मांग पर, ब्लॉक के भीतर प्राथमिकताओं की स्थिति और वितरण को बताता है।

हमारी कक्षा का एक उदाहरण बनाने के बाद, एक फ़ंक्शन को एक ब्लॉक-रेफरेंस बनाने के लिए कहा जाता है, जिसे तुरंत मिटा दिया जाता है (सच) - यह इनपुट को सहेजने पर फ़ाइल को बाधित होने पर ऑब्जेक्ट को स्वचालित रूप से हटाना संभव बनाता है।

  static BlockReference CreateBlock(ref LevelMark lm, ObjectContextCollection occ, ObjectId layerId) { ObjectId id; BlockReference reference; using (AcAp.Application.DocumentManager.MdiActiveDocument.LockDocument()) { using (var transaction = Acad.TransactionManager.StartTransaction()) { using (var blockTable = Acad.Database.BlockTableId.Write<AcDb.BlockTable>()) { var blockId = blockTable.Add(lm.BlockRecord); reference = new AcDb.BlockReference(lm.InsertionPoint, blockId); using (var modelSpace = Acad.Database.CurrentSpaceId/*modelSpaceId*/.Write<AcDb.BlockTableRecord>()) { Matrix3d ucs = Acad.Editor.CurrentUserCoordinateSystem; reference.TransformBy(ucs); id = modelSpace.AppendEntity(reference); ResultBuffer xData = new ResultBuffer(new TypedValue[] { new TypedValue((int)DxfCode.ExtendedDataRegAppName, MyPlugin.CurrentDictionaryName), new TypedValue((int)DxfCode.ExtendedDataAsciiString, "This is a " + MyPlugin.CurrentDictionaryName) }); reference.XData = xData; reference.LayerId = layerId; xData.Dispose(); } transaction.AddNewlyCreatedDBObject(reference, true); reference.Erase(true); transaction.AddNewlyCreatedDBObject(lm.BlockRecord, true); } transaction.Commit(); } if (id != null) { lm.BlockId = id; lm.UpdateParameters(id); } } return reference; } 


जिस तरह से, यह फ़ंक्शन XData में जानकारी रखता है कि यह हमारी वस्तु है - अन्य ब्लॉकों के बीच इसके बाद की खोज के लिए।

यह स्वयं वस्तु के निर्माण के साथ सरल प्रतीत होता है (हालाँकि इस पर एक-दो बार मुझे कार्यान्वयन के लिए दृष्टिकोण बदलना पड़ा)। पहली दिक्कत तब हुई जब आपके ग्रिप्स (पेन) को ब्लॉक करने और उन्हें प्रबंधित करने के साथ-साथ परिवर्तनों को रद्द करते समय।
Autodesk प्रलेखन के अनुसार सब कुछ करने के बाद, ग्रिपऑवर्रू ग्रिप्स वर्ग को विरासत में मिला, मैं मुश्किलों में भाग गया। वे इस तथ्य में शामिल थे कि मैंने ऑब्जेक्ट में किए गए परिवर्तनों को पूर्ववत करने की क्षमता खो दी। इसलिए, मुझे मूल से डेटा के आधार पर एक दूसरा उदाहरण बनाना होगा और इसके साथ बदलाव करना होगा, और यदि परिणाम सकारात्मक है, तो सभी परिवर्तनों को मूल ऑब्जेक्ट में स्थानांतरित करें। और TransientManager का भी उपयोग करना पड़ा। सब कुछ ठीक हो जाएगा, लेकिन यह पता चला कि ऑब्जेक्ट का एक उदाहरण ( एंटिटी ) ओवरराइड फ़ंक्शन MoveGripPointsAt को शून्य के रूप में पारित किया गया था, जिसने ऑब्जेक्ट की आईडी को स्टोर करने वाले कस्टम वर्ग ग्रिपडेटा के निर्माण में प्रवेश किया था

अगला पत्थर एक ही समय में बड़ी संख्या में वस्तुओं का एक साथ परिवर्तन था। मैंने पहले उसके बारे में अनुमान लगाया। लेकिन इस तरह के पैमाने पर नहीं। ऑब्जेक्ट का प्रॉपर्टी पैनल मानक तंत्र के माध्यम से कार्यान्वित किया जाता है, और इसमें कॉम के माध्यम से काम करना शामिल है (ऑटोकैड 2013 में ऐसा लगता है कि एआरएक्स में निकाल लिया गया है), प्लस, ऑब्जेक्ट को बदलने के बाद लेनदेन को बंद करना पागलपन लंबे समय तक चलता है। इसके अलावा, मानक टूल का उपयोग करके ऑब्जेक्ट को फिर से चालू करने के लिए निरंतर कॉल गति के संदर्भ में असंतोषजनक निकला। इन कारणों से, LISP फ़ंक्शंस का उपयोग करने का निर्णय लिया गया जो बहुत तेज़ी से काम करते हैं। लेकिन इससे उन्हें ढूंढने और सामान्य लुक में लपेटने का काम हो गया। यह ध्यान देने योग्य है कि उनमें से कुछ प्लेटफ़ॉर्म-निर्भर हैं।

  [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr acedNEntSelP(string p1, long[] name, Point2d p3, bool p, Matrix3d p4, IntPtr p5); public static ResultBuffer NEntSelP(string p1, ObjectId id, Point2d p3, bool p, Matrix3d p4, ref ResultBuffer p5) { long[] adsName = new long[2]; if (acdbGetAdsName(adsName, id) != 0) return null; IntPtr ip = acedNEntSelP(p1, adsName, p3, p, p4, p5.UnmanagedObject); if (ip != IntPtr.Zero) return ResultBuffer.Create(ip, false); return null; } [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr acdbEntGet(long[] name); public static ResultBuffer EntGet(ObjectId id) { long[] adsName = new long[2]; if (acdbGetAdsName(adsName, id) != 0) return null; IntPtr ip = acdbEntGet(adsName); if (ip != IntPtr.Zero) return ResultBuffer.Create(ip, false); return null; } [DllImport("acdb18.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int acdbGetObjectId(ref ObjectId objId, long[] name); [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] private static extern int acdbEntMakeX(IntPtr resBuf, long[] adsName); public static ObjectId EntMakeX(ResultBuffer resBuf) { long[] adsName = new long[2]; int ip = acdbEntMakeX(resBuf.UnmanagedObject, adsName); if (ip == RTNORM) { ObjectId objId = new ObjectId(); acdbGetObjectId(ref objId, adsName); return objId; } else { return ObjectId.Null; } } [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] private static extern int acdbEntDel(long[] name); public static int EntDel(ObjectId id) { long[] adsName = new long[2]; if (acdbGetAdsName(adsName, id) != 0) return RTERROR; return acdbEntDel(adsName); } [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] private static extern int acdbDictAdd(long[] dictName, string symName, long[] objName); public static int DictAdd(ObjectId dictNameId, string symName, ObjectId objNameId) { long[] dictName = new long[2]; if (acdbGetAdsName(dictName, dictNameId) != 0) return RTERROR; long[] objName = new long[2]; if (acdbGetAdsName(objName, objNameId) != 0) return RTERROR; byte[] srcb = System.Text.UnicodeEncoding.Unicode.GetBytes(symName); System.Text.ASCIIEncoding ue = new System.Text.ASCIIEncoding(); string dst = ue.GetString(srcb); return acdbDictAdd(dictName, dst, objName); } const short RTNORM = 5100; const short RTERROR = -5001; #if WIN32 [DllImport("acdb18.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")] public static extern int acdbGetAdsName(long[] objName, ObjectId objId); //public static extern Autodesk.AutoCAD.Runtime.ErrorStatus acdbGetAdsName(out long adsName, ObjectId id); #else [DllImport("acdb18.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] public static extern int acdbGetAdsName(long[] objName, ObjectId objId); #endif [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] public static extern int acdbEntUpd(long[] ent); public static long[] GetAdsName(ObjectId id) { long[] adsName = new long[1]; acdbGetAdsName(adsName, id); return adsName; } public static bool EntityUpdate(long[] adsName) { return (acdbEntUpd(adsName) == RTNORM); } public static bool EntityUpdate(ObjectId id) { long[] adsName = new long[1]; if (acdbGetAdsName(adsName, id) != 0) return false; return (acdbEntUpd(adsName) == RTNORM); } [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)] private static extern int acdbEntMod(System.IntPtr resbuf); public static int EntMod(ResultBuffer resultBuffer) { return acdbEntMod(resultBuffer.UnmanagedObject); } #if WIN32 [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetStatusBarProgressMeter@@YAHPB_WHH@Z")] public static extern int acedSetStatusBarProgressMeter(string label, int minPos, int maxPos); [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetStatusBarProgressMeterPos@@YAHH@Z")] public static extern int acedSetStatusBarProgressMeterPos(int pos); [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedRestoreStatusBar@@YAXXZ")] public static extern int acedRestoreStatusBar(); #else [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetStatusBarProgressMeter@@YAHPEB_WHH@Z")] public static extern int acedSetStatusBarProgressMeter(string label, int minPos, int maxPos); [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetStatusBarProgressMeterPos@@YAHH@Z")] public static extern int acedSetStatusBarProgressMeterPos(int pos); [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedRestoreStatusBar@@YAXXZ")] public static extern int acedRestoreStatusBar(); #endif 


इसके अतिरिक्त, मुझे इन कार्यों के माध्यम से XRecord को पढ़ना / संपादन करना था।
जिसने उत्पादकता में काफी वृद्धि की। फिलहाल, यदि आप उदाहरण के लिए, 1000 ऑब्जेक्ट बनाते हैं, तो जब आप एक ही समय में उन सभी के गुणों को बदलते हैं, तो मानक विधियों का उपयोग करके बनाई गई 1000 कस्टम ऑब्जेक्ट्स के साथ काम करते समय गति अधिक होती है।
सिद्धांत बहुत संक्षेप में कहा गया है, लेकिन अगर कोई दिलचस्पी रखता है, तो आप स्काइप के माध्यम से संपर्क कर सकते हैं: vsegodvadcatsimvolov या यहाँ।
मुझे उम्मीद है कि कोई उपयोगी होगा।

एक तैयार पुस्तकालय का एक उदाहरण, एक स्तर के निशान के काम को लागू करता है

Source: https://habr.com/ru/post/In154591/


All Articles