Posts Tagged ‘.NET’

Komunikacja projektanta z oprogramowaniem do projektowania (GoogleSketchup)

sobota, Lipiec 9th, 2011

Przez ostatni rok wzmocniłem swój warsztat używanych narzędzi do projektowania. Trochę więcej o jednym z nich będzie dzisiaj, tj. o „Sketchup” firmy Google.

Poza flagowym oprogramowaniem  „Designer” firmy Komandor S.A., w której pracuję i w której rozwijamy ten soft, istnieje szereg innych programów do projektowania. Najbardziej rozbudowanymi z nich są chyba obecnie AutoCad firmy Autodesk oraz wspomniany „Sketchup” firmy Google. Pierwszy z nich poszerzył swój wachlarz zastosowań właściwie już na każdą dziedzinę projektowania dedykując oddzielne wersje dla elektryków, konstruktorów maszyn, architektów itd, a drugi nastawił się na prostotę i komunikację z użytkownikiem i używany jest m.in. do „tworzenia świata” w GoogleMaps.   Co ciekawe obie firmy nastawione są bardzo przyjaźnie do zewnętrznego środowiska developerów;) Do obu produktów każdy dopisać może swoją wtyczkę, którą bez problemu testować i używać może wspomagając swoją pracę, tudzież rozwijając samo oprogramowanie. I tak, AutoCad przyjmuje wtyczki napisane w .NET (lub wewnętrznych językach ObjectARX i AutoLisp), a GoogleSketchup odpowiednio w Ruby (a ostatnio też C++). Wsparcie, tutoriale, API i pomoce jak najbardziej dostarczane są oficjalnie na specjalnie stworzonych stronach dla developerów:
Developer Center AutoDesk
Google Sketchup Developers

Dla przykładu przedstawię poniżej bardzo prosty skrypt napisany w Ruby dla Sketchupa, który nawiąże komunikację z zewnętrznym, równie prostym serwerem, napisanym w C#.

Najpierw samokomentujący się kod dla klienta:

plugins_menu = UI.menu("Plugins") #pobieramy uchwyt do wtyczek w menu "Plugins" - stąd będziemy uruchamiać naszą wtyczkę

plugins_menu.add_item("Connect to server") { server_connection } #dodajemy naszą wtyczkę, która uruchomi metodę server_connection zdefiniowaną poniżej

require 'D:/Programy/Ruby186/lib/ruby/1.8/i386-mingw32/socket' # wskazujemy na standardową bibliotekę - będziemy potrzebować modułu socket.so

#metoda łączaca się z zewnętrznym serwerem, wysyłająca komunikat i wyświetlająca odpowiedź:

def server_connection

port = 2011  #ustalamy port połączenia

streamSock = Socket::new(Socket::AF_INET, Socket::SOCK_STREAM, 0) #tworzymy socket

myaddr = [Socket::AF_INET, port, 127, 0, 0, 1, 0, 0].pack("snCCCCNN") #tworzymy adres, będziemy łączyć się do localhosta, więc jest tu zaszyte 127.0.0.1

streamSock.connect( myaddr ) #łączymy się

streamSock.puts "Hello from GoogleSketchup!" #wysyłamy komunikat do serwera

responseMessage = streamSock.recv(100) #odbieramy odpowiedź z serwera

UI.messagebox(responseMessage) #wyświetlamy w okienku Sketchupa informację zwrotną:)

streamSock.close   #zamykamy socket

end

Jedna UWAGA: Najnowszą wersją Ruby jest 1.9.2, ale (najnowszy) Sketchup 8 używa 1.8.6 i w związku z tym konieczne jest używanie modułu ‘socket’ właśnie z biblioteki skompilowanej w 1.8.6 (wyższa nie działa)

Poniżej kod dla serwera:

class Server

{

private TcpListener tcpListener;

private Thread listenThread;

private int port = 2011;

static void Main(string[] args)

{

Server serv = new Server();

}

public Server()

{

this.tcpListener = new TcpListener(IPAddress.Any, this.port);

this.listenThread = new Thread(new ThreadStart(ListenForClients));

this.listenThread.Start();

}

private void ListenForClients()

{

this.tcpListener.Start();

while (true)

{

//blocks until a client has connected to the server

TcpClient client = this.tcpListener.AcceptTcpClient();

//create a thread to handle communication

//with connected client

Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));

clientThread.Start(client);

}

}

private void HandleClientComm(object client)

{

TcpClient tcpClient = (TcpClient)client;

NetworkStream clientStream = tcpClient.GetStream();

byte[] dataReceived = new byte[4096];

int bytesRead;

while (true)

{

bytesRead = 0;

try

{

//blocks until a client sends a message

bytesRead = clientStream.Read(dataReceived, 0, 4096);

}

catch

{

//a socket error has occured

break;

}

if (bytesRead == 0)

{

//the client has disconnected from the server

break;

}

//message has successfully been received

ASCIIEncoding encoder = new ASCIIEncoding();

string messageRecived = encoder.GetString(dataReceived, 0, bytesRead);

string messageReply = "You said: " + messageRecived + "\nWe say: Welcome designer in our external server;)";

byte[] dataToSent = encoder.GetBytes(messageReply);

clientStream.Write(dataToSent, 0, dataToSent.Length);

}

tcpClient.Close();

}

}

