Created
February 11, 2021 07:56
-
-
Save rajsuvariya/6b99ba4575b74f525ec7dd7948d01af4 to your computer and use it in GitHub Desktop.
A trepezoid view which provides curv functionality when dragged from top middle position
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.Matrix; | |
import android.graphics.Paint; | |
import android.graphics.Path; | |
import android.graphics.Point; | |
import android.graphics.PorterDuff; | |
import android.graphics.PorterDuffXfermode; | |
import android.graphics.Rect; | |
import android.graphics.Region; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.View; | |
public class TrepezoidView extends View implements View.OnTouchListener { | |
private Paint paintRect, paintCircle; | |
public int LEFT; | |
public int TOP; | |
public int RIGHT; | |
public int BOTTOM; | |
Point CIRCLE_TOP_LEFT; | |
Point CIRCLE_TOP_RIGHT; | |
Point CIRCLE_BOTTOM_LEFT; | |
Point CIRCLE_BOTTOM_RIGHT; | |
private int lastX, lastY; | |
private int dragX, dragY; | |
private int curveX = -1, curveY = -1; | |
Bitmap image; | |
Matrix matrix2; | |
boolean isTouchCirclePoints = true; | |
private boolean isInEdit = true; | |
Paint mPaint; | |
int displayWidth; | |
private Rect dst_curve = new Rect(); | |
private Rect dst_resize_left = new Rect(); | |
private Rect dst_resize_right = new Rect(); | |
private Rect dst_resize_bottom = new Rect(); | |
private Rect dst_corner_top_left = new Rect(); | |
private Rect dst_corner_top_right = new Rect(); | |
private Rect dst_corner_bottom_left = new Rect(); | |
private Rect dst_corner_bottom_right = new Rect(); | |
private boolean isBeingDragged = true; | |
private PorterDuffXfermode porterDuffXfermode; | |
private final int CIRCLE_RADIUS = 20; | |
private int TOUCH_CIRCLE_RADIUS = 60; | |
private Bitmap curveBitmap; | |
private Bitmap resizeHorizontalBitmap; | |
private Bitmap resizeVerticalBitmap; | |
private Bitmap cornerBitmap; | |
public TrepezoidView(Context context) { | |
super(context); | |
// TODO Auto-generated constructor stub | |
init(); | |
} | |
public TrepezoidView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
// TODO Auto-generated constructor stub | |
init(); | |
} | |
public TrepezoidView(Context context, AttributeSet attrs, | |
int defStyle) { | |
super(context, attrs, defStyle); | |
// TODO Auto-generated constructor stub | |
init(); | |
} | |
private void init() { | |
this.setOnTouchListener(this); | |
paintRect = new Paint(); | |
paintRect.setColor(0xffff0000); | |
paintRect.setAntiAlias(true); | |
paintRect.setDither(true); | |
paintRect.setStyle(Paint.Style.STROKE); | |
paintRect.setStrokeJoin(Paint.Join.BEVEL); | |
paintRect.setStrokeCap(Paint.Cap.BUTT); | |
paintRect.setStrokeWidth(3); | |
paintRect = new Paint(); | |
paintRect.setColor(0xffff0000); | |
paintRect.setAntiAlias(true); | |
paintRect.setDither(true); | |
paintRect.setStyle(Paint.Style.STROKE); | |
paintRect.setStrokeJoin(Paint.Join.BEVEL); | |
paintRect.setStrokeCap(Paint.Cap.BUTT); | |
paintRect.setStrokeWidth(10); | |
paintCircle = new Paint(); | |
paintCircle.setColor(0xff0000ff); | |
paintCircle.setAntiAlias(true); | |
paintCircle.setDither(true); | |
paintCircle.setStyle(Paint.Style.FILL_AND_STROKE); | |
paintCircle.setStrokeJoin(Paint.Join.BEVEL); | |
paintCircle.setStrokeCap(Paint.Cap.BUTT); | |
mPaint = new Paint(); | |
LEFT = 0; | |
TOP = 0; | |
RIGHT = 440; | |
BOTTOM = 520; | |
CIRCLE_TOP_LEFT = new Point(LEFT, TOP); | |
CIRCLE_TOP_RIGHT = new Point(RIGHT, TOP); | |
CIRCLE_BOTTOM_LEFT = new Point(LEFT, BOTTOM); | |
CIRCLE_BOTTOM_RIGHT = new Point(RIGHT, BOTTOM); | |
curveBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_curve); | |
resizeHorizontalBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_double_arrow); | |
resizeVerticalBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_double_arrow_verticle); | |
cornerBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_corner); | |
matrix2 = new Matrix(); | |
} | |
public void setImageRes(int resId) { | |
image = BitmapFactory.decodeResource(getResources(), resId); | |
invalidate(); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
displayWidth = getContext().getResources().getDisplayMetrics().widthPixels; | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
setLayerType(View.LAYER_TYPE_SOFTWARE, null); | |
// Free Transform bitmap | |
int bw = image.getWidth(); | |
int bh = image.getHeight(); | |
float[] pts = { | |
// source | |
0, 0, | |
0, bh, | |
bw, bh, | |
bw, 0, | |
// destination | |
0, 0, | |
0, 0, | |
0, 0, | |
0, 0}; | |
pts[8] = CIRCLE_TOP_LEFT.x; | |
pts[9] = CIRCLE_TOP_LEFT.y; | |
pts[10] = CIRCLE_BOTTOM_LEFT.x; | |
pts[11] = CIRCLE_BOTTOM_LEFT.y; | |
pts[12] = CIRCLE_BOTTOM_RIGHT.x; | |
pts[13] = CIRCLE_BOTTOM_RIGHT.y; | |
pts[14] = CIRCLE_TOP_RIGHT.x; | |
pts[15] = CIRCLE_TOP_RIGHT.y; | |
matrix2.setPolyToPoly(pts, 0, pts, 8, 4); | |
isTouchCirclePoints = false; | |
canvas.drawBitmap(image, matrix2, null); | |
porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT); | |
mPaint.setXfermode(porterDuffXfermode); | |
mPaint.setColor(Color.TRANSPARENT); | |
Path oval = new Path(); | |
oval.setFillType(Path.FillType.INVERSE_EVEN_ODD); | |
int left = CIRCLE_TOP_LEFT.x; | |
int top = CIRCLE_TOP_LEFT.y; | |
int right = CIRCLE_TOP_RIGHT.x; | |
int bottom = (top + (curveY - CIRCLE_TOP_LEFT.y)); | |
oval.addOval(left, top, right, bottom, Path.Direction.CW); | |
Region region = new Region(); | |
region.setPath(oval, new Region(0, 0, displayWidth, top + (curveY - CIRCLE_TOP_LEFT.y) / 2)); | |
canvas.drawPath(region.getBoundaryPath(), mPaint); | |
dst_curve.left = (int) ((CIRCLE_TOP_LEFT.x + CIRCLE_TOP_RIGHT.x) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_curve.right = (int) ((CIRCLE_TOP_LEFT.x + CIRCLE_TOP_RIGHT.x) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_curve.top = (int) ((CIRCLE_TOP_LEFT.y + CIRCLE_TOP_RIGHT.y) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_curve.bottom = (int) ((CIRCLE_TOP_LEFT.y + CIRCLE_TOP_RIGHT.y) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_resize_left.left = (int) ((CIRCLE_TOP_LEFT.x + CIRCLE_BOTTOM_LEFT.x) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_resize_left.right = (int) ((CIRCLE_TOP_LEFT.x + CIRCLE_BOTTOM_LEFT.x) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_resize_left.top = (int) ((CIRCLE_TOP_LEFT.y + CIRCLE_BOTTOM_LEFT.y) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_resize_left.bottom = (int) ((CIRCLE_TOP_LEFT.y + CIRCLE_BOTTOM_LEFT.y) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_resize_right.left = (int) ((CIRCLE_TOP_RIGHT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_resize_right.right = (int) ((CIRCLE_TOP_RIGHT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_resize_right.top = (int) ((CIRCLE_TOP_RIGHT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_resize_right.bottom = (int) ((CIRCLE_TOP_RIGHT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_resize_bottom.left = (int) ((CIRCLE_BOTTOM_LEFT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_resize_bottom.right = (int) ((CIRCLE_BOTTOM_LEFT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_resize_bottom.top = (int) ((CIRCLE_BOTTOM_LEFT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f - TOUCH_CIRCLE_RADIUS); | |
dst_resize_bottom.bottom = (int) ((CIRCLE_BOTTOM_LEFT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f + TOUCH_CIRCLE_RADIUS); | |
dst_corner_top_left.left = CIRCLE_TOP_LEFT.x - TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_left.right = CIRCLE_TOP_LEFT.x + TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_left.top = CIRCLE_TOP_LEFT.y - TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_left.bottom = CIRCLE_TOP_LEFT.y + TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_right.left = CIRCLE_TOP_RIGHT.x - TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_right.right = CIRCLE_TOP_RIGHT.x + TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_right.top = CIRCLE_TOP_RIGHT.y - TOUCH_CIRCLE_RADIUS; | |
dst_corner_top_right.bottom = CIRCLE_TOP_RIGHT.y + TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_left.left = CIRCLE_BOTTOM_LEFT.x - TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_left.right = CIRCLE_BOTTOM_LEFT.x + TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_left.top = CIRCLE_BOTTOM_LEFT.y - TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_left.bottom = CIRCLE_BOTTOM_LEFT.y + TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_right.left = CIRCLE_BOTTOM_RIGHT.x - TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_right.right = CIRCLE_BOTTOM_RIGHT.x + TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_right.top = CIRCLE_BOTTOM_RIGHT.y - TOUCH_CIRCLE_RADIUS; | |
dst_corner_bottom_right.bottom = CIRCLE_BOTTOM_RIGHT.y + TOUCH_CIRCLE_RADIUS; | |
if (isInEdit) { | |
// line left | |
canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, paintRect); | |
// line top | |
canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, paintRect); | |
// line right | |
canvas.drawLine(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect); | |
// line bottom | |
canvas.drawLine(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect); | |
// circle top left | |
canvas.drawBitmap(cornerBitmap, null, dst_corner_top_left, null); | |
// circle top right | |
canvas.drawBitmap(cornerBitmap, null, dst_corner_top_right, null); | |
// circle bottom left | |
canvas.drawBitmap(cornerBitmap, null, dst_corner_bottom_left, null); | |
// circle bottom right | |
canvas.drawBitmap(cornerBitmap, null, dst_corner_bottom_right, null); | |
// horizontal stretch left | |
canvas.drawBitmap(resizeHorizontalBitmap, null, dst_resize_left, null); | |
// horizontal stretch right | |
canvas.drawBitmap(resizeHorizontalBitmap, null, dst_resize_right, null); | |
// curve top | |
canvas.drawBitmap(curveBitmap, null, dst_curve, null); | |
// vertical stretch bottom | |
canvas.drawBitmap(resizeVerticalBitmap, null, dst_resize_bottom, null); | |
} | |
super.onDraw(canvas); | |
} | |
@Override | |
public boolean onTouch(View view, MotionEvent event) { | |
boolean handled = true; | |
switch (event.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
if (isInCircle(event, CIRCLE_TOP_LEFT, TOUCH_CIRCLE_RADIUS) || | |
isInCircle(event, CIRCLE_TOP_RIGHT, TOUCH_CIRCLE_RADIUS) || | |
isInCircle(event, CIRCLE_BOTTOM_LEFT, TOUCH_CIRCLE_RADIUS) || | |
isInCircle(event, CIRCLE_BOTTOM_RIGHT, TOUCH_CIRCLE_RADIUS) || | |
inCircle(event.getX(), event.getY(), (CIRCLE_TOP_LEFT.x + CIRCLE_BOTTOM_LEFT.x) / 2f, (CIRCLE_TOP_LEFT.y + CIRCLE_BOTTOM_LEFT.y) / 2f, TOUCH_CIRCLE_RADIUS) || | |
inCircle(event.getX(), event.getY(), (CIRCLE_TOP_RIGHT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f, (CIRCLE_TOP_RIGHT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f, TOUCH_CIRCLE_RADIUS) || | |
inCircle(event.getX(), event.getY(), (CIRCLE_BOTTOM_LEFT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f, (CIRCLE_BOTTOM_LEFT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f, TOUCH_CIRCLE_RADIUS)) { | |
isBeingDragged = false; | |
} else if (inCircle(event.getX(), event.getY(), (CIRCLE_TOP_LEFT.x + CIRCLE_TOP_RIGHT.x) / 2f, (CIRCLE_TOP_LEFT.y + CIRCLE_TOP_RIGHT.y) / 2f, TOUCH_CIRCLE_RADIUS)) { | |
if (curveX == -1) { | |
curveX = (int) event.getX(); | |
} | |
if (curveY == -1) { | |
curveY = (int) event.getY(); | |
} | |
isBeingDragged = false; | |
} else if (isInBitmap(event)) { | |
dragX = (int) event.getX(); | |
dragY = (int) event.getY(); | |
isBeingDragged = true; | |
} else { | |
handled = false; | |
} | |
break; | |
case MotionEvent.ACTION_MOVE: | |
lastX = (int) event.getX(); | |
lastY = (int) event.getY(); | |
if (inCircle(lastX, lastY, CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
CIRCLE_TOP_LEFT.set(lastX, lastY); | |
} else if (inCircle(lastX, lastY, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
CIRCLE_TOP_RIGHT.set(lastX, lastY); | |
} else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
CIRCLE_BOTTOM_LEFT.set(lastX, lastY); | |
} else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
CIRCLE_BOTTOM_RIGHT.set(lastX, lastY); | |
} else if (inCircle(lastX, lastY, (CIRCLE_TOP_LEFT.x + CIRCLE_BOTTOM_LEFT.x) / 2f, (CIRCLE_TOP_LEFT.y + CIRCLE_BOTTOM_LEFT.y) / 2f, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
int diff = (int) (lastX - (CIRCLE_TOP_LEFT.x + CIRCLE_BOTTOM_LEFT.x) / 2f); | |
CIRCLE_TOP_LEFT.set(CIRCLE_TOP_LEFT.x + diff, CIRCLE_TOP_LEFT.y); | |
CIRCLE_BOTTOM_LEFT.set(CIRCLE_BOTTOM_LEFT.x + diff, CIRCLE_BOTTOM_LEFT.y); | |
} else if (inCircle(lastX, lastY, (CIRCLE_TOP_RIGHT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f, (CIRCLE_TOP_RIGHT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
int diff = (int) (lastX - (CIRCLE_TOP_RIGHT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f); | |
CIRCLE_TOP_RIGHT.set(CIRCLE_TOP_RIGHT.x + diff, CIRCLE_TOP_RIGHT.y); | |
CIRCLE_BOTTOM_RIGHT.set(CIRCLE_BOTTOM_RIGHT.x + diff, CIRCLE_BOTTOM_RIGHT.y); | |
} else if (inCircle(lastX, lastY, (CIRCLE_TOP_LEFT.x + CIRCLE_TOP_RIGHT.x) / 2f, (CIRCLE_TOP_LEFT.y + CIRCLE_TOP_RIGHT.y) / 2f, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
int diff = (int) (lastY - (CIRCLE_TOP_LEFT.y + CIRCLE_TOP_RIGHT.y) / 2f); | |
CIRCLE_TOP_RIGHT.set(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y + diff); | |
CIRCLE_TOP_LEFT.set(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y + diff); | |
} else if (inCircle(lastX, lastY, (CIRCLE_BOTTOM_LEFT.x + CIRCLE_BOTTOM_RIGHT.x) / 2f, (CIRCLE_BOTTOM_LEFT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f, TOUCH_CIRCLE_RADIUS)) { | |
isTouchCirclePoints = true; | |
int diff = (int) (lastY - (CIRCLE_BOTTOM_LEFT.y + CIRCLE_BOTTOM_RIGHT.y) / 2f); | |
CIRCLE_BOTTOM_RIGHT.set(CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y + diff); | |
CIRCLE_BOTTOM_LEFT.set(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y + diff); | |
} else if (isBeingDragged) { | |
int dragXDist = (int) (event.getX() - dragX); | |
int dragYDist = (int) (event.getY() - dragY); | |
dragX = (int) event.getX(); | |
dragY = (int) event.getY(); | |
curveX += dragXDist; | |
curveY += dragYDist; | |
CIRCLE_TOP_LEFT.x += dragXDist; | |
CIRCLE_TOP_LEFT.y += dragYDist; | |
CIRCLE_TOP_RIGHT.x += dragXDist; | |
CIRCLE_TOP_RIGHT.y += dragYDist; | |
CIRCLE_BOTTOM_LEFT.x += dragXDist; | |
CIRCLE_BOTTOM_LEFT.y += dragYDist; | |
CIRCLE_BOTTOM_RIGHT.x += dragXDist; | |
CIRCLE_BOTTOM_RIGHT.y += dragYDist; | |
} | |
invalidate(); | |
break; | |
} | |
return handled && isInEdit; | |
} | |
public void setInEdit(boolean isInEdit) { | |
this.isInEdit = isInEdit; | |
invalidate(); | |
} | |
private boolean isInCircle(MotionEvent event, Point circle, float circleRadius) { | |
return inCircle(event.getX(), event.getY(), circle.x, circle.y, circleRadius); | |
} | |
private boolean inCircle(float x, float y, float circleCenterX, float circleCenterY, float circleRadius) { | |
double dx = Math.pow(x - circleCenterX, 2); | |
double dy = Math.pow(y - circleCenterY, 2); | |
if ((dx + dy) < Math.pow(circleRadius, 2)) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
private boolean isInBitmap(MotionEvent event) { | |
Point[] points = {CIRCLE_TOP_LEFT, CIRCLE_TOP_RIGHT, CIRCLE_BOTTOM_RIGHT, CIRCLE_BOTTOM_LEFT}; | |
return isInside(points, 4, new Point((int) event.getX(), (int) event.getY())); | |
} | |
// Define Infinite (Using INT_MAX | |
// caused overflow problems) | |
static int INF = 10000; | |
// Given three colinear points p, q, r, | |
// the function checks if point q lies | |
// on line segment 'pr' | |
static boolean onSegment(Point p, Point q, Point r) { | |
if (q.x <= Math.max(p.x, r.x) && | |
q.x >= Math.min(p.x, r.x) && | |
q.y <= Math.max(p.y, r.y) && | |
q.y >= Math.min(p.y, r.y)) { | |
return true; | |
} | |
return false; | |
} | |
// 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 | |
static int orientation(Point p, Point q, Point r) { | |
int val = (q.y - p.y) * (r.x - q.x) | |
- (q.x - p.x) * (r.y - q.y); | |
if (val == 0) { | |
return 0; // colinear | |
} | |
return (val > 0) ? 1 : 2; // clock or counterclock wise | |
} | |
// The function that returns true if | |
// line segment 'p1q1' and 'p2q2' intersect. | |
static boolean doIntersect(Point p1, Point q1, | |
Point p2, Point q2) { | |
// Find the four orientations needed for | |
// general and special cases | |
int o1 = orientation(p1, q1, p2); | |
int o2 = orientation(p1, q1, q2); | |
int o3 = orientation(p2, q2, p1); | |
int o4 = orientation(p2, q2, q1); | |
// General case | |
if (o1 != o2 && o3 != o4) { | |
return true; | |
} | |
// Special Cases | |
// p1, q1 and p2 are colinear and | |
// p2 lies on segment p1q1 | |
if (o1 == 0 && onSegment(p1, p2, q1)) { | |
return true; | |
} | |
// p1, q1 and p2 are colinear and | |
// q2 lies on segment p1q1 | |
if (o2 == 0 && onSegment(p1, q2, q1)) { | |
return true; | |
} | |
// p2, q2 and p1 are colinear and | |
// p1 lies on segment p2q2 | |
if (o3 == 0 && onSegment(p2, p1, q2)) { | |
return true; | |
} | |
// p2, q2 and q1 are colinear and | |
// q1 lies on segment p2q2 | |
if (o4 == 0 && onSegment(p2, q1, q2)) { | |
return true; | |
} | |
// Doesn't fall in any of the above cases | |
return false; | |
} | |
// Returns true if the point p lies | |
// inside the polygon[] with n vertices | |
static boolean isInside(Point polygon[], int n, Point p) { | |
// There must be at least 3 vertices in polygon[] | |
if (n < 3) { | |
return false; | |
} | |
// Create a point for line segment from p to infinite | |
Point extreme = new Point(INF, p.y); | |
// Count intersections of the above line | |
// with sides of polygon | |
int count = 0, i = 0; | |
do { | |
int next = (i + 1) % n; | |
// Check if the line segment from 'p' to | |
// 'extreme' intersects with the line | |
// segment from 'polygon[i]' to 'polygon[next]' | |
if (doIntersect(polygon[i], polygon[next], p, extreme)) { | |
// If the point 'p' is colinear with line | |
// segment 'i-next', then check if it lies | |
// on segment. If it lies, return true, otherwise false | |
if (orientation(polygon[i], p, polygon[next]) == 0) { | |
return onSegment(polygon[i], p, | |
polygon[next]); | |
} | |
count++; | |
} | |
i = next; | |
} while (i != 0); | |
// Return true if count is odd, false otherwise | |
return (count % 2 == 1); // Same as (count%2 == 1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment