Showing posts with label TCanvas. Show all posts
Showing posts with label TCanvas. Show all posts

Tuesday, 31 January 2012

Projecting 3D points to a 2D screen coordinate system

In this article I will put forward a small function to project 3D points to a 2D coordinate system. I have used VLO framework to display all the points after the calculation of different common functions. The most difficult part is to correctly project 3D points into a 2D perspective. Basically the way to display the points is by using a viewport and setting it up correctly. Once all the points are calculated, we need to apply the transformations matrix to position the viewport and then draw the 3D object projected into a 2D canvas from the viewport perspective. The following function will use rotation matrix to correctly position the points. 

Sample code:
procedure T3DMesh.CalcPoints();
function d3Dto2D (viewport: T3DViewPort; point : T3DPoint; centre : T2DPoint; zoom : double) : T2DPoint;
var
  p : T3DPoint;
  t : T3DPoint;
  d2d : T2DPoint;
begin
  p.x := viewport.x + point.x;
  p.y := viewport.y + point.y;
  p.z := viewport.z + point.z;

  t.x := (x * cos(viewport.roll)) - (z * sin(viewport.roll));
  t.z := (x * sin(viewport.roll)) + (z * cos(viewport.roll));
  t.y := (y * cos(viewport.pitch)) - (t.z * sin(viewport.pitch));
  z := (t.y * cos(viewport.pitch)) - (t.z * sin(viewport.pitch));
  x := (t.x * cos(viewport.yaw)) - (t.y * sin(viewport.yaw));
  y := (t.x * sin(viewport.yaw)) + (t.y * cos(viewport.yaw));
  d2d := nil;
  if z > 0 then
  begin
      d2d := T2DPoint.Create(((x / z) * zoom) + centre.x, ((y / z) * zoom) + centre.y);
  end;
  result := d2d;
end ;

var
  listPoint : TObjectList;
  i: Integer;
  j: Integer;
  x, y, z: Double;
  d2dpoint : T2DPoint;
begin
  listPoint := TObjectList.Create;
  listPoint2 := TObjectList.Create;

  x :=-2.0;
  y := -2.0;
  z := 0.0;
  for i := 0 to 40 do
  begin
    y := -2.0;
    for j := 0 to 40 do
    begin
      z := cos((x * x + y * y) * 2) * exp(-1 * ((x * x) + (y * y)));
      listPoint.Add(T3DPoint.Create(x,y,z));
      y := y + 0.1;
    end;
    x := x + 0.1;
  end;

  for i := 0 to listPoint.count - 1 do
  begin
    d2dpoint := d3Dto2D(viewport, T3DPoint(listPoint[i]), centre, zoom);
    if Assigned(d2dpoint) then
      listPoint2.Add(d2dpoint);
  end;
  listPoint.Free;
end;


Examples:
z = sin(x) * cos (y):

z = cos((x^2+y^2)*2) * exp-(((x^2)+(y^2))):

z = x^2*exp(-x*x)*y^2*exp(-y*y):


With parameters:

Related links:

Sunday, 15 January 2012

Scripting Language with Thundax P-Zaggy

