Anyways, I have been following this tutorial http://www.thinkandbuild.it/how-to-build-a-custom-control-in-ios/ in order to make a stop watch using this custom control. (I am not a total beginner, about 4 months in iOS, still new but I understand things.)
However, when I change the CGContextAddArc start angle from 0 to M_PI/2 to look like a clock and initialize the angle to self.angle = 0, it does not start at M_PI/2 but it creates an arc of length M_PI/2. So if you can picture that, imagine the 12 on a clock to the 3 on a clock is the arc length yet I want it to be so when I initialize it to self.angle = 0, it would only show M_PI/2 because that would be the original angle.
Related
I have a problem I just cannot solve, and after a week it's really winding me up.
Background.
I'm placing items onto a circle using basic trig. The number of items can change dynamically, and they are spaced around the circle equally.
The items rotate around the circle, and the speed of rotation changes to be in sync with a BPM (Beats Per Minute) clock. This clock can change at any time.
The problem I'm having is that the items seem to be placed randomly on the circle, not equally spaced in order (see image 1). They'll appear out of order even though it's a basic for loop that places them. I think they may in face be in order, but the rotation values may be off making them look like they are in an odd order.
The second issue is that when the number of items reduces, the speed of rotation increases (it shouldn't) and if the number increases, the speed slows.
So I expect an issue with my trig function. I'm showing the complete code here but can simplify if it'll help.
What have I tried?
I've tried simplified versions without the graphical output, and the numbers all seem to make perfect sense. The radians between items is correct, the placement looks correct. It all looks correct, but it isn't.
The code.
--the variables
orbitalCircle.xPos = x or 0
orbitalCircle.yPos = y or 0
orbitalCircle.circleDiameter = diameter or 10
orbitalCircle.numberOfNotes = number_of_notes
orbitalCircle.spaceBetweenNotes = (360 / number_of_notes)
orbitalCircle.beatsPerSecond = (beats_per_minute / 60)
orbitalCircle.currentRotation = 0
orbitalCircle.framesPerSecond = frames_per_second or 15
orbitalCircle.framesPerFullRotation = (orbitalCircle.numberOfNotes/orbitalCircle.beatsPerSecond)+orbitalCircle.framesPerSecond
orbitalCircle.degreesPerFrame = 360 / orbitalCircle.framesPerFullRotation
orbitalCircle.newRotationValue = orbitalCircle.currentRotation + orbitalCircle.degreesPerFrame
orbitalCircle.sequenceData = sequence_data
--the function that updates the sequence data and therefore the number of items on the circle
function orbitalCircle.updateNotes(sq)
orbitalCircle.sequenceData = sq
orbitalCircle.numberOfNotes = (#sq)
orbitalCircle.spaceBetweenNotes = (360 / orbitalCircle.numberOfNotes)
end
--the function that calculates the new rotation value of the item to be placed on the circle
function orbitalCircle.tick()
orbitalCircle.spaceBetweenNotes = (360 / number_of_notes)
orbitalCircle.framesPerFullRotation = (orbitalCircle.numberOfNotes/orbitalCircle.beatsPerSecond)*orbitalCircle.framesPerSecond
orbitalCircle.degreesPerFrame = (360 / orbitalCircle.framesPerFullRotation)
orbitalCircle.newRotationValue = (orbitalCircle.currentRotation + orbitalCircle.degreesPerFrame)
if orbitalCircle.newRotationValue > 360 then
orbitalCircle.currentRotation = 0
else
orbitalCircle.currentRotation = orbitalCircle.newRotationValue
end
end
--finally the function that places the items onto the circle
function orbitalCircle.redraw()
screen.circle(orbitalCircle.xPos, orbitalCircle.yPos, orbitalCircle.circleDiameter)
screen.stroke()
for i=1, (#orbitalCircle.sequenceData) do
if orbitalCircle.sequenceData[i] > 0 then
screen.circle(
math.cos(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.xPos,
math.sin(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.yPos,
map(orbitalCircle.sequenceData[i], 5, 128, 0.5, 4)
)
end
end
end
end
I'd expect that the items would be:
equally spaced no matter the amount (that works)
in order (they appear not to be)
the speed of rotation should remain fixed unless the BPM changes (this doesn't happen)
I'm lost!
Let us take a closer look at the drawing.
screen.circle(
math.cos(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.xPos,
math.sin(math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i))*orbitalCircle.circleDiameter + orbitalCircle.yPos,
map(orbitalCircle.sequenceData[i], 5, 128, 0.5, 4)
)
What is the angle that is being drawn here? It is the argument to math.cos and math.sin (I will ignore the scaling and the translation that is applied afterwards):
math.rad(orbitalCircle.newRotationValue)+(orbitalCircle.spaceBetweenNotes*i)
So... it is the neRotationValue converted to radians and added to that the space between notes. This one is defined as 360 / number_of_notes, so it is in degrees. Adding a radians and degrees most likely does not produce the expected result.
So, what exactly do you mean with the following?
I've tried simplified versions without the graphical output, and the numbers all seem to make perfect sense.
My code for physics in my game is this:
-- dt = time after each update
self.x = math.floor(self.x + math.sin(self.angle)*self.speed*dt)
self.y = math.floor(self.y - math.cos(self.angle)*self.speed*dt)
-- addVector(speed,angle,speed2,angle2)
self.speed,self.angle = addVector(self.speed,self.angle,g,math.pi)`
when it hits the ground, the code for it to bounce is :
self.angle = math.pi - self.angle
self.y = other.y - self.r`
the function addVector is defined here:
x = math.sin(angle)*speed + math.sin(angle2)*speed2
y = math.cos(angle)*speed + math.cos(angle2)*speed2
v = math.sqrt(x^2 + y^2)
a = math.pi/2 - math.atan(y,x)
return v,a
but when I place a single ball in the simulation without any drag or elasticity, the height of the ball after each bounce keeps getting higher. Any idea what may be causing the problem?
Edit: self.r is the radius, self.x and self.y are the position of the centre of the ball.
Your Y axis is increasing downward and decreasing upward.
Making self.y = math.floor(..) moves your ball a bit upward every frame.
The solution is to store your coordinates with maximal precision.
You could make new variable y_for_drawing = math.floor(y) to draw the ball at pixel with integer coordinates, but your main y value must have fractional part.
I’ve managed to get your code to run and reproduce the behavior you are seeing. I also find it difficult to figure out the issue. Here’s why: movement physics involves position, which is affected by a velocity vector, which in turn is affected by an acceleration vector. In your code these are all there, but are in no way clearly separated. There are trig functions and floor functions all interacting in a way that makes it difficult to see what role they are playing in the final position calculation.
By far the best and easiest-to-understand tutorial to help you implement basic physics lime this is The Nature of Code (free to read online, with interactive examples). As an exercise I ported most of the early exercises into Lua. I would suggest you see how he clearly separates the position, velocity and acceleration calculations.
As an experiemnt, increase g to a much higher number. When I did that, I noticed the ball would eventually settle to the ground, but of course the bouces were too fast and it didnt bounce in a way that seems natural.
Also, define other.y - it doesnt seem to affect the bouncing issue, but just to be clear on what that is.
The picture shows a simple UIView after applying the following transform:
- (CATransform3D) transformForOpenedMenu
{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0 /450;
transform = CATransform3DRotate(transform, D2R(40), 0, 1, 0);
transform = CATransform3DTranslate(transform, 210, 150, -500);
return transform;
}
I'm trying to make the distances highlighted with black to have equal length. Could you please help me understand the logic behind the values and calculations?
Cheers
UPD Sept 13
Looks like removing 3DTranslate keeps distances equal. I see I can use layer's frame property to reposition rotated view to the bottom left of the screen. Not yet sure, but this might actually work.
The .m34 value you are setting is best set on the sublayerTransform of the containing view rather than the view you are transforming.
I don't fully understand the maths behind affine transforms so I made this project which allows me to play around with the transform values to achieve the effect I want. You can plug in the values from your code above and see what it looks like, though note that there is already a perspective value applied using the sublayerTransform property mentioned above.
For your specific case, I think you want to adjust the anchor point of the layer to (0.0,0.5) and apply the rotation transform only. This assumes you want the menu to swing back like a door, with the hinges on the left edge.
The problem you're seeing is caused by your CATransform3DTranslate call. You're essentially setting the Y Axis off center, and hence seeing a different perspective view of the frame.
Think of it this way;
You're standing in the center of a long narrow field stretching off into the horizon. The edge of the field appears as if it is converges to a center point somewhere off in the distance. The angle of each edge to the converging point will appear equal if you are at the center of the field. If, on the other hand, you move either to the left or the right, the angles change and one will seem greater than the other (inversely opposite of course).
This is essentially what is happening with your view; As your converging points are to the right, changing the Y axis away from 0 will have the same effect as moving to the left or right in my example above. You're no longer looking at the parallel lines from the center.
so in your code above Setting the ty in CATransform3DTranslate to 0 Should fix your problem I.E.
transform = CATransform3DTranslate(transform, 210, 0, -500);
You may also need to alter the tz and tx Value to make it fit.
OK, so what eventually solved my question is this:
3D transform on Y axis to swing the view like a door transform = CATransform3DRotate(transform, D2R(40), 0, 1, 0);
set Z anchor point on a layer, to move it back targetView.layer.anchorPointZ = 850;
adjust layer position so that the view is located slightly to the bottom left of the parent view:
newPosition.x += 135 * positionDirection;
newPosition.y += 70 * positionDirection;
This sequence adjusts position without CATransform3DTranslate and keeps the 'swinged' effect not distorted.
Thanks everybody!
I have a problem to use this bulge arc (dxf parser) function in C++ getArcDataFromBulge().
https://github.com/Embroidermodder/Embroidermodder/blob/master/libembroidery/geom-arc.c
I have my drawArc() function which need 'start angle' and 'sweep angle' parameters from this getArcDataFromBulge() function.
My drawArc() function use OpenGL 2D coordinate system with right side zero angle position and when I get values from getArcDataFromBulge() and recalculate it (0+-, 180+-, 360+-) I have something like unexpected opposite angles as results. It looks like clockwise-counterclockwise problem, but I'm think is not, I'm not sure. Do you have some idea what is going on?
For example:
tempBulge.bulge := 0.70;
arcMidAngle := RadToDeg( atan2(tempBulge.arcMidY - tempBulge.arcCenterY,
tempBulge.arcCenterX - tempBulge.arcMidX) );
After calculaton: arcMidAngle = 179.999
When I add and subtract from this point half of arc chord angle, I get start and end angles of my arc: 90°, 270° but it's not the same arc when I open dxf with some CAD software, it is opposite than origin drawing.
If you have an arc from 0° to 90°, it could be a 1/4 circle or a 3/4 circle.
You need to parse the $ANGDIR and $ANGBASE variables from the HEADER section which tells you in which direction angles are defined ($ANGDIR) and where the 0° angle starts ($ANGBASE) within that specific DXF file:
Variable Group code Description
$ANGBASE 50 Angle 0 direction
$ANGDIR 70 1 = Clockwise angles, 0 = Counterclockwise
For DXF, if $ANGBASE = 0, then 0° is on the right of the center, alike Windows.
Furthermore, in DXF, the positive Y-axis is upwards, in contrast to many Windows API's where the positive Y-axis is downwards.
I'm new to Corona and looking for a little help manipulating moving objects:
Basically I want a set up where when I can click on a moving object, a dialog box will pop up giving me the option to change the speed of the object and the vector of travel. I'm pretty sure I can figure out the event handling and the dialog but I'm stuck on simply changing the direction of travel to the new vector
in a simple example, I have a rect moving up the screen as follows:
obj1 = display.newRect(500, 800, 10, 40)
transition.to(obj1,{x=500, y = 100, time = 40000})
I know I can change the speed by adjusting the time, but if I use
obj1:rotate(30)
to turn the object 30 degrees, how do I make it travel in the new direction?
Should I be using physics - linear impulse for example, instead of transitions?
Apologies if this is a stupid question but I have searched without success for a solution.
This sounds like what you are trying to do. You would have to modify bits to fit your code but this is a working example. So if you copy it to a new main.lua file and run it you can see how it works. (Click to rotate obj).
local obj = display.newRect(50,50, 10, 40)
local SPEED = 1
local function move(event)
obj.x = obj.x + math.cos(math.rad(obj.rotation)) * SPEED
obj.y = obj.y + math.sin(math.rad(obj.rotation)) * SPEED
end
local function rotate(event)
obj.rotation = obj.rotation + 45
end
Runtime:addEventListener("enterFrame", move)
Runtime:addEventListener("tap", rotate)
Basically I used the "enterFrame" event to 'move' the rectangle, by recalculating the x and y of the objects location using its rotation (which is easy enough to modify) every frame.