Как можно вставить dwf(x) в текущий документ dwg?

Понадобилось мне тут вставить несколько dwf (или dwfx, не столь суть важно) в текущий документ dwg. Естественно, что захотелось мне задачку решить лиспом, да без применения команд типа _.dwfattach. Вот о своих мытарствах и рассказываю чуть ниже :)

Несложные ковыряния в dwg-файле выявили, что записи о DWF(x) описаниях хранятся в словаре ACAD_DWFDEFINITIONS. Ок, проверить наличие словаря и при необходимости создать его - не вопрос. А вот дальше началось уже не очень понятное и очевидное.

Во-первых, мне никак не удавалось корректно создать запись в этом словаре. Естественно, что dwf существует, естественно, его ACAD находит. Но и все! Решения, которые мне удалось найти, рано или поздно сводятся к коду, показанному на ADN DevBlog. Код приводить не буду, покажу лучше, как я над ним измывался :)

Во-первых, я из команды сделал LISP-функцию, и, во-вторых, убрал вставку DWF в пространство модели. Ну захотелось мне такое провернуть ;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
[LispFunction("kpblc_dwfinsert")]
        public static object lisp_dwfinsert(ResultBuffer Args)
        {
            ObjectId res = ObjectId.Null;
            Array arguments = Args.AsArray();
            string sFileName = Convert.ToString(((TypedValue)(arguments.GetValue(0))).Value);

            if (System.IO.File.Exists(sFileName))
            {

                Document doc = Application.DocumentManager.MdiActiveDocument;
                Database db = doc.Database;
                Editor ed = doc.Editor;

                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    //first check for the required Layout
                    UnderlayFile layouts = UnderlayHost.DwfHost.GetFile(sFileName, "");
                    UnderlayItem selectedItem = null;

                    Regex rxEng = new Regex("model", RegexOptions.IgnoreCase);
                    Regex rxRus = new Regex("модел", RegexOptions.IgnoreCase);

                    if (layouts.Items.Count > 1)
                    {
                        foreach (UnderlayItem item in layouts.Items)
                        {
                            Match strMatchEng = rxEng.Match(item.Name);
                            Match strMatchRus = rxRus.Match(item.Name);
                            if ((String.Compare(item.Name.ToUpper(), "MODEL", false) == 0) || strMatchEng.Success || strMatchRus.Success)
                            { selectedItem = item; break; }
                        }
                    }
                    else
                    { selectedItem = layouts.Items[0]; }

                    if (selectedItem == null)
                    { ed.WriteMessage("error, No page with name Model"); return null; }

                    DBDictionary nod = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                    string defDictKey = UnderlayDefinition.GetDictionaryKey(typeof(DwfDefinition));
                    ObjectId defId = ObjectId.Null;
                    if (!nod.Contains(defDictKey))
                    {
                        using (DBDictionary dict = new DBDictionary())
                        {
                            nod.UpgradeOpen();
                            defId = nod.SetAt(defDictKey, dict);
                            tr.AddNewlyCreatedDBObject(dict, true);
                        }
                    }
                    else
                    { defId = nod.GetAt(defDictKey); }

                    ObjectId idDef = ObjectId.Null;
                    DBDictionary dwfDict = (DBDictionary)tr.GetObject(defId, OpenMode.ForRead);

                    string sDwfName = Path.GetFileNameWithoutExtension(sFileName);

                    if (dwfDict.Contains(sDwfName))
                    { idDef = dwfDict.GetAt(sDwfName); }
                    else
                    {
                        using (DwfDefinition dwfDef = new DwfDefinition())
                        {
                            dwfDict.UpgradeOpen();
                            dwfDef.SourceFileName = sFileName;
                            dwfDef.SetUnderlayItem(sFileName, sFileName, selectedItem);
                            idDef = dwfDict.SetAt(sDwfName, dwfDef);
                            tr.AddNewlyCreatedDBObject(dwfDef, true);
                        }
                    }
                    res = idDef;
                    tr.Commit();
                }
            }

            return res;
        }

Да, я понимаю: код ужасен. Но я и на .NET не пишу :)

Тем не менее свою задачу код выполняет: при условии вызова (kpblc_dwfinsert "c:\\test01.dwf") возвращается ename-указатель на созданную запись в словаре. Если вызвать окно диспетчера внешних ссылок, то мы увидим вполне логичную картину:

1
2
$ (kpblc_dwfinsert "c:\\test01.dwf")
<Entity name: 7ffffb06130>

А вот теперь попробуем создать вхождение dwf в текущий документ. ActiveX-методов для этого не существует, поэтому попробуем использовать обычный entmakex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(entmakex
  (append '((0 . "DWFUNDERLAY")
            (100 . "AcDbEntity")
            (67 . 0)
            (410 . "Model")
            (8 . "0")
            (100 . "AcDbUnderlayReference")
            )
          (list (cons 340 (kpblc_dwfinsert "c:\\test01.dwf")))
          '((10 0.0 0.0 0.0)
            (41 . 1.0)
            (42 . 1.0)
            (43 . 1.0)
            (50 . 0.0)
            (210 0.0 0.0 1.0)
            (280 . 11)
            (281 . 75)
            (282 . 25)
            )
          ) ;_ end of append
  ) ;_ end of entmakex