In this article I will show you the approach taken to solve a common problem: Creating your own Scripting Language using a compiler. Sometimes we need to create our own language and to achieve that we either can create from scratch a lexical analyser in a high level language or use an open source automatic generator of lexical analysers. As I do not want to spent too much time in this task, I obviously chose the second one using an easy approach using JFLEX and CUP. There are many to choose from, e.g. Antlr, JavaCC, SableCC, Coco/R, BYacc/J, Beaver, etc. but I like the way Cup/Jflex work together. Jflex will automatically generate the finite automata of the lexical analyser through the regular expressions that define the tokens from a language. CUP is a system written in Java used to generate LALR syntax analysers. Cup file will contain the syntax definition of the language (Grammar) using a notation similar to BNF (Backus-Naur).
This approach will allow me to create a small compiler which will contain a lexical analyser, a syntax analyser and a semantic analyser without having to add extra workload to my simple Language builder. Cup/Jflex compiler will handle whether the language is well defined or not and in my Delphi project I only have a dummy function that will run if the previous compiler returns 0 errors.
I have also taken advantage of the SynEdit multi-line edit control to enhance the visualization of the simple Scripting Language. The exposed example is pretty basic and it will help to keep the grammar out of the Delphi code. I have tried other Delphi alternatives like GOLD parser and Coco/R but I did not get the expected results. So, If you have any better idea, please do let me know!.
This example will allow the user to define the graph by calling the layout object and connecting one node from another using a numeric description. In left side figure you can actually see the basics of the language and its definition. It invokes the layout object and then it generates a connection from the node(1) to node(2) and it ends the sentence with ";" character. There is no need to define the nodes as if a node does not exist it will be automatically created. The compiler created will manage all kind of errors and warnings and it will inform the user about them. Check that it will inform whether you are committing a lexical error (non recognized symbols, etc) and syntax error (bad composed expressions) through an Error or a semantic error (duplicated lines) through a warning.
A most developed example is shown in the following figure:
Once the language is free of errors, the generator is enabled and P-Zaggy can build the graph using the instructions previously defined and analysed by the external compiler. Note that to be able to check the language you must have installed Java.

The following graph have been created using the basic language:
As you can see it is faster than placing all the objects with the mouse and we can use external tools to generate the script and then check them with the compiler.

Here you can get the latest version of the app:


Jflex regular expressions:

