How to draw Arc between two points on the Canvas?
Finally I got the solution from this code:
float radius = 20;
final RectF oval = new RectF();
oval.set(point1.x - radius, point1.y - radius, point1.x + radius, point1.y+ radius);
Path myPath = new Path();
myPath.arcTo(oval, startAngle, -(float) sweepAngle, true);
To calculate startAngle
, use this code:
int startAngle = (int) (180 / Math.PI * Math.atan2(point.y - point1.y, point.x - point1.x));
Here, point1
means where you want to start drawing the Arc. sweepAngle
means the angle between two lines. We have to calculate that by using two points like the blue points in my Question image.
Draw arc on canvas from two x, y points and a center x, y point
The arc()
method works only with angles so points has to be converted based on their location and distance to center (distance, representing the radius, has to be the same for both in this case).
The signature of arc() is:
void arc(unrestricted double x,
unrestricted double y,
unrestricted double radius,
unrestricted double startAngle,
unrestricted double endAngle,
optional boolean anticlockwise = false);
You can find the two angles from center P2 to P1/P3 by simple trigonometry:
var startAngle = Math.atan2(p1.y - p2.y, p1.x - p2.x),
endAngle = Math.atan2(p3.y - p2.y, p3.x - p2.x);
These can now be fed into the arc method assuming radius is known:
ctx.arc(p2.x, p2.y, radius, startAngle, endAngle);
If radius is unknown but known to be the same you can do:
var diffX = p1.x - p2.x,
diffY = p1.y - p2.y,
radius = Math.abs(Math.sqrt(diffX*diffX + diffY*diffY));
Example
var p2 = {x: 100 , y: 100 }, p1 = {x: 111, y: 30.9}, p3 = {x: 149.5 , y: 149.5}, diffX = p1.x - p2.x, diffY = p1.y - p2.y, radius = Math.abs(Math.sqrt(diffX*diffX + diffY*diffY)), startAngle = Math.atan2(diffY, diffX), endAngle = Math.atan2(p3.y - p2.y, p3.x - p2.x), ctx = document.querySelector("canvas").getContext("2d");
// arcctx.arc(p2.x, p2.y, radius, startAngle, endAngle, false);ctx.stroke();
// points / lines helpers:ctx.fillRect(p1.x - 2, p1.y - 2, 4, 4);ctx.fillRect(p2.x - 2, p2.y - 2, 4, 4);ctx.fillRect(p3.x - 2, p3.y - 2, 4, 4);ctx.beginPath();ctx.moveTo(p1.x, p1.y);ctx.lineTo(p2.x, p2.x);ctx.lineTo(p3.x, p3.x);ctx.strokeStyle = "#999";ctx.stroke();
<canvas height=180></canvas>
HTML Canvas draw arc between two points
I've commented out the line you don't want. By calling closePath()
, you are closing the path of your arc.
Example
JavaScript
ctx.strokeStyle='rgb(0,250,0)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.arc(100,100,45,0,Math.PI/2,true); //use 1/4 of original angle
//ctx.closePath();
ctx.stroke();
jsFiddle.
Is there a convenient way to draw arc only using two points and curve radius in Android?
Probably there is no easier way. All what can do would be to refine your solution by geometrical approach. Since the center of circle is always on the perpendicular bisector of the chord, it's not required to solve so generalized equations.
By the way, it's not clear how you defined Clockwise/Counter-clockwise. Arc's winding direction should be determined independently of node-placements (=A, B's coordinates).
As is shown in the figure below, on the straight path from A to B, the center O is to be placed righthandside(CW) or lefthandside(CCW). That's all.
And, some more aspects to be altered:
- It's better to calculate startAngle by atan2(). Because acos() has singularity at some points.
- It's also possible to calculate sweepAngle with asin().
After all the code can be slightly simplified as follows.
@Throws(Exception::class)
private fun Path.arcFromTo2(
x1: Float, y1: Float, x2: Float, y2: Float, r: Float,
clockwise: Boolean = true
) {
val d = PointF((x2 - x1) * 0.5F, (y2 - y1) * 0.5F)
val a = d.length()
if (a > r) throw Exception()
val side = if (clockwise) 1 else -1
val oc = sqrt(r * r - a * a)
val ox = (x1 + x2) * 0.5F - side * oc * d.y / a
val oy = (y1 + y2) * 0.5F + side * oc * d.x / a
val startAngle = atan2(y1 - oy, x1 - ox) * 180F / Math.PI.toFloat()
val sweepAngle = side * 2.0F * asin(a / r) * 180F / Math.PI.toFloat()
arcTo(
ox - r, oy - r, ox + r, oy + r,
startAngle, sweepAngle,
false
)
}
How to draw a curved line between 2 points on canvas?
I found a solution to my problem myself. Even though there were some great answers, they weren't an exact solution to my particular problem.
Here is what I did:
- Found the point in between the 2 given points
- Calculated the angle 90 degrees between the 2 points
- Calculated the point X pixels from the middle point using the calculated degree from before.
- Used "path.cubicTo" with these 3 points (Takes both negative and positive values to determine which way the line should curve).
Here is my code if anyone else should run into the same problem:
public OverlayBuilder drawCurvedArrow(int x1, int y1, int x2, int y2, int curveRadius, int color, int lineWidth) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(lineWidth);
paint.setColor(ContextCompat.getColor(context, color));
final Path path = new Path();
int midX = x1 + ((x2 - x1) / 2);
int midY = y1 + ((y2 - y1) / 2);
float xDiff = midX - x1;
float yDiff = midY - y1;
double angle = (Math.atan2(yDiff, xDiff) * (180 / Math.PI)) - 90;
double angleRadians = Math.toRadians(angle);
float pointX = (float) (midX + curveRadius * Math.cos(angleRadians));
float pointY = (float) (midY + curveRadius * Math.sin(angleRadians));
path.moveTo(x1, y1);
path.cubicTo(x1,y1,pointX, pointY, x2, y2);
canvas.drawPath(path, paint);
return this;
}
And here is an example of how the implementation looks like:
Draw an arc between two points on a tkinter canvas
There is a start
option for creating the arc, which define where to start the drawing in giving angle. Using this and some math you can use the create_arc
-method to draw an arc for any position:
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.canvas = tk.Canvas(width=400, height=400)
self.canvas.pack(fill="both", expand=True)
self._create_token((100, 100), "white")
self._create_token((200, 300), "pink")
self._create_arc((100,100), (200, 300))
def _create_token(self, coord, color):
'''Create a token at the given coordinate in the given color'''
(x,y) = coord
self.canvas.create_oval(x-5, y-5, x+5, y+5,
outline=color, fill=color, tags="token")
def _create_arc(self, p0, p1):
extend_x = (self._distance(p0,p1) -(p1[0]-p0[0]))/2 # extend x boundary
extend_y = (self._distance(p0,p1) -(p1[1]-p0[1]))/2 # extend y boundary
startAngle = math.atan2(p0[0] - p1[0], p0[1] - p1[1]) *180 / math.pi # calculate starting angle
self.canvas.create_arc(p0[0]-extend_x, p0[1]-extend_y ,
p1[0]+extend_x, p1[1]+extend_y,
extent=180, start=90+startAngle, style=tk.ARC)
'''use this rectangle for visualisation'''
#self.canvas.create_rectangle(p0[0]-extend_x, p0[1]-extend_y,
# p1[0]+extend_x, p1[1]+extend_y)
def _distance(self, p0, p1):
'''calculate distance between 2 points'''
return sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Draw an arc between two points
You misunderstood what d3.path()
is. According to the API:
The d3-path module lets you take [a HTML Canvas] code and additionally render to SVG.
And for d3.path()
:
d3.path(): Constructs a new path serializer that implements
CanvasPathMethods
.
As you can see, the d3-path module has only a bunch of methods that allow you to take a HTML canvas code and use it to draw SVG elements.
That being said, you cannot use arcTo
straight away in the SVG, as you are doing right now. It should be:
var path = d3.path();
path.moveTo(100, 200);
path.arcTo(100,200,150,150,50)
... and then:
svg.append("path")
.attr("d", path.toString())
However, as an additional problem, arcTo
is more complicated than that: the first two values are not the x and y of the starting point, but the coordinates of the first tangent.
Here is a demo, using different values for arcTo
, which I think is what you want:
var joints = [{ x: 100, y: 200, r: 5}, { x: 150, y: 150, r: 5}];
var svg = d3.select("svg");
svg.selectAll("circle") .data(joints) .enter().append("circle") .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }) .attr("r", function(d) { return d.r; });
var path = d3.path();path.moveTo(100, 200);path.arcTo(100, 150, 150, 150, 50);
svg.append("path") .attr("d", path.toString()) .attr("stroke", "firebrick") .attr("stroke-width", 2) .attr("fill", "none");
<script src="https://d3js.org/d3.v4.min.js"></script><svg width="400" height="250" />
Related Topics
How to Update My Adt in Eclipse
How to Check Whether the Sim Card Is Available in an Android Device
Pass Arraylist<? Implements Parcelable> to Activity
Android: Unable to Instantiate Activity/Classnotfoundexception
Android Update Textview in Thread and Runnable
How to Implement a Contentobserver for Call Logs
How to Enable Standard Copy Paste for a Textview in Android
Adding Local .Aar Files to My Gradle Build
Finish Parent and Current Activity in Android
Android: Tabhost Without Tabactivity
Android Displaymetrics Returns Incorrect Screen Size in Pixels on Ics
Android: How to Open Another App from My App
Handling Buttons Inside Android Notifications
Choosing Photo Using New Google Photos App Is Broken
Add Custom Font for Complete Android Application
Android Apps, Communicating with a Device Plugged in the Usb Port