textView getting null exception in customView - java
this is page-curl view , i want when nextView() is called my TextView get the next string
but I can't use TextView from xml layout it gives me null ,
how I can but buttons and TextView in customView ?
can any one help me to solve this with code ?
I have searched with many tutorials but I get this understanding
activity class :
public class StandaloneExample extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.standalone_example);
}
#Override
public void onDestroy(){
super.onDestroy();
System.gc();
finish();
}
/**
* Set the current orientation to landscape. This will prevent the OS from changing
* the app's orientation.
*/
public void lockOrientationLandscape() {
lockOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
/**
* Set the current orientation to portrait. This will prevent the OS from changing
* the app's orientation.
*/
public void lockOrientationPortrait() {
lockOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public void lockOrientation( int orientation ) {
setRequestedOrientation(orientation);
}
}
pageCurlView :
public class PageCurlView extends View {
private class Vector2D {
public float x, y;
public Vector2D(float x, float y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "(" + this.x + "," + this.y + ")";
}
public float length() {
return (float) Math.sqrt(x * x + y * y);
}
public float lengthSquared() {
return (x * x) + (y * y);
}
public boolean equals(Object o) {
if (o instanceof Vector2D) {
Vector2D p = (Vector2D) o;
return p.x == x && p.y == y;
}
return false;
}
public Vector2D reverse() {
return new Vector2D(-x, -y);
}
public Vector2D sum(Vector2D b) {
return new Vector2D(x + b.x, y + b.y);
}
public Vector2D sub(Vector2D b) {
return new Vector2D(x - b.x, y - b.y);
}
public float dot(Vector2D vec) {
return (x * vec.x) + (y * vec.y);
}
public float cross(Vector2D a, Vector2D b) {
return a.cross(b);
}
public float cross(Vector2D vec) {
return x * vec.y - y * vec.x;
}
public float distanceSquared(Vector2D other) {
float dx = other.x - x;
float dy = other.y - y;
return (dx * dx) + (dy * dy);
}
public float distance(Vector2D other) {
return (float) Math.sqrt(distanceSquared(other));
}
public float dotProduct(Vector2D other) {
return other.x * x + other.y * y;
}
public Vector2D normalize() {
float magnitude = (float) Math.sqrt(dotProduct(this));
return new Vector2D(x / magnitude, y / magnitude);
}
public Vector2D mult(float scalar) {
return new Vector2D(x * scalar, y * scalar);
}
}
/**
* Inner class used to make a fixed timed animation of the curl effect.
*/
class FlipAnimationHandler extends Handler {
#Override
public void handleMessage(Message msg) {
PageCurlView.this.FlipAnimationStep();
}
public void sleep(long millis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), millis);
}
}
/**
* Base
*
* #param context
*/
public PageCurlView(Context context) {
super(context);
init(context);
ResetClipEdge();
}
/**
* Construct the object from an XML file. Valid Attributes:
*
* #see android.view.View#View(android.content.Context,
* android.util.AttributeSet)
*/
public PageCurlView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
// Get the data from the XML AttributeSet
{
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.PageCurlView);
// Get data
bEnableDebugMode = a.getBoolean(
R.styleable.PageCurlView_enableDebugMode, bEnableDebugMode);
mCurlSpeed = a.getInt(R.styleable.PageCurlView_curlSpeed,
mCurlSpeed);
mUpdateRate = a.getInt(R.styleable.PageCurlView_updateRate,
mUpdateRate);
mInitialEdgeOffset = a.getInt(
R.styleable.PageCurlView_initialEdgeOffset,
mInitialEdgeOffset);
mCurlMode = a.getInt(R.styleable.PageCurlView_curlMode, mCurlMode);
Log.i(TAG, "mCurlSpeed: " + mCurlSpeed);
Log.i(TAG, "mUpdateRate: " + mUpdateRate);
Log.i(TAG, "mInitialEdgeOffset: " + mInitialEdgeOffset);
Log.i(TAG, "mCurlMode: " + mCurlMode);
// recycle object (so it can be used by others)
a.recycle();
}
ResetClipEdge();
}
/**
* Initialize the view
*/
private final void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.standalone_example, null,
true);
// left text view
textViewContent = (TextView) this.findViewById(R.id.textView);
// Foreground text paint
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16);
mTextPaint.setColor(0xFF000000);
// The shadow
mTextPaintShadow = new TextPaint();
mTextPaintShadow.setAntiAlias(true);
mTextPaintShadow.setTextSize(16);
mTextPaintShadow.setColor(0x00000000);
// Cache the context
mContext = new WeakReference<Context>(context);
hesham = context;
// Base padding
setPadding(3, 3, 3, 3);
// The focus flags are needed
setFocusable(true);
setFocusableInTouchMode(true);
mMovement = new Vector2D(0, 0);
mFinger = new Vector2D(0, 0);
mOldMovement = new Vector2D(0, 0);
// Create our curl animation handler
mAnimationHandler = new FlipAnimationHandler();
// Create our edge paint
mCurlEdgePaint = new Paint();
mCurlEdgePaint.setColor(Color.WHITE);
mCurlEdgePaint.setAntiAlias(true);
mCurlEdgePaint.setStyle(Paint.Style.FILL);
mCurlEdgePaint.setShadowLayer(10, -5, 5, 0x99000000);
// Set the default props, those come from an XML :D
mCurlSpeed = 120;
mUpdateRate = 66;
mInitialEdgeOffset = 30;
mCurlMode = 2;
// LEGACY PAGE HANDLING!
// Create pages
mPages = new ArrayList<Bitmap>();
mPages.add(BitmapFactory.decodeResource(getResources(),
R.drawable.page1));
mPages.add(BitmapFactory.decodeResource(getResources(),
R.drawable.page2));
// Create some sample images
mForeground = mPages.get(0);
mBackground = mPages.get(1);
}
/**
* Reset points to it's initial clip edge state
*/
public void ResetClipEdge() {
// Set our base movement
mMovement.x = mInitialEdgeOffset;
mMovement.y = mInitialEdgeOffset;
mOldMovement.x = 0;
mOldMovement.y = 0;
// Now set the points
// TODO: OK, those points MUST come from our measures and
// the actual bounds of the view!
mA = new Vector2D(mInitialEdgeOffset, 0);
mB = new Vector2D(this.getWidth(), this.getHeight());
mC = new Vector2D(this.getWidth(), 0);
mD = new Vector2D(0, 0);
mE = new Vector2D(0, 0);
mF = new Vector2D(0, 0);
mOldF = new Vector2D(0, 0);
// The movement origin point
mOrigin = new Vector2D(this.getWidth(), 0);
}
/**
* Return the context which created use. Can return null if the context has
* been erased.
*/
private Context GetContext() {
return mContext.get();
}
/**
* See if the current curl mode is dynamic
*
* #return TRUE if the mode is CURLMODE_DYNAMIC, FALSE otherwise
*/
public boolean IsCurlModeDynamic() {
return mCurlMode == CURLMODE_DYNAMIC;
}
/**
* Set the curl speed.
*
* #param curlSpeed
* - New speed in px/frame
* #throws IllegalArgumentException
* if curlspeed < 1
*/
public void SetCurlSpeed(int curlSpeed) {
if (curlSpeed < 1)
throw new IllegalArgumentException(
"curlSpeed must be greated than 0");
mCurlSpeed = curlSpeed;
}
/**
* Get the current curl speed
*
* #return int - Curl speed in px/frame
*/
public int GetCurlSpeed() {
return mCurlSpeed;
}
/**
* Set the update rate for the curl animation
*
* #param updateRate
* - Fixed animation update rate in fps
* #throws IllegalArgumentException
* if updateRate < 1
*/
public void SetUpdateRate(int updateRate) {
if (updateRate < 1)
throw new IllegalArgumentException(
"updateRate must be greated than 0");
mUpdateRate = updateRate;
}
/**
* Get the current animation update rate
*
* #return int - Fixed animation update rate in fps
*/
public int GetUpdateRate() {
return mUpdateRate;
}
/**
* Set the initial pixel offset for the curl edge
*
* #param initialEdgeOffset
* - px offset for curl edge
* #throws IllegalArgumentException
* if initialEdgeOffset < 0
*/
public void SetInitialEdgeOffset(int initialEdgeOffset) {
if (initialEdgeOffset < 0)
throw new IllegalArgumentException(
"initialEdgeOffset can not negative");
mInitialEdgeOffset = initialEdgeOffset;
}
/**
* Get the initial pixel offset for the curl edge
*
* #return int - px
*/
public int GetInitialEdgeOffset() {
return mInitialEdgeOffset;
}
/**
* Set the curl mode.
* <p>
* Can be one of the following values:
* </p>
* <table>
* <colgroup align="left" /> <colgroup align="left" />
* <tr>
* <th>Value</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_SIMPLE com.dcg.pagecurl:CURLMODE_SIMPLE}</code></td>
* <td>Curl target will move only in one axis.</td>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_DYNAMIC com.dcg.pagecurl:CURLMODE_DYNAMIC}</code></td>
* <td>Curl target will move on both X and Y axis.</td>
* </tr>
* </table>
*
* #see #CURLMODE_SIMPLE
* #see #CURLMODE_DYNAMIC
* #param curlMode
* #throws IllegalArgumentException
* if curlMode is invalid
*/
public void SetCurlMode(int curlMode) {
if (curlMode != CURLMODE_SIMPLE && curlMode != CURLMODE_DYNAMIC)
throw new IllegalArgumentException("Invalid curlMode");
mCurlMode = curlMode;
}
/**
* Return an integer that represents the current curl mode.
* <p>
* Can be one of the following values:
* </p>
* <table>
* <colgroup align="left" /> <colgroup align="left" />
* <tr>
* <th>Value</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_SIMPLE com.dcg.pagecurl:CURLMODE_SIMPLE}</code></td>
* <td>Curl target will move only in one axis.</td>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_DYNAMIC com.dcg.pagecurl:CURLMODE_DYNAMIC}</code></td>
* <td>Curl target will move on both X and Y axis.</td>
* </tr>
* </table>
*
* #see #CURLMODE_SIMPLE
* #see #CURLMODE_DYNAMIC
* #return int - current curl mode
*/
public int GetCurlMode() {
return mCurlMode;
}
/**
* Enable debug mode. This will draw a lot of data in the view so you can
* track what is happening
*
* #param bFlag
* - boolean flag
*/
public void SetEnableDebugMode(boolean bFlag) {
bEnableDebugMode = bFlag;
}
/**
* Check if we are currently in debug mode.
*
* #return boolean - If TRUE debug mode is on, FALSE otherwise.
*/
public boolean IsDebugModeEnabled() {
return bEnableDebugMode;
}
/**
* #see android.view.View#measure(int, int)
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int finalWidth, finalHeight;
finalWidth = measureWidth(widthMeasureSpec);
finalHeight = measureHeight(heightMeasureSpec);
setMeasuredDimension(finalWidth, finalHeight);
}
/**
* Determines the width of this view
*
* #param measureSpec
* A measureSpec packed into an int
* #return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = specSize;
}
return result;
}
/**
* Determines the height of this view
*
* #param measureSpec
* A measureSpec packed into an int
* #return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = specSize;
}
return result;
}
/**
* Render the text
*
* #see android.view.View#onDraw(android.graphics.Canvas)
*/
// #Override
// protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent,
// mTextPaint);
// }
// ---------------------------------------------------------------
// Curling. This handles touch events, the actual curling
// implementations and so on.
// ---------------------------------------------------------------
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!bBlockTouchInput) {
// Get our finger position
mFinger.x = event.getX();
mFinger.y = event.getY();
int width = getWidth();
// Depending on the action do what we need to
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mOldMovement.x = mFinger.x;
mOldMovement.y = mFinger.y;
// If we moved over the half of the display flip to next
if (mOldMovement.x > (width >> 1)) {
mMovement.x = mInitialEdgeOffset;
mMovement.y = mInitialEdgeOffset;
// Set the right movement flag
bFlipRight = true;
} else {
// Set the left movement flag
bFlipRight = false;
// go to next previous page
previousView();
// Set new movement
mMovement.x = IsCurlModeDynamic() ? width << 1 : width;
mMovement.y = mInitialEdgeOffset;
}
break;
case MotionEvent.ACTION_UP:
bUserMoves = false;
bFlipping = true;
FlipAnimationStep();
break;
case MotionEvent.ACTION_MOVE:
bUserMoves = true;
// Get movement
mMovement.x -= mFinger.x - mOldMovement.x;
mMovement.y -= mFinger.y - mOldMovement.y;
mMovement = CapMovement(mMovement, true);
// Make sure the y value get's locked at a nice level
if (mMovement.y <= 1)
mMovement.y = 1;
// Get movement direction
if (mFinger.x < mOldMovement.x) {
bFlipRight = true;
} else {
bFlipRight = false;
}
// Save old movement values
mOldMovement.x = mFinger.x;
mOldMovement.y = mFinger.y;
// Force a new draw call
DoPageCurl();
this.invalidate();
break;
}
}
// TODO: Only consume event if we need to.
return true;
}
/**
* Make sure we never move too much, and make sure that if we move too much
* to add a displacement so that the movement will be still in our radius.
*
* #paramradius - radius form the flip origin
* #param bMaintainMoveDir
* - Cap movement but do not change the current movement
* direction
* #return Corrected point
*/
private Vector2D CapMovement(Vector2D point, boolean bMaintainMoveDir) {
// Make sure we never ever move too much
if (point.distance(mOrigin) > mFlipRadius) {
if (bMaintainMoveDir) {
// Maintain the direction
point = mOrigin.sum(point.sub(mOrigin).normalize()
.mult(mFlipRadius));
} else {
// Change direction
if (point.x > (mOrigin.x + mFlipRadius))
point.x = (mOrigin.x + mFlipRadius);
else if (point.x < (mOrigin.x - mFlipRadius))
point.x = (mOrigin.x - mFlipRadius);
point.y = (float) (Math.sin(Math.acos(Math.abs(point.x
- mOrigin.x)
/ mFlipRadius)) * mFlipRadius);
}
}
return point;
}
/**
* Execute a step of the flip animation
*/
public void FlipAnimationStep() {
if (!bFlipping)
return;
int width = getWidth();
// No input when flipping
bBlockTouchInput = true;
// Handle speed
float curlSpeed = mCurlSpeed;
if (!bFlipRight)
curlSpeed *= -1;
// Move us
mMovement.x += curlSpeed;
mMovement = CapMovement(mMovement, false);
// Create values
DoPageCurl();
// Check for endings :D
if (mA.x < 1 || mA.x > width - 1) {
bFlipping = false;
if (bFlipRight) {
// SwapViews();
nextView();
}
ResetClipEdge();
// Create values
DoPageCurl();
// Enable touch input after the next draw event
bEnableInputAfterDraw = true;
} else {
mAnimationHandler.sleep(mUpdateRate);
}
// Force a new draw call
this.invalidate();
}
/**
* Do the page curl depending on the methods we are using
*/
private void DoPageCurl() {
if (bFlipping) {
if (IsCurlModeDynamic())
doDynamicCurl();
else
doSimpleCurl();
} else {
if (IsCurlModeDynamic())
doDynamicCurl();
else
doSimpleCurl();
}
}
/**
* Do a simple page curl effect
*/
private void doSimpleCurl() {
int width = getWidth();
int height = getHeight();
// Calculate point A
mA.x = width - mMovement.x;
mA.y = height;
// Calculate point D
mD.x = 0;
mD.y = 0;
if (mA.x > width / 2) {
mD.x = width;
mD.y = height - (width - mA.x) * height / mA.x;
} else {
mD.x = 2 * mA.x;
mD.y = 0;
}
// Now calculate E and F taking into account that the line
// AD is perpendicular to FB and EC. B and C are fixed points.
double angle = Math
.atan((height - mD.y) / (mD.x + mMovement.x - width));
double _cos = Math.cos(2 * angle);
double _sin = Math.sin(2 * angle);
// And get F
mF.x = (float) (width - mMovement.x + _cos * mMovement.x);
mF.y = (float) (height - _sin * mMovement.x);
// If the x position of A is above half of the page we are still not
// folding the upper-right edge and so E and D are equal.
if (mA.x > width / 2) {
mE.x = mD.x;
mE.y = mD.y;
} else {
// So get E
mE.x = (float) (mD.x + _cos * (width - mD.x));
mE.y = (float) -(_sin * (width - mD.x));
}
}
/**
* Calculate the dynamic effect, that one that follows the users finger
*/
private void doDynamicCurl() {
int width = getWidth();
int height = getHeight();
// F will follow the finger, we add a small displacement
// So that we can see the edge
mF.x = width - mMovement.x + 0.1f;
mF.y = height - mMovement.y + 0.1f;
// Set min points
if (mA.x == 0) {
mF.x = Math.min(mF.x, mOldF.x);
mF.y = Math.max(mF.y, mOldF.y);
}
// Get diffs
float deltaX = width - mF.x;
float deltaY = height - mF.y;
float BH = (float) (Math.sqrt(deltaX * deltaX + deltaY * deltaY) / 2);
double tangAlpha = deltaY / deltaX;
double alpha = Math.atan(deltaY / deltaX);
double _cos = Math.cos(alpha);
double _sin = Math.sin(alpha);
mA.x = (float) (width - (BH / _cos));
mA.y = height;
mD.y = (float) (height - (BH / _sin));
mD.x = width;
mA.x = Math.max(0, mA.x);
if (mA.x == 0) {
mOldF.x = mF.x;
mOldF.y = mF.y;
}
// Get W
mE.x = mD.x;
mE.y = mD.y;
// Correct
if (mD.y < 0) {
mD.x = width + (float) (tangAlpha * mD.y);
mE.y = 0;
mE.x = width + (float) (Math.tan(2 * alpha) * mD.y);
}
}
/**
* Swap between the fore and back-ground.
*/
#Deprecated
private void SwapViews() {
Bitmap temp = mForeground;
mForeground = mBackground;
mBackground = temp;
}
/**
* Swap to next view
*/
private void nextView() {
MySQLiteHelper SqlLiteInstance = new MySQLiteHelper(hesham);
SqlLiteInstance.insertForTest("تايتل", "لبلب", "ثثث");
SqlLiteInstance.insertForTest("تايتل التاني", "5555", "5555");
SqlLiteInstance.insertForTest("التالت", "66666", "66666");
int foreIndex = mIndex + 1;
Cursor myDataBase = SqlLiteInstance.getCurrentPageData(1);
if (myDataBase.moveToFirst() && myDataBase.getCount() >= 1) {
do {
textViewContent.setText(myDataBase.getString(0));
} while (myDataBase.moveToNext());
}
if (foreIndex >= mPages.size()) {
foreIndex = 0;
}
int backIndex = foreIndex + 1;
if (backIndex >= mPages.size()) {
backIndex = 0;
}
mIndex = foreIndex;
setViews(foreIndex, backIndex);
}
/**
* Swap to previous view
*/
private void previousView() {
int backIndex = mIndex;
int foreIndex = backIndex - 1;
if (foreIndex < 0) {
foreIndex = mPages.size() - 1;
}
mIndex = foreIndex;
setViews(foreIndex, backIndex);
}
/**
* Set current fore and background
*
* #param foreground
* - Foreground view index
* #param background
* - Background view index
*/
private void setViews(int foreground, int background) {
mForeground = mPages.get(foreground);
mBackground = mPages.get(background);
}
// ---------------------------------------------------------------
// Drawing methods
// ---------------------------------------------------------------
#Override
protected void onDraw(Canvas canvas) {
// Always refresh offsets
mCurrentLeft = getLeft();
mCurrentTop = getTop();
// Translate the whole canvas
// canvas.translate(mCurrentLeft, mCurrentTop);
// We need to initialize all size data when we first draw the view
if (!bViewDrawn) {
bViewDrawn = true;
onFirstDrawEvent(canvas);
}
canvas.drawColor(Color.WHITE);
// Curl pages
// DoPageCurl();
// TODO: This just scales the views to the current
// width and height. We should add some logic for:
// 1) Maintain aspect ratio
// 2) Uniform scale
// 3) ...
Rect rect = new Rect();
rect.left = 0;
rect.top = 0;
rect.bottom = getHeight();
rect.right = getWidth();
// First Page render
Paint paint = new Paint();
// Draw our elements
drawForeground(canvas, rect, paint);
drawBackground(canvas, rect, paint);
drawCurlEdge(canvas);
// Draw any debug info once we are done
if (bEnableDebugMode)
drawDebug(canvas);
// Check if we can re-enable input
if (bEnableInputAfterDraw) {
bBlockTouchInput = false;
bEnableInputAfterDraw = false;
}
// Restore canvas
// canvas.restore();
}
/**
* Called on the first draw event of the view
*
* #param canvas
*/
protected void onFirstDrawEvent(Canvas canvas) {
mFlipRadius = getWidth();
ResetClipEdge();
DoPageCurl();
}
/**
* Draw the foreground
*
* #param canvas
* #param rect
* #param paint
*/
private void drawForeground(Canvas canvas, Rect rect, Paint paint) {
canvas.drawBitmap(mForeground, null, rect, paint);
// Draw the page number (first page is 1 in real life :D
// there is no page number 0 hehe)
drawPageNum(canvas, mIndex);
}
/**
* Create a Path used as a mask to draw the background page
*
* #return
*/
private Path createBackgroundPath() {
Path path = new Path();
path.moveTo(mA.x, mA.y);
path.lineTo(mB.x, mB.y);
path.lineTo(mC.x, mC.y);
path.lineTo(mD.x, mD.y);
path.lineTo(mA.x, mA.y);
return path;
}
/**
* Draw the background image.
*
* #param canvas
* #param rect
* #param paint
*/
private void drawBackground(Canvas canvas, Rect rect, Paint paint) {
Path mask = createBackgroundPath();
// Save current canvas so we do not mess it up
canvas.save();
canvas.clipPath(mask);
canvas.drawBitmap(mBackground, null, rect, paint);
// Draw the page number (first page is 1 in real life :D
// there is no page number 0 hehe)
drawPageNum(canvas, mIndex);
canvas.restore();
}
/**
* Creates a path used to draw the curl edge in.
*
* #return
*/
private Path createCurlEdgePath() {
Path path = new Path();
path.moveTo(mA.x, mA.y);
path.lineTo(mD.x, mD.y);
path.lineTo(mE.x, mE.y);
path.lineTo(mF.x, mF.y);
path.lineTo(mA.x, mA.y);
return path;
}
/**
* Draw the curl page edge
*
* #param canvas
*/
private void drawCurlEdge(Canvas canvas) {
Path path = createCurlEdgePath();
canvas.drawPath(path, mCurlEdgePaint);
}
/**
* Draw page num (let this be a bit more custom)
*
* #param canvas
* #param pageNum
*/
private void drawPageNum(Canvas canvas, int pageNum) {
mTextPaint.setColor(Color.WHITE);
String pageNumText = "- " + pageNum + " -";
drawCentered(canvas, pageNumText,
canvas.getHeight() - mTextPaint.getTextSize() - 5, mTextPaint,
mTextPaintShadow);
}
// ---------------------------------------------------------------
// Debug draw methods
// ---------------------------------------------------------------
/**
* Draw a text with a nice shadow
*/
public static void drawTextShadowed(Canvas canvas, String text, float x,
float y, Paint textPain, Paint shadowPaint) {
canvas.drawText(text, x - 1, y, shadowPaint);
canvas.drawText(text, x, y + 1, shadowPaint);
canvas.drawText(text, x + 1, y, shadowPaint);
canvas.drawText(text, x, y - 1, shadowPaint);
canvas.drawText(text, x, y, textPain);
}
/**
* Draw a text with a nice shadow centered in the X axis
*
* #param canvas
* #param text
* #param y
* #param textPain
* #param shadowPaint
*/
public static void drawCentered(Canvas canvas, String text, float y,
Paint textPain, Paint shadowPaint) {
float posx = (canvas.getWidth() - textPain.measureText(text)) / 2;
drawTextShadowed(canvas, text, posx, y, textPain, shadowPaint);
}
/**
* Draw debug info
*
* #param canvas
*/
private void drawDebug(Canvas canvas) {
float posX = 10;
float posY = 20;
Paint paint = new Paint();
paint.setStrokeWidth(5);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLACK);
canvas.drawCircle(mOrigin.x, mOrigin.y, getWidth(), paint);
paint.setStrokeWidth(3);
paint.setColor(Color.RED);
canvas.drawCircle(mOrigin.x, mOrigin.y, getWidth(), paint);
paint.setStrokeWidth(5);
paint.setColor(Color.BLACK);
canvas.drawLine(mOrigin.x, mOrigin.y, mMovement.x, mMovement.y, paint);
paint.setStrokeWidth(3);
paint.setColor(Color.RED);
canvas.drawLine(mOrigin.x, mOrigin.y, mMovement.x, mMovement.y, paint);
posY = debugDrawPoint(canvas, "A", mA, Color.RED, posX, posY);
posY = debugDrawPoint(canvas, "B", mB, Color.GREEN, posX, posY);
posY = debugDrawPoint(canvas, "C", mC, Color.BLUE, posX, posY);
posY = debugDrawPoint(canvas, "D", mD, Color.CYAN, posX, posY);
posY = debugDrawPoint(canvas, "E", mE, Color.YELLOW, posX, posY);
posY = debugDrawPoint(canvas, "F", mF, Color.LTGRAY, posX, posY);
posY = debugDrawPoint(canvas, "Mov", mMovement, Color.DKGRAY, posX,
posY);
posY = debugDrawPoint(canvas, "Origin", mOrigin, Color.MAGENTA, posX,
posY);
posY = debugDrawPoint(canvas, "Finger", mFinger, Color.GREEN, posX,
posY);
// Draw some curl stuff (Just some test)
/*
* canvas.save(); Vector2D center = new
* Vector2D(getWidth()/2,getHeight()/2);
* //canvas.rotate(315,center.x,center.y);
*
* // Test each lines //float radius = mA.distance(mD)/2.f; //float
* radius = mA.distance(mE)/2.f; float radius = mA.distance(mF)/2.f;
* //float radius = 10; float reduction = 4.f; RectF oval = new RectF();
* oval.top = center.y-radius/reduction; oval.bottom =
* center.y+radius/reduction; oval.left = center.x-radius; oval.right =
* center.x+radius; canvas.drawArc(oval, 0, 360, false, paint);
* canvas.restore(); /*
*/
}
private float debugDrawPoint(Canvas canvas, String name, Vector2D point,
int color, float posX, float posY) {
return debugDrawPoint(canvas, name + " " + point.toString(), point.x,
point.y, color, posX, posY);
}
private float debugDrawPoint(Canvas canvas, String name, float X, float Y,
int color, float posX, float posY) {
mTextPaint.setColor(color);
drawTextShadowed(canvas, name, posX, posY, mTextPaint, mTextPaintShadow);
Paint paint = new Paint();
paint.setStrokeWidth(5);
paint.setColor(color);
canvas.drawPoint(X, Y, paint);
return posY + 15;
}
}
xml code :
<RelativeLayout
android:id="#+id/game_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.mystictreegames.pagecurl.PageCurlView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/dcgpagecurlPageCurlView1"
android:background="#drawable/facebook">
</com.mystictreegames.pagecurl.PageCurlView>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_centerVertical="true"
android:text="جوهر كون المرء انه انسان لا يسعى الى الكمال"/>
log error:
FATAL EXCEPTION: main
E/AndroidRuntime(2497): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mystictreegames.pagecurl/com.mystictreegames.pagecurl.StandaloneExample}: android.view.InflateException: Binary XML file line #13: Error inflating class com.mystictreegames.pagecurl.PageCurlView
In the init() of the PageCurlView class, you are inflating R.layout.standalone_example. Objects are added in a circular manner (R.layout.standalone_example has PageCurlView which has R.layout.standalone_example which has ...).
Related
How to infinitely repeat background in Libgdx?
I am using this class : import com.badlogic.gdx.graphics.g2d.TextureRegion; public class ParallaxLayer { // the Texture sitting on this layer public TextureRegion region; /** * how much shall this layer (in percent) be moved if the whole background is moved * 0.5f is half as fast as the speed * 2.0f is twice the speed */ float ratioX, ratioY; /** * current position */ float positionX, positionY; /** * * #param pRegion * #param pRatioX * #param pRatioY */ public ParallaxLayer(TextureRegion pRegion, float pRatioX, float pRatioY) { region = pRegion; ratioX = pRatioX; ratioY = pRatioY; } /** * move this layer * #param pDelta */ protected void moveX(float pDelta) { positionX += pDelta * ratioX; } /** * move this layer * #param pDelta */ protected void moveY(float pDelta) { positionY += pDelta * ratioY; } } and this class : import com.badlogic.gdx.graphics.g2d.TextureRegion; public class ParallaxLayer { /** * the Texture sitting on this layer */ public TextureRegion region; /** * how much shall this layer (in percent) be moved if the whole background is moved * 0.5f is half as fast as the speed * 2.0f is twice the speed */ float ratioX, ratioY; /** * current position */ float positionX, positionY; /** * * #param pRegion * #param pRatioX * #param pRatioY */ public ParallaxLayer(TextureRegion pRegion, float pRatioX, float pRatioY) { region = pRegion; ratioX = pRatioX; ratioY = pRatioY; } /** * move this layer * #param pDelta */ protected void moveX(float pDelta) { positionX += pDelta * ratioX; } /** * move this layer * #param pDelta */ protected void moveY(float pDelta) { positionY += pDelta * ratioY; } } And in main class : camera=new OrthographicCamera(400,240); camera.position.x=200; camera.position.y=120; camera.update(); batch=new SpriteBatch(); layer1=atlas.findRegion("layer1"); layer2=atlas.findRegion("layer2"); layer3=atlas.findRegion("layer3"); ParallaxLayer l1=new ParallaxLayer(layer1,0,0); ParallaxLayer l2=new ParallaxLayer(layer2,0.5f,0); ParallaxLayer l3=new ParallaxLayer(layer3,1,0); ParallaxLayer[] layers={l1,l2,l3}; background=new ParallaxBackground(layers, camera,batch); // [...] in render background.moveX(30*delta); // move to the right to show the effect background.render(); to achieve parallax scrolling effect but i want infinite scrolling but unable to get it. I tried doing this in ParallaxBackground class under for loop but repeats only three time. posXbg1L1 = layer.positionX; posXbg2L1 = posXbg1L1 - layer.region.getRegionWidth(); if (camera.position.x <= posXbg2L1 - camera.viewportWidth / 2) { // Gdx.app.log("TAG", camera.position.x + ":" + posXbg2L1 + camera.viewportWidth / 2); posXbg1L1 = posXbg2L1; } batch.draw(layer.region, -camera.viewportWidth / 2 - posXbg1L1, -camera.viewportHeight / 2 - layer.positionY); batch.draw(layer.region, -camera.viewportWidth / 2 - posXbg2L1, -camera.viewportHeight / 2 - layer.positionY); } Any psuedocode/code will be helpful.
You could try something like this: TextureRegion[] backgrounds = [...your array of background textures...]; float[] parallax = {...your parallax coefficients...}; //For example {0.2f, 0.1f} public void drawLayers(Batch batch, OrthographicCamera camera) { batch.setColor(Color.WHITE); for(int b = backgrounds.length - 1; b >= 0; b--) { TextureRegion background = backgrounds[b]; if(background != null) { float x = (camera.position.x - camera.viewportWidth / 2f * camera.zoom); float y = camera.position.y - camera.viewportHeight / 2f * camera.zoom + camera.viewportHeight / 15f * camera.zoom; float rWidth = camera.viewportWidth * 1.5f * camera.zoom; float rHeight = (rWidth / background.getRegionWidth()) * background.getRegionHeight(); drawParallaxLayer(batch, background, parallax[b], x, y, rWidth, rHeight); } } } public static void drawParallaxLayer(Batch batch, TextureRegion region, float parallax, float x, float y, float width, float height) { for(int j = 0; j < 3; j++) { batch.draw(region, x + (j * width) - ((x * parallax) % width) - (width / 2f), y, width, height); } } You might have to adjust some of the position/width/height values in the drawLayers function, but the real magic happens in drawParallaxLayer - which should be able to stay the same.
How to draw hexagons in android?
I used the hexagon code in this tutorial and created a createHex class (Should I post the code?). The linked web page has used the following code to actually draw the hexagons using the math in createHex: #Override public void paint(Graphics g){ for(int j = 0; int j < BOARD_HEIGHT; j++){ for(int i = 0; i < BOARD_HEIGHT; I++){ mCellMetrics.setCellIndex(i, j); if(mCells[j][i] != 0){ mCellMetrics.computeCorners(mCornersX, mCornersY); g.setColor((mCells[j][i] == L_ON) ? COLOR.ORANGE):COLOR.GRAY; g.fillPolygon(mCornersX, mCornersY, NUM_HEX_CORNERS); g.setColor(COLOR.BLACK) g.drawPolygon(mCornersX, mCornersY, NUM_HEX_CORNERS); } } } } The problem I encountered is that Android does not have a Graphics class that contains all the required methods. I did about an hour and a half of fishing around the android documentation and the closest thing I found was the Path class but it doesn't have the methods I need. I want to use the hexagon code in the linked article at the top but I can't find the equivalent of the graphics class. If there isn't an equivalent, can someone show me how to get the results I want using the linked code? My question: How can I port the code in the linked article to android? EDIT: I decided that it might be helpful to others (and potential answerers) if I included the hexagon code that calculates the sides and whatnot of a hexagon, so here is createHex.java: package com.rush; /** * Uniform hexagonal grid cell's metrics utility class. */ public class HexGridCell { private static final int[] NEIGHBORS_DI = { 0, 1, 1, 0, -1, -1 }; private static final int[][] NEIGHBORS_DJ = { { -1, -1, 0, 1, 0, -1 }, { -1, 0, 1, 1, 1, 0 } }; private final int[] CORNERS_DX; // array of horizontal offsets of the cell's corners private final int[] CORNERS_DY; // array of vertical offsets of the cell's corners private final int SIDE; private int mX = 0; // cell's left coordinate private int mY = 0; // cell's top coordinate private int mI = 0; // cell's horizontal grid coordinate private int mJ = 0; // cell's vertical grid coordinate /** * Cell radius (distance from center to one of the corners) */ public final int RADIUS; /** * Cell height */ public final int HEIGHT; /** * Cell width */ public final int WIDTH; public static final int NUM_NEIGHBORS = 6; /** * #param radius Cell radius (distance from the center to one of the corners) */ public HexGridCell(int radius) { RADIUS = radius; WIDTH = radius * 2; HEIGHT = (int) (((float) radius) * Math.sqrt(3)); SIDE = radius * 3 / 2; int cdx[] = { RADIUS / 2, SIDE, WIDTH, SIDE, RADIUS / 2, 0 }; CORNERS_DX = cdx; int cdy[] = { 0, 0, HEIGHT / 2, HEIGHT, HEIGHT, HEIGHT / 2 }; CORNERS_DY = cdy; } /** * #return X coordinate of the cell's top left corner. */ public int getLeft() { return mX; } /** * #return Y coordinate of the cell's top left corner. */ public int getTop() { return mY; } /** * #return X coordinate of the cell's center */ public int getCenterX() { return mX + RADIUS; } /** * #return Y coordinate of the cell's center */ public int getCenterY() { return mY + HEIGHT / 2; } /** * #return Horizontal grid coordinate for the cell. */ public int getIndexI() { return mI; } /** * #return Vertical grid coordinate for the cell. */ public int getIndexJ() { return mJ; } /** * #return Horizontal grid coordinate for the given neighbor. */ public int getNeighborI(int neighborIdx) { return mI + NEIGHBORS_DI[neighborIdx]; } /** * #return Vertical grid coordinate for the given neighbor. */ public int getNeighborJ(int neighborIdx) { return mJ + NEIGHBORS_DJ[mI % 2][neighborIdx]; } /** * Computes X and Y coordinates for all of the cell's 6 corners, clockwise, * starting from the top left. * * #param cornersX Array to fill in with X coordinates of the cell's corners * #param cornersX Array to fill in with Y coordinates of the cell's corners */ public void computeCorners(int[] cornersX, int[] cornersY) { for (int k = 0; k < NUM_NEIGHBORS; k++) { cornersX[k] = mX + CORNERS_DX[k]; cornersY[k] = mY + CORNERS_DY[k]; } } /** * Sets the cell's horizontal and vertical grid coordinates. */ public void setCellIndex(int i, int j) { mI = i; mJ = j; mX = i * SIDE; mY = HEIGHT * (2 * j + (i % 2)) / 2; } /** * Sets the cell as corresponding to some point inside it (can be used for * e.g. mouse picking). */ public void setCellByPoint(int x, int y) { int ci = (int)Math.floor((float)x/(float)SIDE); int cx = x - SIDE*ci; int ty = y - (ci % 2) * HEIGHT / 2; int cj = (int)Math.floor((float)ty/(float)HEIGHT); int cy = ty - HEIGHT*cj; if (cx > Math.abs(RADIUS / 2 - RADIUS * cy / HEIGHT)) { setCellIndex(ci, cj); } else { setCellIndex(ci - 1, cj + (ci % 2) - ((cy < HEIGHT / 2) ? 1 : 0)); } } } For an explanation of how the code works please refer to the linked article.
Try this: import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Path; import android.graphics.Region; import android.util.AttributeSet; import android.view.View; public class HexagonMaskView extends View { private Path hexagonPath; private Path hexagonBorderPath; private float radius; private float width, height; private int maskColor; public HexagonMaskView(Context context) { super(context); init(); } public HexagonMaskView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { hexagonPath = new Path(); hexagonBorderPath = new Path(); maskColor = 0xFF01FF77; } public void setRadius(float r) { this.radius = r; calculatePath(); } public void setMaskColor(int color) { this.maskColor = color; invalidate(); } private void calculatePath() { float triangleHeight = (float) (Math.sqrt(3) * radius / 2); float centerX = width/2; float centerY = height/2; hexagonPath.moveTo(centerX, centerY + radius); hexagonPath.lineTo(centerX - triangleHeight, centerY + radius/2); hexagonPath.lineTo(centerX - triangleHeight, centerY - radius/2); hexagonPath.lineTo(centerX, centerY - radius); hexagonPath.lineTo(centerX + triangleHeight, centerY - radius/2); hexagonPath.lineTo(centerX + triangleHeight, centerY + radius/2); hexagonPath.moveTo(centerX, centerY + radius); float radiusBorder = radius - 5; float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2); hexagonBorderPath.moveTo(centerX, centerY + radiusBorder); hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + radiusBorder/2); hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - radiusBorder/2); hexagonBorderPath.lineTo(centerX, centerY - radiusBorder); hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - radiusBorder/2); hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + radiusBorder/2); hexagonBorderPath.moveTo(centerX, centerY + radiusBorder); invalidate(); } #Override public void onDraw(Canvas c){ super.onDraw(c); c.clipPath(hexagonBorderPath, Region.Op.DIFFERENCE); c.drawColor(Color.WHITE); c.save(); c.clipPath(hexagonPath, Region.Op.DIFFERENCE); c.drawColor(maskColor); c.save(); } // getting the view size and default radius #Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); radius = height / 2 - 10; calculatePath(); } }
Try this or download demo example. public static Bitmap getHexagonalCroppedBitmap(Bitmap bitmap, int radius) { Bitmap finalBitmap; if (bitmap.getWidth() != radius || bitmap.getHeight() != radius) finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius, false); else finalBitmap = bitmap; Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(), finalBitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); Paint paint = new Paint(); final Rect rect = new Rect(0, 0, finalBitmap.getWidth(), finalBitmap.getHeight()); Point point1_draw = new Point(75, 0); Point point2_draw = new Point(0, 50); Point point3_draw = new Point(0, 100); Point point4_draw = new Point(75, 150); Point point5_draw = new Point(150, 100); Point point6_draw = new Point(150, 50); Path path = new Path(); path.moveTo(point1_draw.x, point1_draw.y); path.lineTo(point2_draw.x, point2_draw.y); path.lineTo(point3_draw.x, point3_draw.y); path.lineTo(point4_draw.x, point4_draw.y); path.lineTo(point5_draw.x, point5_draw.y); path.lineTo(point6_draw.x, point6_draw.y); path.close(); canvas.drawARGB(0, 0, 0, 0); paint.setColor(Color.parseColor("#BAB399")); canvas.drawPath(path, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(finalBitmap, rect, rect, paint); return output; } pass your image to be cropped to hexagon as bitmap to this function Bitmap myhexagon = getHexagonalCroppedBitmap(Myimage, yourHexagonalRadius);
Methods to generate image based on Perlin Noise array
I'm trying to begin learning to use Perlin Noise to create a tile map. I'm just beginning so I found some source code online to create an array based on Perlin Noise. So I have an array of good data right now (as far as I know) but I don't understand what kinds of methods can be used to convert this from an array into a tile map. Does anybody have any examples or sources of any methods to do this? Here is the code I'm using the generate the array. package perlin1; import java.util.Random; public class ImageWriter { /** Source of entropy */ private Random rand_; /** Amount of roughness */ float roughness_; /** Plasma fractal grid */ private float[][] grid_; /** Generate a noise source based upon the midpoint displacement fractal. * * #param rand The random number generator * #param roughness a roughness parameter * #param width the width of the grid * #param height the height of the grid */ public ImageWriter(Random rand, float roughness, int width, int height) { roughness_ = roughness / width; grid_ = new float[width][height]; rand_ = (rand == null) ? new Random() : rand; } public void initialise() { int xh = grid_.length - 1; int yh = grid_[0].length - 1; // set the corner points grid_[0][0] = rand_.nextFloat() - 0.5f; grid_[0][yh] = rand_.nextFloat() - 0.5f; grid_[xh][0] = rand_.nextFloat() - 0.5f; grid_[xh][yh] = rand_.nextFloat() - 0.5f; // generate the fractal generate(0, 0, xh, yh); } // Add a suitable amount of random displacement to a point private float roughen(float v, int l, int h) { return v + roughness_ * (float) (rand_.nextGaussian() * (h - l)); } // generate the fractal private void generate(int xl, int yl, int xh, int yh) { int xm = (xl + xh) / 2; int ym = (yl + yh) / 2; if ((xl == xm) && (yl == ym)) return; grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]); grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]); grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]); grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]); float v = roughen(0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh + xh); grid_[xm][ym] = v; grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh); grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh); grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh); grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh); generate(xl, yl, xm, ym); generate(xm, yl, xh, ym); generate(xl, ym, xm, yh); generate(xm, ym, xh, yh); } /** * Dump out as a CSV */ public void printAsCSV() { for(int i = 0;i < grid_.length;i++) { for(int j = 0;j < grid_[0].length;j++) { System.out.print(grid_[i][j]); System.out.print(","); } System.out.println(); } } /** * Convert to a Boolean array * #return the boolean array */ public boolean[][] toBooleans() { int w = grid_.length; int h = grid_[0].length; boolean[][] ret = new boolean[w][h]; for(int i = 0;i < w;i++) { for(int j = 0;j < h;j++) { ret[i][j] = grid_[i][j] < 0; } } return ret; } /** For testing */ public static void main(String[] args) { ImageWriter n = new ImageWriter(null, 1.0f, 250, 250); n.initialise(); n.printAsCSV(); } } The resulting array is all amounts between 0 and 1. Again, I'm just looking for how this array can be converted into a tile map. Any help is appreciated. Thanks
Draw an Arc and gradient it
I would like to know if its possible to draw a Arc on a graphics Panel using a gradient and how I would go about it. My end goal would be to rotate the arc in a full circle so it would be similar to a rotating loading circle. However it is not a loading bar. It would be a background of a custom JButton. Any suggestions to alternatives that would create a similar effect would be appreciated. This is similar to what oi want to draw. Keep in mind that it will be "rotating"
public class TestArc { public static void main(String[] args) { new TestArc(); } public TestArc() { EventQueue.invokeLater(new Runnable() { #Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { } #Override public Dimension getPreferredSize() { return new Dimension(200, 200); } #Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); int radius = Math.min(getWidth(), getHeight()); int x = (getWidth() - radius) / 2; int y = (getHeight() - radius) / 2; RadialGradientPaint rgp = new RadialGradientPaint( new Point(getWidth() / 2, getHeight() / 2), radius, new float[]{0f, 1f}, new Color[]{Color.RED, Color.YELLOW} ); g2d.setPaint(rgp); g2d.fill(new Arc2D.Float(x, y, radius, radius, 0, 45, Arc2D.PIE)); g2d.dispose(); } } } You might like to have a look at 2D Graphics for more info Updated after additional input So you want a conical fill effect then... The implementation I have comes from Harmonic Code, but I can't find a direct reference to it (I think it's part of his (excellent) series), but you can see the source code here Now. I had issues with the angles as it appears that 0 starts at the top point (not the left) and it doesn't like negative angles...you might have better luck, but what I did was create a basic buffer at a position I could easily get working and then rotate the graphics context using an AffineTransformation... public class TestArc { public static void main(String[] args) { new TestArc(); } public TestArc() { EventQueue.invokeLater(new Runnable() { #Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private float angle = 0; private float extent = 270; private BufferedImage buffer; public TestPane() { Timer timer = new Timer(125, new ActionListener() { #Override public void actionPerformed(ActionEvent e) { angle -= 5; if (angle > 360) { angle = 0; } repaint(); } }); timer.setRepeats(true); timer.setCoalesce(false); timer.start(); } #Override public Dimension getPreferredSize() { return new Dimension(200, 200); } protected BufferedImage getBuffer() { if (buffer == null) { int radius = Math.min(getWidth(), getHeight()); int x = (getWidth() - radius) / 2; int y = (getHeight() - radius) / 2; buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = buffer.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); float startAngle = 0; Color start = new Color(0, 128, 0, 128); Color end = new Color(0, 128, 0, 0); ConicalGradientPaint rgp = new ConicalGradientPaint( true, new Point(getWidth() / 2, getHeight() / 2), 0.5f, new float[]{startAngle, extent}, new Color[]{start, end}); g2d.setPaint(rgp); g2d.fill(new Arc2D.Float(x, y, radius, radius, startAngle + 90, -extent, Arc2D.PIE)); // g2d.fill(new Ellipse2D.Float(0, 0, radius, radius)); g2d.dispose(); g2d.dispose(); } return buffer; } protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int radius = Math.min(getWidth(), getHeight()); int x = (getWidth()) / 2; int y = (getHeight()) / 2; BufferedImage buffer = getBuffer(); g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angle), x, y)); x = (getWidth() - buffer.getWidth()) / 2; y = (getHeight() - buffer.getHeight()) / 2; g2d.drawImage(buffer, x, y, this); g2d.dispose(); } } public final class ConicalGradientPaint implements java.awt.Paint { private final java.awt.geom.Point2D CENTER; private final double[] FRACTION_ANGLES; private final double[] RED_STEP_LOOKUP; private final double[] GREEN_STEP_LOOKUP; private final double[] BLUE_STEP_LOOKUP; private final double[] ALPHA_STEP_LOOKUP; private final java.awt.Color[] COLORS; private static final float INT_TO_FLOAT_CONST = 1f / 255f; /** * Standard constructor which takes the FRACTIONS in values from 0.0f to * 1.0f * * #param CENTER * #param GIVEN_FRACTIONS * #param GIVEN_COLORS * #throws IllegalArgumentException */ public ConicalGradientPaint(final java.awt.geom.Point2D CENTER, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException { this(false, CENTER, 0.0f, GIVEN_FRACTIONS, GIVEN_COLORS); } /** * Enhanced constructor which takes the FRACTIONS in degress from 0.0f to * 360.0f and also an GIVEN_OFFSET in degrees around the rotation CENTER * * #param USE_DEGREES * #param CENTER * #param GIVEN_OFFSET * #param GIVEN_FRACTIONS * #param GIVEN_COLORS * #throws IllegalArgumentException */ public ConicalGradientPaint(final boolean USE_DEGREES, final java.awt.geom.Point2D CENTER, final float GIVEN_OFFSET, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException { // Check that fractions and colors are of the same size if (GIVEN_FRACTIONS.length != GIVEN_COLORS.length) { throw new IllegalArgumentException("Fractions and colors must be equal in size"); } final java.util.ArrayList<Float> FRACTION_LIST = new java.util.ArrayList<Float>(GIVEN_FRACTIONS.length); final float OFFSET; if (USE_DEGREES) { final double DEG_FRACTION = 1f / 360f; if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), -0.5) == 0) { OFFSET = -0.5f; } else if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), 0.5) == 0) { OFFSET = 0.5f; } else { OFFSET = (float) (GIVEN_OFFSET * DEG_FRACTION); } for (float fraction : GIVEN_FRACTIONS) { FRACTION_LIST.add((float) (fraction * DEG_FRACTION)); } } else { // Now it seems to work with rotation of 0.5f, below is the old code to correct the problem // if (GIVEN_OFFSET == -0.5) // { // // This is needed because of problems in the creation of the Raster // // with a angle offset of exactly -0.5 // OFFSET = -0.49999f; // } // else if (GIVEN_OFFSET == 0.5) // { // // This is needed because of problems in the creation of the Raster // // with a angle offset of exactly +0.5 // OFFSET = 0.499999f; // } // else { OFFSET = GIVEN_OFFSET; } for (float fraction : GIVEN_FRACTIONS) { FRACTION_LIST.add(fraction); } } // Check for valid offset if (OFFSET > 0.5f || OFFSET < -0.5f) { throw new IllegalArgumentException("Offset has to be in the range of -0.5 to 0.5"); } // Adjust fractions and colors array in the case where startvalue != 0.0f and/or endvalue != 1.0f final java.util.List<java.awt.Color> COLOR_LIST = new java.util.ArrayList<java.awt.Color>(GIVEN_COLORS.length); COLOR_LIST.addAll(java.util.Arrays.asList(GIVEN_COLORS)); // Assure that fractions start with 0.0f if (FRACTION_LIST.get(0) != 0.0f) { FRACTION_LIST.add(0, 0.0f); final java.awt.Color TMP_COLOR = COLOR_LIST.get(0); COLOR_LIST.add(0, TMP_COLOR); } // Assure that fractions end with 1.0f if (FRACTION_LIST.get(FRACTION_LIST.size() - 1) != 1.0f) { FRACTION_LIST.add(1.0f); COLOR_LIST.add(GIVEN_COLORS[0]); } // Recalculate the fractions and colors with the given offset final java.util.Map<Float, java.awt.Color> FRACTION_COLORS = recalculate(FRACTION_LIST, COLOR_LIST, OFFSET); // Clear the original FRACTION_LIST and COLOR_LIST FRACTION_LIST.clear(); COLOR_LIST.clear(); // Sort the hashmap by fraction and add the values to the FRACION_LIST and COLOR_LIST final java.util.SortedSet<Float> SORTED_FRACTIONS = new java.util.TreeSet<Float>(FRACTION_COLORS.keySet()); final java.util.Iterator<Float> ITERATOR = SORTED_FRACTIONS.iterator(); while (ITERATOR.hasNext()) { final float CURRENT_FRACTION = ITERATOR.next(); FRACTION_LIST.add(CURRENT_FRACTION); COLOR_LIST.add(FRACTION_COLORS.get(CURRENT_FRACTION)); } // Set the values this.CENTER = CENTER; COLORS = COLOR_LIST.toArray(new java.awt.Color[]{}); // Prepare lookup table for the angles of each fraction final int MAX_FRACTIONS = FRACTION_LIST.size(); this.FRACTION_ANGLES = new double[MAX_FRACTIONS]; for (int i = 0; i < MAX_FRACTIONS; i++) { FRACTION_ANGLES[i] = FRACTION_LIST.get(i) * 360; } // Prepare lookup tables for the color stepsize of each color RED_STEP_LOOKUP = new double[COLORS.length]; GREEN_STEP_LOOKUP = new double[COLORS.length]; BLUE_STEP_LOOKUP = new double[COLORS.length]; ALPHA_STEP_LOOKUP = new double[COLORS.length]; for (int i = 0; i < (COLORS.length - 1); i++) { RED_STEP_LOOKUP[i] = ((COLORS[i + 1].getRed() - COLORS[i].getRed()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); GREEN_STEP_LOOKUP[i] = ((COLORS[i + 1].getGreen() - COLORS[i].getGreen()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); BLUE_STEP_LOOKUP[i] = ((COLORS[i + 1].getBlue() - COLORS[i].getBlue()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); ALPHA_STEP_LOOKUP[i] = ((COLORS[i + 1].getAlpha() - COLORS[i].getAlpha()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); } } /** * Recalculates the fractions in the FRACTION_LIST and their associated * colors in the COLOR_LIST with a given OFFSET. Because the conical * gradients always starts with 0 at the top and clockwise direction you * could rotate the defined conical gradient from -180 to 180 degrees which * equals values from -0.5 to +0.5 * * #param FRACTION_LIST * #param COLOR_LIST * #param OFFSET * #return Hashmap that contains the recalculated fractions and colors after * a given rotation */ private java.util.HashMap<Float, java.awt.Color> recalculate(final java.util.List<Float> FRACTION_LIST, final java.util.List<java.awt.Color> COLOR_LIST, final float OFFSET) { // Recalculate the fractions and colors with the given offset final int MAX_FRACTIONS = FRACTION_LIST.size(); final java.util.HashMap<Float, java.awt.Color> FRACTION_COLORS = new java.util.HashMap<Float, java.awt.Color>(MAX_FRACTIONS); for (int i = 0; i < MAX_FRACTIONS; i++) { // Add offset to fraction final float TMP_FRACTION = FRACTION_LIST.get(i) + OFFSET; // Color related to current fraction final java.awt.Color TMP_COLOR = COLOR_LIST.get(i); // Check each fraction for limits (0...1) if (TMP_FRACTION <= 0) { FRACTION_COLORS.put(1.0f + TMP_FRACTION + 0.0001f, TMP_COLOR); final float NEXT_FRACTION; final java.awt.Color NEXT_COLOR; if (i < MAX_FRACTIONS - 1) { NEXT_FRACTION = FRACTION_LIST.get(i + 1) + OFFSET; NEXT_COLOR = COLOR_LIST.get(i + 1); } else { NEXT_FRACTION = 1 - FRACTION_LIST.get(0) + OFFSET; NEXT_COLOR = COLOR_LIST.get(0); } if (NEXT_FRACTION > 0) { final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, NEXT_COLOR, (int) ((NEXT_FRACTION - TMP_FRACTION) * 10000), (int) ((-TMP_FRACTION) * 10000)); FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR); FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR); } } else if (TMP_FRACTION >= 1) { FRACTION_COLORS.put(TMP_FRACTION - 1.0f - 0.0001f, TMP_COLOR); final float PREVIOUS_FRACTION; final java.awt.Color PREVIOUS_COLOR; if (i > 0) { PREVIOUS_FRACTION = FRACTION_LIST.get(i - 1) + OFFSET; PREVIOUS_COLOR = COLOR_LIST.get(i - 1); } else { PREVIOUS_FRACTION = FRACTION_LIST.get(MAX_FRACTIONS - 1) + OFFSET; PREVIOUS_COLOR = COLOR_LIST.get(MAX_FRACTIONS - 1); } if (PREVIOUS_FRACTION < 1) { final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, PREVIOUS_COLOR, (int) ((TMP_FRACTION - PREVIOUS_FRACTION) * 10000), (int) (TMP_FRACTION - 1.0f) * 10000); FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR); FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR); } } else { FRACTION_COLORS.put(TMP_FRACTION, TMP_COLOR); } } // Clear the original FRACTION_LIST and COLOR_LIST FRACTION_LIST.clear(); COLOR_LIST.clear(); return FRACTION_COLORS; } /** * With the START_COLOR at the beginning and the DESTINATION_COLOR at the * end of the given RANGE the method will calculate and return the color * that equals the given VALUE. e.g. a START_COLOR of BLACK (R:0, G:0, B:0, * A:255) and a DESTINATION_COLOR of WHITE(R:255, G:255, B:255, A:255) with * a given RANGE of 100 and a given VALUE of 50 will return the color that * is exactly in the middle of the gradient between black and white which is * gray(R:128, G:128, B:128, A:255) So this method is really useful to * calculate colors in gradients between two given colors. * * #param START_COLOR * #param DESTINATION_COLOR * #param RANGE * #param VALUE * #return Color calculated from a range of values by given value */ public java.awt.Color getColorFromFraction(final java.awt.Color START_COLOR, final java.awt.Color DESTINATION_COLOR, final int RANGE, final int VALUE) { final float SOURCE_RED = START_COLOR.getRed() * INT_TO_FLOAT_CONST; final float SOURCE_GREEN = START_COLOR.getGreen() * INT_TO_FLOAT_CONST; final float SOURCE_BLUE = START_COLOR.getBlue() * INT_TO_FLOAT_CONST; final float SOURCE_ALPHA = START_COLOR.getAlpha() * INT_TO_FLOAT_CONST; final float DESTINATION_RED = DESTINATION_COLOR.getRed() * INT_TO_FLOAT_CONST; final float DESTINATION_GREEN = DESTINATION_COLOR.getGreen() * INT_TO_FLOAT_CONST; final float DESTINATION_BLUE = DESTINATION_COLOR.getBlue() * INT_TO_FLOAT_CONST; final float DESTINATION_ALPHA = DESTINATION_COLOR.getAlpha() * INT_TO_FLOAT_CONST; final float RED_DELTA = DESTINATION_RED - SOURCE_RED; final float GREEN_DELTA = DESTINATION_GREEN - SOURCE_GREEN; final float BLUE_DELTA = DESTINATION_BLUE - SOURCE_BLUE; final float ALPHA_DELTA = DESTINATION_ALPHA - SOURCE_ALPHA; final float RED_FRACTION = RED_DELTA / RANGE; final float GREEN_FRACTION = GREEN_DELTA / RANGE; final float BLUE_FRACTION = BLUE_DELTA / RANGE; final float ALPHA_FRACTION = ALPHA_DELTA / RANGE; //System.out.println(DISTANCE + " " + CURRENT_FRACTION); return new java.awt.Color(SOURCE_RED + RED_FRACTION * VALUE, SOURCE_GREEN + GREEN_FRACTION * VALUE, SOURCE_BLUE + BLUE_FRACTION * VALUE, SOURCE_ALPHA + ALPHA_FRACTION * VALUE); } #Override public java.awt.PaintContext createContext(final java.awt.image.ColorModel COLOR_MODEL, final java.awt.Rectangle DEVICE_BOUNDS, final java.awt.geom.Rectangle2D USER_BOUNDS, final java.awt.geom.AffineTransform TRANSFORM, final java.awt.RenderingHints HINTS) { final java.awt.geom.Point2D TRANSFORMED_CENTER = TRANSFORM.transform(CENTER, null); return new ConicalGradientPaintContext(TRANSFORMED_CENTER); } #Override public int getTransparency() { return java.awt.Transparency.TRANSLUCENT; } private final class ConicalGradientPaintContext implements java.awt.PaintContext { final private java.awt.geom.Point2D CENTER; public ConicalGradientPaintContext(final java.awt.geom.Point2D CENTER) { this.CENTER = new java.awt.geom.Point2D.Double(CENTER.getX(), CENTER.getY()); } #Override public void dispose() { } #Override public java.awt.image.ColorModel getColorModel() { return java.awt.image.ColorModel.getRGBdefault(); } #Override public java.awt.image.Raster getRaster(final int X, final int Y, final int TILE_WIDTH, final int TILE_HEIGHT) { final double ROTATION_CENTER_X = -X + CENTER.getX(); final double ROTATION_CENTER_Y = -Y + CENTER.getY(); final int MAX = FRACTION_ANGLES.length; // Create raster for given colormodel final java.awt.image.WritableRaster RASTER = getColorModel().createCompatibleWritableRaster(TILE_WIDTH, TILE_HEIGHT); // Create data array with place for red, green, blue and alpha values int[] data = new int[(TILE_WIDTH * TILE_HEIGHT * 4)]; double dx; double dy; double distance; double angle; double currentRed = 0; double currentGreen = 0; double currentBlue = 0; double currentAlpha = 0; for (int py = 0; py < TILE_HEIGHT; py++) { for (int px = 0; px < TILE_WIDTH; px++) { // Calculate the distance between the current position and the rotation angle dx = px - ROTATION_CENTER_X; dy = py - ROTATION_CENTER_Y; distance = Math.sqrt(dx * dx + dy * dy); // Avoid division by zero if (distance == 0) { distance = 1; } // 0 degree on top angle = Math.abs(Math.toDegrees(Math.acos(dx / distance))); if (dx >= 0 && dy <= 0) { angle = 90.0 - angle; } else if (dx >= 0 && dy >= 0) { angle += 90.0; } else if (dx <= 0 && dy >= 0) { angle += 90.0; } else if (dx <= 0 && dy <= 0) { angle = 450.0 - angle; } // Check for each angle in fractionAngles array for (int i = 0; i < (MAX - 1); i++) { if ((angle >= FRACTION_ANGLES[i])) { currentRed = COLORS[i].getRed() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * RED_STEP_LOOKUP[i]; currentGreen = COLORS[i].getGreen() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * GREEN_STEP_LOOKUP[i]; currentBlue = COLORS[i].getBlue() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * BLUE_STEP_LOOKUP[i]; currentAlpha = COLORS[i].getAlpha() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * ALPHA_STEP_LOOKUP[i]; continue; } } // Fill data array with calculated color values final int BASE = (py * TILE_WIDTH + px) * 4; data[BASE + 0] = (int) (currentRed * 255); data[BASE + 1] = (int) (currentGreen * 255); data[BASE + 2] = (int) (currentBlue * 255); data[BASE + 3] = (int) (currentAlpha * 255); } } // Fill the raster with the data RASTER.setPixels(0, 0, TILE_WIDTH, TILE_HEIGHT, data); return RASTER; } } } }
JNI function gives an error "terminated by signal (2)"
I have a native library which is invoked by the JNI function called from UI. It runs just for a one time, it execute one command and in second run it just exits. I get the following print. D/Zygote ( 111): Process 921 terminated by signal (2) What does signal (2) mean? Can I infer something out of this message as to why the process was terminated? The native library works completely fine with a first execute. My second question is about the accelerometer: package com.example.android.accelerometerplay; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.BitmapFactory.Options; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.util.DisplayMetrics; import android.view.Display; import android.view.Surface; import android.view.View; import android.view.WindowManager; /** * This is an example of using the accelerometer to integrate the device's * acceleration to a position using the Verlet method. This is illustrated with * a very simple particle system comprised of a few iron balls freely moving on * an inclined wooden table. The inclination of the virtual table is controlled * by the device's accelerometer. * * #see SensorManager * #see SensorEvent * #see Sensor */ public class AccelerometerPlayActivity extends Activity { private SimulationView mSimulationView; private SensorManager mSensorManager; private PowerManager mPowerManager; private WindowManager mWindowManager; private Display mDisplay; private WakeLock mWakeLock; /** Called when the activity is first created. */ #Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get an instance of the SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); // Get an instance of the PowerManager mPowerManager = (PowerManager) getSystemService(POWER_SERVICE); // Get an instance of the WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mDisplay = mWindowManager.getDefaultDisplay(); // Create a bright wake lock mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass() .getName()); // instantiate our simulation view and set it as the activity's content mSimulationView = new SimulationView(this); setContentView(mSimulationView); } #Override protected void onResume() { super.onResume(); /* * when the activity is resumed, we acquire a wake-lock so that the * screen stays on, since the user will likely not be fiddling with the * screen or buttons. */ mWakeLock.acquire(); // Start the simulation mSimulationView.startSimulation(); } #Override protected void onPause() { super.onPause(); /* * When the activity is paused, we make sure to stop the simulation, * release our sensor resources and wake locks */ // Stop the simulation mSimulationView.stopSimulation(); // and release our wake-lock mWakeLock.release(); } class SimulationView extends View implements SensorEventListener { // diameter of the balls in meters private static final float sBallDiameter = 0.004f; private static final float sBallDiameter2 = sBallDiameter * sBallDiameter; // friction of the virtual table and air private static final float sFriction = 0.1f; private Sensor mAccelerometer; private long mLastT; private float mLastDeltaT; private float mXDpi; private float mYDpi; private float mMetersToPixelsX; private float mMetersToPixelsY; private Bitmap mBitmap; private Bitmap mWood; private float mXOrigin; private float mYOrigin; private float mSensorX; private float mSensorY; private long mSensorTimeStamp; private long mCpuTimeStamp; private float mHorizontalBound; private float mVerticalBound; private final ParticleSystem mParticleSystem = new ParticleSystem(); /* * Each of our particle holds its previous and current position, its * acceleration. for added realism each particle has its own friction * coefficient. */ class Particle { private float mPosX; private float mPosY; private float mAccelX; private float mAccelY; private float mLastPosX; private float mLastPosY; private float mOneMinusFriction; Particle() { // make each particle a bit different by randomizing its // coefficient of friction final float r = ((float) Math.random() - 0.5f) * 0.2f; mOneMinusFriction = 1.0f - sFriction + r; } public void computePhysics(float sx, float sy, float dT, float dTC) { // Force of gravity applied to our virtual object final float m = 1000.0f; // mass of our virtual object final float gx = -sx * m; final float gy = -sy * m; /* * ·F = mA <=> A = ·F / m We could simplify the code by * completely eliminating "m" (the mass) from all the equations, * but it would hide the concepts from this sample code. */ final float invm = 1.0f / m; final float ax = gx * invm; final float ay = gy * invm; /* * Time-corrected Verlet integration The position Verlet * integrator is defined as x(t+Æt) = x(t) + x(t) - x(t-Æt) + * a(t)Ætö2 However, the above equation doesn't handle variable * Æt very well, a time-corrected version is needed: x(t+Æt) = * x(t) + (x(t) - x(t-Æt)) * (Æt/Æt_prev) + a(t)Ætö2 We also add * a simple friction term (f) to the equation: x(t+Æt) = x(t) + * (1-f) * (x(t) - x(t-Æt)) * (Æt/Æt_prev) + a(t)Ætö2 */ final float dTdT = dT * dT; final float x = mPosX + mOneMinusFriction * dTC * (mPosX - mLastPosX) + mAccelX * dTdT; final float y = mPosY + mOneMinusFriction * dTC * (mPosY - mLastPosY) + mAccelY * dTdT; mLastPosX = mPosX; mLastPosY = mPosY; mPosX = x; mPosY = y; mAccelX = ax; mAccelY = ay; } /* * Resolving constraints and collisions with the Verlet integrator * can be very simple, we simply need to move a colliding or * constrained particle in such way that the constraint is * satisfied. */ public void resolveCollisionWithBounds() { final float xmax = mHorizontalBound; final float ymax = mVerticalBound; final float x = mPosX; final float y = mPosY; if (x > xmax) { mPosX = xmax; } else if (x < -xmax) { mPosX = -xmax; } if (y > ymax) { mPosY = ymax; } else if (y < -ymax) { mPosY = -ymax; } } } /* * A particle system is just a collection of particles */ class ParticleSystem { static final int NUM_PARTICLES = 15; private Particle mBalls[] = new Particle[NUM_PARTICLES]; ParticleSystem() { /* * Initially our particles have no speed or acceleration */ for (int i = 0; i < mBalls.length; i++) { mBalls[i] = new Particle(); } } /* * Update the position of each particle in the system using the * Verlet integrator. */ private void updatePositions(float sx, float sy, long timestamp) { final long t = timestamp; if (mLastT != 0) { final float dT = (float) (t - mLastT) * (1.0f / 1000000000.0f); if (mLastDeltaT != 0) { final float dTC = dT / mLastDeltaT; final int count = mBalls.length; for (int i = 0; i < count; i++) { Particle ball = mBalls[i]; ball.computePhysics(sx, sy, dT, dTC); } } mLastDeltaT = dT; } mLastT = t; } /* * Performs one iteration of the simulation. First updating the * position of all the particles and resolving the constraints and * collisions. */ public void update(float sx, float sy, long now) { // update the system's positions updatePositions(sx, sy, now); // We do no more than a limited number of iterations final int NUM_MAX_ITERATIONS = 10; /* * Resolve collisions, each particle is tested against every * other particle for collision. If a collision is detected the * particle is moved away using a virtual spring of infinite * stiffness. */ boolean more = true; final int count = mBalls.length; for (int k = 0; k < NUM_MAX_ITERATIONS && more; k++) { more = false; for (int i = 0; i < count; i++) { Particle curr = mBalls[i]; for (int j = i + 1; j < count; j++) { Particle ball = mBalls[j]; float dx = ball.mPosX - curr.mPosX; float dy = ball.mPosY - curr.mPosY; float dd = dx * dx + dy * dy; // Check for collisions if (dd <= sBallDiameter2) { /* * add a little bit of entropy, after nothing is * perfect in the universe. */ dx += ((float) Math.random() - 0.5f) * 0.0001f; dy += ((float) Math.random() - 0.5f) * 0.0001f; dd = dx * dx + dy * dy; // simulate the spring final float d = (float) Math.sqrt(dd); final float c = (0.5f * (sBallDiameter - d)) / d; curr.mPosX -= dx * c; curr.mPosY -= dy * c; ball.mPosX += dx * c; ball.mPosY += dy * c; more = true; } } /* * Finally make sure the particle doesn't intersects * with the walls. */ curr.resolveCollisionWithBounds(); } } } public int getParticleCount() { return mBalls.length; } public float getPosX(int i) { return mBalls[i].mPosX; } public float getPosY(int i) { return mBalls[i].mPosY; } } public void startSimulation() { /* * It is not necessary to get accelerometer events at a very high * rate, by using a slower rate (SENSOR_DELAY_UI), we get an * automatic low-pass filter, which "extracts" the gravity component * of the acceleration. As an added benefit, we use less power and * CPU resources. */ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_UI); } public void stopSimulation() { mSensorManager.unregisterListener(this); } public SimulationView(Context context) { super(context); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); mXDpi = metrics.xdpi; mYDpi = metrics.ydpi; mMetersToPixelsX = mXDpi / 0.0254f; mMetersToPixelsY = mYDpi / 0.0254f; // rescale the ball so it's about 0.5 cm on screen Bitmap ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball); final int dstWidth = (int) (sBallDiameter * mMetersToPixelsX + 0.5f); final int dstHeight = (int) (sBallDiameter * mMetersToPixelsY + 0.5f); mBitmap = Bitmap.createScaledBitmap(ball, dstWidth, dstHeight, true); Options opts = new Options(); opts.inDither = true; opts.inPreferredConfig = Bitmap.Config.RGB_565; mWood = BitmapFactory.decodeResource(getResources(), R.drawable.wood, opts); } #Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // compute the origin of the screen relative to the origin of // the bitmap mXOrigin = (w - mBitmap.getWidth()) * 0.5f; mYOrigin = (h - mBitmap.getHeight()) * 0.5f; mHorizontalBound = ((w / mMetersToPixelsX - sBallDiameter) * 0.5f); mVerticalBound = ((h / mMetersToPixelsY - sBallDiameter) * 0.5f); } #Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) return; /* * record the accelerometer data, the event's timestamp as well as * the current time. The latter is needed so we can calculate the * "present" time during rendering. In this application, we need to * take into account how the screen is rotated with respect to the * sensors (which always return data in a coordinate space aligned * to with the screen in its native orientation). */ switch (mDisplay.getRotation()) { case Surface.ROTATION_0: mSensorX = event.values[0]; mSensorY = event.values[1]; break; case Surface.ROTATION_90: mSensorX = -event.values[1]; mSensorY = event.values[0]; break; case Surface.ROTATION_180: mSensorX = -event.values[0]; mSensorY = -event.values[1]; break; case Surface.ROTATION_270: mSensorX = event.values[1]; mSensorY = -event.values[0]; break; } mSensorTimeStamp = event.timestamp; mCpuTimeStamp = System.nanoTime(); } #Override protected void onDraw(Canvas canvas) { /* * draw the background */ canvas.drawBitmap(mWood, 0, 0, null); /* * compute the new position of our object, based on accelerometer * data and present time. */ final ParticleSystem particleSystem = mParticleSystem; final long now = mSensorTimeStamp + (System.nanoTime() - mCpuTimeStamp); final float sx = mSensorX; final float sy = mSensorY; particleSystem.update(sx, sy, now); final float xc = mXOrigin; final float yc = mYOrigin; final float xs = mMetersToPixelsX; final float ys = mMetersToPixelsY; final Bitmap bitmap = mBitmap; final int count = particleSystem.getParticleCount(); for (int i = 0; i < count; i++) { /* * We transform the canvas so that the coordinate system matches * the sensors coordinate system with the origin in the center * of the screen and the unit is the meter. */ final float x = xc + particleSystem.getPosX(i) * xs; final float y = yc - particleSystem.getPosY(i) * ys; canvas.drawBitmap(bitmap, x, y, null); } // and make sure to redraw asap invalidate(); } #Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } } } How to move ball?
2 is SIGINT (Interrupt), you can check it in header file within your ndk directory