<YYINITIAL>layout {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.layout, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>node  {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.node, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>\( {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.OpenBracket, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>\)  {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.CloseBracket, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>tonode {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.tonode, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>parameters  {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.parameters, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>\. {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.dot, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>\; {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.endSentence, new sToken(pos - yytext().length(), yyline, yytext()));
}
<YYINITIAL>[0-9]+ {
  if (CUP$parser$actions.verbose)
    System.out.println(yytext());
  pos += yytext().length();
  return new Symbol(sym.INTEGER, new sToken(pos - yytext().length(), yyline, yytext()));
}

[ \t\r\n]+  { pos = 1; }
[a-z]+          {
  System.out.println("ERROR at line "+(Integer.valueOf(yyline)+1) + ": '" +yytext() + "' not recognized");
  pos += yytext().length();
  return new Symbol(sym.ff, new sToken(pos - yytext().length(), yyline, yytext())); }
.   {
  System.out.println("ERROR at line "+(Integer.valueOf(yyline)+1) + ": '" +yytext() + "' not recognized");
  pos += yytext().length();
  return new Symbol(sym.ff, new sToken(pos - yytext().length(), yyline, yytext()));
}

Cup grammar:

terminal        sToken  layout, node, OpenBracket, CloseBracket, tonode, parameters, dot, endSentence, ff;

terminal  sToken          INTEGER, ITEM, QUOTE;

non terminal  scriptClass graphLine;
non terminal    sToken          itemBracket, itemReturned;

graphLine ::=  layout : t1
   dot : t2
   node : t3
   itemBracket : e1
   dot : t6
   tonode : t7
   itemBracket : e2
          endSentence : t10
          graphLine
                        {:
    scriptLines.AddTokens(e1, e2);
    RESULT = scriptLines; :}
          | error;

itemBracket ::= OpenBracket : t4
   itemReturned : e1
   CloseBracket : t5 {: RESULT = (sToken)e1; :}
                        | error;

itemReturned ::= INTEGER : e1 {: RESULT = (sToken)e1; :}
                 | error;

Related links:

Friday, 30 December 2011

Finite automata to Regular Grammar with Thundax P-Zaggy

Moving ahead with FA, now we can generate the right-linear grammar that corresponds to the finite automata generated. The system is pretty simple and basically what the algorithm does is to go recursively through every state and to store the production (A → bC) using the info from the transition and both states.

P-Zaggy will use description text to assign unique variable names to each state. Each transition in the graph matches a production in the right-linear grammar. For example (right side image), the transition from “A” to “B” along the transition “a” matches the production “A → aB”. This production will be automatically added into the production list in the "Finite Automaton (simulation)" tab. To generate the full grammar, just open your finite automata and press "Get grammar" button to get the linear grammar. Now as any final state carries the production to λ, λ symbol has been added to the system as empty string.

In the following image you will see a general example with the automatically generated grammar:


Example with λ string:


Demo video:

Get the latest version from here:

Looking back/ahead:
This would be the last post of the year 2011 and I'm taking this moment to review all the good stuff I have been publishing in my blog, from the physics engine to different code snippets and all of them with the help of a big an bright Delphi community. I always find difficult to get round to writing more often but I always have my notebook with me and every time and idea pops out I am there to catch it. I have an endless list of really interesting stuff I would like to tackle and I hope next year would be more fruitful as there are less than 50 articles for this year (even though the visits have been increased to almost 6K per month wow!, I am grateful for that!). I am also blissfully happy for putting grain of salt in the community as I have widely used the knowledge of others and it is great to pay back.
Next year I will be implementing different algorithms and I will be focusing on grammars, compilers and AI as I am very keen on those subjects and as you already know I like a lot visual stuff (And everything or almost everything with my loved Delphi). I'm preparing a roadmap about different utilities I have in mind and stay tuned for new and very interesting stuff!.
Happy new year 2012!.
Jordi Corbilla

Related links:

Thursday, 29 December 2011

Finite Automata with Thundax P-Zaggy part II

Going on with the further enhancement of P-Zaggy (part I) to use its graph creation capability to run and simulate DFA, I have released a new version (v1.2.0 build 180) which allows you to check a bunch of strings in batch. One the DFA is defined, we can easily test our input strings by adding them into the list and the application will check every item and it will populate the status with "accepted/rejected" message. This version still only works with one char regular expressions (^[A-Z]$) so more complex expressions (^[A-Z]+$) will be used but not correctly adapted.

Examples:


Related links:

Finite Automata with Thundax P-Zaggy part I

I have moved forward the development of Thundax P-Zaggy with the addition of a Finite Automata builder and simulator. "A deterministic finite automaton (DFA) also known as deterministic finite state machine is a finite state machine that accepts/rejects finite strings of symbols and only produces a unique computation (or run) of the automaton for each input string. (wikipedia)". Building the automata with P-Zaggy is quite simple, so let's start by building a DFA for the following language: 
L = {ba | abna, n > 0}.
As it is shown in the previous image, the DFA would be as follows:


With the tool we would be able to create our diagrams placing the states and transitions. Once the diagram is set up, all transitions need to have the transition string to change the ongoing state and initial and final states need to be selected (using right click and selecting "Mark as Start Node" for Initial state and "Mark as End Node" for Final state).



We can start the simulation with very simple steps. Firstly, select the tab called "Finite Automaton (simulation)" and enter the test input string to test. Then press start button to internally initialize the graph as a DFA and press step to process every character of the input string while the diagram is changing states and showing you which is the actual state and whether the string is being accepted or rejected. To set up a single loop transition, select the node and with right click select "Set connector loop" and add text for the transition.


In this beta version, we can also use Regular Expressions in our transitions thanks to the widespread use of regular expressions inside Delphi XE. 


From the same screen we can test our regular expressions and check whether if they match or not. There are still some issues to tackle like "empty string" and other considerations that I would be delving into detail in the following days. I am also working on a Layered-Tree-Draw Algorithm using Reingold-Tilford Algorithm and the enhancement of the better recognition of more complex regular expressions.

Have a look at this preview of the functioning of the graph, it is really worth it:


Stay tuned and give P-Zaggy a try from here:
Related links:

Wednesday, 24 February 2010

Thundax P-Zaggy v1.2 beta

This week I've been stressed-out in some projects that I'm doing (I'll talk about them this year, but for now it's like a secret - it also depends on the confidentiality agreement that I've signed to keep these projects hidden until they are finished). That's a big deal because I'm preparing a lot of documentation about them but it's impossible to publish it. Anyway, we'll talk about this other day, but not so far.

In this post I'm writing about the next release of Thundax P-Zaggy v1.2. I know that I've been releasing versions very fast, but I need this program done (means tested and documented) by the end of the year, in order to go on with my future plans. This new version is an improvement of the last one with a lot of refactoring. I've changed all the property system applying a template method pattern.

Now, if we take a look at the properties, we can notice:

There are new properties and I've tweaked the buttons to give a better presentation to the application. Now all the property forms have this new image:



I've also changed some forms to give the user more information:

And I've improved the visualization of the "load project" where the user can see a little preview of the document. Now the user can guess what's inside at a glance:



I hope you enjoy!.

Related Articles:

Friday, 19 February 2010

Thundax P-Zaggy v1.1 beta (Bugs Fixed)

After few days working with the Application I've discovered some interesting bugs that needed to be fixed as soon as possible in order to increase the productivity of using the program. That's why I'm releasing the version 1.1 with very good improvements. I've also tested the efficiency of the drawing system creating a graph with more than 400 nodes and 800 edges. And it was totally successful without any feeling of loosing power. You can see the list of bugs into the bug tracker, and add one if you've noticed that anything goes wrong.

In the next video you'll see the power of the application trying to solve a large of complicated connected nodes that are composing a net. You can test by yourselves by downloading this simple test "test.txt" from SourceForge and going to Graph -> Graph Script Implementator and copying the downloaded list. After that you only have to click on the red bolt, but before that be sure to have configured correctly all the parameters referring to the layout system.

As for this example, my configuration is the following one:










I've also fixed the correct drawing of the imported images. Now you'll see the images with a transparent background:

I've changed the background colour to one that's known, for example fuchsia, and then I only need to get the pixel located in the [0,0 coordinates] and use it as the transparent colour. After that, we only need to scan the picture and change the colour of the pixel.

The coding of the transparent image would be something similar to this:


if (FImage <> '') then
begin
Bitmap := Graphics.TBitmap.Create;
Bitmap.LoadFromFile(ExtractFilePath(ParamStr(0)) + Self.FImage);
Bitmap.Transparent := true;
Bitmap.TransparentColor := Bitmap.canvas.Pixels[0, 0];
Bitmap.TransparentMode := tmFixed;
canvas.Draw(ClientToGraph(Vertex1).x, ClientToGraph(Vertex1).y, Bitmap);
FreeAndNil(Bitmap);
end;
I hope you enjoy!. Don't forget to leave a comment if you've tested the application!.
  • Related Articles:
Thundax P-Zaggy v1.0 Released!.
Automation Object Library for Vijeo Citect.

Tuesday, 16 February 2010

Thundax P-Zaggy v1.0 released!

I'm so proud to announce the release of my last application Thundax P-Zaggy v1.0 that implements the VLO Framework v2.0. You can get it from sourceforge download page. I'm working on the user documentation that will help you with the basic parameters of the program. In few weeks I'll release a little presentation that explains all the evolution of the application and where the idea comes from. This new version that merges the working of the Thundax Box Manager and Test Canvas Framework lets you work with the next modules:
  • Graph module (properties and layout scripting)
  • Algorithm module (Dijkstra)
  • Path module (Algorithm to find the path graph)
  • Vijeo Citect module (Scan a vijeo citect page)
  • Export module (module of data exportation)
Every of these modules have their own purpose, and are created to fulfil every of the previous requirements that it was aimed to. The final goal of the project is to scan a vijeo citect scada page with all the objects instantiated and then with my application, get all this objects that are modelling a system (this would be, for example, a transport routing system). When I have all these objects, I can work with them because I've translated from one side to the other, and now I can create a little graph and calculate all the different routes or paths that exists into the modelled system. It's difficult to explain, but you'll understand better with the following videos.

Tuesday, 9 February 2010

Parsing and drawing molecular structures with delphi part II

Today I've released the last version of my program with several changes into the graph script implementation. This new version has a little windows with a simple syntax highlighting system with the usually tokens that I use in my script. The scripting language is very easy to use and very intuitive instead of only writing numbers with no sense. Now we can create and manipulate the way the graphs are created by simple commands. I'm working on the syntax checker that will tell you the error line and a little description of the problem.

Now we can write:


layout.node(x).ToNode(y).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];


where:

layout, is the canvas where we need to create our node or to look for our node. node(x) is the first node to need to be created and this will be connected to toNode(y). We can finish this sentence here (with a semicolon mark ";") or going on calling the parameters. Where we have, the EdgeType, SizeBox, LineColor and PenWidth parameters. On the EdgeType parameter, we can use this list:
  • SimpleEdge
  • SimpleArrowEdge
  • SimpleDoubleArrowEdge
  • SimpleDoubleLinkedArrowEdge
  • DottedEdge
  • DottedArrowEdge
  • DottedDoubleArrowEdge
  • DottedDoubleLinkedArrowEdge
Each of one of these edges, will draw a different kind of component into the layout. For the SizeBox we can specify an integer number in pixels to build or resize the length of every box inside the command. The line colour is a typical delphi constant like clRed, clBlue, clYellow, etc. and the last property as an integer number as well as the SizeBox, PenWidth, that will change the width of the line drawn.

This script will generate the next diagram:

I'll try to finish all the things that I have in mind this week in order to focus on other parts of the application. Due to the last petitions into the post "Automation Object Library for Vijeo Citect", I'm being forced to show you (willingly) my last achievements into this field. I'm still merging my last application "Thundax Box Manager" with the last version of my "Canvas test Framework", and I'm very keen on releasing the new application "Thundax P-zaggy" that will contain all the modules to work with graphs.

You can now download the last released version from SourceForge:
I hope you enjoy!.

Friday, 5 February 2010

Parsing and drawing molecular structures with delphi part I

After being very busy in several projects that I'm enrolled. I've managed to get some time extra to go on in my little project. This week I've been working on a little scripting language that let me build different structures by using it. I still have to fix some bugs and I have a very long list of new features. By using this little structure, we can modify the different nodes and edges that we are building. For example if we have this:


node(1).ToNode(2).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];
node(2).ToNode(3).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];
node(3).ToNode(4).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];
node(4).ToNode(5).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];
node(5).ToNode(6).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];
node(6).ToNode(1).parameters := [EdgeType = SimpleArrowEdge, SizeBox = 20, LineColor = clRed, PenWidth = 2];


The application will build the next structure:

Well, at this point, how can we manage molecular structures? In this case, we only need the adjacent list and parse it to let the application force the position by using its force-directed graph layout. It's amazing the all kind of structures that the system can process and work with.

Sunday, 17 January 2010

Parsing algorithm for Graph implementation part I

Working on your own project has the inconvenient that you have to find some extra time to do all this stuff. My last project (VLO Framework) it's been like a dream come true (Developing a graphic system is not easy). Maybe in two or three months I'll be able to sit back and reflect a bit, but for now it's pretty hectic. I'm keen on releasing a new product (P-Zaggy) that implements a lot of algorithms to use with graphs. I am preparing a power point that I'll publish in order to introduce you to this application. I have a lot of ideas, and sometimes it's quite difficult to tell my brain to shut up!.

In this article, I'll introduce you How I built this little parsing algorithm to implement a graph inside the canvas test framework. With this little gadget, now the application is getting quite spectacular. Now, adding a simple edges list, we can generate a diagram and using the layout algorithm, format the entire graph as we desire.

Sunday, 10 January 2010

Force-Directed graph layout approximation part IV

I'm still working on the component, and I've implemented zoom in and zoom out methods for the better visualization of the graph. The issue here is that when we develop a system like this (visual application with mouse edition), all the action it should do is allegedly involved. Like the drag and drop, the zooming system, printing, etc. And you should always take into account all these problems. We have got into a bad habit by what the other programs do, and when we develop a new application, we usually take a little from everywhere. Nevertheless, it's better to let things clear from the beginning and report the final characteristics of your program.

With this new methods, now we can enlarge the graph and zoom out the view until we see all the drawing inside the picture. I haven't finished it yet, but I can show you the latest results:


Wednesday, 6 January 2010

Force-Directed graph layout approximation part III

Today I've released the last version of my project VLO. You can find the latest win32 desktop application with the canvas test here:
In this version I've made several changes due the bug list that I had. Now, after fixing all the little bugs that the application had, I can say that I'm very satisfied with the results. Indeed, I've changed the hierarchy of classes that I have, and I've moved all of them to a TNode and TGraph classes instead of TBox and TBoxManager. In a few weeks I'm gonna release a new application with all this algorithms (and I'm still thinking in the name of this application).

