I have a point layer in QGIS (extracted vertices from a polygon). I need to select automatically the point which has the minimum X and minimum Y coordinates (the lowest on the left), for any geometry.
I know I can select by expression the minimum coordinate:
"ycoord" = minimum("ycoord")
But I do not know how can I select with "minimum Xcoordinate AND minimum Ycoordinate"
"xcoord" = minimum("xcoord") AND minimum("ycoord")
it does not work.
Thank you in advance for your help!
Image of an example of polygon
Try this:
"xcoord" = minimum("xcoord") AND "ycoord" = minimum("ycoord")
I suggest you to do it this way:
$x = minimum($x) AND $y = minimum($y) and now you don't need to calculate a field with x and y coordinates.
As far as I can see, your proposed solution tries to find a point that does most of the time not exist i.e. with the coordinate pair of the botttom left point of a bounding box encompassing your points.
I suppose you are actually looking for the point with the smallest distance from said point.
I'm not sure if select by expression is the right tool for that, but you could do something like this, which selects the point with the minimum distance to the bottom left corner of your bounding box :
intersects_bbox($geometry,buffer(make_point(minimum($x), minimum($y)),minimum(distance($geometry,make_point(minimum($x), minimum($y))))))
You could also use some hotfix like selecting the minimum of x using a subset of points where y is smaller then the mean of y:
$x = minimum($x,"",$y<mean($y))
Related
The region's hole has been filled and I want to find all edge pixels in anti-clockwise direction.
At first, my solution is
1、 find all pixel at edge
2、get x-direction between centroid and the pixel.
3、sort it.
How to improve it?
Image and code as follows, but when I test code, it found that the concave and bulge make it useless because for at these angles there are possible many points.
function nAngle = create_angle_array(nPosition,centroid)
a = repmat(centroid,[size(nPosition,1),1])
nAngle = mod(angle((nPosition-a)*[1;1j]),2*pi)
end
se = strel('rect',[3,3]);
erodeImage = imerode(binaryImage,se);
erodeImageLeft = binaryImage - erodeImage;
% countPixel = sum(erodeImageLeft(:)== true);
[edgeRow_a,edgeCol_a] = find(erodeImageLeft);
if isscalar(edgeRow_a)
edgeRow = [edgeRow_a];
else
edgeRow = edgeRow_a;
end
if isscalar(edgeCol_a)
edgeCol = [edgeCol_a];
else
edgeCol = edgeCol_a;
end
disp(edgeRow);
disp(edgeCol);
angleValue = create_angle_array(cat(2,edgeRow,edgeCol),centroid);
disp(angleValue);
nPixel = cat(2,angleValue,edgeRow,edgeCol);
fprintf('size(nPixelA) is [%s]\n', int2str(size(nPixel)));
disp(nPixel)
nEdgePixel = sortrows(nPixel)
As you've seen, sorting the pixels along an axis does not guarantee a consistent ordering. A more reliable way is to take a pixel and find the next pixel adjacent to it in the proper direction.
To do this, we need to search the adjacent pixels in the proper order. For a counter-clockwise ordering, we'll define the directions as:
1 0 7
\ | /
\|/
2--+--6
/|\
/ | \
3 4 5
For the current pixel, we will start searching for the next pixel in the direction of the previous pixel plus 1 (modulo 8). So if the previous pixel was in direction 6, we'll first look in direction 7, then 0, then 1, until we find the next perimeter pixel. Then repeat until we reach the starting pixel again.
When we select the starting pixel, we don't have a "previous" pixel, so the easiest way to ensure that we don't miss any pixels is to start on one of the extremes (say, leftmost). Then set the direction of the "previous" pixel to the direction you know there are no more pixels, that is, to the left or direction 2. So,
Set current_pixel and assign previous_direction as above. Add current_pixel to perimeter_list.
Repeat:
Starting at previous_direction + 1 (modulo 8), search adjacent pixels in order until you find another perimeter pixel.
If the new pixel is equal to the starting pixel, break.
Add new perimeter pixel to list. If the direction the new pixel was found in is d, set previous_direction to d+4 mod 8. Set the current_pixel to the newly-found pixel.
This will find all of the perimeter pixels of a region in the proper order without having to explicitly find the perimeter pixels first. Any "spikes", or one pixel wide lines, protruding from the region will list the pixels twice, once traversing the line in each direction, so your final list might be longer than the number of perimeter pixels. You can also skip filling the holes, unless you need them filled for a future step.
Some things to look out for are making sure that you don't look outside the bounds of the image, and getting MATLAB's 1-based array indexing to work with mod. Personally, I have a mod1 function to do one-based modulo. If you do this, just change the direction numbers to be 1 to 8 instead of 0 to 7. I chose to start with the leftmost pixel because that's what find(bwimg, 1) is going to return.
I have a set of cartesian coordinates. What is the best way to find the top most left coordinate?
My approach is to find max Y and then corresponding lowest X coordinate. (Since there could be multiple points with same Ymax). This works fine but wonders if there are other cute methods?
If your x and y coordinates are not sorted, then you have to check all the input coordinates - at first your y values (for topmost, the higher the better) and then all corresponding x values for such y, but now you look for minimal x.
Trying to find the distance from point a to point b given a custom axis. I have some pictures to help me better explain:
I'm trying to find the distance from red to pink (or gray) on two custom axes. The axis from red to green (axis RG) and the axis from red to blue (axis RB).
You're asking about vector projection.
Given two vectors A and B, what is A projected onto B?
In your case, A seems to be the difference between red and pink, where B is what you're calling a custom axis.
Calculating this projection usually involves a dot product. Lucky for you, Unity provides Vector3.Dot to make this easy.
We can calculate the projection as a scalar. A is "this much" in the direction of B:
float projScalar = Vector3.Dot(A, B.normalized);
This gives us the length you're asking about.
If needed, we can convert that result into a vector, by casting that length in the direction of B:
Vector3 projVector = B.normalized * projScalar;
I have a question to you...
Imagine square with size A x A. Now lets simulate circles with diameter of d, randomly distributed within this square, something like on the image below (in this case d's are the same, but its not the rule, they might be also randomly distributed within some range like d1 to d2).
Lets say that circles are described in matrix as:
circles(1, :) = [x, y, d];
circles(2, :) = [x, y, d];
...and so on
where x, y are coordinates, d is diameter. Now the question is, how to simulate this circles, until given crowding parameter c is reached? c is simply defined as: c = yellow area / square area (in this case A^2).
And the second thing - lets say that everything is simulated and I want to check if some coordinate (x,y) is within or outside yellow area... How to do it? I was doing it by checking if my (x,y) is within area of each circle (but its getting more difficult when instead of circles I use i.e. round shape rectangles), one by one, but there must be some better way of doing it.
Thanks for help : )
Here is an approach that should do the trick:
Start with a large empty matrix (big enough to guarantee that every shape generated is fully inside the matrix). Suppose we do it like this color = zeros(100)
while we have not yet reached the cowding ratio: the midpoint and diameter of one circle, I assume you can manage this
change the color of all points in the circle, for example by setting it to one.
Calculate the crowding ratio (something like c = mean(mean(color))
Note, if you only want to use part of the matrix (enable shapes to fall partially out of the picture) this can for example be achieved by using mean(mean(color(11:end-11)) in step 4, ignoring the 10 pixels near the edge.
Now if you want to know whether point (x,y) is yellow, simply check the value of color(x,y). Or if you want to ignore the edges check color(x+10,y+10)
I have a grid with fixed points and random generated user's positions.
Distances for each point and user are measured from the beginning of the axis 0.0. I want to associate each user to the closest fixed point. I calculate both distance vectors and the min of them per user is pointing to the closest fixed point.
But i am stuck on finding a working way so each fixed point and associated user have something same in plot, p.e. same color and color area.
So my problem is two dimensional:
First is to manage to associate each user to its closest fixed poind
How to color the result.
Thank you.
For the point searching I would use dsearchn for this kind of thing. You can use it with or without delaunay triangulation depending on the ratio of users to fixed sites. I tend to use it the quick and easy way, which in your case would be:
indices_of_closest_fixed_points = dsearchn(fixed_points, user_points)
As for the colors I would suggest you define a color map using something like
mymap = lines(n)
where n is the number of fixed points you have. You can then use scatter to plot the points with specific colors and sizes. Perhaps something like this to get you started:
x = user_points(1,:);
y = user_points(2,:);
S = []; % point sizes, left empty for now
C = mymap(indices_of_closest_fixed_points,:); %colors
scatter(x,y,S,C);
To find the nearest point simply compute the euclidean distance between each user point and the complete set of fixed points. Then the index of the shortest distance will also be the index of the fixed point.
dist = calc_dist(fixedPts, aSingleUserPt)
[~, idx] = min(dist);
To solve the color problem, you'll need to create a colormap from a fixed point index to a unique color. Then when you plot a user point you will set the color of the plot equal to the colormap evaluated at idx
Note the euclidean distance is very easy to calcuate:
euc_dist = sqrt( (x1 - x2)^2 + (y1 - y2)^2 );
There are functions on File Exchange that will let you compute this quickly.