How to use GetGeoCoding in delphi - delphi

The idea is to get the coordinates of an address and be able to use these coordinates in the code that follows. This should all happen in one function. Now, converting the address to coordinates is not the problem. this just works. Only when I assign the longitude and latitude to a variable it does not give any values when I call the variables later in the function. TTMSFNCGeoCoding is used for this.
Function TestFunction:Boolean;
var
ALongitude,ALatitude : string;
FstartAdres : TTMSFNCMapsCoordinateRec;
begin
TMSFNCGeocoding1.GetGeocoding('New York',
procedure(const ARequest : TTMSFNCGeocodingRequest;
const ARequestResult : TTMSFNCCloudBaseRequestResult)
begin
FStartAdres := ARequest.Items[0].Coordinate.ToRec;
ALongitude := FloatToStr(FstartAdres.Longitude);
ALatitude := FloatToStr(FStartAdres.Latitude);
end);
//for example i want to show the data
showmessage(ALongitude); //message is empty
showmessage(ALatitude);//message is empty
end;
if I have forgotten important information let me know

Related

Deleting char's in a ansiString

I have this ansiString for example
DISC506002000001008100021041511207123051520515308154091550920TN177869-0151J1 36J207 70077 0 0
Trying to extract TN177869-0151J1
but the code I am using keeps returning me the whole ansistring.
function TForm5.ParseDataPartNumber(Data: AnsiString):ansistring;
var
ExtraData: Ansistring;
begin
extraData := data;
Delete(extraData,76,30);
Delete(extraData,0,61);
result:=extraData;
end;
What am I doing wrong? Is it due to it being an ansistring instead of string? that is throwing me off?
Your code is not working because you are passing wrong values in the params of the Delete method. Anyway you can use the Copy function instead like so
function TForm5.ParseDataPartNumber(const Data: AnsiString): ansistring;
begin
Result:=Copy(Data, 62,15);
end;
Strings are 1 based, so change your 2nd Delete to index 1 instead of 0.
ie:
function TForm5.ParseDataPartNumber(Data: AnsiString):ansistring;
var
ExtraData: Ansistring;
begin
extraData := data;
Delete(extraData,77,43);
Delete(extraData,1,61);
result:=extraData;
end;
Your indexes were wrong too to extract that string. My answer shows changed values.

Can one initialize multiple variables of some type in one line?