Monday, 4 January 2010

Force-Directed graph layout approximation part II

In this article I'll describe the different calculations that we have to do in Repulsive and Attraction methods to calculate the position of the different nodes. As I published yesterday in part I, I'll focus on the Hooke's and Coulomb's laws and the integration inside the platform.
  • Hooke's Law (attractive force):
The functionality here is very simple, we need to think that every edge represents a spring, and when 2 nodes that are connected try to move in opposite direction (by a force of repulsion), the spring tend to be deformed by that force. When this happens (the spring is being forced to move) , it returns to the initial state of equilibrium. For this, we need to create a model to generate this behaviour. I've found several examples on the Internet, like in johngrindall.com (Pendulum simulation ), for example in youtube we can find very good videos explaining the hooke's law:

Sunday, 3 January 2010

Force-Directed graph layout approximation part I

I've been working on these last days in a Force-Directed graph layout approximation applicated in my VLO Framework (That's why I've been off these days without posting anything). The system consists on applying physics laws to each node calculating the repulsion force using Coulomb's law and the attractive force using Hooke's law. To do this, I've made a lot of changes to accomplish all the requirements of the new functionality. Now, every TBox class implements a TNode class which has all the physics components like hooke_force, coulomb_force, speed, mass, etc. And the manager ThundaxBoxManager that handle all the canvas methods now implements the TGraph class which has all the data about repulsion calculation, attraction calculation, energy of the system, etc. The algorithm is easy to understand because it works in a simple way. We need to iterate every node and calculate in steps the hooke and coulomb force for everyone. In every step there will be new forces that interact with each node, and when the total amount of energy is nearly zero, we can stop the algorithm.

