Matlab: Bottom of text from `text()` chopped - matlab-figure

I am trying to label my bars in a 3D bar graph:
clf
yMax = 2;
xMax = 3;
z=floor(10*rand(yMax,xMax));
bar3(z)
xlabel('x-axis')
ylabel('y-axis')
x = reshape( repmat(1:xMax,yMax,1), [], 1 );
y = repmat( (1:yMax)', xMax,1 );
%htext = text( x, y, z(:), repmat( {'TEST'}, xMax*yMax, 1 ) )
htext = text( x, y, z(:), 'TEST' )
No matter how big I make the figure, the text gets chopped at the bottom:
Can anyone suggest a way to track down the cause, and/or suggest a solution?

I was fortunate to catch a few minutes with a guru. The explanation: The VerticalAlignment defaults to middle, which works fine for 2D plots. For each of the 3D bars above, however, middle means that the middle of the text sits right at the top surface of the box. Therefore, the bottom half of the text is inside the box. The problem is solved by modifying the text command:
htext = text( x, y, z(:), 'TEST' , 'VerticalAlignment','Bottom' )
Weird how I couldn't find it in a web search, but hopefully, this answer will fix that.

Related

Plot image on dome

I am struggling to plot a round image on the surface of the dome in Matlab. Here is what I have. This is the png image:
And this is the dome:
Now, I need to project this image on the dome. I've written a code to place the image on the surface:
r = 10;
r2 = 9;
cdata = imread('circle_image.png');
props.EdgeColor = 'none';
figure();
n = 50;
[X,Y,Z] = sphere(n) ;
X1 = X * r;
Y1 = Y * r;
Z1 = Z * r;
for i = 1:n+1
for j = 1:n+1
if Z1(i,j) < r2
X1(i,j) = NaN;
Y1(i,j) = NaN;
Z1(i,j) = NaN;
end
end
end
my_dome = surf(X1,Y1,Z1,props) ;
alpha = 1;
set(kopula, 'FaceColor', 'texturemap', 'CData', cdata, 'FaceAlpha', alpha, 'EdgeColor', 'none');
axis equal
What I am getting looks like this:
It seems like the image is centred in the wrong place, or even in the wrong axis. How can I fix that?
Yes, the image is centered in the wrong place.
The texture mapping is applied on the whole surface, not just the "active" points (the one you didn't NaN). Basically, what you are getting is the image being spread onto the full sphere, and then when you crop the top of the sphere to get your dome, the image is cropped as well:
What you need to do, is actually remove all those points you converted to NaN, so they are not part of the surface at all and the texture mapping is aplied only on the top dome surface.
So replace your nested for loop with the following code:
idx_Raws2crop = Z1(:,1) < r2 ;
X1(idx_Raws2crop,:) = [] ;
Y1(idx_Raws2crop,:) = [] ;
Z1(idx_Raws2crop,:) = [] ;
Then continue with your code, you'll get:
Actually I also added the instruction:
cdata = flipud(cdata) ;
in order to have the THE CIRCLEwriting in the proper orientation (otherwise it appears upside down).
Edit:
To render the picture on the dome in the way you'd like according to your comment, I can see 2 options:
Options 1: Build upon what we have already
This will consist of:
Extend the [X,Y] domain on a square grid (so the picture is not distorted when texture mapped onto the surface).
Extend the picture itself (add some transparent margin), so the margin will cover the domain extension we introduced and the actual visible part of the picture will be nicely centered on the dome.
With the same X1, Y1 and Z1 than we obtained with the code above:
% Create a square grid large enough to cover the dome and a bit more:
[X2,Y2] = meshgrid(linspace(-5,5,100),linspace(-5,5,100)) ;
% reinterpolate Z1 over this new grid
Z2 = griddata(X1,Y1,Z1,X2,Y2) ;
Now your surface looks like this:
As I warned you, the image is now properly applied but the edge of the dome looks rather ugly. To ease that you could replace the NaN with the base value for your dome, this will transition a lot better between dome and flat domain:
Z2(isnan(Z2)) = 9 ;
Will now yield:
The next problem, as you can see, is that (as in your first question), the image is stretched onto the whole surface. So part of the writing is now on the flat part of the surface. To simply alleviate that, you can modify the picture (add a bit of transparent margin on every side), until the visible part of the image matches the dome size.
Options 2: Build your surface differently
This is actually easier and more straighforward. We will build a dome out of a square surface in the first place (no trimming and NaNing).
This code does not require any part of your previous code, it is self contained:
r = 10 ;
% Build a square grid
[X2,Y2] = meshgrid(linspace(-5,5,100),linspace(-5,5,100)) ;
% build Z2 according to the sphere equation.
Z2 = sqrt( r^2 - X2.^2 - Y2.^2) ;
figure();
my_dome = surf(X2,Y2,Z2,'EdgeColor', 'none', 'FaceColor', 'texturemap', 'CData', cdata, 'FaceAlpha', 1) ;
axis equal
Which yields a nicely centered texture map:
Note: The texture mapping works so well because your actual surface is still a square, only bent a bit to conform to a sphere. The texture mapping does not display the part of the surface where the picture is transparent, so it is invisible, but if you look at your surface without the texture mapping you'll understand what went on in the background:
hs=surf(X2,Y2,Z2) ; shading interp ; axis equal

SAT Collision detection - Corners fix

I'm building a game and I'm currently working on the physics.
I'm using the SAT algorithm to detect collisions. The collisions are between the character (AxisAlignedBoundingBox) and some rectangles (with rotation).
Everything works fine, except the collision near to a corner in specific situations. (This is a pretty known problem but I didn't find any good solutions).
On Example 1, in the second scene the character should move upwards (stay on the obstacle).
It happens to move left.
On Example 2, in the second scene the character should not get up. Sometimes it gets.
I know why this is happening, because of dx and dy, the Minimum Translation Vector isn't always the wanted one.
There are several solutions to this problem, but not a really good one (in terms of solving the problem and not creating others!).
I'm willing to even use a totally different algorithm from the beginning.
Please give me a hint about an algorithm better than the SAT, or some workaround.
THANK YOU!
A picture is worth many words.
The image has two boxes to test the red and the black..
Note how the center of the black box is always on the darker red box when it is just touching.
You can simplify any AABB test by increasing the size of one box by the size of the other. As long as you referance the boxes position by their centers all works well.
// x,y are box centers
var bBox = { w : 100 , h : 50, x : ?, y ? }; // black
var rBox = { w : 200 , h : 200, x : ?, y ? }; // red
to test if bBox is inside rBox
if(bBox.x > rBox.x - (rBox.w + bBox.w)/2 &&
bBox.x < rBox.x + (rBox.w + bBox.w)/2 &&
bBox.y > rBox.y - (rBox.h + bBox.h)/2 &&
bBox.y < rBox.y + (rBox.h + bBox.h)/2)
// boxes are touching.
}
Also works if boxes are moving. You just test if the vector of bBox movement intersects any of rBox's 4 sides.

Matlab: binary image open to minimum rectangle size

I have a binary image:
and I'm trying to see if a 100x150 rectangle will fit in any blank space on the map.
I tried creating a rectangular strel & then eroding & dilating the picture to get rid of any areas smaller than needed:
se = strel('rectangle',[150, 100]);
BW = imerode(BW,se);
BW = imdilate(BW,se);
Unfortunately, it finds a hole prematurely
which is only 80x150. I think the erosion is failing since it's against the wall & only needs half the width, but don't know how to fix it.
Also, if I'm headed down the wrong path, please feel free to set me straight. Ultimately, I just need to find the upper-left corner of the a blank space at least as big as 100x150.
The approach below works quite well and runs fairly quickly. It has a few nested loops but you can probably further optimize the performance, I mainly just wanted to get it working for you. Keep in mind though that if you comment out the fprintf() and the plotting command, that will speed things up.
I downloaded your image from your Stack post but I believe that my downloaded version has a different size (398x398) than the raw data you are working with, so keep that in mind when viewing my results below.
As indicated in the code, you supply the width (w) and height (h), the algorithm then returns all of the (col, row) positions where the rectangle can fit.
Side Note: I believe this provides a solution to a 2D version of the Bin packing problem, but I'm not sure about that, you can check out the link above if thats of interest to you.
Either way, its a great example of computational problem where an exhaustive search can be a carried out rather quickly.
To verify the results, I added simple plotting of the rectangles. Keep in mind that if the rectangle fits in more than one position, a plot of the multiple rectangles begins to look rather jumbled as they are drawn repeatedly on top of one another (with offsets).
As an example case where only a single rectangle is found, I use: w = 29; h = 102; and then the result shows that the only position where this particular rectangle can fit, has the upper left corner = (row = 295, col = 368) (this rectangle size will likely only work for my downloaded version of your data):
In summary, I first I load the data and then convert to a binary map (0's and 1's):
% Note: '0' = black; '1' = white
data = round(im2double(rgb2gray(imread(filepath))));
figure(1);imshow(data); set(gcf,'Color',[1 1 1]);
hold on;
Input the search width and height:
w = 29;
h = 102;
sze = size(data);
numRows = sze(1);
numCols = sze(2);
Next we just do a search to see what will fit at each row and col position:
for col = 1:numCols - w - 1
for row = 1:numRows - h - 1
doesFit = fitshere(data, row,col, w, h);
if (doesFit == 1)
fprintf('row = %d; col = %d \n',row,col);
colX = [col col+w col+w col col];
colY = [row row row+h row+h row];
line(colX,colY,'Color','r','linewidth',2);
end
end
end
hold off;
You will need the following function to check if a given rectangle can fit in the array:
function [val] = fitshere(data, row, col, w, h)
val = 1;
for i = col:col + w
for j = row:row + h
if (data(j,i) == 0) % if this is true, we are in the black!
val = 0;
return;
end
end
end
return;
If your interested in knowing if your rectangle will fit at all (say either width X height or height X width), you can simply repeat the search after swapping the width and height.
Hope this helps.
lets do this with some matlab idioms
M=binaryImage;
sz=size(M);
nrows = 100;
ncols = 150 ;
colsum = cumsum(M,1);
cols_are_good = colsum(nrows+1:end,:)-colsum(1:end-nrows+1,:)==0;
% nrows empty rows below this point. in this column
rows_are_also_good = cols_are_good(:,ncols+1:end)-cols_are_good(:,1:end+1-ncols)==0;
and Bob's your uncle, that last variable contains 1 in all places that have nrows below them clear and each of those has ncols to the side

Love2d Rotating an image

I would like to rotate an image in Love2D.
I have found a documentation on love2d.org: https://love2d.org/wiki/love.graphics.rotate
But I can't seem to get it to work when I try to load an image.
Heres my code:
local angle = 0
function love.load()
g1 = love.graphics.newImage("1.png")
end
function love.draw()
width = 100
height = 100
love.graphics.translate(width/2, height/2)
love.graphics.rotate(angle)
love.graphics.translate(-width/2, -height/2)
love.graphics.draw(g1, width, height)
end
function love.update(dt)
love.timer.sleep(10)
angle = angle + dt * math.pi/2
angle = angle % (2*math.pi)
end
Could anyone show me an simple example of rotating an image in love2d?
https://love2d.org/wiki/love.graphics.draw
You may be better off using the fourth argument, shown as 'r' to rotate images, such as:
love.graphics.draw(image, x, y, math.pi/4)
It's not worth the trouble of using the translate functions for a single draw, and keeping those for when you're batching many draws at once.
Your code worked perfectly for me, aside from a small unrelated issue (love.timer.sleep uses seconds in LÖVE 0.8.0).
We will be able to help you better, and perhaps reproduce your error, if you provide us with more information.
When you say
I can't seem to get it to work when I try to load an image
..what is the result?
Is the image a white box? Does the application crash? Is there nothing on the screen?
All of these imply a image loading issue, rather than a rotation issue. Although, it could be the case that the image is rotating off of the screen.
If you continue to use translate, rotate, and scale (which is usually a good idea), I recommend you take a look at the push and pop functions.
They allow you to 'stack' transformations so you can render sub elements.
Example uses are rendering a GUI (each child pushes its translation and then renders the children) and drawing sprites on a scrolling map (the camera translates the entire map and then does for entity in entities do push() entity:draw() pop() end. Each entity can translate and rotate in local coordinates (0,0 = centre of sprite)).
love.graphics.draw( drawable, x, y, r, sx, sy, ox, oy, kx, ky )
the R is the rotation.. why don't you just set it to a variable and change it as you please? ... I'm new to programming so I may be wrong but this is how I would do it.
Example of rotating at center of image using LOVE 11.3 (Mysterious Mysteries):
function love.draw()
love.graphics.draw(img, 400,300, wheel.r, wheel.sx, wheel.sy, wheel.w / 2, wheel.h / 2)
end
function love.update(dt)
wheel.r = wheel.r + dt
end
function love.load()
wheel = {x = 0, y = 0, w = 0, h = 0, sx = 0.5, sy = 0.5, r = 0, image = "wheel.png"}
img = love.graphics.newImage(wheel.image)
wheel.w = img:getWidth()
wheel.h = img:getHeight()
end
Normaly the axis for rotating is the upper left corner. To center the axis to the middle of an image you have to use the parameters after the r parameter to half of width and half of height of the image.

R plot expot with actual size

I'm new in R coding, so I need help or advise.
I'm building plot based on coordinates (originally this is eye tracking data). I`m exporting just dots without any axes or text. Later I will have to compare this dots with Image at which person was looking at.
So my aim is 1) to have exported image with very specific size (same to original image) and without any distortion (it seems to appear after manual entering of sizes in export dialog window). 2) to have this plot exported without extrafields, that obviously appers at every side.
Thank you in advance
UPD i`m thinking now if there is any way to move point of zero to left bottom corner of image? I was trying to work my problem out with cutting margins: par(mar=c(0, 0, 0, 0), xaxs='i', yaxs='i'), but it seems to cut all the empty parts of image. And I want to stay potentially working parts safe and keep size and proportions.
that is my source code
card1 <- "D:/01_experiment/02.04/p02/card1.txt"
table01 <- read.table(card1, strip.white = TRUE, sep="\t", header = TRUE)
jpeg('card81.jpg',
width = 842,
height = 595)
par(mar=c(0, 0, 0, 0), xaxs='i', yaxs='i')
plot(x = table01[,10],
y = table01[,11],
pch=20,
type="o",
#xaxt='n',
yaxt='n',
ann=FALSE,
bty="n",
xlab = "desity.x",
ylab = "desity.y"
)
dev.off()
Try this,
library(grid)
pdf("points.pdf", width=5, height=3)
grid.points(x <- runif(10), y <- runif(10), vp=dataViewport(x, y, extension = 0))
dev.off()

Resources