This could very well be a duplicate, but I could not seem to find something specific to my problem.
I have a xy grid in a picture box. Each grid cell has a specific mass. I would like to create contour lines on this xy grid based on the mass.
Does anyone have any ideas to a good algorithm to perform this task? I am trying to get this done in VB6 but any algorithm would do.
Edit
Contour Grid
I have a grid. I want to display contour lines based on mass (IE, the cells with more than one point in them will be heavier in mass)
This question's a bit stale, but so's my experience: I did something like this almost 30 years ago.
This produces simple contours on a bitmap:
Calculate the field-strength at each point in the grid (I'm assuming you're trying to plot something like gravitational field contours based on the masses of the points).
Colour the alternate spaces between contour lines (which you haven't got yet) in two alternate colours. e.g. if the contour lines should be 100 units (of field-strength) apart then choose the colour of each pixel based on ToInt(pixel_field_strength / 100) % 2.
Trace the edges of the colour boundaries to produce contours. For example, if your two colours are white and black, then only retain white pixels adjacent to a black pixel.
If you're just interested in the results, use a library as suggested in the comments.
Purely for nostalgia's sake, I found my original BBC BASIC code. It still runs on modelb (a BBC Micro emulator).
10 REM THIS COMES WITH NO WARRANTY!
20
30 REM Gravity field
40
50 MODE 1
60 PROCsetup
70 FOR Y%=300 TO 900 STEP 4
80 FOR X%=200 TO 800 STEP 4
90 R=LOG(FNforce(X%,Y%))
100 GCOL0,((R*10) MOD 2)+1
110 PLOT69,X%,Y%
120 NEXT
130 NEXT
140 PROCcontour
150 VDU19,1,0,0,0,0
160 VDU19,2,0,0,0,0
170 END
180 DEFPROCsetup
190 N%=5
200 DIM X%(N%),Y%(N%),M%(N%)
210 FOR P%=1 TO N%
220 READ X%(P%),Y%(P%),M%(P%)
230 NEXT
240 ENDPROC
250 DATA 625,625,1000000
260 DATA 425,725,1000000
270 DATA 475,425,1000000
280 DATA 375,575,1000000
290 DATA 725,525,1000000
300 DEFFNforce(X,Y)
310 P=0
320 FOR P%=1 TO N%
330 DX=X%(P%)-X:DY=Y%(P%)-Y
340 R=SQR(DX*DX+DY*DY)
350 P=P+M%(P%)/R
360 NEXT
370 =P
380 DEFPROCcontour
390 GCOL0,3
400 FOR Y%=300 TO 900 STEP 4
410 FOR X%=200 TO 800 STEP 4
420 IF POINT(X%,Y%)=1 AND (POINT(X%+4,Y%)=2 OR POINT(X%-4,Y%)=2 OR POINT(X%,Y%+4)=2 OR POINT(X%,Y%-4)=2) THEN PLOT69,X%,Y%
430 NEXT
440 NEXT
450 ENDPROC
Related
Can I print a GTIN-14 barcode using ZPL?
I have searched, but can't find much information on weather or not it is possible to print this type of bar code, including the border around it.
Any help is greatly appreciated.
Thanks!
GTIN-14 is simply an interleaved 2 of 5 barcode with bearer bars and special text formatting. Assuming a 203dpi printer and an approximate x-dimension of 25 mils (.64mm), you can calculate all the dimensions of the barcode and its border box.
25mils is approximately 5 dots at 203dpi.
The barcode height should be 1.25 inches, which is ~250 dots.
The border around the barcode should be the width of the wide bar (3x narrow, or 15 dots).
Each character in the barcode is 45 dots (9 modules * 5 dots).
The start/stop also adds 45 dots (9 modules * 5 dots).
So the total length of the barcode is 15 * 45 dots = 675 dots.
Quite zone is 0.25 inches (50 dots) left and right of the barcode.
So the box around the barcode is 805 dots wide (15 border + 50 quiet + 675 barcode + 50 quiet + 15 border) and 280 dots high (15 border + 250 barcode + 15 border).
Here's how it looks in ZPL:
^XA
^FO100,100^BY5,3
^B2N,250,N,N,N
^FD00012345678905^FS
^FO35,85^GB805,280,15^FS
^FO115,380^AB,44,28^FD0 00 12345 67890 5^FS
^XZ
The top left corner of the barcode is at 100,100. The top left corner of the border box is at 35,85.
The example uses the built-in B font, you may want to change that...
And here it is in labelary.
I'm using the Marching Squares algorithm to take a lattice of values and turn them into a contour when the values exceed 50%. My values have the property that most are 0% and 100% where the transitions from 0% to 100% occurs across at most a single intervening value, such that the contour created will pass through every lattice position where the value is greater than 0% and less than 100%. For example, consider this field of values representing the approximate percentages shown in the greyscale squares of the following image:
0 0 0 0 0 0 0 0
0 0 6 71 71 20 0 0
0 28 35 100 100 48 20 0
0 100 100 100 100 100 71 0
0 100 100 100 100 100 71 0
0 9 18 100 100 35 6 0
0 0 9 100 100 28 0 0
0 0 0 0 0 0 0 0
The traditional Marching Squares algorithm would produce a contour as shown in this image:
The blue field represents the contour and the greyscale squares represent the lattice values for the above data.
Given the resulting contour, I can convert it back to a lattice of numbers again by taking the area covered by the contour for each lattice position as the recreated value for that lattice position. For the above contour, it looks like this image that shows the same contour and the resulting values converted back to a lattice of values shown by greyscale squares:
The new values are similar but not exactly the same as the original, some are larger, others are smaller, thus information has been lost and the algorithm is lossy compression. The decompressed field of values looks approximately like this:
0 0 0 0 0 0 0 0
0 0 3 67 70 4 0 0
0 12 43 100 100 59 4 0
0 91 100 100 100 100 70 0
0 88 100 100 100 100 67 0
0 4 27 100 100 43 3 0
0 0 3 88 91 12 0 0
0 0 0 0 0 0 0 0
Is there a way to adjust the linear interpolation step to not lose information, or at least come much closer to the original data field? If not, can the contour have extra points added to resolve this. For example, perhaps the interpolation step is left as is, but instead of a straight line between the points in the Marching Squares algorithm, there are extra points added along the path to force the desired area in each corner of the four lattice squares considered at each part of the Marching Steps algorithm?
In the lower right area of the example, one step of the Marching Steps algorithm finds these four values:
100 28
0 0
The interpolation produces 50% on left side and 70% on top side. This means on the left, the point A is placed exactly on the border between the 0% square in lower left and the 100% square in upper left. This means on the top, the point B is placed 70% of the way toward the center of the 28% value in upper right. The foregoing results in a diagonal line from A to B taking the upper left corner whose value is 100.
We could add additional intervening points between A and B such that the area values are not lost upon return back (decompression) from contour to lattice values. For example, consider this drawing:
The original Marching squares gives the points A and B in the drawing. The yellow highlight shows additional points X, Y, and Z that could be added so that the area covered is 100% in upper left, 0% in lower left, and 28% in upper right. For the 28%, 14% is handled below point B and 14% above point B.
Is this a known problem that has existing solutions or are there similar problems in compression of images that can be drawn upon to help solve this problem? Does the proposed solution seem reasonable or can it be simplified further? I'm concerned that it will be pretty complex to handle the four quadrants for each of the 14 variations of Marching Squares that produce lines, so if there is a way to simplify this, I'd like to find it.
In summary, would like to adjust the computation of the blue contour, such that the area of each lattice square covered by the contour matches the original data used to create the blue contour, and thus have lossless compression to convert the lattice into a contour that is perfectly reversible.
I have run the ‘More Bouncing Balls’ Basic program from chapter 5 of the C64 user’s manual, with the addition from the final page of the chapter. The code is as follows:
10 PRINT CHR$(147):REM SHIFT CLR/HOME
20 POKE 53280,7 : POKE 53281,13
30 X=1:Y=1
40 DX=1:DY=1
50 POKE 1024 + X + 40*Y, 81
60 FOR T=1 TO 10: NEXT T
70 POKE 1024 + X + 40*Y, 32
80 X=X+DX
90 IF X=0 OR X=39 THEN DX=-DX
100 Y=Y+DY
110 IF Y=0 OR Y=24 THEN DY=-DY
120 GOTO 50
To this were added the lines at the end, ɔ:
21 FOR L=1 TO 10
25 POKE 1024+INT(RND(1)*1000),160
27 NEXT L
85 IF PEEK(1024+X+40*Y)=160 THEN DX=-DX:GOTO 80
105 IF PEEK(1024+X+40*Y)=160 THEN DY=-DY:GOTO 100
These lines are not relevant to the question, but I included them for sake of completeness.
I wanted to add randomness to the direction of the ball (chr$(81)), and noticed that by changing DX and DY to other numbers, I would get it to move at angles other than 45°; of course, having both DX and DY set to 1, would have them both ‘push’ the ball in perpendicularly opposite directions, ɔ: halfway between both, equalling 45°.
But when trying to use a random number, I would get truly odd behaviour. I assumed the number had to be between 0 and 1, and so tried (INT(10*RND(1))+1)/10, and changed line 40 to set DX and DY to this random number. What I got instead was some very odd behaviour. The ball would move very fast at a predictable angle, disappearing at the right side and reappearing on the left, moving a few lines down, then disappearing completely, then turning up on top of the screen drawing unmoving balls one after another horizontally, then crash.
When instead setting DX or DY to an integer, i.e. 2, I would still get some strange behaviour, such as the ball disappearing at one end and reappearing at the opposite, and on this occasion the program would end after a few seconds.
What is causing this erratic behaviour? And how can I set the parameters in line 40 to allow the ball to move in different directions (kind of like in Pong) when it hits a wall?
Note 1: When changing DX and DY in lines 80 and 100 instead, I got some interesting jittering movement, but as expected, as though the ball drawn on-screen was an uneven sphere.
Note 2: I am aware one generally should not include tags in titles, but was unsure whether the question would be too unsearchable if I left them out. Feel free to edit the title if need be; I am happy to be educated.
I modified the program in this way:
1-DX is step for X.
2-DY is step for Y.
2-VX is direction of X, -1 left and +1 rigth.
3-XY is direction of Y, -1 up and +1 down.
3-When Bouncing Ball angle changes randomly (subroutine 300)
Calculation of DX and DY is for a right triangle with hypotenuse of 1 (one).
4-When plotting use only integer numbers so the "ball" doesn't have odd moves.
5-Control off limits, so "ball" doesn't disappear.
5 rem 2018-08-24 bouncing balls
6 rem https://stackoverflow.com/questions/51907035
7 rem /generating-random-direction-in-c64-basic
10 print chr$(147);:rem shift+clr/home=clear screen
20 poke 53280,7:poke 53281,13
25 rem random initial position
40 p=rnd(1)*40:x=p
45 q=rnd(1)*25:y=q
50 gosub 300
60 rem vector direction
70 vx=(rnd(1)<0.5):if vx>=0 then vx=1
80 vy=(rnd(1)<0.5):if vy>=0 then vy=1
100 rem plot
110 poke 1024+int(p)+40*int(q),32
120 poke 1024+int(x)+40*int(y),81
130 for t=1 to 30:next t
140 p=x:q=y
150 x=x+dx*vx
160 ca=0:rem change angle
170 if x<=0 or x>=39 then vx=-vx:ca=-1
175 if x<0 then x=0
176 if x>39 then x=39
180 y=y+dy*vy
190 if y<=0 or y>=24 then vy=-vy:ca=-1
195 if y<0 then y=0
196 if y>24 then y=24
200 if ca then gosub 300
210 goto 100
300 rem random angle between 15 and 75 d
egrees
305 rem a=angle in degrees r=radians
310 a=15+rnd(1)*(75-15+1):r=a*{pi}/180
320 dx=cos(r)
330 dy=sin(r)
340 return
On C64 replace {pi} using SHIFT+UP_ARROW.
If line 110 is REM then you can see the walk.
I modified the program so:
- Start position X and Y are random
- Direction DX and DY are random, values -1 or +1
10 PRINT CHR$(147):REM SHIFT CLR/HOME
20 POKE 53280,7:POKE 53281,13
25 REM RANDOM INITIAL POSITION
30 X=INT(RND(1)*39)+1:Y=INT(RND(1)*24)+1
35 REM RANDOM DIRECTION
40 DX=(RND(1)<0.5):IF DX>=0 THEN DX=1
45 DY=(RND(1)<0.5):IF DY>=0 THEN DY=1
50 POKE 1024+X+40*Y,81
60 FOR T=1 TO 30:NEXT T
70 POKE 1024+X+40*Y,32
80 X=X+DX
90 IF X<=0 OR X>=39 THEN DX=-DX
100 Y=Y+DY
110 IF Y<=0 OR Y>=24 THEN DY=-DY
120 GOTO 50
File datafile.txt
code x y
23 22.1 33.11
23 110 22
23 11 200
24 111 321
24 222 111
24 10 22.1
10 88.3 99.3
10 110 32
10 121 143
10 190 200
In the above file, the first column represents the image code which is displayed on the screen, and the x and y columns represent the point where people look on the image. There were three different images displayed to the user. The problem with the code below is that I don't know how to save the image with the plotted x-y on with the same name of file as it opened.
fid = fopen(datafile.txt);
A = textscan(fid,'%f%f%f'); %Read data from the file
code = A{1};
xfix = A{2};
yfix = A{3};
for k=1:length(code)
imagefile=code(k)
I = imread([num2str(imagefile) '.jpg']); %# Load a sample image
imshow(I); %# Display it
[r,c,d] = size(I) %# Get the image size
set(gca,'Units','normalized','Position',[0 0 1 1]); %# Modify axes size
set(gcf,'Units','pixels','Position',[200 200 c r]); %# Modify figure size
hold on;
x = xfix2(k);
y = yfix2(k);
plot(x,y,'+ b');
f = getframe(gcf); %# Capture the current window
imwrite(f.cdata,([num2str(imagefile) '.jpg'])); %# Save the frame data
hold off
end
However, I have a little problem. The "cross plots" which I overlay on the image, were surrounded by gray shadow (like when we photocopy a paper, they will be a gray color on it). How did this happen?
There are numerous ways:
Superimposing line plots on images
Can I use a JPEG file as a background in a MATLAB plot?
How do I add a background image to my GUI or figure window?
And there's always some kind of problem with adjusting the axes afterwards.
I have a dynamic number of equally proportioned and sized rectangular objects that I want to optimally display on the screen. I can resize the objects but need to maintain proportion.
I know what the screen dimensions are.
How can I calculate the optimal number of rows and columns that I will need to divide the screen in to and what size I will need to scale the objects to?
Thanks,
Jamie.
Assuming that all rectangles have the same dimensions and orientation and that such should not be changed.
Let's play!
// Proportion of the screen
// w,h width and height of your rectangles
// W,H width and height of the screen
// N number of your rectangles that you would like to fit in
// ratio
r = (w*H) / (h*W)
// This ratio is important since we can define the following relationship
// nbRows and nbColumns are what you are looking for
// nbColumns = nbRows * r (there will be problems of integers)
// we are looking for the minimum values of nbRows and nbColumns such that
// N <= nbRows * nbColumns = (nbRows ^ 2) * r
nbRows = ceil ( sqrt ( N / r ) ) // r is positive...
nbColumns = ceil ( N / nbRows )
I hope I got my maths right, but that cannot be far from what you are looking for ;)
EDIT:
there is not much difference between having a ratio and the width and height...
// If ratio = w/h
r = ratio * (H/W)
// If ratio = h/w
r = H / (W * ratio)
And then you're back using 'r' to find out how much rows and columns use.
Jamie, I interpreted "optimal number of rows and columns" to mean "how many rows and columns will provide the largest rectangles, consistent with the required proportions and screen size". Here's a simple approach for that interpretation.
Each possible choice (number of rows and columns of rectangles) results in a maximum possible size of rectangle for the specified proportions. Looping over the possible choices and computing the resulting size implements a simple linear search over the space of possible solutions. Here's a bit of code that does that, using an example screen of 480 x 640 and rectangles in a 3 x 5 proportion.
def min (a, b)
a < b ? a : b
end
screenh, screenw = 480, 640
recth, rectw = 3.0, 5.0
ratio = recth / rectw
puts ratio
nrect = 14
(1..nrect).each do |nhigh|
nwide = ((nrect + nhigh - 1) / nhigh).truncate
maxh, maxw = (screenh / nhigh).truncate, (screenw / nwide).truncate
relh, relw = (maxw * ratio).truncate, (maxh / ratio).truncate
acth, actw = min(maxh, relh), min(maxw, relw)
area = acth * actw
puts ([nhigh, nwide, maxh, maxw, relh, relw, acth, actw, area].join("\t"))
end
Running that code provides the following trace:
1 14 480 45 27 800 27 45 1215
2 7 240 91 54 400 54 91 4914
3 5 160 128 76 266 76 128 9728
4 4 120 160 96 200 96 160 15360
5 3 96 213 127 160 96 160 15360
6 3 80 213 127 133 80 133 10640
7 2 68 320 192 113 68 113 7684
8 2 60 320 192 100 60 100 6000
9 2 53 320 192 88 53 88 4664
10 2 48 320 192 80 48 80 3840
11 2 43 320 192 71 43 71 3053
12 2 40 320 192 66 40 66 2640
13 2 36 320 192 60 36 60 2160
14 1 34 640 384 56 34 56 1904
From this, it's clear that either a 4x4 or 5x3 layout will produce the largest rectangles. It's also clear that the rectangle size (as a function of row count) is worst (smallest) at the extremes and best (largest) at an intermediate point. Assuming that the number of rectangles is modest, you could simply code the calculation above in your language of choice, but bail out as soon as the resulting area starts to decrease after rising to a maximum.
That's a quick and dirty (but, I hope, fairly obvious) solution. If the number of rectangles became large enough to bother, you could tweak for performance in a variety of ways:
use a more sophisticated search algorithm (partition the space and recursively search the best segment),
if the number of rectangles is growing during the program, keep the previous result and only search nearby solutions,
apply a bit of calculus to get a faster, precise, but less obvious formula.
This is almost exactly like kenneth's question here on SO. He also wrote it up on his blog.
If you scale the proportions in one dimension so that you are packing squares, it becomes the same problem.
One way I like to do that is to use the square root of the area:
Let
r = number of rectangles
w = width of display
h = height of display
Then,
A = (w * h) / r is the area per rectangle
and
L = sqrt(A) is the base length of each rectangle.
If they are not square, then just multiply accordingly to keep the same ratio.
Another way to do a similar thing is to just take the square root of the number of rectangles. That'll give you one dimension of your grid (i.e. the number of columns):
C = sqrt(n) is the number of columns in your grid
and
R = n / C is the number of rows.
Note that one of these will have to ceiling and the other floor otherwise you will truncate numbers and might miss a row.
Your mention of rows and columns suggests that you envisaged arranging the rectangles in a grid, possibly with a few spaces (e.g. some of the bottom row) unfilled. Assuming this is the case:
Suppose you scale the objects such that (an as-yet unknown number) n of them fit across the screen. Then
objectScale=screenWidth/(n*objectWidth)
Now suppose there are N objects, so there will be
nRows = ceil(N/n)
rows of objects (where ceil is the Ceiling function), which will take up
nRows*objectScale*objectHeight
of vertical height. We need to find n, and want to choose the smallest n such that this distance is smaller than screenHeight.
A simple mathematical expression for n is made trickier by the presence of the ceiling function. If the number of columns is going to be fairly small, probably the easiest way to find n is just to loop through increasing n until the inequality is satisfied.
Edit: We can start the loop with the upper bound of
floor(sqrt(N*objectHeight*screenWidth/(screenHeight*objectWidth)))
for n, and work down: the solution is then found in O(sqrt(N)). An O(1) solution is to assume that
nRows = N/n + 1
or to take
n=ceil(sqrt(N*objectHeight*screenWidth/(screenHeight*objectWidth)))
(the solution of Matthieu M.) but these have the disadvantage that the value of n may not be optimal.
Border cases occur when N=0, and when N=1 and the aspect ratio of the objects is such that objectHeight/objectWidth > screenHeight/screenWidth - both of these are easy to deal with.