Tuesday, 22 December 2009

Stretching an image

Muchas aplicaciones disponen de una pequeña previsualización de sus documentos, de ésta manera echando un vistazo a su preview o thumbnail nos podemos hacer una idea de que documento o proyecto hay dentro de ese fichero. El problema me vino a la mente cuando trabajando en mi proyecto (VLO) me di cuenta de que había hecho más de 20 proyectos y ya ni me acordaba que había en cada uno de ellos, y claro la única solución es abrir cada uno de los documentos hasta encontrar el proyecto que querías abrir.

La solución que propongo aún está muy verde pero es una solución que de momento va bien y que permite obtener la imagen del documento que se está editando sobre el canvas, recortar la parte útil y redimensionarla para que luego podamos mostrarla en el preview de la carga de proyectos.

Monday, 21 December 2009

New features with VLO framework part V

Aún estoy retocando diversas características de la plataforma y me queda mucho trabajo por delante. Pero lo bueno es que el proyecto sigue en pie, con muchísimos cambios insignificantes a simple vista, pero que marcan una gran diferencia en el comportamiento final. He actualizado temas de movimiento y conexionado de nodos, de ésta manera podemos realizar ediciones mucho más rápidas y más precisas. Además estoy empezando a llevar el sistema al límite, realizando pruebas unitarias sobre las diversas clases que tengo (os recomiendo el Pragmatic unit testing donde se muestran muchas de las técnicas utilizadas sobre las pruebas unitarias) y sobrecargando los diversos objetos intentando que el sistema se vuelva inestable.

