2012-07-30 27 views
6

Me gustaría saber cómo dibujar un semicírculo en JavaFX. Traté de usar Shape y QuadCurve pero no pude hacer un semicírculo perfecto.Dibuja un semi anillo - JavaFX

Aquí está una imagen de lo que estoy tratando de dibujar:

enter image description here

Respuesta

10

La imagen se enlazó es en realidad un semi-anillo. Puede obtenerlo en JavaFX dibujando 2 arcos anidados y algunas líneas. Pero mi forma preferida es usar el 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); 
    } 
} 

Consulte Shape API de JavaFX para obtener más información sobre las formas utilizadas en el código.
Captura:

enter image description here

+0

Año, perfecto! : D Es exactamente lo que necesito ^^ ¡Muchas gracias! – AwaX

+0

¿Sabes si existe una forma simple de modificar el punto de rotación de una ruta? – AwaX

+0

@AwaX path.setRotate (45); –

4

Sugerencias:

  • Si no es necesario un camino esquematización completo, sólo puede utilizar una Arco.
  • Si no necesita rellenar el arco y solo quiere rastrear la ruta del contorno del arco, establezca el relleno del arco en nulo.
  • Si desea que la trayectoria de contorno del arco sea gruesa, establezca los parámetros de trazo en el arco.
  • Si necesita un arco grueso que también está delineado, entonces es mejor definir un arco completo como en la respuesta de Uluk.

Código de ejemplo:

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); } 
} 
+0

Gracias pero es un semicírculo completo, lo que quiero dibujar es un semicírculo vacío en el centro. Incluí un ejemplo en mi publicación anterior que muestra exactamente lo que intento dibujar. – AwaX

+0

Respuesta actualizada para demostrar el dibujo de un arco con un trazo especificado y sin relleno (que generará una imagen de medio anillo). – jewelsea

+0

Muchas gracias por su actualización, su solución es más conveniente pero no puede completar el arco como usted dijo, así que creo que tomaré la otra solución. – AwaX

0

Path.arcTo() el parámetro SweepAngle se refiere al grado de rotación, si sweepAngle es positivo, el arco es hacia la derecha, si sweepAngle es negativo, el arco es en sentido antihorario.

Este código se utiliza en mi entorno de producción, que atrae un anillo semi-círculo utilizando una imagen de mapa de bits, el camino va en sentido horario en el radio exterior, y en sentido antihorario en el radio interior:

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); 
2

Como experimento, traté de hacer lo mismo en un lienzo. Esto es lo que me ocurrió, haciendo uso de un radialGradient y la función GraphicsContext.fillArc:

/** 
* 
* @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 
    ); 
} 

puntos clave aquí son el tipo de arco como ArcType.ROUND y el uso de Color.TRANSPARENT como el primer color.

A continuación, se puede utilizar algo a lo largo de la línea:

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

No es una solución perfecta, pero funcionó para mí.