Quantcast
Channel: TMS Software
Viewing all 1006 articles
Browse latest View live

Function approximation with TMS Analytics and Physics numerical tools

$
0
0

The problem of data approximation (curve fitting, surface fitting) arises from many areas: economics, physics, informatics and many others. There are many libraries, realizing numerical tools for using the approximation in software applications. The TMS Analytics and Physics pack contains the approximation numerical tool which has one unique feature – it is totally integrated with symbolic calculus. Using symbolic expressions with the numerical approximation gives the developer many advantages.

Let us consider a simple case of using the approximation tool for curve fitting (one-dimensional approximation). For this case we have a set of points Pi=(xi,yi), i=1..N. From the programming point of view we just have two arrays of real values, say X and Y. The approximation problem is to build a function y=f(x) which is close to the set of points. The most popular approach of the approximation is the linear least squares (https://en.wikipedia.org/wiki/Linear_least_squares_(mathematics)). With TMS approximation tool the problem can be solved in five lines of code:

var
  approximator: TLinearApproximator;
  basis: TLinearBasis;
  variables: TArray;
  functions: TArray;
  cValues: TArray;
begin
  variables:= TArray.Create('x'); // 1
  functions:= TArray.Create('e^x', 'sin(x)', 'e^-x', 'x^2', '3^x',   'sinh(2*x)'); // 2
  basis:= TLinearScalarBasis.Create(variables, 'C', nil, functions); // 3
  approximator:= TLinearLeastSquares.Create; // 4
  cValues:= approximator.Approximate(basis, X, Y); // 5
  
  // Using the basis with optimal coefficient values.
end;
Line 1: Create the array of variable names, as this is 1D approximation, there is one variable name ‘x’ in the array.
Line 2: Create the array of approximation functions (basis functions). The functions only depend on the ‘x’ variable. The type and the number of the basis functions can be arbitrary.
Line 3: Create the basis instance with the specified arguments. The ‘C’ argument specifies the name of approximation coefficients. The ‘nil’ argument tells that there is no parameters in the functions.
Line 4: Create the appropriate approximator instance. For the linear least squares approximation it is ‘TLinearLeastSquares’;
Line 5: Calculate the approximation coefficients for the specified basis and arrays of points ‘X’ and ‘Y’.

After the optimal coefficients found, we can evaluate the basis in any point and make other analytical manipulations. As example, here is the plotted approximation function with the original data points on the picture.

The main feature of the TMS numerical tools is they are totally integrated with the symbolic calculus. It brings the following advantages to the developer:
- Minimal code writing, because there is no need to write special classes for the function method references (delegates) as in other numerical libraries.
- Convenient data representation for the developer and user as math expressions, not as programming code.
- Easily using the user input data (string data) for manipulations in programming code.
- Almost unlimited choice of math expressions for manipulations, including special functions.
- Easily transfer input data and the output results via network as strings, easily storing and serializing the data.

The result of the approximation can be easily used with other numerical tools. For example, we can analyze the approximation function for the roots and special points – extremums. The code for the analysis is the following:
var
  f: string;
  sf1D: TSymbolicFunction1D;
  opt: TSolverOptions;
  points: TArray;
begin
  f:= basis.Evaluate(cValues); // 1 
  sf1D:= TSymbolicFunction1D.Create('x', f); // 2 
  opt:= TSolverOptions.Create(true);  // 3
  points:= TFunctionAnalyser.Analyse(sf1D, TNewton, opt, -2, 3, 10); // 4 
  
  // Using the points array.
end;

Line 1: Make the function expression with optimal coefficient values.
Line 2: Create the symbolic function instance for the analysis.
Line 3: Create default options for the nonlinear solver (which used for the function analysis).
Line 4: Finding all function's special points on the interval [-2..3]. The Newton’s method used for finding roots and extremums of the function which specified with the second argument.

The result of the analysis – function’s roots and extremums, presented on the picture below.

The TMS Analytics and Physics pack includes the library with 5 ready-to-use numerical tools totally integrated with analytical features, such as symbolic derivatives. The version can be downloaded from the product page. There is the source code example for all numerical tools with the new version download.


Generating customer loyalty cards, event tickets, coupons, boarding passes for the smartphone with TMS PassKit

$
0
0

With iOS 9 and iPhone 6, Apple introduced the digital wallet on your smartphone. It is a system that holds passes to redeem rewards, get movie tickets, use discount coupons, get boarding passes for transport, offer prepaid cards etc.. An introduction to using the iPhone Wallet on an iPhone or iPod touch can be found here.
The pass for the iPhone or iPod is nothing more than a digitally signed file that can be distributed via a download, attached to an email, shared via AirDrop, ...

To facilitate generating such wallet PassKit files, we have released a new product TMS PassKit. TMS PassKit handles all the complexities of the signing of the files and has support for all PassKit type passes: coupons, tickets, store cards, traffic pass, generic pass ... It makes generating a wallet file as easy as setting up properties and call TMSPassKitBuilder.Generate() to generate the file. This component can make is really easy to automatically send out a wallet file with a loyalty card to all your customers, send tickets for inviting people to an event, create payment cards for employees and more...

This is an example wallet file that was created with TMS PassKit for a sample event: TMS training day 2017:


PassKit frontPassKit back

As you can see the wallet file can have both a front and back side. The appearance of the front can be customized via various settings, images can be added and as can be seen here, optionally, it can include a barcode in different formats.
The back of the card can contain additional fields and when these fields include an email, phone number, URL, date, ... this can be used to link to the mail app, calendar app, phone, ...

Wallet files have more important features, such as location sensitivity, beacon sensitivity, NFC coupling. With these features, supported from TMS PassKit, it is possible to make a pass only active in the neighbourhood of a specific location or beacon and do a transaction via NFC.
Finally, a wallet pass file also has built-in support for localization. Content for multiple languages for the wallet pass can be setup via TMS PassKit. Users with their smartphone configured in a specific language will see the wallet pass in their language of choice.

We are pleased that from today, TMS PassKit is released and available as standalone product but it is also part of the TMS VCL Subscription and TMS ALL-ACCESS. So, customers with an active subscription to either of these subscriptions have received this product for free today.
Head over to the TMS PassKit product page and discover the new possibilities you can add to your Delphi applications for creating wallet files for your users, customers, employees, network, friends, ..

Browser push notifications for announcements from tmssoftware.com

$
0
0

We are pleased to inform that from today, there is an additional channel, you can opt-in for, to keep in the loop with the news from tmssoftware.com.
For some time already, all our news is announced on our social media channels Twitter, Facebook, Google+ and LinkedIn and via a mailing list:

   

and from now on, for users with an account on our website, there is also the possibility to be informed via browser push notifications:



These browser push notifications are at this time a built-in notification mechanism of the Google Chrome and Firefox browsers. When you login on our website, you can opt-in to receive these push notifications when clicking "Allow" on the prompt:



With the new notification system inplace, you'll be aware of news from tmssoftware.com when you just open your browser, so you really can't miss news anymore!

TMS WebGMaps brings submarkers and extra options to load POI files

$
0
0

We're pleased to announce TMS WebGMaps v2.9 has been released today. TMS WebGMaps is our VCL component that exposes a myriad of geographical functions for integration in Delphi or C++Builder Windows applications.

In this new version, we introduce submarkers. When at a given position, more than one interesting item can be highlighted, it is now possible to add multiple items via submarkers at the same position and when the main marker is clicked, the submarkers are displayed.

In the sample, we've coupled different interesting items to see in Florida via submarkers for the marker at Florida. When the marker is clicked, different submarkers are displayed showing POIs such as Disney park, Cape Canaveral, Orlando resort... This technique keeps the number of simultaneously displayed markers light and only shows the detail when the user is interested and clicks the main marker.



Adding a marker with submarkers is very easy as this code snippet shows:

var
  m: TMarker;
  sm: TSubMarker;
begin
  m := WebGMaps1.Markers.Add(WebGMaps1.MapOptions.DefaultLatitude, WebGMaps1.MapOptions.DefaultLongitude);
  m.Title := 'Florida Landmarks';

  sm := m.SubMarkers.Add;
  sm.Title := 'Walt Disney World';

  sm := m.SubMarkers.Add;
  sm.Title := 'Cape Canaveral';

  ....

end;

In the new version, we have also refined the functions to load & save markers in POI file format. A POI file is a file that contains geocoordinates and description of places of interest. Now it is also possible to specify custom marker images when loading POI files. TMS WebGMaps can handle the POI file format as used by well-known navigation software such as Garmin, Tomtom, Route66, Becker, ...
There is a wealth of already existing POI files you can directly use with TMS WebGMaps. A resource of millions of POI files for 221 countries is for example www.poiplaza.com. In our sample, we have demonstrated this by loading a POI containing for example the IBIS hotels and movie theatres in Germany.



The code needed for this is just two lines:

    WebGMaps1.Markers.LoadFromPOI(FilePath + 'D-Cinema.csv', FilePath + 'projector_24.png');
    WebGMaps1.Markers.LoadFromPOI(FilePath + 'D-IbisHotel.csv', FilePath + 'ibis_24.png');

It refers to the POI filename and the (local) marker image to use. The WebGMaps component does all the needed things to show the custom Ibis image marker on the map in Germany for the Ibis hotel locations and the movie theatre image for the movie theatre locations.

We look forward to learn about your interesting integrations of TMS WebGMaps in your applications!

Storing objects in the Google Firebase cloud with TMS Cloud Pack

$
0
0

Since the latest release of TMS Cloud Pack, there is now also built-in support to use Google Firebase for cloud data storage. The architecture of Google's Firebase is quite simple. It offers storage of JSON data in the cloud. The JSON data has a unique identifier in a table and via access with this unique identifier, this JSON data can be read, updated or deleted. In addition, indexing rules can be set to perform query on the data in a Firebase table, for example, retrieve all JSON objects where a field X has value Y.

To make it really easy use to use data on Google Firebase from a Delphi or C++Builder application, we have added capabilities to put objects or generic lists of objects in a Firebase table. This is done via the non-visual component TFirebaseObjectDatabase that you can put on the form.



To demonstrate this, consider a class we want to use in the Delphi application that descends from TFirebaseObject:

  TFirebaseCustomer = class(TFirebaseObject)
  private
    FName: string;
    FStreet: string;
    FZIP: integer;
    FDoB: TDate;
    FCity: string;
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZIP: integer read FZIP write FZIP;
    property DoB: TDate read FDoB write FDoB;
  end;

Now, after we have retrieved a connection for TAdvFirebaseObjectDataBase to Firebase via:

  AdvFirebaseObjectDatabase1.DatabaseName := 'TMS';
  AdvFirebaseObjectDatabase1.TableName := 'Customers';
  AdvFirebaseObjectDatabase1.Connect;
we can create and put TFirebaseCustomer objects in the Google Firebase realtime data cloud:

var
  cst: TFireBaseCustomer;
begin
  cst := TFireBaseCustomer.Create;
  try
    cst.Name := 'Bill Gates';
    cst.Street := 'Microsoft Av';
    cst.ZIP := 2123;
    cst.City := 'Redmond';
    cst.DoB := EncodeDate(1969,04,18);
    cst.ID := '1240';
    AdvFirebaseObjectDatabase1.InsertObject(cst);
  finally
    cst.Free;
  end;
end;

All published properties of the object will be automatically persisted on the Google Firebase cloud. This is how the data looks when inspecting it on the Firebase console

Note that we have explicitly set the unique ID of the object via the cst.ID property. When the ID is set at application level, it is the responsibility of the app to use unique IDs. When no ID is set, the AdvFirebaseObjectDatabase will automatically create a GUID as ID.

In this example, we have created a rather simple object with simple data types. But nothing prevents you from using class properties as in this example:

  TCareerPeriod = class(TPersistent)
  private
    FFinish: integer;
    FStart: integer;
  published
    property Start: integer read FStart write FStart;
    property Finish: integer read FFinish write FFinish;
  end;

  TFirebaseCustomer = class(TFirebaseObject)
  private
    FName: string;
    FStreet: string;
    FZIP: integer;
    FDoB: TDate;
    FCity: string;
    FPicture: TFireBasePicture;
    FCareer: TCareerPeriod;
    procedure SetCareer(const Value: TCareerPeriod);
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZIP: integer read FZIP write FZIP;
    property DoB: TDate read FDoB write FDoB;
    property Career: TCareerPeriod read FCareer write SetCareer;
  end;

And now this code can be used to persist this slightly more complex object:
var
  cst: TFireBaseCustomer;
begin
  cst := TFireBaseCustomer.Create;
  try
    cst.Name := 'Elon Musk';
    cst.Street := '3500 Deer Creek Road';
    cst.ZIP := 2123;
    cst.City := 'Palo Alto';
    cst.DoB := EncodeDate(1975,03,21);
    cst.ID := '1241';
    cst.Career.Start := 2011;
    cst.Career.Finish := 2017;
    AdvFirebaseObjectDatabase1.InsertObject(cst);
  finally
    cst.Free;
  end;
end;

As you can see, more complex classes can be easily & automatically persisted in the Google Firebase cloud.


With respect to types of fields, there is one caveat though, Google Firebase doesn't offer out of the box support for binary blobs. Imagine that we'd want to persist a Delphi object that has a TPicture property. The TPicture is internally streamed in a custom way to the DFM (via the DefineProperties(Filer: TFiler); override) and the JSON persister does not automatically get this data. There is however an easy workaround to add a published string property to a class descending from TPicture and use this string to hold hex encoded binary data of the picture. The DataString property getter & setter methods use the StreamToHex() and HexToStream() functions that are included in the unit CloudCustomObjectFirebase:

  TFireBasePicture = class(TPicture)
  private
    function GetDataString: string;
    procedure SetDataString(const Value: string);
  published
    property DataString: string read GetDataString write SetDataString;
  end;


{ TFireBasePicture }

function TFireBasePicture.GetDataString: string;
var
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    SaveToStream(ms);
    Result := StreamToHex(ms);
  finally
    ms.Free;
  end;
end;

procedure TFireBasePicture.SetDataString(const Value: string);
var
  ms: TMemoryStream;
begin
  ms := HexToStream(Value);
  try
    LoadFromStream(ms);
  finally
    ms.Free;
  end;
end;


This way, we can extend the class to have a picture property:

  TFireBaseCustomer = class(TFirebaseObject)
  private
    FName: string;
    FStreet: string;
    FZIP: integer;
    FDoB: TDate;
    FCity: string;
    FPicture: TFireBasePicture;
    FCareer: TCareerPeriod;
    procedure SetPicture(const Value: TFireBasePicture);
    procedure SetCareer(const Value: TCareerPeriod);
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZIP: integer read FZIP write FZIP;
    property DoB: TDate read FDoB write FDoB;
    property Career: TCareerPeriod read FCareer write SetCareer;
    property Picture: TFireBasePicture read FPicture write SetPicture;
  end;

and persist the object with picture via:

var
  cst: TFireBaseCustomer;
begin
  cst := TFireBaseCustomer.Create;
  try 
    cst.Name := 'Tim Cook';
    cst.Street := '1 Infinite Loop';
    cst.ZIP := 2123;
    cst.City := 'Cupertino';
    cst.DoB := EncodeDate(1975,03,21);
    cst.ID := '1242';
    cst.Picture.LoadFromFile('tim_cook.jpg');
    cst.Career.Start := 2006;
    cst.Career.Finish := 2017;

    AdvFirebaseObjectDatabase1.InsertObject(cst);
  finally
    cst.Free;
  end;
end;

To retrieve the objects back that were persisted, we can use:

var
  fbo: TFirebaseObject;
begin
  fbo := AdvFirebaseObjectDatabase1.ReadObject('1240');

  if Assigned(fbo) then
  begin
    if (fbo is TFirebaseCustomer) then
      ShowMessage((fbo as TFirebaseCustomer).Name+';'+(fbo as TFirebaseCustomer).City);
    fbo.Free;
  end;
end;



To persist a property change of the object, for example to change the career date of customer 1241 to 2018, we could write:

var
  fbo: TFirebaseObject;
begin
  fbo := AdvFirebaseObjectDatabase1.ReadObject('1241');

  if Assigned(fbo) then
  begin
    if (fbo is TFirebaseCustomer) then
    begin 
      ((fbo as TFirebaseCustomer).Career.Finish := 2018;
      AdvFirebaseObjectDatabase1.WriteObject(fbo);
    end;
  end;
end;

Working with generic lists


The previous samples all showed how to perform CRUD operations on single objects in the Google Firebase cloud. Our component TAdvFirebaseObjectDatabase also facilitates dealing with generic lists of objects. Imagine you want to persist a score table of game and have following simple classes to store this:

  TSimpleClass = class(TFirebaseObject)
  private
    FName: string;
    FScore: integer;
  published
    property Name: string read FName write FName;
    property Score: integer read FScore write FScore;
  end;

  TSimpleList = TList<TSimpleClass>;


With this class and its generic list, we can add a list of data at once in the Google Firebase cloud:

var
  sl: TFirebaseObjectList;
  sc: TSimpleClass;
  I: Integer;
begin
  sl := TFirebaseObjectList.Create;
  try
    sc := TSimpleClass.Create;
    sc.Name := 'Bruno';
    sc.Score := 48;
    sc.ID := '1';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Nancy';
    sc.Score := 83;
    sc.ID := '2';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Pieter';
    sc.Score := 17;
    sc.ID := '3';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Bart';
    sc.Score := 299;
    sc.ID := '4';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Wagner';
    sc.Score := 55;
    sc.ID := '5';
    sl.Add(sc);

    AdvFirebaseObjectDatabase1.TableName:= 'List';
    AdvFirebaseObjectDatabase1.InsertList(sl);

    for I := 0 to sl.Count - 1 do
      sl[I].Free;
  finally 
    sl.Free;
  end;
end;

Inspecting this on the Google Firebase console results in:



If at a later time we'd like to retrieve the score of Bart, we could use the code:

var
  c: TFirebaseObjectList;
  I: Integer;

begin
  AdvFirebaseObjectDatabase1.TableName := 'List';
  c:= AdvFirebaseObjectDatabase1.QueryList('Name', 'Bart');
  if Assigned(c) then
  begin
    for I := 0 to c.Count - 1 do
    begin
      ShowMessage((c[I] as TSimpleClass).Score.ToString);
      c[I].Free;
    end;
    c.Free;
  end;
end;

This performs a query on the List table for value 'Bart' set in the 'Name' field. The result of the query is a generic list (in case multiple matching results are found).

This was a glimpse at the TAdvFirebaseObjectDataBase component as an introduction for the new Google Firebase access features in the TMS Cloud Pack. Explore the full set of powerful capabilities of TAdvFirebaseObjectDataBase and the many other components in TMS Cloud Pack to make consuming cloud services in Delphi & C++Builder a piece of cake.


Exploring parametric ODE with TMS Analytics and Physics numerical tool

$
0
0

Ordinary differential equations (ODE) used in many applications for physical, economical and other problem solution. The equations commonly describe the time evolution of some system from known initial state – initial value problem (https://en.wikipedia.org/wiki/Initial_value_problem).

The TMS Analytics and Physics pack contains the ODE solution tool of solving initial value problems for systems of ODEs. This tool is totally integrated with the symbolic capabilities of the library. This allows solving parametric problems and exploring how the parameter value influences the system behavior.

Let us consider the following simple parametric ODE:



with initial condition y(0)=1 on the time interval t=[0, 10]. The problem is parametric because there are parameters ‘A’ and ‘b’ in the equation. Our goal is exploring how the solution (function y(t)) depends on the value of ‘b’ parameter.

First we create the instance of analytical ODE object, here is the code:

var
  A, b: TVariable;
  prms: TArray<TVariable>;
  fv, equations: TArray<string>;
  ode: TAnalyticalODE;
  solver: TODESolverClass;
  y0: TArray<TFloat>;
  t: TArray<TFloat>;
  y: TArray<TArray<TFloat>>;
  i: Integer;
begin
  A:= TRealVariable.Create('A', 1.0);    // 1
  b:= TRealVariable.Create('b', 0.0);    // 2
  prms:= TArray<TVariable>.Create(A, b); // 3
  fv:= TArray<string>.Create('y');       // 4
  equations:= TArray<string>.Create('sin(t)+A*t/y^b'); // 5
  ode:= TScalarODE.Create('t', fv, equations, prms);   // 6
  ...
 
Line 1: Create the variable for ‘A’ parameter.
Line 2: Create the variable for ‘b’ parameter.
Line 3: Create array of parameters.
Line 4: Create array of function names (one name required for the problem).
Line 5: Create array of equations (one equation).
Line 6: Create the instance of analytical ODE system with specified equation and parameters.

After the instance of the analytical ODE system created we must select appropriate solver and specify initial condition for the problem. We will use the Runge-Kutta direct solver of the 4-th order. The code continued:

solver:= TRungeKutta4Solver;          // 7
y0:= TArray.Create(1.0);      // 8
And finally we must solve the initial value problem for various values of ‘b’ parameter, say b=1..8:

for i:=1 to 8 do
begin
  ode.Parameters['b'].Value:= TValue.From(i); // 9
  y:= solver.Solve(ode, y0, 10.0, 1000, t);           // 10
  
  // Code for using the result data ‘y’ and ‘t’.
end; 
Line 9: Change value of ‘b’ parameter using the array property ‘Parameters’ of the analytical ODE class. Line 10: Solving the specified initial value problem for current value of ‘b’ parameter, on the time interval t=[0, 10], with 1000 discretization steps.

The solution result for changing value of ‘b’ parameter presented on the picture below.


TMSFNCChart cross-platform / cross-framework chart displaying the result

As can be seen from the code above, there is no need creating new analytical ODE instance for exploring the parametric problem. As the analytical ODE is parametric, it is solved for the current parameter values and they can be easily changed via parametric interface.

Other advantages of using the numerical ODE tool with the symbolic calculus are:
- Minimal code writing, because there is no need to write special classes for the function method references (delegates) as in other numerical libraries.
- Convenient data representation for the developer and user as math expressions, not as programming code.
- Easily using the user input data (string data) for manipulations in programming code.
- Easily transfer input data via network as strings, easily storing and serializing the data.

The TMS Analytics and Physics pack includes the library with 5 ready-to-use numerical tools totally integrated with analytical features, such as symbolic derivatives. The trial version of TMS Analytics and Physics pack can be downloaded here. Total source code of the example application of ODE tool can be downloaded here.

TMS Subscription Manager v2 is here

$
0
0

One comprehensive tool to manage any of the many bundle subscriptions you can purchase from TMS software was our goal for TMS Subscription Manager v2.0 that is now finally released. TMS Subscription Manager v2.0 supports TMS ALL-ACCESS, TMS VCL Subscription, TMS Business Subscription, TMS Component Studio, TMS FMX Component Studio, TMS FNC Component Studio and TMS IntraWeb Component Studio.

With TMS Subscription Manager v2.0, you can use a single login in this application and you get instant access to all products in the purchased bundle. For TMS ALL-ACCESS, this is at this moment a whopping 63 products. The TMS Subscription Manager v2.0 now categorizes the products neatly per technology : VCL, FMX, BIZ, FNC, DEV, .NET, IntraWeb and LCL.



Per product, you get a description, link to the product webpage, info on latest available version and release date, info on your last download version and download date and info on your last product install version and date. With colors, the status of each product is indicated. In white are products ready for download, in yellow products ready for install, in orange products for which you can meanwhile download a newer version and in green the products for which the latest version was installed, so you are up-to-date for. If you have our premier TMS ALL-ACCESS subscription, you can much easier find your way in the many products by filtering. You can open & close per product technology, you can filter to see for example only all installed products for which there is a new version, you can perform a search in product name or product description. If you perform a search on 'grid', you'll see we have a grid for VCL in the TMS Component Pack, a grid for FireMonkey in the TMS FMX UI Pack, a grid for cross-framework development in TMS FNC UI Pack and a grid for web application development in TMS IntraWeb Component Pack.

But there is more. If you are working on a project that includes several specific TMS products, you can mark these products as your favourite products by clicking the heart icon and then perform a filtering to see the latest status of only your favourite products.



The new v2.0 version also allows to start multiple downloads. To get all new releases since your last login, you could filter on "New version", then check all products and click the "Download all" button in the column header cell for the download column and it will do all downloads for you and make the products ready for install.

And that is not all, behind the scenes, TMS Subscription Manager is now keeping a backup of any product versions you have downloaded. From the settings page, the folder where all downloads are stored can be directly opened. With keeping a full backup of every single version you have downloaded (and probably installed) it is now possible to perform rollback if it would be necessary for some reason. Right-click on the downloaded version number cell per product and from the context menu you can see all available versions (if there are any) and activate another version for install.



Finally, the TMS Subscription Manager v2.0 keeps you always informed about the validity of your subscription and will guide you to the renewal order upon expiry. Last but not least, from the TMS Subscription Manager there is a comprehensive list of links to interact with us, via email, social media, forums, RSS, Youtube videos ...



To round up, some technical tidbits: TMS Subscription Manager is built with Delphi 10.2 Tokyo as a single EXE portable executable. The products are displayed and managed in our TAdvStringGrid UI control. The application will self-update thanks to our TWebUpdate component and in case something goes wrong, exception logging is handled by Eurekalog.

If you have any TMS bundle subscription, you can download TMS Subscription Manager v2.0 now from the "My products" page and get started with the new tool. We hope you enjoy it and it will make you more productive than with the v1.0.

We have already several ideas for further developments on TMS Subscription Manager v2.0, like making it optionally a Delphi IDE plugin with automatic notifications, allowing to invoke the installers silently, integrating the downloads of our free tools, making it possible to also manage separate product purchases, ... but we also eagerly look forward to your ideas. We're sure that with your brilliant ideas, we can make the tool even more awesome than it is today!

TMS FNC Ribbon : modern ribbon UI on every operating system and for every Pascal framework

$
0
0

With the FNC product line (framework-neutral-components), it is our vision to enable developers with a single UI controls set, a single learning-curve and a single license to have the freedom of choice to develop Delphi VCL Windows applications, Delphi FMX cross-platform applications for Windows, macOS, Android, iOS or even LCL based Lazarus applications for Windows, macOS or Linux.

Since our study & research to realize this FNC layer, we have already created a powerful grid, a flexible planning/scheduling/calendar control, a feature-rich treeview, a rich editor, a toolbar and many more smaller UI controls. The next logical step was to create a ribbon UI control to enable building modern user interfaces for your VCL, FireMonkey Delphi applications of Windows, macOS or Linux applications created with Lazarus/FPC. Our ribbon UI control takes the hard work out of your hands to offer the subtle differences a Microsoft Office 2016 style colourful ribbon UI comprises on these different operating systems.

To get started, we have integrated ribbon application and ribbon form repository items in the Delphi "new item" wizard. You can select from there to create a new VCL or FMX ribbon project or to add a new VCL or FMX ribbon form to your existing project.



It is of course also possible to add a new ribbon UI to an existing form. To do so, drop the TTMSFNCRibbon control on the form and do not forget to descend your form from TTMSFNCRibbonForm instead of a TForm.

The ribbon architecture
Let's have a look at the TTMSFNCRibbon control itself. It consists of several parts, the main parts being:



TMSFNCRibbonWrapper : This is the container component for the ribbon form caption that contains the QAT, caption text, system menu
TMSFNCRibbonQAT : This is the quick access toolbar that can sit in the window caption or below the ribbon. The position can be set via the property TTMSFNCRibbon.QATMode.
TMSFNCRibbonCaption : This represents the caption text of the window itself
TMSFNCRibbonSystemMenu : This is the application system menu typically used to close, minimize or maximize the form
TTMSFNCRibbonFileButton : This is the application menu button
TMSFNCRibbonPageControl : This is the page control that is used to paginate between different ribbon pages
TTMSFNCRibbonPageControlContainer : This is a single ribbon page that is a container for toolbars on the ribbon

To add a toolbar and toolbar controls to the ribbon, right-click the TTMSFNCRibbonPageControlContainer and from the context menu select to add a toolbar.
Next, right-click the toolbar and from the context menu you can choose to add several toolbar controls.


The controls that can be added to the ribbon toolbar are not limited to this set of controls and as such other UI controls can be added as well to the toolbar. More later about the dynamic sizing configurability of the toolbar controls and the toolbar compact mode.

Matching the Microsoft Office 2016 theme, the TTMSFNCRibbon has a property Theme from where a number of predefined colors can be selected (like the MS Word, MS Excel, MS PowerPoint ribbon colors) but this property can also be set to rbtCustom and then a custom application color can be selected with TTMSFNCRibbon.CustomThemeColor. The TTMSFNCRibbon control will automatically calculate lighter & darker color variants to make up such custom color theme. The color & appearance of each individual element on the ribbon can be customized, but the easiest way to select a consistent looking color is clearly with the TTMSFNCRibbon.Theme and TTMSFNCRibbon.CustomThemeColor setting.

The ribbon toolbar
The place where buttons for interaction with your application are placed is the ribbon toolbar and typically, controls are grouped on toolbars that belong together. By default, the size of the toolbar will automatically adapt to the number & size of controls added to the toolbar. The default size is TMSFNCRibbonToolBar.AutoSize = true, TMSFNCRibbonToolBar.AutoWidth = true, TMSFNCRibbonToolBar.AutoAlign = true. This means that when adding controls to the toolbar, these will be added starting left aligned and the size of the toolbar will grow as controls are added. The toolbar can have a dynamic sizing behavior. That means that when the application window width will become smaller or larger, the toolbar can dynamically size to fit all toolbars in the width of the ribbon. The smallest mode for the toolbar is the compact state. In this state, the toolbar is only a button and the toolbar buttons will only become visible when the toolbar compact state button is clicked. In compact state, the toolbar can display a picture on the button and this is selected via TMSFNCRibbonToolBar.CompactBitmaps: TTMSFNCScaledBitmaps. This is a collection of bitmaps that can be used for different DPI sizes. The control will decide itself what bitmap to use from the collection depending on the DPI of the screen the application is running on. Further customization of the compact state is done via TTMSFNCRibbonToolBar.CompactAppearance, TTMSFNCRibbonToolBar.CompactWidth, TTMSFNCRibbonToolBar.CompactBitmapVisible. When the toolbar is not in compact state, its controls are visible but these can be visible in different sizes. The sizes a ribbon toolbar button can have is set with TMSFNCRibbonDefaultToolBarButton.MinimumLayout, TMSFNCRibbonDefaultToolBarButton.MaximumLayout. By default, the minimum size is bblBitmap, the maximum size is bblLarge and the size in between is bblLabel. When the application is maximized for example and thus the toolbar has sufficient space, all buttons on the toolbar can be shown in bblLarge state. When the application width shrinks, the controls on the toolbar can first reduce to bblLabel state where the controls become a label with attached glyph. When the form width further shrinks, the next step is when the toolbar controls are rendered in bblBitmap state, essentially, only showing the button glyph. Of course, if for a button the MinimumLayout and MaximumLayout are both set to bblLarge, the toolbar control size will never change during application for width changes. Only when the toolbar width cannot longer fit on the ribbon, the entire toolbar will go to compact state.

Visualizing this is probably the best way to make this more clear.
In this first step, notice the Insert toolbar that has sufficient space for hosting two large state buttons:


As the form width decreases, the Insert toolbar shrinks by putting its controls in label layout:


Making the form even smaller now makes the toolbar shrink its controls to bitmap layout:


The final and smallest state of the toolbar is the compact state, where all its controls are hidden and the toolbar controls only become visible by clicking the compact state toolbar button to show the full toolbar in a popup:


The ribbon page groups
Another often used ribbon UI feature is the ribbon page groups. Sometimes functionality in the application has so much controls to interact with the features of the functionality that it is too much to have one ribbon page for it and that it is better to divide it in two or more pages. To make the ribbon pages look consistently together, the concept of page groups is used. This is a group indicator above the ribbon page tabs. Adding a ribbon page group can be easily done via the collection TTMSFNCRibbon.Groups. Add a new TMSFNCRibbonGroup item to this collection and here it can be configured what the index is of the first ribbon page in the group (TMSFNCRibbonGroup.StartPageIndex) and the last page (TTMSFNCRibbonGroup.EndPageIndex). The group can be given a group name set via TTMSFNCRibbonGroup.Text and with the group the selected ribbon page tab can have its own color set via TTMSFNCRibbonGroup.Color & TTMSFNCRibbonGroup.TextColor. The page group itself is a darker variant from the ribbon theme color. In this example, a ribbon page group was created for the Insert and Export page. The page group name is Tools and was created by setting TMSFNCRibbonGroup.StartPageIndex to 1 and TTMSFNCRibbonGroup.EndPageIndex to 2.

g := rb.Groups.Add;
g.Text := 'Tools';
g.StartPageIndex := 1;
g.EndPageIndex := 2;



The ribbon QAT
Frequently used functions, like a save, undo, ... function can be added to the always visible QAT (quick access toolbar). This QAT sits normally on the form caption or right below the ribbon. By default, on a new TMSFNCRibbon, the QAT is available on the caption. To add controls to it, also right-click the control at design-time and from the context menu select the controls to add. The QAT has by default an automatically managed option menu (at the right-side of the QAT). From this options menu, controls on the QAT can be hidden or made visible and the position of the QAT can be selected. The option menu can be further customized by implementing any of its menu event handlers like OnOptionsMenuCustomize, OnOptionsMenuItemCanShow, OnOptionsMenuMoreCommands, ...



Learn more
Several resources are available for you to learn more about our FNC abstraction layer and controls:
Blog post about FNC UI pack
Blog post about developing FNC custom controls
FNC controls video series

Conclusion
Our TMS FNC ribbon control has everything on board to allow you to add a ribbon UI to your applications, be it Delphi VCL Windows applications, cross platform FireMonkey applications or applications created with Lazarus for Windows, macOS or Linux. It is easy & fast to configure but at the same time can be extensively and in detail customized. Together with our FNC grid control, you can build Excel like user interfaces in a matter of hours, or in combination with our FNC rich editor a word processor like application, etc... Once you learned to use the TMS FNC Ribbon control, you can apply this knowledge to your next project developed against another UI control framework or you could reuse code from one application in a given framework for another application using another framework. We look forward to see awesome applications you create and hear about further needs you might have to facilitate your development and make it even faster.


Join us in The Netherlands and Germany at several upcoming Delphi conferences

$
0
0

We look forward to connect with you at the upcoming conferences! TMS will be present at following Delphi events:

The LAB - European Delphi & C++Builder Conference 2017
19 September 2017 - Eindoven, The Netherlands

TMS software will be present with a booth where you can meet us and find out about our latest product offerings.
Bruno Fierens will give a session about VCL & FMX Delphi applications based on Google Maps and TMS WebGMaps. He will demonstrate how locations on the map can be indicated in different ways, how addresses can be associated with locations, how locations can be coupled to pictures and how to load POI files and visualize the POIs on the map. Furthermore, route directions can be calculated, displayed and imported & exported for exchange with navigation systems or smartphone apps. Finally the GeoJSON file format is explained and it is shown how these can be used together with Google Maps.Dutch spoken


Foren-Tage 2017
23 September 2017 - Hamburg, Germany

TMS software will be present with a booth where you can meet us and find out about our latest product offerings.
Bruno Fierens will give a session about VCL & FMX Delphi applications based on Google Maps and TMS WebGMaps. He will demonstrate how locations on the map can be indicated in different ways, how addresses can be associated with locations, how locations can be coupled to pictures and how to load POI files and visualize the POIs on the map. Furthermore, route directions can be calculated, displayed and imported & exported for exchange with navigation systems or smartphone apps. Finally the GeoJSON file format is explained and it is shown how these can be used together with Google Maps.


EKON 21
24 October - Cologne, Germany

Bruno Fierens will give a presentation about creating cross-framework UI controls. The similarities and differences between the two key UI frameworks VCL and FMX that come with Delphi are explained. With this knowledge, it is possible to create an abstraction layer that allows to create UI controls that will work both in VCL applications and in FMX applications (and also in the LCL framework). The abstraction layer FNC (Framework Neutral Components) is introduced and explained and with the help of this FNC layer, it is demonstrated to create a UI control from scratch for VCL, FMX and LCL.


TMS hands-on training day
23 November 2017 - Meerbusch-Büderich, Germany

After an introduction on the latest news from Embarcadero, the first half of the day will be devoted to an in-depth look at TMS VCL components, in particular TAdvStringGrid and TAdvTreeView. In the second part of the day, focus will be on cross-platform development and cross platform UI controls. We'll round up the day with a look at Google Maps integration and a "What's cooking in the labs" session. Sessions will be in German.




Formatted emails (HTML email) from TAdvRichEditor

$
0
0

Our TAdvRichEditor UI control has everything on-board to generate HTML from its rich document content, including exporting images that are possibly used in the document. Although generating this HTML can be easily done via the TAdvRichEditorHTMLIO non-visual component connected to the TAdvRichEditor, we frequently receive support emails from users struggling to use the generated HTML to send it as email with the Indy components (TIdMessage, TidSMPT).

Therefore, we decided not only to create a sample code snippet to show how this can be done, but also to create a non-visual component (available in the latest TMS Component Pack release) to reduce the code to generate such email message to the minimum possible, that is, to one line of code:

    emailio.GenerateEmail(idmessage);

But, back to full code first that shows how to use the Indy components to generate HTML emails with embedded images as this can be generally applied for cases also where no TAdvRichEditor is used.

Drop a TIdMessage component on the form. We create a multipart message, with a part for the plain text version of the email, a part for the HTML email header and a part for the HTML itself. Then we add attachments to the message where ContentDisposition is set to 'inline' and the ContentID is set to the ID used in the HTML image reference cid attribute. So, if we have in the HTML code an image reference like:

then the ContentID for the attachment containing the image will be :
ContentID := 'imageref1';

Now, let's put this together using a TAdvRichEditor, TAdvRichEditorHTMLIO, idMessage on the form. We set AdvRichEditorHTMLIO.RichEditor to the TAdvRichEditor instance we want to export. It is very important to set AdvRichEditor.HTMLImages to igID as this instructs the TAdvRichEditor to export images references as CID URI attributes. The export to HTML and image files from TAdvRichEditor becomes:
var
  i: integer;
begin
  AdvRichEditor1.HTMLImages := igID;
  // we save the output to a temporary HTML file
  AdvRichEditorHTMLIO1.Save('.
icheditor.html');

  for i := 0 to AdvRichEditor1.HTMLImageList.Count - 1 do
    begin
      // we prepare the images as temporary images files for use as attachments for the message
      AdvRichEditor1.HTMLImageList.Items[i].SaveToFile('.img'+i.ToString+'.png');
    end;
end;

As you can see, the images to be used in the export are available via the collection AdvRichEditor.HTMLImageList. From there, we can save the images to file to be used as attachments for the Indy idMessage. The code to construct the idMessage from here becomes:
  idMessage1.IsEncoded := True ;
  idMessage1.ContentType := 'multipart/alternative';
  idMessage1.ClearBody;

  with TIdText.Create(idMessage1.MessageParts, nil) do
  begin
    // here we include the text as plain text
    Body.Text := AdvRichEditor1.PlainText;
    ContentType := 'text/plain';
  end;

  with TIdText.Create(idMessage1.MessageParts, nil) do
  begin
    ContentType := 'multipart/related; type="text/html"';
  end;

  with TIdText.Create(idMessage1.MessageParts, nil) do
  begin
    // we load the content from the temporary HTML file
    Body.LoadFromFile('.
icheditor.html');
    ContentType := 'text/html';
    ParentPart := 1;
  end;

  // here we loop over images to add all as attachments 
  for i := 0 to FRichEditor.HTMLImageList.Count - 1 do
  begin
    with TIdAttachmentFile.Create(idMessage1.MessageParts,  + '.img' + i.ToString + '.png') do
    begin
      ContentID := 'image'+ i.ToString;
      ContentType := 'image/png';
      ContentDisposition := 'inline';
      ParentPart := 1;
    end;
  end;

When the idMessage message has been created, it is straightforward to send it via the idSMTP component, i.e., this is minimally:
  IdMessage1.From.Address := 'info@tmssoftware.com';
  IdMessage1.Recipients.Add.Address := 'bruno@tmssoftware.com';
  IdMessage1.Sender.Address := 'info@tmssoftware.com';

  idsmtp1.Host := 'smtp.mailserver.com';
  IdSMTP1.Connect;
  idsmtp1.Send(idMessage1);
  idsmtp1.Disconnect();

With this code now explained, let's introduce the class TAdvRichEditorEmailIO included in unit AdvRichEditorEMailIO.pas in the latest version 8.7.3.0 of TMS Component Pack. With this class, we can reduce the code to send a HTML email from TAdvRichEditor to:
  AdvRichEditorEMailIO.GenerateEmail(idmessage);
  idMessage.Subject := 'A HTML email from TAdvRichEditor';

  idSMTP1.Host := 'smtp.mailserver.com';
  IdSMTP1.Connect;
  idSMTP1.Send(idMessage);
  idSMTP1.Disconnect();

The resulting Delphi application looks like this:

and when opening the email sent in MS Outlook, it looks like:

You can easily get started to build your own HTML formatted text email client. You can download the source code of the application here and you can compile and use this with the latest TMS Component Pack release. In the next updates of TMS FMX UI Pack that also includes the FireMonkey version of our rich editor component, we'll also include a FireMonkey version of the HTML email creator class and the same applies for the cross-framework version of the rich editor in the TMS FNC UI Pack.

Array and Matrix operations with Analytics 2.2

$
0
0

New version 2.2 of TMS Analytics and Physics pack includes total support of operations with N-element arrays and MxN matrices. The operations realized in the Linear Algebra extension package. Array and matrix operations allow advanced calculations with small, compact formulae.

Let us consider the examples of using the array/matrix operations for solving some common math/statistics problems. First of all we need to add special variables to the translator instance:

var
  av: TArray<TFloat>;
  mv: TArray<TArray<TFloat>>;
begin
  translator:= TTranslator.Create;

  translator.Add('µ', 0.0);

  av:=TArray<TFloat>.Create(0.2, -0.1, -0.25, 0.4);
  translator.Add('A', av);

  av:=TArray<TFloat>.Create(-0.2, 0.2, -0.1, 0.25, 0.35, 0.15, -0.04, 0.01, -0.12, 0.1);
  translator.Add('B', av);

  SetLength(mv, 4, 3);
  mv[0,0]:= 0.5; mv[0,1]:=-0.4; mv[0,2]:= 0.33;
  mv[1,0]:=-0.3; mv[1,1]:= 0.1; mv[1,2]:= 0.28;
  mv[2,0]:=-0.4; mv[2,1]:=-0.2; mv[2,2]:=-0.75;
  mv[3,0]:=0.44; mv[3,1]:=0.25; mv[3,2]:= 1.00;
  translator.Add('M', mv);
end;
The code above adds to the translator instance the ‘µ’ variable with value 0.0, the array variable ‘A’ with 4 components, the array variable ‘B’ with 10 components and the 4x3 matrix ‘M’.

The first problem to solve is calculation of statistics square deviation from the mean value for the ‘B’ array. Math formula for the deviation of discrete random variable is (https://en.wikipedia.org/wiki/Standard_deviation):

where µ is the mean value

N is the number of elements.

This formula can be evaluated with using array operations by the following code:
var
  m, d: TValue;
begin
  m:= translator.Calculate('∑B/#B');
  translator.Variables['µ'].Value:= m;
  d:= translator.Calculate('∑((B-µ)^2)/#B');
  // print the ‘d’ value
end;
First we calculate the mean value. The number operator ‘#’ in the formula returns the array element count. Then we assign the calculated value to the ‘µ’ variable and, finally, calculate the deviation value. Notice that there are the parentheses for the square operation in the formula, because the summation operation has higher priority. Here is the output for the evaluation:

µ = ∑B/#B = 0.06
D = ∑((B-µ)^2)/#B = 0.02876


Next problem is solving an over-determined linear equation system with the least squares approach (https://en.wikipedia.org/wiki/Linear_least_squares_(mathematics)). Let the system is set up by the ‘M’ matrix and the ‘A’ vector. Then the solution ‘X’ is defined by the formula:

where MT – is the transposed matrix, 1 means the inversed matrix.

This formula can be evaluated with the Analytics library as the following ‘M'*A/(M'*M)’. Here the apostrophe ‘'’ operator is for transposition operation and the division is equivalent to the multiplication by the inversed matrix. Evaluating the formula we get the following output:

X = M'*A/(M'*M) = TArray<TFloat>[3]=
(0.459953357586789 0.163947437790482 0.113927221302585 )

Here the ‘X’ array is the solution vector that minimizes the square error for the over-determined system.

As can be seen from the examples above, the realized array/matrix operations allow easily solve complicated problems with small, compact formulae. The complicated code for the array/matrix operations implemented inside the Analytics library and totally integrated with analytical evaluations. For an example, linear algebra operations allow solving so called ‘matrix’ ordinary differential equations (https://en.wikipedia.org/wiki/Matrix_differential_equation).

The TMS Analytics and Physics pack version 2.2 can be downloaded here. Total source code of the example application can be downloaded here .

TMS Data Modeler 3 is out!

$
0
0

We are happy to announce that TMS Data Modeler 3 has been released today. TMS Data Modeler is our tool to design databases models, ER diagrams, import existing database schema and, among others, generate source code with TMS Aurelius mapped classes based on the database schema. Below is a list of the new features in this release.

Updated User Interface

To start with, we have improved user interface, by using a more modern look-and-feel. A new cleaner color theme is used, logo, file menu, splash screen have been updated.



Customization Script for TMS Aurelius Export

When generating TMS Aurelius classes from database, you can now fully customize the output source code. Users don’t need to manually tweak the source code anymore, or wait for us to explicitly implement an option that changes how source code is created.

You can simply write a script that is based on event handlers. You can for write the following script to add the [Version] attribute to any field named “FVersion” in all of your classes:

procedure OnColumnGenerated(Args: TColumnGeneratedArgs);
begin
  if Args.Field.Name = 'FVersion' then
    Args.Field.AddAttribute('Version');
end; 

In case you script gets complex, you can also use a full-feature debugger to check what’s wrong with your code.



For the scripting system and debugger, TMS Data Modeler internally uses our scripting frameworks TMS Scripter.

You can refer to documentation for more info on how you can use customization scripts in TMS Data Modeler.

Export TMS Aurelius classes to multiple units

In previous versions all TMS Aurelius classes would be exported to a single unit. Now you can choose the name of unit where a specific class will be exported to. TMS Data Modeler will even warn you if there are cyclical references between classes declared in different units.

Source code preview

You can now preview the output source code in the TMS Aurelius Export Dialog itself, without needing to generate the source code files to view them. Just click the Preview tab and you will see the final source code generated.



Separate classes into models

You can also define to which models each class belongs to. One or more TMS Aurelius Model attributes will be added to each class. If you already have multiple ER diagrams in your Data Modeler project, then you can optionally ask for each diagram to be considered a different model and have your classes be marked automatically with one Model attribute for each diagram it belongs to.

It’s also worth saying that we have updated a lot of internal processes, frameworks and tools. It took a lot of effort. While it’s not directly perceived by the end-user, it doesn’t reflect directly on user experience, we’re sure that it will make release of newer versions easier and faster.

I hope you are excited with these new features as much as we are, and enjoy the new TMS Data Modeler!



TMS Component Pack v8.8 is here

$
0
0

What initially started in 1999 as a small bundle of about 15 VCL user interface controls for Delphi, has grown in about 18 years to a set of over 400 powerful and feature-rich components for development of VCL Windows applications with Delphi and C++Builder.
Thousands and thousands of hours work went into this VCL component set that found its way to thousands of Delphi & C++Builder developers world-wide and this way, also to thousands of Windows applications used in so many places day-in, day-out to help and improve the life and work of so many people. As a small example, we learned that our VCL Planner is being used to track maintenance schedules of the French trains all over France, all in real-time.
And yet, every day our team continues to improve, extend the TMS Component Pack, assist the users in getting the most out of it and listen carefully to your needs and wishes. Also with the newest v8.8 release, we focused on user needs and added no less than 11 new features in existing components and 3 new components that were requested. We have our feature request logging & voting system for this where customers can add new feature requests and up-vote feature requests from other users so we can set the right priorities in our development.
As a result of this, these 3 new controls were added to TMS Component Pack v8.8:

New : TAdvHighLightLabel v1.0.0.0 : Label that allows to highlight specific words in the label text in different colors.

highlight label

New : TAdvTouchSpinEdit v1.0.0.0 : Spin edit control with spin buttons left and right from the edit control to allow easy up/down button access from touch screens.

spinedit

New : TAdvDBListBox v1.0.0.0 : Listbox control with embedded filter + insert data capability that can be bound to a dataset field.

listbox

In addition, 11 new features were added to existing components:


Whether you are using the newest Delphi 10.2.1, C++Builder 10.2.1 or still using an older version of Delphi, our TMS Component Pack installer detects the versions of Delphi or C++Builder installed on your system and will install for any version (from Delphi 7 onwards) it finds.
If you haven't used the TMS Component Pack yet, check out all the feature-rich components you have been missing all this time. If you have used an older verison of the TMS Component Pack, check out all latest additions & improvements and if you have just downloaded & installed the latest version 8.8, check out the new components and features that were added.

Now that TMS Component Pack v8.8 is released, we are already laying out plans for the next version and eagerly awaiting your favorite feature requests or feedback that you can send by email, in our forum or add to our feature request system.

TMS Analytics for nonlinear multiparametric approximation of surface data

$
0
0

The new version 2.2 of TMS Analytics and Physics pack contains the nonlinear least squares approximation tools. The nonlinear approximation tasks are widely used in statistics to fit experimental data with some random distribution function.


Let us consider the example of surface data fitting with the 2D Gaussian function. The Gaussian distribution of 2 variables x and y (https://en.wikipedia.org/wiki/Gaussian_function) has the following math expression:

Except the amplitude A, the distribution nonlinearly depends on four parameters: center coordinates x0, y0 and deviations sx, sy. The task of fitting data with the Gaussian function is to find optimal values of the four parameters, those minimize the error of the distribution and the experimental data zi(xi,yi), i=1..N.

The approximation task can be solved by the numerical tool with the following code:

var
  variables, coefficients: TArray;
  f: string;
  basis: TNonlinearBasis;
  cValues: TArray;
  appr: TNonlinearApproximator;
  opt: TSolverOptions;
  eValues: TArray;
  eValue: TFloat;
begin
  variables:= TArray.Create('x', 'y'); // 1
  coefficients:= TArray.Create('x0', 'Sx', 'y0', 'Sy'); // 2 
  f:= 'e^-((x-x0)^2/(2*Sx^2)+(y-y0)^2/(2*Sy^2))'; // 3
  basis:= TNonlinearScalarBasis.Create(variables, coefficients, nil, f); // 4 

  appr:= TGaussNewtonLeastSquares.Create; // 5
  appr.C0:= TArray.Create(0.1, 0.1, 0.1, 0.1); // 6
  opt:= TSolverOptions.Create(true);
  opt.MaxIterationCount:= 100;
  opt.Precision:= 0.2;
  appr.Options:= opt; // 7

  cValues:= appr.Approximate(basis, xyData, zData); // 8

  // use basis with optimal coefficients
end;

Line 1: Create array of variable names.
Line 2: Create array of four distribution coefficient names.
Line 3: Set up the approximation function expression.
Line 4: Create the nonlinear basis instance with specified data.
Line 5: Create the appropriate nonlinear approximator instance.
Line 6: Set up initial guess of coefficient values for nonlinear solution.
Line 7: Set up appropriate nonlinear solution options.
Line 8: Solve the problem (finding optimal values).

When optimal values of the Gauss distribution parameters found, they can be used with the basis instance to calculate the distribution function in any specified point (x,y) or for other analysis methods, like derivative calculations and so on.

On the pictures below there are results of the approximation made with some generated noisy data. The result presented as 1D section of the 2D function for two different x values: x=0.0 and x=0.6.





In this sample, we used the TMS FNC Chart to display the values and the approximated function. The advantage of using the TMS FNC Chart is that it can be used both for VCL and FMX applications and we can use the same code to create a VCL Windows application or a FireMonkey cross platform application.
The source code of the example application can be downloaded here.

The TMS Analytics and Physics pack version 2.2 includes also many other useful numerical tools: linear least squares approximation, 1D and 2D integration, ordinary differential equation solution, function analysis. Due to the addition of array and matrix support in version 2.2, many numerical calculations can be implemented in vector form with small and compact formulae. The version can be downloaded from the product page.

Document and test your REST API using OpenAPI/Swagger support in TMS XData

$
0
0

TMS XData 2.7 has been just release with lots of new features. The most interesting one, in my opinion, is OpenAPI/Swagger support.

TMS XData server can now optionally provide a JSON file containing the OpenAPI Specification (OAS, formerly Swagger) for your whole server API. This opens up a lot of possibilities, usage of several tools of the OpenAPI ecosystem is now possible. Main one would be the Swagger UI, a web front-end to describe and test your API.

Enabling support for OpenAPI

To enable OpenAPI support in your server, just use the unit XData.OpenAPI.Service and call the method RegisterOpenAPIService anywhere in your application:

uses {...}, XData.OpenAPI.Service;
 
{...}
  RegisterOpenAPIService;
It's as simple as that. XData will scan your whole API and build the specification file describing that API automatically. The specification will be very detailed as XData has all the metadata for your API: the method parameters, the mappings for entity classes, the data types, etc.

Retrieving the OpenAPI Specification (OAS) file

The OAS file is available through a GET request to the URL "/openapi/swagger.json" relative to your server root URL. For example, if your server root is http://myserver/tms/xdata/, then you will be able to access the file from this URL:

GET http://myserver/tms/xdata/openapi/swagger.json

Using Swagger UI

One of the main use cases is to be able to use the Swagger UI. It's a web-based front-end to dynamically document and test your API. From their website: "Swagger UI allows anyone - be it your development team or your end consumers - to visualize and interact with the API's resources without having any of the implementation logic in place. It's automatically generated from your Swagger specification, with the visual documentation making it easy for back end implementation and client side consumption.".

You can visit their site for more information, but here are quick steps to see it in action from your own server:

1. Create your XData Server and enable OpenAPI support as described above.

2. Enable CORS in your TXDataServerModule:
    Module.AccessControlAllowOrigin := '*';
3. Open the existing live demo of the Swagger UI at https://petstore.swagger.io.

4. In the edit box that appears at the top of the page, just type the URL that returns the OpenAPI Specification. For example, "http://myserver/tms/xdata/openapi/swagger.json", and click "Explore". That would be enough to list your API.

If you want an even faster way to see it in action with XData:

1. Run the demo named SQLiteConsoleServer. It's located in folder demossimple_sqlite. That demo is available when you install TMS XData trial or licensed version.

2. Open web site https://petstore.swagger.io.

3. In the edit box, enter the OAS file address: "http://localhost:2001/tms/music/openapi/swagger.json":



4. Click Explore to browse the API and test.



And that's it!

This new XData release doesn't stop there, there are lots of new features including several new types supported in method parameters, entity properties, PODO properties, and more!



Improvements for symbolic expressions simplification in TMS Analytics & Physics developing library

$
0
0

One of the unique features of the Analytics library is symbolic derivatives calculation. The derivative can be calculated just with several lines of Delphi code, for an example:

var
  f, df: string;
  t: TTranslator;
begin
  t:= TTranslator.Create;
  f:= 'x^2*e^(x/3)';
  df:= t.Derivative(f, 'x');
  //...
end;


The Analytics library guarantees that the result derivative expression is syntactically and mathematically correct and satisfies the derivative rules. From the first version, the derivative algorithm automatically simplifies the result derivative expression. Nevertheless, the library is not a Computer Algebra system, so it cannot simplify all the result expressions to the optimal representation.

New version 2.3 introduces new simplification algorithms for providing more readable and short symbolic derivatives. New simplification algorithms include: constants reducing in sum and product expressions; reducing nested sum or product expressions to one; reducing negation pairs in product expressions and others.

There are some examples of functions and their derivative expressions, evaluated with the old version of the library and with the 2.3 version:

f(x)       : x^2*e^(x/3)
df/dx (old): (2*x)*e^(x/3)+(e^(x/3)*(1/3))*x^2
df/dx (2.3): 2*x*e^(x/3)+e^(x/3)/3*x^2

f(x)       : 2*x^3+A/4*x^2-x/3
df/dx (old): (3*x^2)*2+((2*x)*A)/4-1/3
df/dx (2.3): 6*x^2+1/2*x*A-1/3

f(x)       : (A/2)*arctan(x^2)
df/dx (old): ((1/(1+(x^2)^2))*(2*x))*(A/2)
df/dx (2.3): x*A/(1+x^4)

f(x)       : P{n-1 m+2}(x)
df/dx (old): ((((n-1)+1)-(m+2))*P{(n-1)+1 m+2}(x) -(((n-1)+1)*x)*P{n-1 m+2}(x))/(x^2-1)
df/dx (2.3): ((n-m-2)*P{n m+2}(x)-n*x*P{n-1 m+2}(x))/(x^2-1)


As can be seen from the examples, new version gives shorter and more readable symbolic expressions for different function cases. The simplified representation of the formulae also reduces the calculation time. The new library version is already available here

The Exit Procedure

$
0
0

Photo by Kev Seto on Unsplash

All Pascal programmers know the Exit() procedure since the early versions of the compilers. But do they know how to use it correctly?

The Exit() procedure is used when we want to exit of running scope. That scope could be a function, procedure, method, or even the program itself.

Let's say that a console program calls a procedure named Execute:

    procedure Execute;
    begin
      Writeln('1. Passing on this line...');
      Exit;
      Writeln('2. It will not pass here');
    end;

In the example above, only the information from the first Writeln will be shown on the console.

When exiting a scope, the program immediately returns to the previous scope (another function/procedure/method or the program itself). The only exception to this rule is when there are try-finally blocks. If Exit () is called within a try-finally block, the compiler will execute the code inside the finally-end before it exits the scope.

Here is another example:

    procedure Execute;
    begin
      try
        Writeln('1. Passing on this line...');
        Exit;
      finally
        Writeln('2. I am still here!');
      end;
      Writeln('3. It will not pass here');
    end;

Texts #1 and #2 will be shown on the console. Even though Exit() was called before the text #2 was printed, the code still runs because of try-finally.

Another example of using Exit() is when we do validations. If a validation or checking does not return true, we use Exit() to stop execution of the current scope.

Suppose that we want to add two integer numbers, but we only want integers bigger than zero:

    function Sum(A, B: Integer): string;
    begin
      Result := 'Invalid result';
      if (A < 0) or (B < 0) then
        Exit;
      Result := Format('The result is %d', [A + B]);
    end;

In the above example, the return of Sum function is initialized with an invalid value and then there is a validation to know if the values are less than 0. If the test fails, the program will return to the prior scope to calling Sum function with the invalid result. But if the test does not fail, the function result will be the sum of A and B.

There are those who are adept at structured programming and prefer do not "break" the program execution with an "early exit", which means they do not use Exit() because they believe the code would be simpler.

So, let's rewrite the previous example:

    function Sum(A, B: Integer): string;
    begin
      if (A > 0) and (B > 0) then
        Result := Format('The result is %d', [A + B]);
      else
        Result := 'Invalid result';
    end;

Looks simpler? Well, in this example I would say yes. But for examples with more conditionals, I'd say no (let's see this below).

What if we wanted to tell the user that their data is not correct?

    function Sum(A, B: Integer): string;
    begin
      Result := 'Invalid result';
      if (A > 0) then
      begin
        if (B > 0) then
          Result := Format('The result is %d', [A + B]);
        else
          Writeln('B should be greater than zero');
      end
      else
        Writeln('A should be greater than zero');
    end;

In this example, we do not use Exit() and I think the code is quite confusing. The tests are "separated" from the warning return to the user (Writeln).

Kent Beck, Martin Fowler stated categorically that "one exit point is really not a useful rule. Clarity is the key principle: If the method is clearer with one exit point, use one exit point, otherwise don't".

So, let's rewrite the previous example using Exit():

    function Sum(A, B: Integer): string;
    begin
      Result := 'Invalid result';
      if (A < 0) then
      begin
        Writeln('A should be greater than zero');
        Exit;
      end;
      if (B < 0) then
      begin
        Writeln('B should be greater than zero');
        Exit;
      end;
      Result := Format('The result is %d', [A + B]);
    end;

The code got a little bigger, it's true, but the tests and warnings for the user got simpler, in my opinion. You do not have to follow all nested if-else's. For each test that fails, the warning is just below and the scope will be aborted with the use of Exit. If all tests do not fail, the function will return the sum of A and B.

In Delphi, as of 2009 version, Exit() procedure has gained an improvement: Exit() can have a parameter specifying a result. The parameter must be of the same type as the result of the function.

The FPC also has the same definition, but I do not know who implemented this new feature first.

Again, let's rewrite the previous example:

    function Sum(A, B: Integer): string;
    begin
      if (A < 0) then
        Exit('A should be greater than zero');
      if (B < 0) then
        Exit('B should be greater than zero');
      Result := Format('The result is %d', [A + B]);
    end;

Simple and clean.

Exit() can be given any type of return, even instances of Interfaces. Using this parameter, it is as if we get the same behavior as the return reserved word in Java. However, Exit() together with Result, gives us even more possibilities to return from functions.

See you.



Formatted emails (HTML email) from TAdvRichEditor

$
0
0

Our TAdvRichEditor UI control has everything on-board to generate HTML from its rich document content, including exporting images that are possibly used in the document. Although generating this HTML can be easily done via the TAdvRichEditorHTMLIO non-visual component connected to the TAdvRichEditor, we frequently receive support emails from users struggling to use the generated HTML to send it as email with the Indy components (TIdMessage, TidSMPT).

Therefore, we decided not only to create a sample code snippet to show how this can be done, but also to create a non-visual component (available in the latest TMS Component Pack release) to reduce the code to generate such email message to the minimum possible, that is, to one line of code:

    emailio.GenerateEmail(idmessage);

But, back to full code first that shows how to use the Indy components to generate HTML emails with embedded images as this can be generally applied for cases also where no TAdvRichEditor is used.

Drop a TIdMessage component on the form. We create a multipart message, with a part for the plain text version of the email, a part for the HTML email header and a part for the HTML itself. Then we add attachments to the message where ContentDisposition is set to 'inline' and the ContentID is set to the ID used in the HTML image reference cid attribute. So, if we have in the HTML code an image reference like:

then the ContentID for the attachment containing the image will be :
ContentID := 'imageref1';

Now, let's put this together using a TAdvRichEditor, TAdvRichEditorHTMLIO, idMessage on the form. We set AdvRichEditorHTMLIO.RichEditor to the TAdvRichEditor instance we want to export. It is very important to set AdvRichEditor.HTMLImages to igID as this instructs the TAdvRichEditor to export images references as CID URI attributes. The export to HTML and image files from TAdvRichEditor becomes:
var
  i: integer;
begin
  AdvRichEditor1.HTMLImages := igID;
  // we save the output to a temporary HTML file
  AdvRichEditorHTMLIO1.Save('.
icheditor.html');

  for i := 0 to AdvRichEditor1.HTMLImageList.Count - 1 do
    begin
      // we prepare the images as temporary images files for use as attachments for the message
      AdvRichEditor1.HTMLImageList.Items[i].SaveToFile('.img'+i.ToString+'.png');
    end;
end;

As you can see, the images to be used in the export are available via the collection AdvRichEditor.HTMLImageList. From there, we can save the images to file to be used as attachments for the Indy idMessage. The code to construct the idMessage from here becomes:
  idMessage1.IsEncoded := True ;
  idMessage1.ContentType := 'multipart/alternative';
  idMessage1.ClearBody;

  with TIdText.Create(idMessage1.MessageParts, nil) do
  begin
    // here we include the text as plain text
    Body.Text := AdvRichEditor1.PlainText;
    ContentType := 'text/plain';
  end;

  with TIdText.Create(idMessage1.MessageParts, nil) do
  begin
    ContentType := 'multipart/related; type="text/html"';
  end;

  with TIdText.Create(idMessage1.MessageParts, nil) do
  begin
    // we load the content from the temporary HTML file
    Body.LoadFromFile('.
icheditor.html');
    ContentType := 'text/html';
    ParentPart := 1;
  end;

  // here we loop over images to add all as attachments 
  for i := 0 to FRichEditor.HTMLImageList.Count - 1 do
  begin
    with TIdAttachmentFile.Create(idMessage1.MessageParts,  + '.img' + i.ToString + '.png') do
    begin
      ContentID := 'image'+ i.ToString;
      ContentType := 'image/png';
      ContentDisposition := 'inline';
      ParentPart := 1;
    end;
  end;

When the idMessage message has been created, it is straightforward to send it via the idSMTP component, i.e., this is minimally:
  IdMessage1.From.Address := 'info@tmssoftware.com';
  IdMessage1.Recipients.Add.Address := 'bruno@tmssoftware.com';
  IdMessage1.Sender.Address := 'info@tmssoftware.com';

  idsmtp1.Host := 'smtp.mailserver.com';
  IdSMTP1.Connect;
  idsmtp1.Send(idMessage1);
  idsmtp1.Disconnect();

With this code now explained, let's introduce the class TAdvRichEditorEmailIO included in unit AdvRichEditorEMailIO.pas in the latest version 8.7.3.0 of TMS Component Pack. With this class, we can reduce the code to send a HTML email from TAdvRichEditor to:
  AdvRichEditorEMailIO.GenerateEmail(idmessage);
  idMessage.Subject := 'A HTML email from TAdvRichEditor';

  idSMTP1.Host := 'smtp.mailserver.com';
  IdSMTP1.Connect;
  idSMTP1.Send(idMessage);
  idSMTP1.Disconnect();

The resulting Delphi application looks like this:

and when opening the email sent in MS Outlook, it looks like:

You can easily get started to build your own HTML formatted text email client. You can download the source code of the application here and you can compile and use this with the latest TMS Component Pack release. In the next updates of TMS FMX UI Pack that also includes the FireMonkey version of our rich editor component, we'll also include a FireMonkey version of the HTML email creator class and the same applies for the cross-framework version of the rich editor in the TMS FNC UI Pack.

Array and Matrix operations with Analytics 2.2

$
0
0

New version 2.2 of TMS Analytics and Physics pack includes total support of operations with N-element arrays and MxN matrices. The operations realized in the Linear Algebra extension package. Array and matrix operations allow advanced calculations with small, compact formulae.

Let us consider the examples of using the array/matrix operations for solving some common math/statistics problems. First of all we need to add special variables to the translator instance:

var
  av: TArray<TFloat>;
  mv: TArray<TArray<TFloat>>;
begin
  translator:= TTranslator.Create;

  translator.Add('µ', 0.0);

  av:=TArray<TFloat>.Create(0.2, -0.1, -0.25, 0.4);
  translator.Add('A', av);

  av:=TArray<TFloat>.Create(-0.2, 0.2, -0.1, 0.25, 0.35, 0.15, -0.04, 0.01, -0.12, 0.1);
  translator.Add('B', av);

  SetLength(mv, 4, 3);
  mv[0,0]:= 0.5; mv[0,1]:=-0.4; mv[0,2]:= 0.33;
  mv[1,0]:=-0.3; mv[1,1]:= 0.1; mv[1,2]:= 0.28;
  mv[2,0]:=-0.4; mv[2,1]:=-0.2; mv[2,2]:=-0.75;
  mv[3,0]:=0.44; mv[3,1]:=0.25; mv[3,2]:= 1.00;
  translator.Add('M', mv);
end;
The code above adds to the translator instance the ‘µ’ variable with value 0.0, the array variable ‘A’ with 4 components, the array variable ‘B’ with 10 components and the 4x3 matrix ‘M’.

The first problem to solve is calculation of statistics square deviation from the mean value for the ‘B’ array. Math formula for the deviation of discrete random variable is (https://en.wikipedia.org/wiki/Standard_deviation):

where µ is the mean value

N is the number of elements.

This formula can be evaluated with using array operations by the following code:
var
  m, d: TValue;
begin
  m:= translator.Calculate('∑B/#B');
  translator.Variables['µ'].Value:= m;
  d:= translator.Calculate('∑((B-µ)^2)/#B');
  // print the ‘d’ value
end;
First we calculate the mean value. The number operator ‘#’ in the formula returns the array element count. Then we assign the calculated value to the ‘µ’ variable and, finally, calculate the deviation value. Notice that there are the parentheses for the square operation in the formula, because the summation operation has higher priority. Here is the output for the evaluation:

µ = ∑B/#B = 0.06
D = ∑((B-µ)^2)/#B = 0.02876


Next problem is solving an over-determined linear equation system with the least squares approach (https://en.wikipedia.org/wiki/Linear_least_squares_(mathematics)). Let the system is set up by the ‘M’ matrix and the ‘A’ vector. Then the solution ‘X’ is defined by the formula:

where MT – is the transposed matrix, 1 means the inversed matrix.

This formula can be evaluated with the Analytics library as the following ‘M'*A/(M'*M)’. Here the apostrophe ‘'’ operator is for transposition operation and the division is equivalent to the multiplication by the inversed matrix. Evaluating the formula we get the following output:

X = M'*A/(M'*M) = TArray<TFloat>[3]=
(0.459953357586789 0.163947437790482 0.113927221302585 )

Here the ‘X’ array is the solution vector that minimizes the square error for the over-determined system.

As can be seen from the examples above, the realized array/matrix operations allow easily solve complicated problems with small, compact formulae. The complicated code for the array/matrix operations implemented inside the Analytics library and totally integrated with analytical evaluations. For an example, linear algebra operations allow solving so called ‘matrix’ ordinary differential equations (https://en.wikipedia.org/wiki/Matrix_differential_equation).

The TMS Analytics and Physics pack version 2.2 can be downloaded here. Total source code of the example application can be downloaded here .

TMS Data Modeler 3 is out!

$
0
0

We are happy to announce that TMS Data Modeler 3 has been released today. TMS Data Modeler is our tool to design databases models, ER diagrams, import existing database schema and, among others, generate source code with TMS Aurelius mapped classes based on the database schema. Below is a list of the new features in this release.

Updated User Interface

To start with, we have improved user interface, by using a more modern look-and-feel. A new cleaner color theme is used, logo, file menu, splash screen have been updated.



Customization Script for TMS Aurelius Export

When generating TMS Aurelius classes from database, you can now fully customize the output source code. Users don’t need to manually tweak the source code anymore, or wait for us to explicitly implement an option that changes how source code is created.

You can simply write a script that is based on event handlers. You can for write the following script to add the [Version] attribute to any field named “FVersion” in all of your classes:

procedure OnColumnGenerated(Args: TColumnGeneratedArgs);
begin
  if Args.Field.Name = 'FVersion' then
    Args.Field.AddAttribute('Version');
end; 

In case you script gets complex, you can also use a full-feature debugger to check what’s wrong with your code.



For the scripting system and debugger, TMS Data Modeler internally uses our scripting frameworks TMS Scripter.

You can refer to documentation for more info on how you can use customization scripts in TMS Data Modeler.

Export TMS Aurelius classes to multiple units

In previous versions all TMS Aurelius classes would be exported to a single unit. Now you can choose the name of unit where a specific class will be exported to. TMS Data Modeler will even warn you if there are cyclical references between classes declared in different units.

Source code preview

You can now preview the output source code in the TMS Aurelius Export Dialog itself, without needing to generate the source code files to view them. Just click the Preview tab and you will see the final source code generated.



Separate classes into models

You can also define to which models each class belongs to. One or more TMS Aurelius Model attributes will be added to each class. If you already have multiple ER diagrams in your Data Modeler project, then you can optionally ask for each diagram to be considered a different model and have your classes be marked automatically with one Model attribute for each diagram it belongs to.

It’s also worth saying that we have updated a lot of internal processes, frameworks and tools. It took a lot of effort. While it’s not directly perceived by the end-user, it doesn’t reflect directly on user experience, we’re sure that it will make release of newer versions easier and faster.

I hope you are excited with these new features as much as we are, and enjoy the new TMS Data Modeler!



Viewing all 1006 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>