This is a bit of a long-shot. I really don't know where to ask this question.
I've been trying out CodeConnection + MakeCode with Minecraft and I haven't been able to figure out if there is correct way to place half-slabs at 0.5 step y axes increments.
I tried using a line between 2 points, but it left gaps between each slab.
If I try moving up 0.5, then it rounds it up to 1, and again leaves gaps.
It appears that all of the builder functions seem operate at a resolution of 1 block. However in-game I can obviously place slabs in 0.5 block increments to make stairs etc.
Blocks only exist at integer coordinates. Half slabs that exist in the top half of their space are still at a full integer coordinate. They just have a BlockState value of bottom=top (or top_slot_bit=true on Bedrock, represented by the integer value 8 as a bitflag, eg: 0b1... where the . bits are the integer representation of what type of slab (wood, stone, quartz...)).
What you're looking for is this widget, under Blocks:
You can set the block and then an integer representation of the desired data value (see the wiki on data values) in the numerical slot. This widget can then be dragged into the (block) portion of any block widget:
You'll probably have to some variable fiddling to get the data value to swap back and forth as you need it to, but that should solve the hurdle you've been facing.
I'm working in 2D.
My user can draw some lines & line-segments, which I store in a custom object class, but basically in startX-Y & endX-Y.
Now I want to find, actually only the polygon where the ball is inside, but after reading and researching about some algoirthms etc. I think I have to find all polygons and serach after that the right one.
Is there anyone with some example code, c#, java objective-c !?
I tried several times with some pseudo-code explanations, I don't get it.
Overview
There are a number of different interesting questions at play here:
1. Given you have a set of lines on the screen, and the user places their finger from an arbitrary point and drags it to an arbitrary end point, we need to form a new line which does not cross over lines and where the start and end point actually lie on existing lines or on borders.
2. The next question is how do we maintain an active set of "relevant" line segments which form the convex hull which the ball resides in.
3. Finally given we have an active set of line segments how do we find the area of this shape.
Now It seems you've already answered part 1. So we focus on parts 2 and 3.
For part 2, we will also be interested in asking:
4. If we have a convex hull and a point, how do we determine if that point is in the hull.
We refer to here for the solution to 4 Find if a point is inside a convex hull for a set of points without computing the hull itself
The full implementation can be done efficiently if you are careful with the data structures you are using. This is left as a simple exercise. Let me know if I have done something incorrect here or you do not understand something. I look forward to playing your game when its ready!
Solution to Part 3
In fact 3 is easy from 2, since if we know the active set of line segments containing the ball (this is a list of pairs of tuples ((x_1start,y_1start), (x_1end, y1_end))), there are two ways to compute the area. The first is to do a straightforward algorithm to compute the area of the convex hull formed by all start and end points in this list of tuples. Look up more sophisticated algorithms for area, but if you cannot find one, note that the hull with n sides has n-2 non-overlapping triangles, and the area of triangles is easy to compute (http://www.mathopenref.com/polygontriangles.html). Note:
area = abs((x1-x2)*(y1-y3)-(y1-y2)*(x1-x3)) for triangle (x1,y1)(x2,y2)(x3,y3)
Now if you sort all (x,y) points by their angle about the positive x axis, then we simply fix the first point, and consecutively walk through the remaining pairs and find the areas of those triangles. Left as an easy exercise why this sorting step is required (hint: draw a picture).
Solution to Part 2
Now the tough part is 2. Given that we have an active set of line segments enclosing the ball, how do we add a new line, and then adjust the size and number of line segments inside our active set. Note that at the beginning of the game there are precisely 4 lines in the active set which are the borders of the screen (this will be our base case if you like induction).
Now suppose we have an arbitrary active set containing the ball, and the user adds a new line, we assume it hits exactly two existing line segments and does not cross any line segments (by part 1 algorithm). Now we need to modify the active set. By algorithm 1, we know which line segments are hit by this point. So the only way that the active set can change is if both line segments hit by this point are in the active set (draw a picture to see this fact).
Now assume that the new line segment hits two lines inside the active set (this means it essentially splits the active set into two convex hulls). If we maintain our active set in a rotated order (that is to say we ensure that it is always sorted by angle about the positive x axis), we simply need to add our new points in a way that maintains this sorted ordering. So for instance suppose our points of the active set (collapsing line segments to single lines) are:
[(x1, y1), (x2, y2), (x3, y3), ..., (xn, yn), (x1, y1)]
And we want to add the new line segment ((x', y'), (x'', y'')), and our new set looks like:
[(x1, y1), (x2, y2), (x', y'), (x3, y3), ..., (xn, yn), (x'', y''), (x1, y1)]
Then there are now two convex hulls that are formed:
1. [(x1, y1), (x2, y2), (x', y'), (x'', y''), (x1, y1)]
2. [(x', y'), (x3, y3), ..., (xn, yn), (x'', y'')]
So the only remaining question is which is our new active set. Simply use algorithm 4.
Data Structures for Part 2
First we need the classes line segment and point (im avoiding implementing things like equals, hashcode for simplicity):
class Point {
public int x;
public int y;
}
class LineSegment {
public Point lineStart;
public Point lineEnd;
}
Now we can represent our active set datastructure:
class ActiveSet {
public List<Line> thesortedlist;
}
Now we first initialize our active set with four lines and denote the center of the screen as (0,0):
LineSegment TopBorder = new LineSegment(new Point(10, 10), new Point(-10, 10));
LineSegment LftBorder = new LineSegment(new Point(-10, 10), new Point(-10, -10));
LineSegment BtmBorder = new LineSegment(new Point(-10, -10), new Point(10, -10));
LineSegment RightBorder = new LineSegment(new Point(10, -10), new Point(10, 10));
ActiveSet activeset = new ActiveSet();
activeSet.theActiveLines.add(TopBorder);
activeSet.theActiveLines.add(LftBorder);
activeSet.theActiveLines.add(BtmBorder);
activeSet.theActiveLines.add(RightBorder);
Now say the user adds a line from point (0, 10) to (10, 0), so this is a diagonal (call it newSegment) and the new active set will look like:
------
- -
- -
- -
- -
- -
- B -
- -
-----------
Note the cut in the upper right corner, and B denotes the ball. Now by algorithm 1 we know that lines TopBorder and RightBorder are hit. Now both of these are inside the activeset (we can test membership faster by using a hashmap). Now we need to form two activesets as follows:
ActiveSet activesetLeft = new ActiveSet();
ActiveSet activesetRight = new ActiveSet();
Now in order to build these sets proceed as follows:
List<LineSegment> leftsegments = activeset.GetSegmentsBetween(TopBorder,
RightBorder);
List<RightSegment> rightsegments = activeset.GetSegmentsBetween(RightBorder,
TopBorder);
This function GetSegmentsBetween(LineSegment firstline, LineSegment secondline) should just locate firstline in the list and then return all elements until it finds secondline (this may need to do two passes through the list). It should not include these firstline or secondline in its return value. Now suppose we have activesetLeft and activesetright, we need to do the following:
activesetLeft.append(new Line(secondLine.lineStart, newSegment.lineStart));
activesetLeft.append(newSegment);
activesetLeft.append(new Line(newSegment.lineEnd, firstLine.lineEnd));
activesetRight.append(new Line(firstLine.lineStart, newSegment.lineEnd));
activesetRight.append(new Line(newSegment.lineEnd, newSegment.lineStart));
activesetRight.append(new Line(newSegment.lineStart, secondLine.lineEnd));
It is really hard to understand in code, but the order of everything above is important, sicne we want to maintain sorted going in counterclockwise order.
It is left as an exercise how you can speed this up (in fact you dont need to build two active sets, just first figure out if the ball is above or below the new segment and build the left or right activeset accordingly).
I'm trying to build a MKPolygon using the outer boundary of a set of coordinates.
From what I can tell, there is no delivered functionality to achieve this in Xcode (the MKPolygon methods would use all points to build the polygon, including interior points).
After some research I've found that a convex-hull solves this problem.
After looking into various algorithms, the one I can best wrap my head around to implement is QuickHull.
This takes the outer lat coords and draws a line between the two. From there, you split your points based on that line into two subsets and process distance between the outer lats to start building triangles and eliminating points within until you are left with the outer boundary.
I can find the outer points just by looking at min/max lat and can draw a line between the two (MKPolyline) - but how would I determine whether a point falls on one side or the other of this MKPolyline?
A follow up question is whether there is a hit test to determine whether points fall within an MKPolygon.
Thanks!
I ended up using a variation of the gift wrap algorithm. Certainly not a trivial task.
Having trouble with formatting of the full code so I'll have to just put my steps (probably better because I have some clean up to do!)
I started with an array of MKPointAnnotations
1) I got the lowest point that is furthest left. To do this, I looped through all of the points and compared lat/lng to get lowest point. This point will definitely be in the convex hull, so add it to a NSMutableArray that will store our convex hull points (cvp)
2) Get all points to the left of the lowest point and loop through them, calculating the angle of the cvp to the remaining points on the left. Whichever has the greatest angle, will be the point you need to add to the array.
atan(cos(lat1)sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1), sin(lon2-lon1)*cos(lat2))
For each point found, create a triangle (by using lat from new point and long from previous point) and create a polygon. I used this code to do a hit test on my polygon:
BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO);
If anything was found in the hit test, remove it from the comparison array (all those on the left of the original array minus the hull points)
Once you have at least 3 points in your cvp array, build another polygon with all of the cvp's in the array and remove anything within using the hit test.
3) Once you've worked through all of the left points, create a new comparison array of the remaining points that haven't been eliminated or added to the hull
4) Use the same calculations and polygon tests to remove points and add the cvp's found
At the end, you're left with a list of points in that make up your convex hull.
The path I'm using has no curves; just a series of connected points.
The method I'm currently using involves iterating through the NZBezierPathElement components of the path and getting each point, but this is clumsy - especially because I have to save the last point to get each new distance. If any of you know of a better method, that would be very much appreciated.
Your algorithm sounds exactly right - the length of the path is the sum of the lengths between each pair of points. It's hard to see why you think this is "clumsy", so here is the algorithm in pseudo code just in case:
startPoint <- point[1]
length <- 0
repeat with n <- 2 to number of points
nextPoint <- point[n]
length <- length + distanceBetween(startPoint, nextPoint)
startPoint <- nextPoint // hardly clumsy
end repeat
Maybe you're doing it differently?
The notion of current point is fundamental to NSBezierPath (and SVG, turtle graphics, etc.), with its relative commands (e.g. move relative, line relative) - there is no escaping it!
I have a projectile that I would like to pass through specific coordinates at the apex of its path. I have been using a superb equation that giogadi outlined here, by plugging in the velocity values it produces into chipmunk's cpBodyApplyImpulse function.
The equation has one drawback that I haven't been able to figure out. It only works when the coordinates that I want to hit have a y value higher than the cannon (where my projectile starts). This means that I can't shoot at a downward angle.
Can anybody help me find a suitable equation that works no matter where the target is in relation to the cannon?
As pointed out above, there isn't any way to make the apex be lower than the height of the cannon (without making gravity work backwards). However, it is possible to make the projectile pass through a point below the cannon; the equations are all here. The equation you need to solve is:
angle = arctan((v^2 [+-]sqrt(v^4 - g*(x^2+2*y*v^2)))/g*x)
where you choose a velocity and plug in the x and y positions of the target - assuming the cannon is at (0,0). The [+-] thing means that you can choose either root. If the argument to the square root function is negative (an imaginary root) you need a larger velocity. So, if you are "in range" you have two possible angles for any particular velocity (other than in the maximum range 45 degree case where the two roots should give the same answer).
I suspect one trajectory will tend to 'look' much more sensible than the other, but that's something to play around with once you have something working. You may want to stick with the apex grazing code for the cases where the target is above the cannon.