I have stuck with small problem.
Imagine two things: form, that should be covered - Cover-Form; and forms that will cover Cover-Form - Tiles.
My main goal is to cover my Cover-Form with Tiles. So it will looks like the tiles. I illustrate this idea with image below
Yellow color is a Cover-Form, brown forms - Tiles. On this image you can see that forms are positioned too close each other - there is no free space between them. That's what I need.
But when I try to reach the same effect, I just get non-satisfying result. It is presented on picture below
Second image has an offset after the last tile. It is happens because of different size of form. I don't know exactly what width my Cover-Form will have. I simply divide the whole width of Cover-Form into three parts. But if Cover-Form has width, for example, 173 pixels, each of my Tiles will have width equal 173/3=57.6 pixels, that will be round to 58, but 58*3=174 and it is bad.
Code below runs situation as on second image.
type
TTileArray = Array of Array of TPoint;
// This routine comes here from David's answer below and were changed by me
procedure EvenlySpacedTiles(PixelCountH, PixelCountV, TileCount: Integer; var ArrayOut: TTileArray);
var
X: Integer;
Y: Integer;
OldH: Integer;
OldV: Integer;
OldCount: Integer;
OldCount1: Integer;
TempInt: Integer;
begin
if (PixelCountH) or (PixelCountV) or(TileCount) = 0 then
Exit;
OldH := PixelCountH;
OldCount1 := TileCount;
for X:=Low(ArrayOut) to High(ArrayOut) do
begin
OldV := PixelCountV;
OldCount := TileCount;
TempInt := OldH div OldCount1;
Dec(OldH, TempInt);
Dec(OldCount1);
for Y:=Low(ArrayOut) to High(ArrayOut) do
begin
ArrayOut[X, Y] := Point(TempInt, OldV div OldCount);
Dec(OldV, ArrayOut[X, Y].Y);
Dec(OldCount);
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
F: TForm;
P: TForm;
Delta: Integer;
PrevLeft: Integer;
PrevTop: Integer;
X:Integer;
Y: Integer;
Arr: TTileArray;
IncLeft: Integer;
begin
Delta := 3;
F := TForm.Create(Application);
F.BorderStyle := Forms.bsNone;
F.SetBounds(0, 0, 173, 115);
F.Position := poDesktopCenter;
F.Color := $11DFEE;
F.Show;
SetLength(Arr, Delta, Delta);
EvenlySpacedTiles(F.Width, F.Height, Delta, Arr);
PrevLeft := F.Left;
PrevTop := F.Top;
IncLeft := 0;
for X:=Low(Arr) to High(Arr) do
begin
PrevTop := F.Top;
Inc(PrevLeft, IncLeft);
for Y:=Low(Arr) to High(Arr) do
begin
P := TForm.Create(Application);
P.FormStyle := fsStayOnTop;
P.BorderStyle := Forms.bsNone;
P.Color := Random($FFFFFF);//clSkyBlue;
P.Show;
P.Width := Arr[X, Y].X;
P.Height := Arr[X, Y].Y;
P.Left := PrevLeft;
P.Top := PrevTop;
P.Canvas.Rectangle(P.ClientRect);
Inc(PrevTop, Arr[X, Y].y);
IncLeft := Arr[X, Y].X;
end;
end;
end;
So there is my question: how can I adjust width of all tiles (3 per row) independently of cover form's width?
Thanks in advance.
Edited
P.S.
I modified some parts of code above. Now it works perfectly even with extremely small and large Cover-Form width - from 67 px. to 1237 px.
Of course there is a way to improve this code, but the main goal is achieved.
I think I will able to finish vertical Tiles placing tomorrow and publish this part there.
In many ways the comment by David gives me an idea how to do this. Thank you, David!
P.S.S.
I have read David's first comment diagonally, so I update code to work in another way, but the result still not good. You can see it on the picture below.
The first Tile has 57 px. width; the second one - 59 px.; the third Tile - only 31 px.
I just can't get how to place Tiles correctly using an algorithm suggested in David's comment.
P.S.S.S.
And again there is no result.
Right red line demonstrates a big size of the last tile. Each tile has width 58 px.
David wrote this:
173/3=58. 173-58=115. 115/2=58. 115-58=57. 57/1=57
I am able to calculate it in real life, but I am not able to implement it in the code.
Source code is updated.
P.S.S.S.S.
David's procedure doesn't do what it should do. Picture below illustrates it.
There are a gap between the first and the second Tile, and red line on the right side as on previous picture.
P.S.S.S.S.S.
Well, at this time the first part of my task is accomplished. The second one - is adding more tiles, but I don't sure if I really need them. And I am thankful for this to David Heffernan!! He spend so much time to explain me some things and I don't know how to say him more than simlply 'Thank you very much'. I am afraid, I am able just increase his reputation and accept his post as an answer. It really does the job!
On picture we can see the result I needed
P.S.S.S.S.S.S.
I have updated source code, so it can place tile and vertically too.
I would use a simple algorithm like this:
function EvenlySpacedColumns(PixelCount, ColumnCount: Integer): TArray<Integer>;
var
i: Integer;
begin
Assert(PixelCount>0);
Assert(ColumnCount>0);
SetLength(Result, ColumnCount);
for i := low(Result) to high(Result) do begin
Result[i] := PixelCount div ColumnCount;
dec(PixelCount, Result[i]);
dec(ColumnCount);
end;
end;
Here I use div which in effect uses division followed by truncation. But you could equally use Round(PixelCount / ColumnCount) if you would prefer. It's somewhat arbitrary so I personally would opt for integer arithmetic on the grounds that one should avoid floating point arithmetic if it is not necessary.
Related
I've been trying to understand NeRF. I finished reading the paper(Tancik) and watched some of the videos. I have been looking at some parts of the code. However, I can't quite wrap my head around what the get_rays function does in terms of the code. Could anybody just run through line-by-line about what each line in the the get_rays function is supposed to do?
def get_rays(H,W , focal, c2w): #c2w is pose
i, j = tf.meshgrid(tf.range(W, dtype=tf.float32), tf.range(H, dtype=tf.float32), indexing='xy')
dirs = tf.stack([(i-W*.5)/focal, -(j-H*.5)/focal, -tf.ones_like(i)], -1)
rays_d = tf.reduce_sum(dirs[..., np.newaxis, :] * c2w[:3,:3], -1)
rays_o = tf.broadcast_to(c2w[:3,-1], tf.shape(rays_d))
return rays_o, rays_d
It creates two lists, rays_o represents points where rays originate (camera centre) and rays_d represents direction vectors of each ray casting through the centre of every pixel of the camera. In this case, all values in the rays_o are the same because the function gets rays from a single camera.
How do I open an (dm4) image with annotations in a script in dm-script?
When a dm4 image has annotations (e.g. a scale bar or some text), this is displayed when I open the image via the menu (Ctrl + O). But when I open the same file in a script by openImage() they do not show up as shown below.
On the left there is the image opened via the menu, on the right is the exact same image opened by openImage(). It is missing the annotations.
The following example shows the same thing. The code adds text to an image, saves it and opens it again. The opened image does not show the annotations just as the images above:
String path = GetApplicationDirectory("current", 0);
path = PathConcatenate(path, "temp.dm4");
// get the current image
image img;
img.getFrontImage();
ImageDisplay display = img.ImageGetImageDisplay(0);
// add some test annotations
number height = img.ImageGetDimensionSize(1);
number padding = height / 100;
number font_size = height/10;
for(number y = padding; y + font_size + padding < height; y += font_size + padding){
Component annotation = NewTextAnnotation(padding, y, "Test", font_size);
annotation.componentSetForegroundColor(255, 255, 255);
display.ComponentAddChildAtEnd(annotation);
}
// save the current image
img.saveImage(path);
// show the saved image
image img2 = openImage(path);
img2.showImage();
You have a mistake in the second to last line.
By using = instead of := you are copying (the values only) from the opened image into a new image. You want to do
image img2 := openImage(path)
This is a rather typical mistake made when being new to scripting, because this is a "specialty" of the scripting language not found in other languages. It comes about because scripting aims to enable very simple scripts like Z = log(A) where new images (here Z) are created on-the-fly from processing existing images (here A).
So there needs to be a different operator when one wants to assign an image to a variable.
For further details, see the F1 help documentation here:
The same logic / source of bugs concerns the use of := instead of = when "finding" images, "creating new images" and cloning images (with meta data).
Note the differences when trying both:
image a := RealImage("Test",4,100,100)
ShowImage(a)
image b = RealImage("Test",4,100,100)
ShowImage(b)
and
image a := GetFrontImage()
a = 0
image b = GetFrontImage()
b = 0
and
image src := GetFrontImage()
image a := ImageClone( src )
showImage(a)
image b := ImageClone( src )
showImage(b)
I have a MDI child form that when opening doesn't maximize at once.
I can see that the datagrid on it is created and then the form is maximized
I use the following constructor to create the form.
Properties:
FormStyle = fsMDIChild
Position = poDefaultPosOnly
WindowState = wsMaximized
constructor TfrmJsContacts.Create(aOwner: TComponent);
begin
WindowState := wsMaximized;
inherited Create(aOwner);
TimerDelay.Enabled := True;
end;
The problem is a visual problem so to speak - everything works as it should. It just looks wrong that the form is shown before it is maximized. What really could be nice was to have a AfterShow event to play with. I think that would help me in this situation.
MDIChild popups comes with a little animation.
If MDIChild.Position is set to
poDefaultPosOnly
poDefaultSizeOnly
poScreenCenter
poDesktopCenter
poMainFormCenter
poOwnerFormCenter
Top and Left are calculated at creating
assume Top = 300 and Left = 400 now
at on Show MDIChild are now part of MDIParent and so
Top = 300 and Left = 400 are now Inside MDIParent.
Means left top corner of MDIChild is now in the middle of MDIParent form.
with wsMaximized the animation is shown from middle right to top left.
Now use Position
poDesigned
poDefault
and with Top and Left set to 0 the animation will not longer be seen.
constructor TfrmJsContacts.Create(aOwner: TComponent);
begin
Top := 0;
Left := 0;
WindowState := wsMaximized;
inherited Create(aOwner);
....
end;
In Design mode when frmJsContacts is selected, go look at the Object Inspector.
IF Property WindowState is set to wsMaximized
You can see for a short time the whole form !
If the changes are as follows, can be seen for a short time only the title bar, not the whole form.
set, Object Inspector : Property WindowState to wsNormal.
move code WindowState := wsMaximized below inherited Create(aOwner).
code should like
constructor TfrmJsContacts.Create(aOwner: TComponent);
begin
Top := 0;
Left := 0;
inherited Create(aOwner);
WindowState := wsMaximized;
....
end;
I am not sure if this is possible as I have been looking for a few hours and cant find what I am looking for.
What i am doing is taking a color from a game panel which is semi translucent so the color which I am taking is always subtly changing. What is need is a way to check if it is +/- 10 or so shades of my desired color.
Something like
If color1 is +/-10 of 0x?
I have tried using the image search to do similar but that didn't work.
Any help would be greatly appreciated
In addition to Robert's answer, you can compare the colors mathematically.
First start by separating the Red, Green, and Blue values.
ToRGB(color) {
return { "r": (color >> 16) & 0xFF, "g": (color >> 8) & 0xFF, "b": color & 0xFF }
}
Then we need a function that compares the colors. Each of thee variables holds a number representing the difference in the two color values. For example if red is 255 in c1, and 200 in c2, rdiff will be 55. We use Abs so that we don't end up with -55 when c2 has a higher value. Then we make sure the difference for each of these is less than our vary.
Compare(c1, c2, vary=20) {
rdiff := Abs( c1.r - c2.r )
gdiff := Abs( c1.g - c2.g )
bdiff := Abs( c1.b - c2.b )
return rdiff <= vary && gdiff <= vary && bdiff <= vary
}
Here's how it can be used. We take some numbers, and then compare them to each other with the default vary of 20.
light_pink := ToRGB(0xFFAAFF)
darker_pink := ToRGB(0xFAACEF)
purple := ToRGB(0xAA00FF)
MsgBox % Compare(light_pink, dark_pink) ; True
MsgBox % Compare(light_pink, purple) ; False
I assume that your read about the limitations of PixelGetColor: Known limitations:
"A window that is partially transparent or that has one of its colors marked invisible (TransColor) typically yields colors for the window behind itself rather than its own.
PixelGetColor might not produce accurate results for certain applications. If this occurs, try specifying the word Alt or Slow in the last parameter."
When using ImageSearch, you can specify the Delta of the colours. Example:
ImageSearch, FoundX, FoundY, %SearchRangeLeft%, %SearchRangeTop%, %SearchRangeRight%, %SearchRangeBottom%, *20 %ImageFile%
Here the *20 indicates the variation in the range from 0 to 255 of my search colour. When searching for a pixel inside the image of 100,100,100 (RGB), it will match anything between 80,80,80 and 120,120,120. Hope this helps, but matching transparent colours is difficult and prone to errors. The smaller the image and search range the better (and faster)
In Crystal Reports 2008, there's a "Graphic Location" image property where it can be set to a file path so when the report gets run, it uses the selected picture file instead of the one on the report. I tried setting this via the .NET API, but it's only working some of the time.
In the report itself, I've set Graphic Location to {#LogoPath}, then when I run the report via .NET API, I set {#LogoPath} to the filename of the picture. I've put the formula on the report itself, and it's indeed getting set to the correct filename, but the image on the report doesn't always update. It would consistently show up for some time, then consistently not show it again.
Here's what I ended up using, the code is in Delpi Prism. One of the awkward thing to deal with is if the image being replaced is different size to the image on the report, Crystal doesn't resize it correctly. The other problem was I needed to free the picture object manually otherwise Crystal sometimes doesn't display it on the report.
method SetShadingAndLogo(const AReport:ReportDocument);
var
LogoPath:String;
PicObj:PictureObject;
Logo:System.Drawing.Image;
PicRatio:Double;
ContWidth, ContHeight:Double;
ContainerRatio:Double;
NewDimension:Double;
PosAdj:Integer;
Scale:Double;
begin
for each Section:Section in AReport.ReportDefinition.Sections do
begin
for each RptObj:ReportObject in Section.ReportObjects do
begin
if RptObj.Name.StartsWith('LOGO', StringComparison.CurrentCultureIgnoreCase) and
(RptObj.Kind = ReportObjectKind.PictureObject) then
begin
//set to company logo
LogoPath := "C:\logo.jpg";
PicObj := RptObj as PictureObject;
if not System.IO.File.Exists(LogoPath) then
PicObj.ObjectFormat.EnableSuppress := true
else
begin
Logo := System.Drawing.Image.FromFile(LogoPath);
//work out the aspect ratios of the image and the container
PicRatio := Double(Logo.Width) / Double(Logo.Height);
//convert twips to pixels
//96 is the default dpi for Windows, but should really check Windows settings
//instead of hard coding
ContWidth := Double(TwipsToPx(PicObj.Width, 96));
ContHeight := Double(TwipsToPx(PicObj.Height, 96));
ContainerRatio := ContWidth / ContHeight;
// adjust the size of the container on the report to maintiain the original
// image's ratio
if PicRatio > ContainerRatio then
begin
// reset the vertical position to remain centred on the original location
// get the new height of the container (in pixels)
NewDimension := (ContWidth / Logo.Width) * Logo.Height;
// get the movement (in twips)
PosAdj := PxToTwips(Integer((ContHeight - NewDimension) / 2), Integer(Logo.VerticalResolution));
// adjust the position
PicObj.Top := PicObj.Top + PosAdj;
// picture is wider so adjust the height accordingly
// need to scale using the logo's dpi to resize correctly
Scale := Double(PicObj.Width) / Double(PxToTwips(Logo.Width, Integer(Logo.VerticalResolution)));
PicObj.Width := Integer(PicObj.Width * Scale);
PicObj.Height := Integer(PicObj.Height * Scale);
end
else
begin
// picture is taller and needs to be scaled to height
// reset the horizontal position to remain centred on the original location
// get the new width of the container (in pixels)
NewDimension := (ContHeight / Logo.Height) * Logo.Width;
// get the movement (in twips)
PosAdj := PxToTwips(Integer((ContWidth - NewDimension) / 2), Integer(Logo.VerticalResolution));
// adjust the position
PicObj.Left := PicObj.Left + PosAdj;
// picture is taller and needs to be scaled to height
// need to scale using the logo's dpi to resize correctly
Scale := Double(PicObj.Height) / Double(PxToTwips(Logo.Height, Integer(Logo.VerticalResolution)));
PicObj.Width := Integer(PicObj.Width * Scale);
PicObj.Height := Integer(PicObj.Height * Scale);
end;
//must free the logo, otherwise Crystal sometimes doesn't display it on report
Logo.Dispose;
for each fm:FormulaFieldDefinition in AReport.DataDefinition.FormulaFields do
begin
if fm.Name.Equals("LogoPath") then
fm.Text := """"+LogoPath+"""";
end;
end;
end;
end;
end;
end;
method TwipsToPx(const AValue, ADpi:Integer):Integer;
begin
//convert to twips using specified dpi, 96 is Windows' default dpi
Result := System.Convert.ToInt32(Double(AValue) * ADpi / 1440);
end;
method PxToTwips(const AValue, ADpi:Integer):Integer;
begin
//convert to pixels using specified dpi, 96 is Windows' default dpi
Result := System.Convert.ToInt32(Double(AValue) * 1440 / ADpi);
end;
Take a look at my Crystal Reports: Dynamic Images posting.
In Graphics Location formula, you might want to do like as follow:-
{?imageUrl}
You can set this parameter in your CS file dynamically by doing as follow:-
ParameterFields paramFields = new ParameterFields();
ParameterField paramField = new ParameterField();
ParameterDiscreteValue parameterValue = new ParameterDiscreteValue();
paramField.Name = "imageUrl";
parameterValue.Value = "**URL FOR IMAGE**";
paramField.CurrentValues.Add(parameterValue1);
paramFields.Add(paramField);
In Report, Create "imageUrl" Parameter field. By doing as follow :-
1) Go to report and open Field Explorer on your left. If its not there you can get it by going
Crystal Report >> Filed Explorer.
2) Right click on Parameter Field and click on "New"
3) Give Parameter name as "imageUrl". In "Value Option" set "Prompt With display only" and "Optional Prompt" to false.
This should work.
Let me know if it helps.