I have drawn multiple circles of varying sizes and positions to a canvas, but I need to detect collisions between them.
public void run() {
while(Run){
if(!sHold.getSurface().isValid())
continue;
c[0][cnum].r++;
canvas = sHold.lockCanvas();
canvas.drawRGB(02, 02, 150);
Paint white = new Paint();
white.setColor(Color.WHITE);
if(c[0][cnum].x != 0 && c[0][cnum].y != 0)
canvas.drawCircle(c[0][cnum].x, c[0][cnum].y, c[0][cnum].r, white);
if(cnum!=0)
for(int i=0; i<cnum; i++)
canvas.drawCircle(c[1][i].x, c[1][i].y, c[1][i].r, white);
sHold.unlockCanvasAndPost(canvas);
if(((c[0][cnum].x - c[0][cnum].r)<0)||((c[0][cnum].y-c[0][cnum].r)<0)||((c[0][cnum].y+c[0][cnum].r)>height)||((c[0][cnum].x+c[0][cnum].r>width))){
c[1][cnum].x = c[0][cnum].x;
c[1][cnum].y = c[0][cnum].y;
c[1][cnum].r = c[0][cnum].r;
broken = true;
break;
}
}
}
You shouldn't do that on render phases.
When processing the logics you should check if circles intersects as described:
v1 = center of circle1
v2 = center of circle2
intersects = v1 - v2 < circle1radius + circle2radius
This Link is pretty useful!
Circle-Circle Collisions
It's very detailed and didatic
At the bottom of that page there are another links, to even more detailed stuff!
I used the Distance Between Centers method ---
Circles
By measuring the distance between each center you can say if they are colliding.
The distance should never be more then the sum of the 2 radius.
Here's what I did:
private boolean checkDrawContains(ShapeDrawable newHole)
{
long newCenterX = newHole.getBounds().left + (newHole.getBounds().width()/2); //Get the center of my shapes
long newCenterY = newHole.getBounds().top + (newHole.getBounds().height()/2);
for(ShapeDrawable hole: mHoles) // I was storing the circles in an ArrayList
{
long centerX = hole.getBounds().left + (hole.getBounds().width()/2); //Get the center of my shapes
long centerY = hole.getBounds().top + (hole.getBounds().height()/2);
long x = centerX - newCenterX;
long y = centerY - newCenterY;
long aux = (long) ((Math.pow(Math.abs(x),2)) + (Math.pow(Math.abs(y),2))); //Pythagoras the hard way :P
long distance = (long) Math.sqrt(aux);
long sRads = (newHole.getBounds().width()/2) + (hole.getBounds().width()/2);
if(distance <= sRads ) {
return true; //Is Colliding!
}
}
return false; // Is not Colliding!
}
Related
I am using CCDrawNode to create mask type effect (not exactly mask). Everything works well but there is one problem that CCDrawNode only draws square and i want to draw it with custom texture/sprite. Is there any solution to it.
Below is my code of using CCDrawNode
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
CCLayer *layer = CCLayer::create();
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
layer->addChild(pSprite, 0);
addChild(layer);
//this is the layer that we want to "cut"
CCLayer* layer1 = CCLayerColor::create(ccc4(122, 144, 0, 255), visibleSize.width, visibleSize.height);
this->setTouchEnabled(true);
//we need to create a ccnode, which will be a stencil for ccclipingnode, draw node is a good choice for that
stencil = CCDrawNode::create();
//CCClipingNode show the intersection of stencil and theirs children
CCClippingNode *cliper = CCClippingNode::create(stencil);
cliper->setInverted(true);
cliper->addChild(layer1);
addChild(cliper);
return true;
}
void HelloWorld::ccTouchesMoved(CCSet* touches, CCEvent* event)
{
CCTouch* touch = (CCTouch*)touches->anyObject();
// get start & end location
CCPoint start = touch->getLocationInView();
CCPoint end = touch->getPreviousLocationInView();
// get corrected location
start = CCDirector::sharedDirector()->convertToGL(start);
end = CCDirector::sharedDirector()->convertToGL(end);
//stencil->drawDot(start, 25, ccc4f(0, 0, 0, 255));
stencil->drawSegment(start, end, 25, ccc4f(0, 0, 0, 255));
}
If you want to draw custom texture you should use CCRenderTexture. In order to draw something you should go smthin like this
myRenderTexture->begin();
mySpriteLoadedWithTexture->visit();
myRenderTexture->end();
Also if you want the drawn lines to be smooth you should draw it in loop so that they are placed in equal distance
float distance = ccpDistance(start, end);
for (int i = 0; i < distance; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
m_brush->setPosition(CCPoint(start.x + (difx * delta), start.y + (dify * delta)));
m_brush->visit();
}
Hope it helps
I'm trying to generate random ImageViews on a Layout without the ImageViews intersecting each other. I'm generating a random point within the screen dimensions like this:
private Point generateRandomLocation(Point dimensions) {
Random random = new Random();
// generate random x
int x = random.nextInt((dimensions.x - 0) + 1);
// generate random y
int y = random.nextInt((dimensions.y - 0) + 1);
Point location = new Point(x, y);
if(!collision(location)) {
return new Point(x, y);
} else {
return generateRandomLocation(dimensions);
}
}
The collision method contains the following method to determine wether the ImageViews collide or not. BubbleImage is a simple extension of ImageView.
private boolean collision(Point location) {
// takes 100 as inital width & height
int x_1 = location.x;
int y_1 = location.y;
int x_2;
int y_2;
boolean collided = false;
// get all bubbleimages
for (int i = 0; i < mainLayout.getChildCount(); i++) {
View childView = mainLayout.getChildAt(i);
if (childView instanceof BubbleImage) {
x_2 = (int) childView.getX();
y_2 = (int) childView.getY();
// create rectangles
Rect rect1 = new Rect(x_1, y_1, x_1 + 100, y_1 - 100);
Rect rect2 = new Rect(x_2, y_2, x_2 + 100, y_2 - 100);
collided = Rect.intersects(rect1, rect2);
}
}
return collided;
}
Anyone spotting the faulty logic here?
Edit: Rect.intersects() seems to be returning false, even when the imageviews are intersecting.
When creating new Rects rect1 & rect2, the constructor is Rect(left, top, right, bottom). E.g. Rect(10, 10, 20, 20), because android screen origin is in the top left corner.
You have created the Rects in a wrong way, as Rect(left, bottom, right, top). Try switching the 2nd and 4th parameters in the constructor calls, or increase the 4th parameter to be bigger than 2nd.
Like this:
Rect rect1 = new Rect(x_1, y_1, x_1 + 100, y_1 + 100);
I'm trying to drag a path around my canvas by re-plotting the coordinates, stored in an array of point, then re creating it. The path drags but flips horizontally and vertically, like a mirror image, over where the user clicks. I have no idea why.
private void drag(MotionEvent e) {
// TODO correct weird flip
if (clicked(e)) {
for (Point p : points) {
int modX = (int) (e.getX() + (e.getX() - p.x));
int modY = (int) (e.getY() + (e.getY() - p.y));
p.set(modX, modY);
}
updateOutline();
}
}
private void updateOutline() {
// update the outline
outline = new Path();
outline.moveTo(points.get(0).x, points.get(0).y);
for (Point coor : points)
outline.lineTo(coor.x, coor.y);
}
Any help will be appreciated, thanks
In my opinion there is a problem in these lines:
int modX = (int) (e.getX() + (e.getX() - p.x));
int modY = (int) (e.getY() + (e.getY() - p.y));
Consider two points A(1,5) and B(4,5). If user clicks in C(3,6), then point A will be translated to A'(5, 7) and point B to B'(2, 7). As you can see, points A and B will change places.
You might want to store start drag position and calculate distance and updated path position using this information.
Is it possible to draw a polygon on the mapview of OSMDroid? It should scale easy with the Mapview so I didn't want to use the canvas. Any advice?
I have my own MapOverlay (extends org.osmdroid.views.overlay.Overlay), but can't get my Polygon on it.
If your class is extending org.osmdroid.views.overlay.Overlay you have to modify the draw method so it looks somehow like in the code below:
#Override
protected void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
if (shadow) {
return;
}
if (this.mPoints.size() < 2) {
//Do nothing
return;
}
final Projection pj = mapView.getProjection();
// precompute new points to the intermediate projection.
final int size = this.mPoints.size();
while (this.mPointsPrecomputed < size) {
final Point pt = this.mPoints.get(this.mPointsPrecomputed);
pj.toMapPixelsProjected(pt.x, pt.y, pt);
this.mPointsPrecomputed++;
}
Point screenPoint0 = null; // points on screen
Point screenPoint1 = null;
Point projectedPoint0; // points from the points list
Point projectedPoint1;
// clipping rectangle in the intermediate projection, to avoid performing projection.
final Rect clipBounds = pj.fromPixelsToProjected(pj.getScreenRect());
mPath.rewind();
mPath.setFillType(Path.FillType.EVEN_ODD);
projectedPoint0 = this.mPoints.get(size - 1);
mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);
for (int i = size - 2; i >= 0; i--) {
// compute next points
projectedPoint1 = this.mPoints.get(i);
mLineBounds.union(projectedPoint1.x, projectedPoint1.y);
if (!Rect.intersects(clipBounds, mLineBounds)) {
// skip this line, move to next point
projectedPoint0 = projectedPoint1;
screenPoint0 = null;
continue;
}
// the starting point may be not calculated, because previous segment was out of clip
// bounds
if (screenPoint0 == null) {
screenPoint0 = pj.toMapPixelsTranslated(projectedPoint0, this.mTempPoint1);
mPath.moveTo(screenPoint0.x, screenPoint0.y);
}
screenPoint1 = pj.toMapPixelsTranslated(projectedPoint1, this.mTempPoint2);
// skip this point, too close to previous point
if (Math.abs(screenPoint1.x - screenPoint0.x) + Math.abs(screenPoint1.y - screenPoint0.y) <= 1) {
continue;
}
mPath.lineTo(screenPoint1.x, screenPoint1.y);
// update starting point to next position
projectedPoint0 = projectedPoint1;
screenPoint0.x = screenPoint1.x;
screenPoint0.y = screenPoint1.y;
mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);
}
mPath.close();
canvas.drawPath(mPath, this.mPaint);
}
I'm looking for a way to manage Info Windows (open, close, set content) for polygons, just like it's done for markers
I can probably listen for onClick event and put a some hidden marker there and open an InfoWindow for that marker. There is a problem finding a polygon to retrieve an InfoWindow content though.
There is a more elegant solution?
I have been working out in a solution similar to your problem.
As you said, the main problem is how to get if LatLng coordinate got from OnMapLongClickListener() is inside a polygon.
There is a popular algorithm you can use for doing this called Point-in-polygon algorithm.. This is a adaptation for Java of this algorithm.
private boolean containsInPolygon(LatLng latLng, Polygon polygon) {
boolean oddTransitions = false;
List<VerticesPolygon> verticesPolygon = polygon.getVertices();
float[] polyY, polyX;
float x = (float) (latLng.latitude);
float y = (float) (latLng.longitude);
// Create arrays for vertices coordinates
polyY = new float[verticesPolygon.size()];
polyX = new float[verticesPolygon.size()];
for (int i=0; i<verticesPolygon.size() ; i++) {
VerticesPolygon verticePolygon = verticesPolygon.get(i);
polyY[i] = (float) (verticePolygon.getVertice().getLongitude());
polyX[i] = (float) (verticePolygon.getVertice().getLatitude());
}
// Check if a virtual infinite line cross each arc of the polygon
for (int i = 0, j = verticesPolygon.size() - 1; i < verticesPolygon.size(); j = i++) {
if ((polyY[i] < y && polyY[j] >= y)
|| (polyY[j] < y && polyY[i] >= y)
&& (polyX[i] <= x || polyX[j] <= x)) {
if (polyX[i] + (y - polyY[i]) / (polyY[j] - polyY[i])
* (polyX[j] - polyX[i]) < x) {
// The line cross this arc
oddTransitions = !oddTransitions;
}
}
}
// Return odd-even number of intersecs
return oddTransitions;
}
Finally, create a CustomInfoWindowsAdapter for managing what you want to show.