Draw a half ring - JavaFX

I would like to know how to draw a half ring in JavaFX. I tried to use Shape and QuadCurve, but I could not make a perfect half circle.

Here is an image of what I'm trying to do:

enter image description here

+6
source share
4 answers

The image you linked is actually a half ring. You can get it in JavaFX by drawing nested 2 arcs and some lines. But my preferred way is to use Path .

 public class SemiDemo extends Application { @Override public void start(Stage primaryStage) { Group root = new Group(); root.getChildren().add(drawSemiRing(120, 120, 100, 50, Color.LIGHTGREEN, Color.DARKGREEN)); root.getChildren().add(drawSemiRing(350, 350, 200, 30, Color.LIGHTSKYBLUE, Color.DARKBLUE)); Scene scene = new Scene(root, 300, 250); primaryStage.setScene(scene); primaryStage.show(); } private Path drawSemiRing(double centerX, double centerY, double radius, double innerRadius, Color bgColor, Color strkColor) { Path path = new Path(); path.setFill(bgColor); path.setStroke(strkColor); path.setFillRule(FillRule.EVEN_ODD); MoveTo moveTo = new MoveTo(); moveTo.setX(centerX + innerRadius); moveTo.setY(centerY); ArcTo arcToInner = new ArcTo(); arcToInner.setX(centerX - innerRadius); arcToInner.setY(centerY); arcToInner.setRadiusX(innerRadius); arcToInner.setRadiusY(innerRadius); MoveTo moveTo2 = new MoveTo(); moveTo2.setX(centerX + innerRadius); moveTo2.setY(centerY); HLineTo hLineToRightLeg = new HLineTo(); hLineToRightLeg.setX(centerX + radius); ArcTo arcTo = new ArcTo(); arcTo.setX(centerX - radius); arcTo.setY(centerY); arcTo.setRadiusX(radius); arcTo.setRadiusY(radius); HLineTo hLineToLeftLeg = new HLineTo(); hLineToLeftLeg.setX(centerX - innerRadius); path.getElements().add(moveTo); path.getElements().add(arcToInner); path.getElements().add(moveTo2); path.getElements().add(hLineToRightLeg); path.getElements().add(arcTo); path.getElements().add(hLineToLeftLeg); return path; } public static void main(String[] args) { launch(args); } } 

See the JavaFX Shape API for more information on the forms used in code.
Screenshot:

enter image description here

+10
source

Suggestions:

  • If you don't need the full selection path, you can just use Arc.
  • If you do not need a filled arc and just want to trace the contour of the arc, then set the arc filling to null.
  • If you want the outline of the arc to be thick, specify the arc parameters on the arc.
  • If you need a thick arc, which is also indicated, then it is best to define a full arc, as in Uluk's answer.

Code example:

 import javafx.application.Application; import javafx.scene.*; import javafx.scene.paint.Color; import javafx.scene.shape.*; import javafx.stage.Stage; public class SemiCircleSample extends Application { @Override public void start(Stage stage) { Arc arc = new Arc(50, 50, 25, 25, 0, 180); arc.setType(ArcType.OPEN); arc.setStrokeWidth(10); arc.setStroke(Color.CORAL); arc.setStrokeType(StrokeType.INSIDE); arc.setFill(null); stage.setScene(new Scene(new Group(arc), 100, 80)); stage.show(); } public static void main(String[] args) { launch(args); } } 
+4
source

As an experiment, I tried to do the same on canvas. This is what I came up with using the RadialGradient and the GraphicsContext.fillArc function:

 /** * * @param x Coordinate x of the centre of the arc * @param y Coordinate y of the centre of the arc * @param outer Outer radius of the arc * @param innerPercentage Inner radius of the arc, from 0 to 1 (as percentage) * @param arcStartAngle Start angle of the arc, in degrees * @param arcExtent Extent of the arc, in degrees */ private void drawSemiCircle(float x, float y, float outer, float innerPercentage, float arcStartAngle, float arcExtent) { RadialGradient rg = new RadialGradient( 0, 0, x, y, outer, false, CycleMethod.NO_CYCLE, new Stop((innerPercentage + (.0 * innerPercentage)), Color.TRANSPARENT), new Stop((innerPercentage + (.1 * innerPercentage)), Color.RED), new Stop((innerPercentage + (.6 * innerPercentage)), Color.YELLOW), new Stop((innerPercentage + (1 * innerPercentage)), Color.GREEN) ); gc.setFill(rg); gc.fillArc( x - outer, y - outer, outer * 2, outer * 2, arcStartAngle, arcExtent, ArcType.ROUND ); } 

Arc types such as ArcType.ROUND and using Color.TRANSPARENT as the first color are key here.

Then it can be used something along the line:

 drawSemiCircle(100, 100, 100, .5f, -45, 270); 

This is not an ideal solution, but it worked for me.

+2
source

Path.arcTo () the SweepAngle parameter refers to the degree of rotation, if sweepAngle is positive, the arc is clockwise, if sweepAngle is negative, the arc is counterclockwise.

This code is used in my production environment, it draws a semicircular ring using a bitmap image, the path goes clockwise in the outer radius and counterclockwise in the inner radius:

 drawpercent = 0.85; //this draws a semi ring to 85% you can change it using your code. DegreesStart = -90; DegreesRotation = 180; radiusPathRectF = new android.graphics.RectF((float)CentreX - (float)Radius, (float)CentreY - (float)Radius, (float)CentreX + (float)Radius, (float)CentreY + (float)Radius); innerradiusPathRectF = new android.graphics.RectF((float)CentreX - (float)InnerRadius, (float)CentreY - (float)InnerRadius, (float)CentreX + (float)InnerRadius, (float)CentreY + (float)InnerRadius); Path p = new Path(); //TODO put this outside your draw() function, you should never have a "new" keyword inside a fast loop. degrees = (360 + (DegreesStart)) % 360; radians = (360 - degrees + 90) * Math.PI / 180.0; //radians = Math.toRadians(DegreesStart); int XstartOuter = (int)Math.round((Math.cos(radians) * Radius + CentreX)); int YstartOuter = (int)Math.round((Math.sin(-radians)* Radius + CentreY)); int XstartInner = (int)Math.round((Math.cos(radians) * InnerRadius + CentreX)); int YstartInner = (int)Math.round((Math.sin(-radians) * InnerRadius + CentreY)); degrees = (360 + (DegreesStart + drawpercent * DegreesRotation)) % 360; //radians = degrees * Math.PI / 180.0; radians = (360 - degrees + 90) * Math.PI / 180.0; //radians = Math.toRadians(DegreesStart + drawpercent * DegreesRotation); int XendOuter = (int)Math.round((Math.cos(radians) * Radius + CentreX)); int YendOuter = (int)Math.round((Math.sin(-radians) * Radius + CentreY)); int XendInner = (int)Math.round((Math.cos(radians) * InnerRadius + CentreX)); int YendInner = (int)Math.round((Math.sin(-radians) * InnerRadius + CentreY)); //draw a path outlining the semi-circle ring. p.moveTo(XstartInner, YstartInner); p.lineTo(XstartOuter, YstartOuter); p.arcTo(radiusPathRectF, (float)DegreesStart - (float)90, (float)drawpercent * (float)DegreesRotation); p.lineTo(XendInner, YendInner); p.arcTo(innerradiusPathRectF, (float)degrees - (float)90, -1 * (float)drawpercent * (float)DegreesRotation); p.close(); g.clipPath(p); g.drawBitmap(bitmapCircularBarImage, bitmapRect0, bitmapRectXY, paint); 
0
source

Source: https://habr.com/ru/post/921658/


All Articles