package com.gebauz.bauzoid.math.collision;
import java.util.Vector;
import com.gebauz.bauzoid.game.Game;
import com.gebauz.bauzoid.game.GameObject;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.sprite.SpriteTransform;
import com.gebauz.bauzoid.math.Vector2;
/** Collection of shape elements that form a complex shape. */
public class Shape extends GameObject
{
// Constants========================================================================================
// Embedded Types===================================================================================
// Fields===========================================================================================
private Vector<BaseShapeElement
> mShapes =
new Vector<BaseShapeElement
>();
private String mShapeFile =
null;
private boolean mIsAsync =
false;
public SpriteTransform transform =
new SpriteTransform
();
private PolyElement mConvexHull =
null;
private AABoundingBox mBoundingBox =
null;
private AABoundingBox mTransformedBoundingBox =
null;
// Methods==========================================================================================
public Shape(Game game,
String shapeFile
)
{
super(game
);
mShapeFile = shapeFile
;
}
/** Clone a shape and its shape elements to new shape. */
public Shape(Shape clone
)
{
super(clone.
getGame());
for (int i =
0; i
< clone.
getShapeElementCount(); i++
)
{
mShapes.
add(clone.
getShapeElement(i
).
copy(this));
}
}
public void initAsync
()
{
mIsAsync =
true;
if (mShapeFile
!=
null)
{
getAssetManager
().
load(mShapeFile, ShapeData.
class,
new ShapeDataAsyncLoader.
ShapeDataParameter(this));
}
}
public void init
()
{
if (mShapeFile
!=
null)
{
ShapeData shapeData =
null;
if (!mIsAsync
)
{
shapeData = ShapeUtil.
createShapeFromFile(this, mShapeFile
);
}
else
{
shapeData = getAssetManager
().
get(mShapeFile, ShapeData.
class);
}
for (int i =
0; i
< shapeData.
getShapeElementCount(); i++
)
{
mShapes.
add(shapeData.
getShapeElement(i
).
copy(this));
}
}
calculateConvexHull
();
}
/** Calculate the untransformed convex hull and the axis aligned bounding box of the shape element group. */
public void calculateConvexHull
()
{
Vector<Vector2
> pointCloud =
new Vector<Vector2
>();
Vector<Vector2
> hull =
new Vector<Vector2
>();
for (int i =
0; i
< getShapeElementCount
(); i++
)
{
BaseShapeElement e = getShapeElement
(i
);
Vector2
[] pt = e.
getUntransformedPoints();
for (int j =
0; j
< pt.
length; j++
)
{
pointCloud.
add(pt
[j
]);
}
}
// find leftmost point
int leftMostIndex =
0;
for (int i =
1; i
< pointCloud.
size(); i++
)
{
if (pointCloud.
get(i
).
x < pointCloud.
get(leftMostIndex
).
x)
leftMostIndex = i
;
}
// start from leftmost point
int p = leftMostIndex
;
int q
;
do
{
// search for point q such that orientation(p, i, q) is counterclockwise for all points i
q =
(p +
1) % pointCloud.
size();
for (int i =
0; i
< pointCloud.
size(); i++
)
{
if (orientation
(pointCloud.
get(p
), pointCloud.
get(i
), pointCloud.
get(q
)) ==
2)
q = i
;
}
hull.
add(pointCloud.
get(q
).
copy());
p = q
; // set p as q for next iteration
}
while (p
!= leftMostIndex
);
mBoundingBox =
new AABoundingBox
(hull
);
mTransformedBoundingBox = mBoundingBox.
createFromTransformed(transform
);
mConvexHull =
new PolyElement
(this, hull
);
}
/** To find orientation of ordered triplet (p, q, r).
* The function returns following values
* 0 --> p, q and r are colinear
* 1 --> Clockwise
* 2 --> Counterclockwise
*/
private static int orientation
(final Vector2 p,
final Vector2 q,
final Vector2 r
)
{
final float x1 =
(q.
x - p.
x) * (r.
y - p.
y);
final float x2 =
(r.
x - p.
x) * (q.
y - p.
y);
final float val = x1 - x2
;
if (val ==
0) return 0;
return (val
> 0) ? 1 :
2;
}
/** Render debug output. */
public void renderDebug
(Graphics graphics, SpriteTransform t
)
{
for (int i =
0; i
< getShapeElementCount
(); i++
)
{
getShapeElement
(i
).
renderDebug(graphics, t
);
}
mConvexHull.
renderDebug(graphics, t
);
}
public void addElement
(BaseShapeElement shapeElement
)
{
mShapes.
add(shapeElement
);
}
// Getters/Setters==================================================================================
public final BaseShapeElement getShapeElement
(int i
)
{
return mShapes.
get(i
);
}
public final int getShapeElementCount
()
{
return mShapes.
size();
}
public final PolyElement getConvexHull
()
{
return mConvexHull
;
}
public final AABoundingBox getBoundingBox
()
{
return mBoundingBox
;
}
public final AABoundingBox getTransformedBoundingBox
()
{
return mBoundingBox.
createFromTransformed(transform
);
/*
mBoundingBox.transform(transform, mTransformedBoundingBox);
return mTransformedBoundingBox;*/
}
}