This question is purely based on GestureDetector flutter.
For Example:
In Application, GestureDetector class is implemented so multitouch is supported by default, now we need to disable the multitouch so what would be the best way to do it?. Otherwise in a drawing app using GestureDetector in flutter cause multi touch issue.
So how to disable multitouch in gesture detector?
I faced the same problem but I solve it by measuring the distance between two points.
The rule of how to measure the distance between two points
// Convert a rule to the code
double distanceBetweenTwoPoints(double x1,double y1 ,double x2, double y2){
double x = x1 - x2;
x = x * x;
double y = y1 - y2;
y = y * y;
double result = x + y;
return sqrt(result);
}
First of all, declare two variables with their values
// These two variables are to save the previous points
var fingerPostionY = 0.0,fingerPostionX = 0.0;
Then inside the onPanUpdate method, I took two points to calculate the distance between them. After that, I made a comparison, if the distance was large (e.g. 50) then there are many fingers, so I ignore it otherwise it will be just one finger on the screen.
onPanUpdate: (details) {
if (fingerPostionY < 1.0){
// assigen for the first time to compare
fingerPostionY = details.globalPosition.dy;
fingerPostionX = details.globalPosition.dx;
}else{
// they use a lot of fingers
double distance = distanceBetweenTwoPoints(details.globalPosition.dx,details.globalPosition.dy,
fingerPostionX,fingerPostionY);
// the distance between two fingers must be above 50
// to disable multi touch
if(distance > 50)
return;
// update to use it in the next comparison
fingerPostionY = details.globalPosition.dy;
fingerPostionX = details.globalPosition.dx;
}
// the code of drawing
setState(() {
RenderBox renderBox = context.findRenderObject();
points.add(TouchPoints(
points: renderBox.globalToLocal(details.globalPosition),
paint: Paint()
..strokeCap = strokeType
..isAntiAlias = true
..color = activeColor.withOpacity(opacity)
..strokeWidth = strokeWidth));
});
},
IMPORTANT NOTES:
Inside onPanEnd method, you must write this line, because it
means the finger is up now
fingerPostionY = 0.0;
Still there is some performance issue not solved yet in the drawing code
EDIT:
I enhanced the performance by using path.
You can see my code on the GitHub:
free painting on flutter
Related
Openlayers provides useful functions for drawing boxes and rectangles and also has ol.geom.Geometry.prototype.rotate(angle, anchor) for rotating a geometry around a certain anchor. Is it possible to lock the rotation of a box/rectangle while modifying it?
Using the OpenLayers example located here to draw a box with a certain rotation to illustrate the point:
I would like the box/rectangle to maintain its rotation while still being able to drag the sides longer and shorter. Is there a simple way to achieve this?
Answering with the solution I came up with.
First of all, add the feature(s) to a ModifyInteraction so you are able to modify by dragging the corners of the feature.
this.modifyInteraction = new Modify({
deleteCondition: eventsCondition.never,
features: this.drawInteraction.features,
insertVertexCondition: eventsCondition.never,
});
this.map.addInteraction(this.modifyInteraction);
Also, add event handlers upon the events "modifystart" and "modifyend".
this.modifyInteraction.on("modifystart", this.modifyStartFunction);
this.modifyInteraction.on("modifyend", this.modifyEndFunction);
The functions for "modifystart" and "modifyend" look like this.
private modifyStartFunction(event) {
const features = event.features;
const feature = features.getArray()[0];
this.featureAtModifyStart = feature.clone();
this.draggedCornerAtModifyStart = "";
feature.on("change", this.changeFeatureFunction);
}
private modifyEndFunction(event) {
const features = event.features;
const feature = features.getArray()[0];
feature.un("change", this.changeFeatureFunction);
// removing and adding feature to force reindexing
// of feature's snappable edges in OpenLayers
this.drawInteraction.features.clear();
this.drawInteraction.features.push(feature);
this.dispatchRettighetModifyEvent(feature);
}
The changeFeatureFunction is below. This function is called for every single change which is done to the geometry as long as the user is still modifying/dragging one of the corners. Inside this function, I made another function to adjust the modified rectangle into a rectangle again. This "Rectanglify"-function moves the corners which are adjacent to the corner which was just moved by the user.
private changeFeatureFunction(event) {
let feature = event.target;
let geometry = feature.getGeometry();
// Removing change event temporarily to avoid infinite recursion
feature.un("change", this.changeFeatureFunction);
this.rectanglifyModifiedGeometry(geometry);
// Reenabling change event
feature.on("change", this.changeFeatureFunction);
}
Without going into too much detail, the rectanglify-function needs to
find rotation of geometry in radians
inversely rotate with radians * -1 (e.g. geometry.rotate(radians * (-1), anchor) )
update neighboring corners of the dragged corner (easier to do when we have a rectangle which is parallel to the x and y axes)
rotate back with the rotation we found in 1
--
In order to get the rotation of the rectangle, we can do this:
export function getRadiansFromRectangle(feature: Feature): number {
const coords = getCoordinates(feature);
const point1 = coords[0];
const point2 = coords[1];
const deltaY = (point2[1] as number) - (point1[1] as number);
const deltaX = (point2[0] as number) - (point1[0] as number);
return Math.atan2(deltaY, deltaX);
}
i have a question about moving a Box2D body to a specific position without using this for example.
body->SetTransform(targetVector,body->GetAngle())
I have some code which works for applyForce (here):
const float destinationControl = 0.3f;
b2Vec2 missilePosition = _physicalBody->GetPosition();
b2Vec2 diff = targetPosition - missilePosition;
float dist = diff.Length();
if (dist > 0)
{
// compute the aiming direction
b2Vec2 direction = b2Vec2(diff.x / dist, diff.y / dist);
// get the current missile velocity because we will apply a force to compensate this.
b2Vec2 currentVelocity = _physicalBody->GetLinearVelocity();
// the missile ideal velocity is the direction to the target multiplied by the max speed
b2Vec2 desireVelocity = b2Vec2(direction.x * maxSpeed, direction.y * maxSpeed);
// compensate the current missile velocity by the desired velocity, based on the control factor
b2Vec2 finalVelocity = control * (desireVelocity - currentVelocity);
// transform our velocity into an impulse (get rid of the time and mass factor)
float temp = (_physicalBody->GetMass() / normalDelta);
b2Vec2 finalForce = b2Vec2(finalVelocity.x * temp, finalVelocity.y * temp);
_physicalBody->ApplyForce(finalForce, _physicalBody->GetWorldCenter());
}
But the when the maxSpeed is to high the body move over the point to fast.
So does anyone know how to calculate a force (ApplyForce) or an impluse (ApplyLinearImpulse) to move the body to a target position (very exactly) in a specific time.
Or a solution with the code above. I mean calculate the maxSpeed to move the body in a specific time to the target position.
In my google search i found the interesting article from iforce about projected trajectory
(here). Maybe this could be help too?
Thank you in advance
I think you have it mostly correct, but you are not checking to see if the body will overshoot the target in the next time step. Here is what works for me:
b2Vec2 targetPosition = ...;
float targetSpeed = ...;
b2Vec2 direction = targetPosition - body->GetPosition();
float distanceToTravel = direction.Normalize();
// For most of the movement, the target speed is ok
float speedToUse = targetSpeed;
// Check if this speed will cause overshoot in the next time step.
// If so, we need to scale the speed down to just enough to reach
// the target point. (Assuming here a step length based on 60 fps)
float distancePerTimestep = speedToUse / 60.0f;
if ( distancePerTimestep > distanceToTravel )
speedToUse *= ( distanceToTravel / distancePerTimestep );
// The rest is pretty much what you had already:
b2Vec2 desiredVelocity = speedToUse * direction;
b2Vec2 changeInVelocity = desiredVelocity - body->GetLinearVelocity();
b2Vec2 force = body->GetMass() * 60.0f * changeInVelocity;
body->ApplyForce( force, body->GetWorldCenter(), true );
There is a way for single-time applied force to move by given distance (previous answer suggests that you can correct error in calculation by additional force in future frames):
public static void applyForceToMoveBy(float byX, float byY, Body body) {
force.set(byX, byY);
force.sub(body.getLinearVelocity());
float mass = body.getMass();
force.scl(mass * 30.45f);
body.applyForceToCenter(force, true);
}
Known limitations:
1) LinearVelocity effect was not tested;
2) calculation was tested with body linear damping = 0.5f. Appreciate, if somebody know how to add it into formula;
3) magic number 30.45f - maybe this could be fixed by point 2 or by world frame delta.
I am using AchartEngine library to plot the measurements from a sensor. The values are in the order of 1E-6.
When I try to plot the values they are shown correctly but as I zoom the plot, the maximum resolution I can see in the x Labels is in the order of 1E-4. I am using following code to change the number of labels:
mRenderer.setXLabels(20);
mRenderer.setYLabels(20);
I am also changing the range of the y axis, but the resolution remains unchanged. Has anyone found this problem before?
EDIT
I do not have enough reputation to post images, but the following link shows the chartview that I am getting.
https://dl.dropboxusercontent.com/u/49921111/measurement1.png
What I want is to have more grid lines between 3.0E-5 and 4.0E-5. Unfortunately I have not found how to do that. I also tried changing the renderer pan, initial range of the plot and zoom limits. all without sucess. I was thinking the only option left would be to override some of the draw methods but I have no clue how to do that.
I Have digged into the source code of AChartEngine and found the problem that it has when small numbers are to be plotted. It is in a static function used to draw labels by every chart:
private static double[] computeLabels(final double start, final double end,
final int approxNumLabels) {
// The problem is right here in this condition.
if (Math.abs(start - end) < 0.000001f) {
return new double[] { start, start, 0 };
}
double s = start;
double e = end;
boolean switched = false;
if (s > e) {
switched = true;
double tmp = s;
s = e;
e = tmp;
}
double xStep = roundUp(Math.abs(s - e) / approxNumLabels);
// Compute x starting point so it is a multiple of xStep.
double xStart = xStep * Math.ceil(s / xStep);
double xEnd = xStep * Math.floor(e / xStep);
if (switched) {
return new double[] { xEnd, xStart, -1.0 * xStep };
}
return new double[] { xStart, xEnd, xStep };
}
So this function basically takes the start (minimum) and and end (maximum) values of the plot and the aproximate number of labels. Then it rounds the values and computes the step of the grid (xStep). If the difference between start and end is too small (0.000001f) then the start and end are the same and the step is 0. That is why its not showing any labels in between this small values nor any grid lines!. So I just need to change the 0.000001f with a smaller number or with a variable in order to control the resolution of the grid. I hope this can help someone.
I'm making an app that (among other things) displays a simplified compass image that rotates according to the device's rotation. The problem is that simply doing this:
float heading = -1.0f * M_PI * trueHeading / 180.0f; //trueHeading is always between 0 and 359, never 360
self.compassNeedle.transform = CGAffineTransformMakeRotation(heading);
inside CLLocationManager's didUpdateHeading method makes the animation ugly and choppy.
I have already used Instruments to find out whether its simply my app not being able to render at more than 30-48 fps, but that's not the case.
How can I smooth out the image view's rotation so that it's more like Apple's own Compass app?
Instead of using the current instant value, try using the average of the last N values for the true heading. The value may be jumping around a lot in a single instant but settle down "in the average".
Assuming you have a member variable storedReadings which is an NSMutableArray:
-(void)addReading(float):newReading
{
[storedReadings addObject:[NSNumber numberWithFloat:newReading]];
while([storedReadings count] > MAX_READINGS)
{
[storedReadings removeObjectAtIndex:0];
}
}
then when you need the average value (timer update?)
-(float)calcReading
{
float result = 0.0f;
if([storedReadings count] > 0)
{
foreach(NSNumber* reading in storedReadings)
{
result += [reading floatValue];
}
result /= [storedReadings count];
}
return result;
}
You get to pick MAX_READINGS a priori.
NEXT LEVEL(S) UP
If the readings are not jumping around so much but the animation is still choppy, you probably need to do something like a "smooth" rotation. At any given time, you have the current angle you are displaying, theta (store this in your class, start it out at 0). You also have your target angle, call it target. This is the value you get from the smoothed calcReading function. The error is defined as the difference between the two:
error = target-theta;
Set up a timer callback with a period of something like 0.05 seconds (20x per second). What you want to do is adjust theta so that the error is driven towards 0. You can do this in a couple of ways:
thetaNext += kProp * (target - theta); //This is proportional feedback.
thetaNext += kStep * sign(target-theta); // This moves theta a fixed amount each update. sign(x) = +1 if x >= 0 and -1 if x < 0.
The first solution will cause the rotation to change sharply the further it is from the target. It will also probably oscillate a little bit as it swings past the "zero" point. Bigger values of kProp will yield faster response but also more oscillation. Some tuning will be required.
The second solution will be much easier to control...it just "ticks" the compass needle around each time. You can set kStep to something like 1/4 degree, which gives you a "speed" of rotation of about (1/4 deg/update) * (20 updates/seconds) = 5 degrees per second. This is a bit slow, but you can see the math and change kStep to suit your needs. Note that you may to "band" the "error" value so that no action is taken if the error < kStep (or something like that). This prevents your compass from shifting when the angle is really close to the target. You can change kStep when the error is small so that it "slides" into the ending position (i.e. kStep is smaller when the error is small).
For dealing with Angle Issues (wrap around), I "normalize" the angle so it is always within -Pi/Pi. I don't guarantee this is the perfect way to do it, but it seems to get the job done:
// Takes an angle greater than +/- M_PI and converts it back
// to +/- M_PI. Useful in Box2D where angles continuously
// increase/decrease.
static inline float32 AdjustAngle(float32 angleRads)
{
if(angleRads > M_PI)
{
while(angleRads > M_PI)
{
angleRads -= 2*M_PI;
}
}
else if(angleRads < -M_PI)
{
while(angleRads < -M_PI)
{
angleRads += 2*M_PI;
}
}
return angleRads;
}
By doing it this way, -pi is the angle you reach from going in either direction as you continue to rotate left/right. That is to say, there is not a discontinuity in the number going from say 0 to 359 degrees.
SO PUTTING THIS ALL TOGETHER
static inline float Sign(float value)
{
if(value >= 0)
return 1.0f;
return -1.0f;
}
//#define ROTATION_OPTION_1
//#define ROTATION_OPTION_2
#define ROTATION_OPTION_3
-(void)updateArrow
{
// Calculate the angle to the player
CGPoint toPlayer = ccpSub(self.player.position,self.arrow.position);
// Calculate the angle of this...Note there are some inversions
// and the actual image is rotated 90 degrees so I had to offset it
// a bit.
float angleToPlayerRads = -atan2f(toPlayer.y, toPlayer.x);
angleToPlayerRads = AdjustAngle(angleToPlayerRads);
// This is the angle we "wish" the arrow would be pointing.
float targetAngle = CC_RADIANS_TO_DEGREES(angleToPlayerRads)+90;
float errorAngle = targetAngle-self.arrow.rotation;
CCLOG(#"Error Angle = %f",errorAngle);
#ifdef ROTATION_OPTION_1
// In this option, we just set the angle of the rotated sprite directly.
self.arrow.rotation = CC_RADIANS_TO_DEGREES(angleToPlayerRads)+90;
#endif
#ifdef ROTATION_OPTION_2
// In this option, we apply proportional feedback to the angle
// difference.
const float kProp = 0.05f;
self.arrow.rotation += kProp * (errorAngle);
#endif
#ifdef ROTATION_OPTION_3
// The step to take each update in degrees.
const float kStep = 4.0f;
// NOTE: Without the "if(fabs(...)) check, the angle
// can "dither" around the zero point when it is very close.
if(fabs(errorAngle) > kStep)
{
self.arrow.rotation += Sign(errorAngle)*kStep;
}
#endif
}
I put this code into a demo program I had written for Cocos2d. It shows a character (big box) being chased by some monsters (smaller boxes) and has an arrow in the center that always points towards the character. The updateArrow call is made on a timer tick (the update(dt) function) regularly. The player's position on the screen is set by the user tapping on the screen and the angle is based on the vector from the arrow to the player. In the function, I show all three options for setting the angle of the arrow:
Option 1
Just set it based on where the player is (i.e. just set it).
Option 2
Use proportional feedback to adjust the arrow's angle each time step.
Option 3
Step the angle of the arrow each timestep a little bit if the error angle is more than the step size.
Here is a picture showing roughly what it looks like:
And, all the code is available here on github. Just look in the HelloWorldLayer.m file.
Was this helpful?
I am making an app in which I want to have some thing happen If an image moves over another point. such as
first I have an image moving horizontally across the screen,'
self.ball.center = CGPointMake(self.ball.center.x + self.gravity.x / 8.0 * 200.0, 9);
then when it gets to a certain place another image moves down from that spot.
CGPoint a = CGPointMake(9, 9);
if (CGPointEqualToPoint(ball.center,a)) {
balla.hidden = NO;
self.balla.center = CGPointMake(self.balla.center.x , (self.balla.center.y)- (self.gravity.y / 8.0 * 200.0));
}
the first time it works ok but when I put in the next statement to move another image down from another spot nothing happens.
CGPoint b = CGPointMake(86, 9);
if (CGPointEqualToPoint(ball.center,b)) {
ball2a.hidden = NO;
self.ball2a.center = CGPointMake(self.ball2a.center.x , (self.ball2a.center.y)- (self.gravity.y / 8.0 * 200.0));}
Any ideas as to why this isn't working
If you're moving the ball by adding some floating-point value offset, you might be "skipping over" the point b - you may never hit b, but rather appear slightly before it and then slightly after it.
Rather than testing if you're "equal" to the point, you could be better off comparing the distance between the ball and the point and seeing if it is inside some small radius. A simple euclidean distance could work.
CGFloat euclid_dist(CGPoint a, CGPoint b)
{
return sqrt((b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y));
}
You could then use this to see if you've "hit" the point:
if (euclid_dist(ball.center, b) < 0.1)
{
// React appropriately
}
In general it's problematic to test for equality between floating point numbers.