Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    drawing module to draw and fill arbitrary shape

    Hello, I'm trying to understand if i may use the Drawing module to draw and fill (with a color) arbitrary shapes.

    Well, not really arbitrary, I'm actually wondering if I can write code to convert an SVG consisting of paths with 'curveto' cubic Bézier curve in a DrawShape.

    But I see that I can't use all the shapes available as DrawItem subclasses, DrawCurve for instance, for cubic bezier curves, because in the DrawShape commands the only curve is 'circleto'.

    Obviously I may draw my shape using multiple DrawItem objects, but then I can't fill the resulting (closed) shape.

    Is it true that I'm out of luck, or am I missing something?




    #2
    You can see by modifying the ShapeGallery Showcase sample that drawItem.fillColor works on open shapes too, like DrawCurve. If your curve is convex, then fillColor should do what you want. You are correct though that DrawShape does not support a "curveto" command.

    Comment


      #3
      Hello Isomorphic , yes I noticed, but I need to fill a closed shape, composed of open shapes, like in this example:

      Code:
      var mainPane = isc.DrawPane.create({
          autoDraw: false,
          showEdges: true,
          width: 720,
          height: 475
      });
      
      var commonProps = {
          autoDraw: true,
          drawPane: mainPane,
          canDrag: true,
          titleRotationMode: "neverRotate"
      };
      
      isc.DrawCurve.create({
          startPoint: [335.5, 101.25],
          controlPoint1: [344.061, 101.25],
          controlPoint2: [351, 97.053],
          endPoint: [351, 91.875],
      }, commonProps);
      
      isc.DrawCurve.create({
          startPoint: [351, 91.875],
          controlPoint1: [351, 86.697],
          controlPoint2: [344.061, 82.5],
          endPoint: [335.5, 82.5],
      }, commonProps);
      
      isc.DrawCurve.create({
          startPoint: [335.5, 82.5],
          controlPoint1: [325.75, 82.5],
          controlPoint2: [320, 86.697],
          endPoint: [320, 91.875],
      }, commonProps);
      
      isc.DrawCurve.create({
          startPoint: [320, 91.875],
          controlPoint1: [320, 97.053],
          controlPoint2: [326.939, 101.25],
          endPoint: [335.5, 101.25],
      }, commonProps);
      
      mainPane.drawItems.callMethod("setFillColor", "red")
      
      isc.HStack.create({
          width: "100%",
          members: [mainPane]
      });
      And the result is not what I'm after, unfortunately. I think that only a DrawShape with a curveto command would work.

      Comment


        #4
        We're looking into the situation, but one alternative you might find useful since you spoke of SVG is that SVG files can be loaded by the framework, either embedded as separate documents, or shown as images. See the documention here and the Showcase sample here.

        Comment


          #5
          We have some hacky approaches in mind we could share, but as far as framework support, this simplest thing is probably to add a DrawShapeCommand for bezier curves.

          Two questions:

          1. does just loading the SVG as suggested work for you as an alternate approach?

          2. DrawCurve supports bezier curves. and provides support for knobs to adjust the curve. Would you need this kind of support, or do you just need a curve that cannot be end-user-edited

          Comment


            #6
            Originally posted by Isomorphic View Post
            We have some hacky approaches in mind we could share, but as far as framework support, this simplest thing is probably to add a DrawShapeCommand for bezier curves.

            Two questions:

            1. does just loading the SVG as suggested work for you as an alternate approach?
            no, not really
            Originally posted by Isomorphic View Post
            2. DrawCurve supports bezier curves. and provides support for knobs to adjust the curve. Would you need this kind of support, or do you just need a curve that cannot be end-user-edited
            the latter would suffice, I don't need it to be user-editable

            Comment


              #7
              Right now, without framework support for a single DrawItem composed of multiple bezier curves, the only way to do what you want is to add some extra steps:
              • Draw a polygon formed from the endpoints of your bezier curves, allowing it to be filled like the other drawItems in your sample code. We can't show the edges of this polygon, as they would protrude from the curves, so they must be hidden.
              • For non-SVG DrawPanes (HTML5 Canvas), there is a slight misalignment for some reason that exposes the underlying background when the polygon is drawn without edges, so we must come back and individually draw the edge line segments with lineCap set to "butt" to minimize protusion.

              Code:
              var mainPane = isc.DrawPane.create({
                  autoDraw: false,
                  showEdges: true,
                  width: 1200,
                  height: 475
              });
              
              var commonProps = {
                  autoDraw: true,
                  drawPane: mainPane,
                  canDrag: true,
                  titleRotationMode: "neverRotate"
              };
              
              function fillDrawCurves (items) {
                  var points = items.map(function (item) { return item.startPoint; });
              
                  // create a convex polygon from the DrawCurve array that will be filled
                  isc.DrawPolygon.create({
                      lineOpacity: 0, points: points, zIndex: 0
                  }, commonProps);
              
                  // add back the edges with lineCap setting to avoid protrusion (non-SVG)
                  for (var i = 0; i < points.length; i++) {
                      isc.DrawLine.create({
                          startPoint: points[i], endPoint: points[(i + 1) % points.length],
                          lineWidth: 2, lineColor: "red", lineCap: "butt", zIndex: 0
                      }, commonProps);
                  }
              }
              
              var curve1 = isc.DrawCurve.create({
                  startPoint: [335.5, 101.25],
                  controlPoint1: [344.061, 101.25],
                  controlPoint2: [351, 97.053],
                  endPoint: [351, 91.875]
              }, commonProps);
              
              var curve2 = isc.DrawCurve.create({
                  startPoint: [351, 91.875],
                  controlPoint1: [351, 86.697],
                  controlPoint2: [344.061, 82.5],
                  endPoint: [335.5, 82.5]
              }, commonProps);
              
              var curve3 = isc.DrawCurve.create({
                  startPoint: [335.5, 82.5],
                  controlPoint1: [325.75, 82.5],
                  controlPoint2: [320, 86.697],
                  endPoint: [320, 91.875]
              }, commonProps);
              
              var curve4 = isc.DrawCurve.create({
                  startPoint: [320, 91.875],
                  controlPoint1: [320, 97.053],
                  controlPoint2: [326.939, 101.25],
                  endPoint: [335.5, 101.25]
              }, commonProps);
              
              fillDrawCurves([curve1, curve2, curve3, curve4]);
              
              mainPane.drawItems.callMethod("setFillColor", "red");
              
              isc.HStack.create({
                  width: "100%",
                  members: [mainPane]
              });
              Note the use of zIndex to ensure that extra stuff ends up underneath the DrawCurve items. (If you set DrawPane.drawingType to "svg", you should be able to omit the second part of the hack.) Even with this hack in place, it's still possible that you may see some pixels protrude, especially on the bottom of the shape.

              We could add a bezier "curveto" DrawShapeCommand as a roughly 2 day sponsorship. (It's more complicated that it appears, and you can take a look at the "circleto" DrawShapeCommand code in the implementation of DrawShape if you needs to see why.)


              Comment


                #8
                Hello, thanks for the clever hack. Unfortunately it doesn't work well when the shape changes to convex:

                Click image for larger version

Name:	2022-11-02 16.22.31.jpg
Views:	229
Size:	4.7 KB
ID:	268967


                Code:
                var svgPath = "M 481.5 294 C 479.482 273.251 443.75 245.75 432.938 242.863 C 428.333 243.31 423.45 243.239 418.5 242.5 C 405.695 240.589 371.5 240.833 367.667 246.833 C 363.834 252.833 352.167 252.666 348 246.833 C 343.833 241 318.333 242.333 302.667 243.166 C 297.373 243.447 291.794 242.492 286.608 241.007 C 278.604 244.487 240.575 267.433 234.481 299.315 C 234.022 301.717 233.737 304.167 233.667 306.666 C 232.667 342.333 233.67 378.776 233.502 392.388 C 233.885 392.292 243.168 417.499 245.668 423.166 C 248.168 428.833 250.75 441 254.25 447.75 C 262.5 455.5 301 473 327.5 466 C 354 459 364 459.756 392.5 466.128 C 421 472.5 445.168 463.334 465.584 438.917 C 466.834 435.667 470.334 427.167 470.917 423.917 C 471.5 420.667 473.584 416.918 475.001 414.168 C 476.418 411.418 482.456 392.493 483.006 392.992 C 483.678 379.65 482.667 306.001 481.5 294 Z";
                
                var svgPaths = {"first": svgPath};
                
                isc.DrawPane.create({
                    ID: "bodyPane",
                    autoDraw: false,
                    showEdges: true,
                    width: 800,
                    height: 800
                });
                
                var commonProps = {
                    autoDraw: true,
                    drawPane: bodyPane,
                    canDrag: true,
                    titleRotationMode: "neverRotate"
                };
                
                function fillDrawCurves(items) {
                    var points = items.map(function (item) {
                        return item.startPoint;
                    });
                
                    // create a convex polygon from the DrawCurve array that will be filled
                    isc.DrawPolygon.create({
                        lineOpacity: 0, points: points, zIndex: 0
                    }, commonProps);
                
                    // add back the edges with lineCap setting to avoid protrusion (non-SVG)
                    for (var i = 0; i < points.length; i++) {
                        isc.DrawLine.create({
                            startPoint: points[i], endPoint: points[(i + 1) % points.length],
                            lineWidth: 2, lineColor: "red", lineCap: "butt", zIndex: 0
                        }, commonProps);
                    }
                }
                
                for (var pathName in svgPaths) {
                    var path = svgPaths[pathName];
                    path = path.substring(2, path.length - 2);
                    var curvePoints = path.split(" C ");
                    var startPoint = curvePoints.get(0).split(" ").map(function (item) {
                        return Number(item);
                    });
                    for (var pointsIndex = 1; pointsIndex < curvePoints.getLength(); pointsIndex++) {
                        var points = curvePoints.get(pointsIndex).split(" ").map(function (item) {
                            return Number(item);
                        });
                        var controlPoint1 = [points.get(0), points.get(1)];
                        var controlPoint2 = [points.get(2), points.get(3)];
                        var endPoint = [points.get(4), points.get(5)];
                        isc.DrawCurve.create({
                            ID: pathName + pointsIndex + "_BodyPart",
                            startPoint: startPoint,
                            controlPoint1: controlPoint1,
                            controlPoint2: controlPoint2,
                            endPoint: endPoint
                        }, commonProps);
                        startPoint = endPoint;
                    }
                }
                
                fillDrawCurves(bodyPane.drawItems);
                
                bodyPane.drawItems.callMethod("setFillColor", "red");
                
                isc.HStack.create({
                    width: "100%",
                    members: [bodyPane]
                });

                Comment


                  #9
                  Originally posted by claudiobosticco View Post
                  Hello, thanks for the clever hack. Unfortunately it doesn't work well when the shape changes to convex:
                  You must mean concave. Yes, the approach doesn't work for closed shapes containing DrawCurves that are concave with respect fo the closed shape. In that case, the mere filling of the DrawCurve itself breaks the appearance as the fill will appear outside the shape. With enough work, you might be able to modify the hack to exclude such concave DrawCurves, but it would be beyond what we provide here.

                  For a general solution, the suggested feature sponsorship is probably what you need.

                  Comment

                  Working...
                  X