I have been trying to write as less code as possible.
So, I use:
MyBoolean := Memo1.Text <> '';
instead of
if Memo1.Text = '' then
MyBoolean := true
else
MyBoolean := false;
Declare and initialize
var
myGlobal: integer = 99;
to declare and initialize global variable. I would like to do the same for local variables, but seems it is not possible, so, I wonder if there is a way to initialize multiple variables of some type in one line, like in C
int x, y, z;
x=y=z=0;
Thank you.
In C assignment is an expression (returns a value).
In Pascal assignment is a statement (does not return a value).
The difference has some interesting consequences. For example in C both
while (x=0)
and
while (x==0)
are syntactically valid constructions (it is the source of innumerable errors) while in Pascal
while (x:=0)
is syntactically invalid because x:=0 is a statement.
You can only initialize a single local variable per statement.
Of course it would be possible to write a function
function AssignInteger(var _AssignTo: integer; _Value: integer): integer;
begin
Result := _Value;
_AssignTo := _Value;
end;
and use it like this:
var
i, j, k: integer;
begin
i := AssignInteger(j, AssignInteger(k, 5));
But that's not quite what you want, saying you want to write as short as possible code.
I'm pointing this out nonetheless just in case.
As dummzeuch says, you could write your own routine. However, I would prefer one with a signature something like: procedure AssignIntegers(AValue, ATargetArray);. And ideally call the routine with: AssignInteger(99, [X, Y, Z]);.
Unfortunately the ideal option does not work, but the following procedure is close enough and should suffice. It works by taking pointers to the integers that need to be assigned.
procedure AssignIntegers(AValue: Integer; const ATargets: array of PInteger);
var
I: Integer;
begin
for I := Low(ATargets) to High(ATargets) do
ATargets[I]^ := AValue;
end;
The following DUnit test case demonstrates that it works. You can even keep an array of these integer pointers handy to reassign at any time.
type
TArrayPInteger = array of PInteger;
procedure TDelphiTests.TestAssignIntegers;
var
X,Y,Z: Integer;
LGroup: TArrayPInteger;
begin
AssignIntegers(1, [#X, #Y, #Z]); { Pass open arrray using addresses of integers to initialise }
CheckEquals(1, X);
CheckEquals(1, Y);
CheckEquals(1, Z);
LGroup := TArrayPInteger.Create(#X, #Y); { Handy technique to initialise dynamic arrays }
AssignIntegers(2, LGroup);
CheckEquals(2, X);
CheckEquals(2, Y);
CheckEquals(1, Z); { Not part of group }
end;
WARNING
The only real drawback is that you lose type-checking. The compiler won't prevent you from passing the address of non-integer types. This can lead to corrupting other structures' data or access violations.

Get name of object clicked

I have a bunch of Tcubes made at runtime inside a viewport3D. I would like to know if one is clicked on. and if so return the name of this TCube.
small example of what i am talking about.
procedure blockClicked;
begin
//get name of block
//checkMode ( add , delete, other)
//get name of block x, y, and z
//do other stuff
end;
procedure TForm1.cubeClick(Sender: TObject);
var
Cube: TCube;
begin
// Senders points to the cube clicked
cube := Sender as Tcube;
end;

Pass static byte array in parameter in Delphi

I have a static array:
myArray: array [0..15] of byte;
I wish to pass this array (not a copy of the array) into a function. Inside the function, I will manipulate the data in array.
Different lengths of STATIC byte array may be passed in to Init at different times. Therefore, I do not wish to declare Init to be able to receive only a certain length of byte array. (e.g. in this case it is a 16 bytes. At other times it may be 65000 bytes)
This is the way I used the function:
Init(#myArray[0]); //passing in pointer to static array
I tried to declare Init like this:
procedure Init(x: array of byte);
begin
//Do some stuff with x, for e.g.
Length(x); //I do not intend to pass in the length as a parameter,
//but determine it in this function itself.
end;
Is this also a correct way of declaring the Init function parameter?
Instead of Init(#myArray[0]) use Init(myArray). Delphi will transfer the myArray by reference
You declared x as open array of bytes. The open array parameters are type compatible with the array variables with the same element type. Delphi will transfer fixed array length as a hidden parameters. You can access it with Length(x) and e.g. for i := Low(x) to High(x) do.
Open array parameters cannot be set to nil. If you need to set x to nil, then you have to declare x as pointer to Byte or pointer to array[..] of Byte.
For static arrays there is no information about their length at runtime, but only at compile time.
So if you loose the type information at passing a static array to a function, there is no way to find out the length of the array within the function.
=> If you want to use static arrays with variable sizes, you must pass the size as additional parameter.
The clean way would be to work with pointer aritmetic rather than arrays here.
PByte = ^byte;
procedure Init(arr: PByte; len: Integer);
var
i: Integer;
begin
//Write 0, 1, 2 ... to arr
for i:= 0 to len-1 do
begin
arr^:= i;
Inc(arr);
end;
end;
Unclean solution:
TByteArray = array [0..$FFFFFFFF] of Byte;
PByteArray = ^TByteArray;
procedure Init(arr: PByteArray; len: Integer);
begin
arr^[0]:= 0;
arr^[1]:= 1;
...
end;
...
var
myAray: array[0..10] of byte;
begin
Init(PByteArray(#myArray[0]), 10);
end;
First, declaring
procedure Init(x: array of byte);
declare an open array parameter (not a dynamic array, unlike some other stated).
To do what you want, you need to declare like this :
type
TMyArray: array [0..15] of byte;
var
MyArray : TMyArray;
Procedure Init(var X : TMyArray)
Still, I'm not sure why you try to set the variable to nil. A static array variable is a little bit like a record, you can't set it to nil. And IF you pass a pointer to the function instead, you will need to assign your array to a variable first anyway(or allocate the memory directly in the function). Like this :
type
TMyArray : Array[0..15] of byte;
pTMyArray : ^TMyArray;
Procedure Init(var X : pTMyArray);
procedure DoSomething;
var P : pTMyArray;
begin
New(P); //or if you array is global, simply do "P := #MyArray"
try
//code here
Init(P);
//code here
finally
Dispose(P);
end;
end
But that would be a bad construct IMO, because if you set your array pointer to nil inside the Init function, you will get a memory leak. So this is pretty bad to start with. But I guess if it's your Init function that reserve the memory that would be OK.
If you settle for an open array parameter, I'd suggest using the Low and High to determine the bounds of the array.
I think that's the best info I can give you until you give more detail on what you are trying to achieve.
EDIT
Ok, if you need the function to accept an array of different size, you need an open array parameter.
You did it right in your exemple. But you can't set it to nil within the function.
I don't think it's possible to pass to a function a pointer to an open array type. If you really want a pointer to set it to nil, you will need to pass it as PByteArray... But you will need to also pass the size of the array.
first when your are declarating this
procedure Init(x: array of byte);
you are using a dynamic array open array parameter instead of a static array.
to pass a static array as a parameter , you must define a type
like this
type
Arr15 = array [0..15] of byte;
and then declare the procedure like this, using the keyword var to pass by reference.
procedure Init(var x: Arr15);
about the nil assign , you cannot set to nil a static array.
another alternative is use a dynamic array
check this sample
type
ByteArray = array of byte;
procedure Init(var x : ByteArray);
const
LenArray=15;
var
i : Byte;
begin
SetLength(x,LenArray); //alocate the memory and set the length of the array.
for i:=0 to LenArray-1 do //fill the array
x[i]:=i;
Writeln(Length(x)); //show the len of the array
SetLength(x,0); //now dealocates de memory
Writeln(Length(x)); //show the len of the array again
end;
Var
myArray : ByteArray;
begin
try
Init(myArray);
Readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.

String representation of the content type of a Variant?

First, apologies for my English, I hope it makes sense what I`ve written here. Now to my problem.
How can I get the string representation of the content type of a Variant using TypInfo.GetEnumName(). I have tried the following, without luck, I get a numeric representation.
myString := GetEnumName( TypeInfo(TVarType), TVarData(myVar).VType );
Thank you.
Just use the build-in Delphi function for getting the string representation of a Variant type.
var
MyVariantType: string;
MyVariant: Variant;
begin
MyVariant := 'Hello World';
MyVariantType := VarTypeAsText(VarType(MyVariant));
ShowMessage(MyVariantType); //displays: String
MyVariant := 2;
MyVariantType := VarTypeAsText(VarType(MyVariant));
ShowMessage(MyVariantType); //displays: Byte
end;
Quoting from the Delphi 2007 help:
Use GetEnumName to convert a Delphi enumerated value into the symbolic name that represents it in code.
That means that you can't use it for that purpose, as TVarData.VType is not an enumerated value, but an integer which is set to one of the constants in System.pas that are taken from the Windows SDK wtypes.h file. Look at the source of GetEnumName(), it does immediately return a string containing the value of the integer.
Edit:
is there any other way to get the string representation of TVarData.VType
You can determine the string representation manually. First you need to be aware of that there are several bits of information encoded in that integer, so a simple case statement or array lookup will not work. The lower 12 bits are the type mask, and the upper bits encode information about whether it is a vector or array type and whether it is given by reference or not. The important parts are:
const
varTypeMask = $0FFF;
varArray = $2000;
varByRef = $4000;
So you could do something like:
function VariantTypeName(const AValue: TVarData): string;
begin
case AValue.VType and varTypeMask of
vtInteger: Result := 'integer';
// ...
end;
if AValue.VType and varArray <> 0 then
Result := 'array of ' + Result;
if AValue.VType and varByRef <> 0 then
Result := Result + ' by ref';
end;
Since it's not an enum, you'll have to do it manually. Write something like this:
function VariantTypeName(const value: TVarData): string;
begin
case value.VType of
vtInteger: result := 'integer';
//and so on
end;
Or, since the values in System.pas are listed in order, you could try declaring a const array of strings and have your VariantTypeName function return the appropriate member of the array.
Here's a thought for Delphi versions that don't support VarTypeAsText: You could define a enumerate type yourself that follows the VType values:
type
{$TYPEINFO ON}
TMyVarType = (
varEmpty = System.varEmpty,
varNull = System.varNull,
// etc...
);
(Fill the unused enum slots too - see Why do I get "type has no typeinfo" error with an enum type for the reasoning behind this).
Next, use these functions to read the Variants' type as your own enumerate type :
function MyVarType(VType: TVarType): TMyVarType; overload;
begin
Result := TMyVarType(VType);
end;
function MyVarType(V: Variant): TMyVarType; overload;
begin
Result := TMyVarType(TVarData(V).VType);
end;
And then you can convert it to a string like this :
function VarTypeToString(aValue: TMyVarType): string;
begin
Result := GetEnumName(TypeInfo(TMyVarType), Ord(aValue));
end;

Resources