De momento las pruebas son satisfactorias y la aplicación parece robusta. Aquí os dejo las nuevas funcionalidades de la plataforma:
  • Mejora en el conexionado entre nodos (corrección del cursor)
  • Posibilidad de incrustar una imagen en el background de la aplicación
Por ejemplo ahora en minutos podemos crear increíbles diagramas de todo tipo y lo mejor de todo es que luego podremos personalizar el funcionamiento de los objetos para propósito general. El siguiente ejemplo es una muestra a un vistazo a un enrutamiento de red:

Ésta imagen dispone de más de 200 nodos y 230 vértices y el movimiento y los cálculos siguen siendo muy rápidos.

Además al poder cargar una imagen de fondo, podemos dibujar diagramas sobre planos y así luego diseñar diversos algoritmos para la búsqueda de caminos mínimos o rutas:

También os dejo el último vídeo que ha subido mostrando las últimas características implementadas y que espero que os sorprendan y os gusten:





Aquí os dejo también el enlace al último built que he hecho de la plataforma en Win32 para que so la podáis descargar y probar. Los ejemplos con las imágenes también los podréis encontrar aquí.


Monday, 30 November 2009

New features with VLO framework part IV


Ultimando detalles del editor de objetos sobre un canvas de delphi, aquí os dejo la última modificación permitiendo así poder mover los diferentes componentes de la pantalla con total libertad. Con ésta nueva versión ya casi está listo el editor con el que podré crear diagramas mucho más complejos y con una estructura más intelijible y más bonita. Aún me queda el tema de centrar el texto dentro de Tbox, pero aún me estoy pensando si va a ser útil o no (además no es fácil hacer el cálculo y tengo que calcular el tiempo que voy a invertir).