Jedyne co trzeba zrobić to skompilować kod C#, uruchomić serwer, a potem zapisać skrypt klienta (z rozszerzeniem *.rb) do katalogu ‘Plugins’ tam, gdzie jest zainstalowany Sketchup (to wystarczający warunek, aby Sketchup przyjął nasz skrypt!),  uruchomić Sketchup i kliknąć Plugins->Connect to server, aby dostać po oczach okienkiem:

Taka komunikacja, choć wymagająca jeszcze rozbudowania, może się przydać do pewnej obróbki danych tworzonych podczas projektowania, podczas której zewnętrzny serwer „pilnuje” lub informuje projektanta o poczynionych krokach na bieżąco;) Całość operacji moglibyśmy zaszyć dzięki temu w zewnętrznym serwerze, a skrypt w Sketchup potrzebny byłby nam w zasadzie jedynie do wysłania danych z programu do projektowania. Notabene analogicznie moglibyśmy zrobić z AutoCadem, ujednolicając sposób obróbki danych gdzieś na zewnątrz, ale o tym może wkrótce…

Biblioteka do wykrywania kolizji na siatkach geometrycznych

czwartek, Kwiecień 8th, 2010

Głównym projektem, nad którym pracuję obecnie (w ramach researchu w mojej pracy magisterskiej) jest biblioteka z algorytmami wykrywania kolizji na siatkach. Przed godzinką utworzyłem projekt, którego postępy można będzie śledzić tutaj:
http://code.google.com/p/interactingmeshes/

Jest to prosta aplikacja, wykorzystująca zaawansowane algorytmy do wykrywania kolizji na siatkach (Mesh), a więc popularnych strukturach geometrycznych reprezentujących obiekty w scenie. Na daną chwilę działan wykrywanie kolizji dla siatek wypukłych (zastosowany jest tu algorytm Gilberta-Johnsona-Keerthi). Ciekawe jak długo potrwa mi jeszcze zakodowanie sensownej wersji dla zbiorów wklęsłych (przy użyciu drzew BSP) i ewentualne usprawniania całego tego przedsięwzięcia, a więc wprowadzenia struktur kd-tree czy też uproszczonych testów na box-ach… pewnie jeszcze hoho:) aczkolwiek powolutku czuję się coraz większym znawcą tematyki kolizji obiektów geometrycznych…

Z cyklu ważne interfejsy .NET – ICloneable

wtorek, Marzec 16th, 2010

Na łamach bloga chciałbym abyśmy zrobili sobie małą powtórkę. Zapewne dla niektórych będą to też duże nowości. Niemniej znajomość interfejsów, które postaram się tu przytoczyć jest na tyle ważna, że każdy post zwróci się z nawiązką zarówno jednej jak i drugiej grupie osób:)

Otóż w bibliotece .NET znajduje się wiele interfejsów godnych uwagi. Twórcy z Microsoftu umieścili nawet część z nich w przestrzeni nazw „System”. Jednym (i zarazem jednym z najprostszych) z nich jest interfejs System.ICloneable, którego zadaniem jest utrzymywanie kontroli nad sposobem tworzenia kopii elementów. Interfejs posiada bowiem jedną metodę o nazwie Clone(), używaną do tworzenia kopii tego elementu:

public interface ICloneable
{
   object Clone();
}

Istnieją dwa sposoby implementacji interfejsu: tzw. głęboka kopia (deep-copy) i płytka kopia (shallow copy). Głęboka kopia polega na kopiowaniu danego obiektu i wszystkich obiektów, do których dana instancja się odnosi (przechodząc rekurencyjnie do wszystkich osiągalnych). Płytka kopia polega na kopiowaniu jedynie wybranych danych, najczęściej tych na najwyższym poziomie (choć nie musi realizować niczego, tak jak może realizować jedynie część głębokiej kopii). Należy zwrócić na to szczególną uwagę, gdyż z powodu tej różnicy różne klasy mogą mieć różne jej implementacje i nie możemy z góry polegać na realizacji jednej z nich. Standardowo, w celu stworzenia płytkiej kopii wystarczy zastosować bowiem metodę MemberwiseClone (dostępną dla każdego obiektu): System.Object.MemberwiseClone. Kopia taka nie radzi sobie jednak z typami referencyjnymi zagnieżdżonymi w klonowanym obiekcie – potrafi poprawnie kopiować tylko tzw. Value Types.

Przykład zastosowania:

using System;
class MyClass :ICloneable
{
   public int myField;
   public MyClass()
   {
      myField = 0;
   }
   public MyClass(int value)
   {
      myField = value;
   }
   public object Clone()
   {
      return this.MemberwiseClone();
   }
}

public class TestMyClass
{
   public static void Main()
   {
      MyClass my1 = new MyClass(44);
      MyClass my2 = (MyClass) my1.Clone();
      Console.WriteLine("my1 {0} my2 {1}",my1.myField, my2.myField);
      my2.myField = 22;
      Console.WriteLine("my1 {0} my2 {1}",my1.myField, my2.myField);
   }
}

wyświetli nam odpowiednio:
my1 44 my2 44
my1 44 my2 22

…a przykład zaczerpnięty został przeze mnie stąd: http://www.gnu.org/projects/dotgnu/pnetlib-doc/System/ICloneable.html.

…już wkrótce o IDisposable:)