Так, код сработал: возвращает указатель на созданный примитив (); в пространстве модели появилось вхождение dwf:

А вот в диспетчере ссылок творится что-то странное:

А если повести себя как обезьяна с гранатой и выполнить "Detach" (отключить) ссылку?

Попытки выделить вставленный dwf, описание которого отсутствует в словаре, ACAD2015 не рушит (ACAD2009 падал моментально при попытке простого выделения DWF-ссылки на чертеже), но как-то лично мне неуютно от того, что в файле dwg начинается такой бардак. Кроме того, можно в ACAD20015 скрыть отображение этой "неправильной" dwf-ссылки и потом попробовать снова ее отобразить: вместо более-менее нормального вида будет показываться черт-те что (но при этом имеющее некоторые свойства DWF-подложки).

Подводя итоги, можно сказать следующее: если надо вставить DWF-подложку в документ, то либо использовать командные методы, либо полностью разрабатывать на .NET: лисп с этой задачей не справится.



Комментарии

Есть 6 коммент. к “Как можно вставить dwf(x) в текущий документ dwg?”
  1. Андрей пишет:

    либо на .net написать дополнительные lisp-функции. Собственно подобные ситуации я и имел в виду, когда создавал этот опрос: http://adn-cis.org/forum/index.php?topic=349.0

  2. Кулик Алексей aka kpblc пишет:

    Андрей, но ведь это же костыли будут! Оно надо? Я, скорее всего, буду для этой задачи использовать c#, благо работающие примеры есть )))

  3. Андрей пишет:

    >Андрей, но ведь это же костыли будут! Оно надо? Я, скорее всего, буду для этой задачи использовать c#, благо работающие примеры есть )))

    Чем этот случай отличается от той ситуации, когда ты на .net недавно писал lisp-функции по взрыву\расчленению proxy? То были не костыли, а это костыли?

  4. Кулик Алексей aka kpblc пишет:

    Конечно, костыли. У меня сейчас вообще какой-то Франкенштейн получается :) И лисп, и arx, и .NET - все в одном :)

  5. ElpanovEvgeniy пишет:

    Всем привет!

    У меня получилось и через dxf создать ссылку на dwf.
    Прошу прощения, код только демонстрация, не рассматриваются никакие частные случаи, т.е запускаем в пустом файле.
    "D:\\test.dwf" = путь к dwf
    "test_dwf" = название ссылки

    Ссылка на dwf вставляется и нормально работает, но в диспетчере появляется только после сохранения файла.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    (setq f  "D:\\test.dwf"
          n  "test_dwf"
          e5 (entmakex (list '(0 . "DWFDEFINITION")
                             '(100 . "AcDbUnderlayDefinition")
                             (cons 1 f)
                             '(2 . "Несохраненный чертеж-Model")
                             '(-3 ("ACAD" (1000 . "LOAD")))
                       )
             )
          e3 (entmakex (list '(0 . "DICTIONARY")
                             '(102 . "{ACAD_REACTORS")
                             (cons 330 (NAMEDOBJDICT))
                             '(102 . "}")
                             (cons 330 (NAMEDOBJDICT))
                             '(100 . "AcDbDictionary")
                             '(280 . 0)
                             '(281 . 1)
                             (cons 3 f)
                             (cons 350 e5)
                       )
             )
    )
    (entmod (append (entget (namedobjdict)) (list '(3 . "ACAD_DWFDEFINITIONS") (cons 350 e3))))
    (setq e4 (entmakex (list '(0 . "DWFDEFINITION")
                             (cons 330 e3)
                             '(100 . "AcDbUnderlayDefinition")
                             (cons 1 f)
                             (cons 2 n)
                       )
             )
          e6 (entmakex (list '(0 . "DWFUNDERLAY")
                             '(100 . "AcDbEntity")
                             '(67 . 0)
                             '(410 . "Model")
                             '(8 . "0")
                             '(100 . "AcDbUnderlayReference")
                             (cons 340 e5)
                             '(10 16.3241 9.47381 0.0)
                             '(41 . 1.0)
                             '(42 . 1.0)
                             '(43 . 1.0)
                             '(50 . 0.0)
                             '(210 0.0 0.0 1.0)
                             '(280 . 11)
                             '(281 . 75)
                             '(282 . 25)
                       )
             )
    )
    (entmod
      (append (reverse (member (assoc 5 (entget e5)) (reverse (entget e5))))
              (list '(102 . "{ACAD_REACTORS") (cons 330 e3) (cons 330 e6) '(102 . "}") (cons 330 e3))
              (member '(100 . "AcDbUnderlayDefinition") (entget e5))
      )
    )
  6. ElpanovEvgeniy пишет:

    Забыл добавить, код писал в AutoCAD 2015, там же и проверял...

Поделитесь своим мнением


Я не робот.