Posts Tagged ‘Ruby’

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…