La modificación ha sido relativamente fácil ya que dispongo de los diferentes métodos de movimiento sobre Tbox, luego solo tengo que ir a los enlaces, buscar los diferentes Tbox asociados (origen, destino) y mover los puntos de éste permitiendo así mover el diagrama completamente.

Además he añadido 2 propiedades nuevas para poder personalizar el editor, una que nos permite cambiar el color de fondo y otra el color de la grid.

Ahora podemos visualizar los diagramas de la siguiente manera:

Aquí os dejo también uno de mis famosos vídeos a los que ya me estoy empezando a aficionar, ya que de una manera fácil y rápida os puedo mostrar las diferentes modificaciones de la plataforma y podéis ver el resultado.





También os dejo la aplicación de test para probar el componente:



Wednesday, 28 October 2009

Cálculo de rutas de transporte parte III

Continuando con los artículos sobre el tema del cálculo de rutas, aquí os dejo la última versión estable y mejorada sobre un ejemplo un poco más complejo y más real para diferentes destinos y con bloqueos entre elementos. El término bloqueo significa que no puede existir una ruta sin antes bloquear una serie de elementos. Éstos se tienen que vigilar, entre sí, ya sea por un equipo inteligente u otro tipo de algoritmo o aplicación. En éste ejemplo veréis como puede llegar a complicarse un sistema de rutas:

Si nos fijamos bien, existen muchos destinos y además existen bloqueos entre caminos (representados por un nuevo concepto de símbolo):


¿Ésto que indica?. Nos indica que los 4 elementos están bloqueados entre sí, y para no dibujar (n-1) flechas entre los diferentes objetos, creamos uno diferente que creará automáticamente el enlace con las demás cajas. De ésta manera cuando se cree el camino que pase por el elemento 4, éste llamará a la caja superior y recogerá los 3 elementos que tiene para introducirlos en la descripción de la ruta.

De ésta manera obtenemos lo siguiente:


Aquí os dejo la última versión de la aplicación más los ejemplos hasta ahora hechos. Éste último ejemplo lo he hecho en menos de 3 minutos, y el cálculo total de rutas en un total de 16ms.
PD: Ésta última versión está protegida con mxProtector y solo permitirá 10 ejecuciones. De momento tengo que poner ésto ya que no es una versión definitiva y no quiero que corra por la red sin antes tener montada una buena base. Además, ahora ya empieza a hacer cosas importantes.

Monday, 26 October 2009

Cálculo de rutas de transporte parte II

