perlon

Użytkownik forum
  • Content Count

    334
  • Joined

  • Last visited

  • Days Won

    22

perlon last won the day on February 14

perlon had the most liked content!

1 Follower

About perlon

  • Rank
    Średniozaawansowany

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Niepotrzebnie w przypadku ESC rzucałem wyjątkiem który nie przechodził przez Resolve() z kontenera DI. Brak punkty koty przekazałem przez property i teraz jest już OK. Poprawka już zpushowana. No dopóki czegoś w ZWSOFT'cie nie poprawią to bez language packa EN działać nie będzie 😞
  2. Wracając do tematu wątku. Środowisko : maszyna wirtualna z Windows7 64bit i zainstalowanym ZwCAD2020SP1 PL 64bit. Przeprowadziłem następującą sekwencję działań: 1. Uruchomienie wersji PL. Autofac zgłasza brak zarejestrowanych typów. Nakładka nie działa prawidłowo. 2. Instalacja ZwCAD2020SP1 EN bez uruchomienia po instalacji. Uruchomienie wersji PL. Autofac wywala błąd. 3. Uruchomienie wersji EN a następnie jej zamknięcie. Uruchomienie wersji PL. Nakładka uruchamia się prawidłowo UWAGA. Instalacja wersji EN po wersji PL jest tak naprawdę instalacją Language Pack'a EN Przynajmniej tak to wygląda na liście zainstalowanych programów. 4. Restart maszyny wirtualnej. Uruchomienie wersji PL. Nakładka działa prawidłowo. 5. Odinstalowanie wersji EN z usunięciem user data. Uruchomienie wersji PL. Autofac wywala błąd. 6. Instalacja wersji EN bez uruchomienia po instalacji. Uruchomienie wersji PL. Autofac wywala błąd. 7. Uruchomienie i wyłączenie wersji EN. Uruchomienie wersji PL. Nakładka działa prawidłowo. 8. Odinstalowanie wersji EN z zachowaniem user data. Uruchomienie wersji PL. Autofac wywala błąd. Wnioski. Do prawidłowego działania nakładki (Autofac'a) wymagane jest zainstalowanie wersji EN i jednokrotne jej uruchomienie. Po tej operacji również po restarcie maszyny nakładka na wersji PL uruchamia się prawidłowo aż do czasu odinstalowania wersji EN. Zachowanie lub nie user data nie ma w tym przypadku znaczenia. Coś z tym można zrobić?
  3. Jeszcze uwaga dotycząca procesu kompilacji. Ponieważ projekt CADKit jest niezależny od CADKitBasic i CADKitElevationMarks choć jest główną biblioteką która ma wczytywać pozostałe nie może być projektem głównym. Tzn może być ale jego kompilacja nie spowoduje kompilacji dwóch pozostały bibliotek. Więc ich nie będzie i przy starcie nie zostaną załadowane. Żeby to obejść dopisałem w post-buildzie pozostałych projektów : copy $(TargetPath) $(SolutionDir)\CADKit\bin\$(ConfigurationName) co każdorazowo po kompilacji projektu skopiuje dll'kę do katalogu CADKit/bin/$(ConfigurationName). No ale F5 wywołuje kompilację głównego projektu i tylko jego zależności. Tak więc wymagany jest F6 (Build solution) a potem F5 (Start debugging). Obejściem problemu może być uczynienie głównym projektem testów jednostkowych. Jest to projekt do którego są podpięte jako zależności wszystkie pozostałe projekty i jego kompilacja wywoła kompilację wszystkich pozostałych a więc skopiowanie gotowych dll do katalogu CADKit/bin/$(ConfigurationName). Pozostaje tylko odpalić F5 ustawić Start external program. (Chyba to powinienem opisać w Readme na GITHubie ). Tak na marginesie testy jednostkowe też leżą i kwiczą. Jak widać projekt ma jeszcze mnóstwo mankamentów, niedoróbek i wymaga licznych refaktoryzacji. Jeżeli dojrzeje być może znajdzie swoje miejsce w dziale" Nakładki na ZWCAD i ZWCAD+". Dlatego wszelka pomoc jest bardzo mile widziana z zastrzeżeniem że zawsze to będzie Open Source.
  4. Znalazłem sposób na monitorowanie zmiany interfejsu więc się dzielę moim rozwiązaniem dla potomności co pozwoli zamknąć ten wątek: 1. Trzeba zasubskrybować się do handlera ApplicationServices.SystemVariableChangedEventHandler 2. W obsłudze zdarzenia trzeba sprawdzić, zmiana której zmiennej systemowej wywołała to zdarzenie. Jeżeli zdarzenie wywołała zmienna COLORSCHEME należy odczytać z rejestru systemowego wartość COLORSCHEME klucza Software\ZWSOFT\ZWCAD\2020\en-US\Profiles\Default\Config (dla wersji EN, dla PL trzeba odczytać z gałęzi pl-PL) Dzięki Adam Klaczek. Twoja podpowiedź była bardzo pomocna. podpięcie do handlera i metoda podpinana do handlera Application.SystemVariableChanged += OnSystemVariableChanged private void OnSystemVariableChanged(object _sender, SystemVariableChangedEventArgs _arg) { if (_arg.Name == "COLORSCHEME") { // tu pobieram z kontenera dependece injection instancję serwisu obsługującego schemat kolorów interfejsu ZwCAD'a // i odpalam własne zdarzenie rozgłaszające, że została dokonana zmiana kolorów using(var scope = DI.Container.BeginLifetimeScope()) { var service = DI.Container.Resolve<IInterfaceSchemeService>(); ChangeInterfaceScheme?.Invoke(_sender, new ChangeInterfaceSchemeEventArgs(service)); } } } w której odpalam już własne zdarzenie ChangeInterfaceScheme (skoro nie dokopałem się do takiego zdarzenia dostarczanego przez ZwSOFT to sobie zrobiłem własne 😁 ) public event EventHandler<ChangeInterfaceSchemeEventArgs> ChangeInterfaceScheme; public class ChangeInterfaceSchemeEventArgs : EventArgs { public IInterfaceSchemeService Service { private set; get; } public ChangeInterfaceSchemeEventArgs(IInterfaceSchemeService _service) { Service = _service; } } W mojej konkretnej implementacji do zdarzenia mogą być podpinane metody przyjmujące w argumencie serwis IInterfaceSchemeService który zajmuje się dostarczaniem kolorów do kontrolek interfejsu użytkownika. Jest to instancja mojej własnej klasy którą pozyskuję z kontenera zależności Autofac. Handler ChangeInterfaceScheme jest właściwością mojej klasy statycznej AppSettings która jest dostępna w całej aplikacji i trzyma róże globalne ustawienia. Klasyczny singleton. Dlatego do tego handlera mogę podpiąć w dowolnym miejscu aplikacji dowolną obsługę zdarzenia zmiany interfejsu uzyskując dostęp do serwisu podającego na tacy jakie kolory mają mieć aktualnie kontrolki. Wystarczy zmienić właściwości kontrolek WindowsForms, HTML, WPF czy czego tam się nie używa. Jeszcze tylko specyfikacja IInterfaceSchemeService public interface IInterfaceSchemeService { InterfaceScheme GetScheme(); Color GetBackColor(); Color GetForeColor(); } Na koniec należy dodać, że mój serwis InterfaceSchemeService posiada statyczną właściwość ColorScheme którą mogę odczytać w dowolnym miejscu aplikacji w szczególności przy starcie aplikacji i dzięki temu moja nakładka od razu może startować ze zgodnymi kolorami. Pełna implementacja z zastosowaniem jest dostępna w moim szarpowaniu opisanym w tym wątku gdzie znajduje się link do GITHub'a z kompletnymi źródłami.
  5. Co do samej nakładki ja to nazwałem na własny użytek jako wprawki w szarpowaniu CAD'a. Każdy, kto coś niecoś kodził czy to w LISP'ie czy VBA czy C# napisał kody do wstawiania jakichś obiektów. Parafrazując starą reklamę : "Wszyscy mają koty wysokościowe, mam i ja". Nie jest to żaden wyczyn ani nie jest to odkrywcze. Raczej powód do ćwiczeń i okazja do zastosowania kilku wzorców projektowych ogólnego przeznaczenia jak factory pattern, dependence injection, klas abstrakcyjnych etc. Przy okazji starałem się rozwiązać temat zmiany schematu kolorów interfejsu ciemny/jasny czy synchronizacji CANONSCALE. Jest też zawarta propozycja automatycznego ładowania kolejnych modułów jeżeli tylko istnieją i spełniają odpowiednie warunki oraz uruchomienie jednego okna PALETTESET z dynamicznie dodawanymi zakładkami reprezentującymi kolejne biblioteki z ich funkcjonalnościami. Dodatkowo jeszcze samo okno jest budowane za pomocą wzorca MVP (Model-View-Presenter). To co jest w tej chwili nie ma zbyt wiele użytecznej funkcjonalności, ale posiada infrastrukturę do łatwego rozbudowania. Przykładowo żeby dołożyć dodatkowe koty wysokościowe wystarczy tylko zdefiniować jedną klasę dziedziczącą po klasie Mark, dodać ją do serwisu MarkServis i jest dodatkowy przycisk w oknie. Można to sobie obejrzeć w kodzie zapraszam na GITHuba. Jeżeli jest ktoś zainteresowany takimi ćwiczeniami z szarpowania a przy okazji chciałby tworzyć jakąś funkcjonalność w ramach Open Source to zapraszam do grona "developerów" 😎 Acha. Jeszcze dodam, że podjąłem (jak na razie nieudaną) próbę stworzenia biblikoteki/klasy Proxy na różne platformy CAD która by przesłoniła te platformy uniezależniając samą nakładkę od tego gdzie jest uruchamiana. Chodzi o to żeby była jedna biblioteka CADKitZwCAD.dll z odwołaniem do ZwDatabaseMgd.dll, ZwManaged.dll, a pozostałe moduły odwoływały by się poprzez Proxy do mechanizmów ZwCAD'a. Na chwilę obecną działa to na zasadzie kompilacji warunkowej na podstawie zdefiniowanego symbolu "preprocesora".
  6. Fakt. Zapomniałem dołączyć loadera lispowego. Jest w załączeniu. Podstawową biblioteką jest CADKitZwCAD.dll. W niej jest "autostart" który ładuje pozostałe biblioteki, które są w tej samej lokalizacji i zaczynają się od CADKit... (vl-load-com) (cond ((= (getvar "PRODUCT") "ZWCAD") (vl-cmdf "netload" "CADKitZwCAD.dll")) ((= (getvar "PRODUCT") "AutoCAD") (vl-cmdf "netload" "CADKitAutoCAD.dll")) (T (progn (princ "\nNieznana platforma CAD. CADKit nie może być wczytany.") ) ) ) (princ) Z grubsza funkcjonalność pokazana jest na filmie. Tak na marginesie. Gdzieś jest instrukcja jak wstawić do posta film z youtuba? https://youtu.be/Pwgb96g_7Oc
  7. Dzień dobry. Nie bardzo wiedziałem gdzie to umieścić więc trafia do wsparcia programistycznego. Popełniłem kawałek aplikacji, w której wykorzystuję kontener wstrzykiwania zależności Autofac. Powiedzmy, że aplikacja już działa, więc postanowiłem ją dać kolegom w biurze do testowania. No i spotkał mnie taki zonk: wersja ZwCAD 2020 SP2 PL i komunikat : An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = ElevationMarksPresenter (ReflectionActivator), Services = [CADKit.Contracts.IPresenter, CADKitElevationMarks.Contracts.Presenters.IElevationMarksPresenter], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = MarkService (ReflectionActivator), Services = [CADKitElevationMarks.Contract.Services.IMarkService], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = MarkIconService (ReflectionActivator), Services = [CADKitElevationMarks.Contracts.Services.IMarkIconService], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An exception was thrown while invoking the constructor 'Void .ctor()' on type 'MarkIconService'. ---> Odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu. (See inner exception for details.) (See inner exception for details.) (See inner exception for details.) (See inner exception for details.) Ewidentnie kontener nie poradził sobie z rejestracją typów choć dziwne jest to że część typów załadował i obsługuje a część tych ładowanych z jednej tylko DLL'ki już nie. Po kilku testach na czystej maszynie wirtualnej z Windows 7 zainstalowałem równolegle z PL wersję EN. Na swoim kompie używam wyłącznie wersji EN. No i o dziwo poszło zarówno na EN jak i na PL. Jest dobrze. Więc odinstalowałem wersję EN no i niestety komunikat powrócił 😞. Jest coś w wersji EN czego brakuje w wersji PL co powoduje, że moja nakładka się buntuje. Może ktoś pomóc w temacie? Załączam na razie same skompilowane biblioteki DLL. W najbliższym czasie w osobnym wątku skrobnę parę słów na temat i załączę kompletne kody, ale tak na szybko chciałem wrzucić problem który mnie dotknął i nie jest on związany ściśle z kodem aplikacji w C# pod ZwCAD'a. Jeszcze zrzuty które pokazują że jest coś nie tak: Autofac.dll CADKitBasicZwCAD.dll CADKitElevationMarksZwCAD.dll CADKitZwCAD.dll
  8. perlon

    ZWCAD2020 SP2

    Eksport layout jest fajny. Docina polilinie na krawędzi rzutni, koło zamienia na łuk itp ale ma również drobne mankamenty np.nie docina hatchy, text multiline jest w nowym rysunku w całości a nie tylko w widocznej części, podobnie teksty jednowierszowe. Mam świadomość, że z tekstami to może być decyzja strategiczna ale hatche powinien docinać. Generalnie dobra robota i nie trzeba korzystać z zewnętrznych narzędzi. Co do eksportu do dgn to wydaje się, zamiast osobnego polecenia exptort coś tam powinien format zapisu rysunku być dostępny bezpośrednio w oknie SaveAs i Open. Nie widzę powodu dla którego mnoży się komendy zamiast zaszyć to w listę dostępnych formatów. Podobnie STL nie można by zrobić typu w oknie SaveAs zamiast komendy STLOUT?
  9. Kontekst powyższego jest nieco szerszy, ale nie chciałem zbyt komplikować kodu. W szczególności chciałem wstawiać do rysunku blok z atrybutem lub opcjonalnie encje w grupie mając w jig'u obraz takiego bloku/grupy. W ogólnym przypadku chciałem coś innego mieć na podglądzie a co innego ostatecznie wstawiać do rysunku. Stąd poszukiwania prawidłowej reprezentacji graficznej bez faktycznego wstawiania do bazy rysunku. Wygląda jednak, że chyba się nie da uzyskać 100% reprezentacji graficznej obiektu bez jego wstawienia do bazy. Ostatecznie chyba przeniosę zapis do rysunku do wnętrza klasy Jig public Jig(Entity txt, Point3d point) : base() { entity = txt; basePoint = point; Prepare(); } private void Prepare() { var doc = Application.DocumentManager.MdiActiveDocument; using (var tr = doc.TransactionManager.StartTransaction()) { var btr = tr.GetObject(doc.Database.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; btr.AppendEntity(entity); tr.AddNewlyCreatedDBObject(entity, true); entity.Erase(); tr.Commit(); } } co uprości nieco wywołanie [CommandMethod("JIG")] public void Jig() { try { var tx1 = new DBText(); tx1.SetDatabaseDefaults(); tx1.Height = 2; tx1.Position = new Point3d(0, 0, 0); tx1.TextString = "Tekst"; tx1.VerticalMode = TextVerticalMode.TextVerticalMid; var jig = new Jig(tx1, new Point3d(0, 0, 0)); var result = Application.DocumentManager.MdiActiveDocument.Editor.Drag(jig); if(result.Status == PromptStatus.OK) { SaveToDatabase(jig.GetEntity()); } } catch(Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message); } } Powyższe trzeba jeszcze uzupełnić o kontrolę czy obiekt aktualnie jest w bazie czy nie i jeden lub dwa try catch'e i da to kod całkiem uniwersalny
  10. Witam. Chciałbym zaprezentować przykładowy kod do wstawiania obiektów do rysunku z podglądem tego co zostanie wstawione. Rozwiązanie oparte o klasę JigDraw. Starałem się maksymalnie skrócić kod usuwając bloki try catch oraz wstawiając tylko jedną entycję. Z powodzeniem można go jednak przerobić zastępując Typ Entity typem IEnumerable<Entity> i wstawiać całe zespoły obiektów. Mam jednak pewną zagwostkę dla pary klas jak w temacie. Poniżej kod wstawiający obiekt klasy DBText z justifikacją LeftCenter uzyskaną za pomocą: tx1.VerticalMode = TextVerticalMode.TextVerticalMid; Najpierw efekt którego nie chcę: Kompletny kod który to realizuje: using ZwSoft.ZwCAD.DatabaseServices; using ZwSoft.ZwCAD.EditorInput; using ZwSoft.ZwCAD.Geometry; using ZwSoft.ZwCAD.GraphicsInterface; using ZwSoft.ZwCAD.ApplicationServices; using ZwSoft.ZwCAD.Runtime; namespace JigTest { public class Jig : DrawJig { private readonly Point3d basePoint; private readonly Entity entity; private Point3d currentPoint; private Matrix3d transformation; public Jig(Entity txt, Point3d point) : base() { entity = txt; basePoint = point; } public Entity GetEntity() { var result = entity.Clone() as DBText; result.TransformBy(transformation); return result; } protected override SamplerStatus Sampler(JigPrompts prompts) { JigPromptPointOptions jigOpt = new JigPromptPointOptions("Wskaż punkt wstawienia:") { UserInputControls = UserInputControls.Accept3dCoordinates, BasePoint = basePoint }; PromptPointResult res = prompts.AcquirePoint(jigOpt); currentPoint = res.Value; return SamplerStatus.OK; } protected override bool WorldDraw(WorldDraw draw) { transformation = Matrix3d.Displacement(basePoint.GetVectorTo(currentPoint)); var geometry = draw.Geometry; if (geometry != null) { geometry.PushModelTransform(transformation); geometry.Draw(entity); } return true; } } public class JigCommands { [CommandMethod("JIG")] public void Jig() { try { var tx1 = new DBText(); tx1.SetDatabaseDefaults(); tx1.TextStyle = Application.DocumentManager.MdiActiveDocument.Database.Textstyle; tx1.Height = 2; tx1.Position = new Point3d(0, 0, 0); tx1.TextString = "Tekst"; tx1.VerticalMode = TextVerticalMode.TextVerticalMid; var jig = new Jig(tx1, new Point3d(0, 0, 0)); Application.DocumentManager.MdiActiveDocument.Editor.Drag(jig); var ent = jig.GetEntity(); SaveToDatabase(ent); } catch(Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message); } } public static void SaveToDatabase(Entity ent) { Document doc = Application.DocumentManager.MdiActiveDocument; using (var tr = doc.TransactionManager.StartTransaction()) { var btr = tr.GetObject(doc.Database.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; btr.AppendEntity(ent); tr.AddNewlyCreatedDBObject(ent, true); tr.Commit(); } } } } Jak widać obiekt DBText przed wstawieniem do bazy rysunku ignoruje ustawienie TextVerticalMode. W trakcje wybory miejsca wstawienia ma osadzenie domyślne LeftBottom. Po zapisaniu encji do bazy rysunku dopasowanie jest respektowane i obiekt jest wyświetlany prawidłowo LeftCenter. Rozwiązaniem jest przed przekazaniem do klasy Jig obiektu uprzednio zapisanego do bazy a następnie usunięcie go z bazy przed wywołaniem metody Drag() [CommandMethod("JIG")] public void Jig() { try { var tx1 = new DBText(); tx1.SetDatabaseDefaults(); tx1.TextStyle = Application.DocumentManager.MdiActiveDocument.Database.Textstyle; tx1.Height = 2; tx1.Position = new Point3d(0, 0, 0); tx1.TextString = "Tekst"; tx1.VerticalMode = TextVerticalMode.TextVerticalMid; SaveToDatabase(tx1); var jig = new Jig(tx1, new Point3d(0, 0, 0)); EraseFromDatabase(tx1); Application.DocumentManager.MdiActiveDocument.Editor.Drag(jig); var ent = jig.GetEntity(); SaveToDatabase(ent); } catch(Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message); } } public static void EraseFromDatabase(Entity ent) { Document doc = Application.DocumentManager.MdiActiveDocument; using (var tr = doc.TransactionManager.StartTransaction()) { ent.ObjectId.GetObject(OpenMode.ForWrite).Erase(true); tr.Commit(); } } Efekt jest prawidłowy ale metoda wydaje się być nieco na około. Na koniec pytanie: Czy jest jakiś elegancji sposób aby metoda geometry.Draw(entity) wołana w metodzie WorlDraw klasy Jig respektowała właściwości obiekty typu DBText zanim ten obiekt zostanie utrwalony w bazie rysunku?
  11. Faktycznie zmianą tego klucza można sterować jaki interfejs się załaduje przy starcie. Zmiana w trakcie działania nie przynosi efektu tzn. przy zamknięciu i tak do rejestru jest zapisywana ponownie wartość zgodna z chwilą zamknięcia. Tak więc tą metodą można sterować stylem gdy ZwCAD nie jest uruchomiony. Ale odczytać jak najbardziej można. Dzięki za podpowiedź. Natomiast otwartym pozostaje pytaniem o zdarzenie które jest uruchamiane w momencie zmiany w opcjach okna Options->Display->Color scheme.
  12. No niestety. Chodzi mi o zmianę stylu interfejsu ciemny/jasny a nie zmianę koloru tła obszaru roboczego. Doprecyzuję cel. Chodzi o automatyzowanie dostosowania ładowanych pasków narzędzi do aktualnego stylu. Czy maja być ładowane ikony dostosowane do jasnego czy ciemnego tła.
  13. Witam. Czy mógłby ktoś podpowiedzieć jakie zdarzenie należy zasubskrybować, żeby śledzić zmianę schematu kolorów Dark/Light? Czy jest może jakaś zmienna systemowa albo jakaś propertka którą można sprawdzić aktualny schemat kolorów ZwCAD'a, no i czy można taką zmianę sprowokować programowo?
  14. Można też użyć Ctrl+C Ctrl+V z pomocą trybu Object snap tracking (F11)
  15. perlon

    Zamiana obiektów

    Można również bez filtra zaznaczyć wszystkie okręgi, zmienić im średnicę na oczekiwaną, a potem lisp'em do kasowania duplikatów usunąć nadmiarowe.