9

I'm working on an application to model some problem specific 2D geometry. And of course i would like to draw that geometry on the screen for the user to actually see it.

JavaFX has some 2D shapes like rectangles, ellipses, etc. It also has cubic and quartic curves, implemented as Bezier curves. Searching for custom shapes didn't help, since all I found was examples of taking some shape elements like paths and putting them together to draw a custom shape, like a heart or diamond. Searching for information on how to implement a new shape by extending the Shape class was even less helpfull.

What I want to draw are B-Spline curves of arbitrary order and length. I know how to calculate and implement the Splines itself, but i don't know how to implement them as a new Shape, or a Shape Wrapper.

I looked at the source code of JavaFX and the documentary. It seems as if those shapes are some kind of wrapper classes themselves. E.g. the Ellipse class contains an ellipse as member, which is part of the geometry package. This recursion goes pretty far.

Now there has to be some kind of method JavaFX uses to actually draw the curve, but I couldn't find it.

So how do I extend a JavaFX Shape to create e.g. a Spline class? What methods/classes are the key for Java to draw it?

I hope someone can help me.

Yours sincerely Thorsten

3
  • Can you explain in more detail why Path (which extends Shape) is not sufficient? Commented Mar 18, 2016 at 17:23
  • 1
    I don't think you will be able to extend Shape directly and get your extended shape rendered without relying on APIs marked: "@deprecated This is an internal API that is not intended for use and will be removed in the next version". Commented Mar 18, 2016 at 18:42
  • @VGR With Path i would simply combine different shapes to one. That limits me to the standard shape classes. So, e.g., i could only draw curves up to fourth degree. For everything with no prebuild class i would have to create that curve with the prebuild shape classes and put together curves and line segments to create and approximation. Commented Mar 19, 2016 at 10:29

2 Answers 2

1

I'd take a look at how JSilhoutte has implemented their shapes.

Cross for example, does not extend Shape, but it generates a Shape representing a cross by creating two rectangles and combining them using Shape.union. Here is the relevant method:

@Override
protected void calculateShape() {
        double cx = getCenterX();
        double cy = getCenterY();
        double r = getRadius();
        double n = validateRoundness(getRoundness());
        double w = validateWidth(getWidth(), r);

        double arcWH = w * n;
        Rectangle beam1 = new Rectangle(cx - r, cy - (w / 2), r * 2, w);
        Rectangle beam2 = new Rectangle(cx - (w / 2), cy - r, w, r * 2);
        beam1.setArcWidth(arcWH);
        beam1.setArcHeight(arcWH);
        beam2.setArcWidth(arcWH);
        beam2.setArcHeight(arcWH);
        Shape shape = Shape.union(beam1, beam2);

        shape.getStyleClass().addAll("silhouette", "silhoutte-cross");

        setShape(shape);
}

So you could use Shape.union to combine together several CubicCurve/QuadCurve shapes to create your B-Spline curves of arbitrary order and length.

Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, what you're saying is consistent with what I'm saying. Trying to extend shape is most likely futile. You need to take another approach! And I read this as an alternative approach on how to make your own custom shape. The original question is: How do I extend Shape? And the point I'm raising is that seems not to be reasonable possible. And we're both saying, take an alternative approach rather than going down the path to extend Shape. If someone knows how to successfully extend Shape, I'd be happy and humble to see that answer.
0

I was trying to do a similar thing, but instead of trying to extend Shape, I tried to extend PathElement. I was doing that so I could implement a nurbsTo method that would allow me to draw NURBS or B-Spline curves. PathElement is an abstract class that wants you to override:

void addTo(NGPath)

It's not public so if you wanted to do that, your new class would have to be in the javafx/scene/shape package. So basically, you can't do that. Seeing this post, I took a quick look at whether it feasible to write a call that extends shapes, and as Thorsten correctly points out, that looks like a gnarly path to try to go down, so I didn't pursue it.

The approach I took was to make my NURBS class generate a set of MoveTo commands. I iterate over U(t) at a sufficient increment value to get the enough points so that curves look smooth. That's probably the most reasonable way to accomplish Thorsen posted needs. If you look at the javafx implementation for something like Circle, internally it's doing that same thing. By default, the Circle class computes 64 points on the circle shape and draws lines. For most NURBS and B-Spline curves I find that 100 points look nice and smooth, but that of course depends on the degree, control points and knots being used.

3 Comments

And in the end all non-trivial curved geometry is flattened to linear line segments anyway before rendering.
See: "com.sun.javafx.geom.FlatteningPathIterator".
Yes of course, you are flattening the not-trivial curve before rendering. That's what you have to do since JavaFX graphics capabilities makes it nearly impossible to extend a PathElement or developing new custom shapes. The posted question is "how do you extend Shape?", and I'm suggesting not to do that and take the flatten curve approach. FlattenPathIterator isn't useful since you can't make a custom PathElement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.