Continuando con mi anterior artículo, he mejorado el algoritmo de búsqueda de caminos, de tal manera que ahora permite la búsqueda de un sinfín de posibilidades con tiempos extremadamente pequeños. En la versión anterior me di cuenta de que había un problema con el diseño del algoritmo y era referente a que a la hora de buscar los nodos adyacentes, éstos tienen que estar ordenados por el número de conexiones entrantes que tienen. De ésta manera podemos calcular cosas tan complejas como éstas:

A simple vista parece ser bastante difícil el obtener el número de caminos disponibles pero al final acaba siendo un simple recorrido de nodos:

Como podéis ver en la última imagen, hay 31 rutas disponibles. Además, en ésta última versión, ya está resuelto el problema de multi-orígenes y multi-destinos de tal manera que el algoritmo ya es capaz de recorrerlos todos con un coste cuadrático. Hay que mejorar un poco el coste pero estamos hablando de hacer el cálculo de unas 30 rutas en unos 16 mili segundos.

Si nos fijamos en la siguiente imagen, podréis ver la resolución con múltiples orígenes y múltiples destinos:

Si os fijáis en la imagen también queda marcado el camino seleccionado en la grid, de ésta manera visualmente podemos reconocer la ruta seleccionada y comprobar que los cálculos estén correctamente realizados.

El cálculo ahora es bastante diferente de como se hacía en el artículo anterior. Se me ocurrió la idea de realizar la búsqueda a través de la tabla de adyacentes sin tener que hacer antes un barrido. De ésta manera realizando una serie de operaciones que ahora detallaré, tenemos resuelto el problema del cálculo de rutas de transporte.

Con el siguiente código realizamos el recorrido total de la lista de adyacentes:


fila := 1;
filas := 0;
columna := 1;
for i := 0 to length(AdjacentList) - 1 do
begin
if AdjacentList[i].isSource then
begin
grid[columna, fila] := Inttostr(AdjacentList[i].source);
grid[columna + 1, fila] := Inttostr(AdjacentList[i].destiny);
AdjacentList[i].visited := true;
filas := filas + 1;
fila := fila + 1;
end;
end;

bVisited := false;
while not bVisited do
begin
sum := 0;
for i := 1 to filas do
begin
columna := getLastColumn(i);
SetLength(Connector, 0);
GetList(Connector, AdjacentList, StrToInt(grid[columna - 1, i]));
if Length(Connector) <> 0 then
grid[columna, i] := IntToStr(Connector[0].destiny);
if Length(Connector) > 1 then
begin
newRows := CloneRow(i, Connector);
sum := sum + newRows;
end;
end;
filas := filas + sum;
bVisited := AllRowsFinished(filas, DestinoList);
end;


  • ¿Como funciona?
Primero buscamos los orígenes de la lista de adyacentes y los situamos en la grid, por ejemplo:
1 2
1 3
Luego recorremos ésta lista buscando los adyacentes de los últimos nodos, 2 y 3. Por lo tanto encontraremos que el 2 estará conectado con el 4 y el 5 y el 3 solo con el 6. En el momento que tenemos que añadir el valor 4 detrás del 2, si vemos que hay más conexiones, realizamos un clonado de la línea que estamos tratando y insertamos el siguiente valor en la línea clonada:
1 2 4
1 3
1 2 5 (clonado)
Continuamos con la siguiente fila:
1 2 4
1 3 6
1 2 5
Ahora, tenemos que volver a empezar y volver a añadir las conexiones de los nodos posteriores e ir clonando las diferentes filas hasta llegar al final:
1 2 4 8
1 3 6 7 8
1 2 5 8
1 3 6 8
De ésta manera tan fácil conseguimos construir la lista de rutas de transporte, siempre teniendo en cuenta los diferentes orígenes y destinos que nos podemos encontrar.

Podéis descargar la última versión de la aplicación con los ejemplos aquí:
PD : Para la ejecución del algoritmo correcto, hay que ir al menú Citect -> Calc Routes 2 una vez el diagrama está abierto.