sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    Why does this code break?

    Scheduled Pinned Locked Moved Developers' Forum
    9 Posts 4 Posters 480 Views 4 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J Offline
      johnwmcc
      last edited by

      I'm trying to develop a plugin to create regular polyhedra - initially, the Platonic Solids.

      I have already extended the original Sketchup Shapes plugin, which draws a cone (among other shapes) and works.

      But when I copy and adapt the code to draw a Tetrahedron, it fails, and I can't see why.

      This works, for a cone:
      ` # Create the base
      circle = container.add_circle ORIGIN, Z_AXIS, radius, num_segments
      base = container.add_face circle
      base_edges = base.edges

      Create the sides

      apex = [0,0,height]
      edge1 = nil
      edge2 = nil
      base_edges.each do |edge|
      edge2 = container.add_line edge.start.position, apex
      edge2.soft = true
      edge2.smooth = true
      if edge1
      container.add_face edge, edge2, edge1
      end
      edge1 = edge2
      end

      Create the last side face

      edge0 = base_edges[0]
      container.add_face edge0.start.position, edge0.end.position, apex`

      I've adapted the code to draw a Tetrahedron, centred on the origin, with size specified by the radius from origin to corner points.

      All the variables are defined.

      This code doesn't work. (Errors shown below the code)

      ` # Draw base and define apex point
      base_down_by = -radius/3.0
      triangle = container.add_ngon [0,0, base_down_by], Z_AXIS, radius * COS_ASIN_0333, 3
      base = container.add_face triangle
      base_edges = base.edges
      p "Base edges: " + base.edges.inspect

      Create the sides

      apex = [0,0,radius]
      edge1 = nil
      edge2 = nil
      base_edges.each do |edge|
      p "Edge: " + edge.inspect
      edge2 = container.add_line edge.start.position, apex
      edge2.soft = false
      edge2.smooth = false

      if edge1
        container.add_face edge, edge2, edge1
      end
      edge1 = edge2
      

      end # do

      Create the last side face

      edge = base_edges[0]
      container.add_face edge.start.position, edge.end.position, apex`

      For some reason I can't make out, the third base edge is being deleted before or during the .each do loop.

      Error messages in Ruby console:
      "Base edges: [#<Sketchup::Edge:0xef0cc88>, #<Sketchup::Edge:0xef0cc70>, #<Sketchup::Edge:0xef0cc58>]" "Edge: #<Sketchup::Edge:0xef0cc88>" "Edge: #<Sketchup::Edge:0xef0cc70>" "Edge: #<Deleted Entity:0xef0cc58>" Error: #<TypeError: reference to deleted Edge> D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/polyhedra.rb:126:instart'
      D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/polyhedra.rb:126:in block in create_entities' D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/polyhedra.rb:124:in each'
      D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/polyhedra.rb:124:in create_entities' D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/parametric.rb:49:in initialize'
      D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/polyhedra.rb:255:in new' D:/Documents/GitHub/my-polyhedra/src/jwm_polyhedra/polyhedra.rb:255:in block in module:Polyhedra'
      -e:1:in call'

      What's deleting the third edge before it can be used? When I comment out the line that draws the edges, the base triangle is drawn correctly.

      The code excerpt starts at line 114. Line 126 (where the code errors) is the line
      base_edges.each do |edge|

      Any pointers as to what's happening here would be welcome.

      I'm using SU2014 Pro, on Windows 7 Pro 64 bit.

      Many thanks in advance to anyone who can help me understand why this code isn't working.

      I can find a workaround, I'm sure, but I'm really puzzled and would like to understand what's going wrong.

      John McC

      PS. Further exerimentation merely confuses me.

      If I omit the line in the do loop container.add_face edge, edge2, edge1 then there aren't any errors, and the tetrahedron is partially drawn, with all three edges going to the apex, and the last side face drawn, but the other two faces not drawn.

      If I replace this code altogether by:

      # Create the sides apex = [0,0,radius] edge1 = nil edge2 = nil for i in 0..2 edge = base_edges[i] tetrahedron = container.add_face edge.start.position, edge.end.position, apex end

      I get a tetrahedron drawn as I want, but with the reverse of all faces outside.

      It doesn't matter what order I specify the points of the faces, they always come out reversed.

      How do I iterate over the faces of the tetrahedron to do face.reverse!

      PPS
      This seems to do the trick:
      container.each do |entity| if entity.is_a? Sketchup::Face entity.reverse! end end

      1 Reply Last reply Reply Quote 0
      • D Offline
        driven
        last edited by

        you should have a look at geodesic .rb, if you haven't already...

        uses Geom::PolygonMesh.new to populate the point arrays...

        it's very fast.
        john

        learn from the mistakes of others, you may not live long enough to make them all yourself...

        1 Reply Last reply Reply Quote 0
        • S Offline
          slbaumgartner
          last edited by

          @driven said:

          you should have a look at geodesic .rb, if you haven't already...

          uses Geom::PolygonMesh.new to populate the point arrays...

          it's very fast.
          john

          If you do that, be aware that a PolygonMesh triangulates each Face, which might not be what you wanted. The triangulating edges may be hidden, so be sure to view hidden geometry to know what you got.

          1 Reply Last reply Reply Quote 0
          • S Offline
            slbaumgartner
            last edited by

            Your code contains an assumption that can cause errors: you assume that the iterator will traverse the edges of the base triangle in reverse order to how their start and end are oriented. Suppose you label the edges of the base A, B, C in the order the iterator finds them. Your code begins by drawing an edge from A.start to the apex, and remembers it as edge1. In the next iteration it draws an edge from B.start to the apex and sets it as edge2. It then tries to add a face bounded by B, edge2 (from B.start) and edge1 (from A.start). But unless the iterator is traversing the edges in reverse direction to their start->end orientation, A.start is not a vertex of B at all! The Face will fail because the edges do not form a closed shape! If you insert a pause such as a UI.messagebox in the iteration you can see this happen as the edges are drawn. Switch to using A.end instead of A.start and it the nature of the problem will change. Of course, that just builds in the reverse assumption.

            I didn't get your error about a deleted edge, so I'm not certain, but this may be happening because sometimes when SU adds a face it redraws the edges - possibly to reorder their start->end orientations to form a continuous loop. When it does this, even though the new edge is in the identical location to the original, the original is marked as deleted. As a rule, it is not safe to hold references across an operation that adds faces to an entities collection.

            You might want to try just adding all the edges and then iterating the final collection invoking find_faces on each edge.

            Steve

            1 Reply Last reply Reply Quote 0
            • J Offline
              johnwmcc
              last edited by

              Many thanks to all respondents.

              I am a good deal clearer now about what's happening.

              I found a workaround before I saw the responses, but they will stand me in good stead for future work.

              I iterated on the base edges instead of separate edge1, edge2, and this worked:
              ` # Draw base and define apex point
              base_down_by = -radius/3.0
              triangle = container.add_ngon [0,0, base_down_by], Z_AXIS, radius * COS_ASIN_0333, 3

              Reverse to get front face outside

              triangle.reverse!
              base = container.add_face triangle
              base_edges = base.edges

              Create the sides

              apex = [0,0,radius]

              for i in 0..2
              edge = base_edges[i]
              tetrahedron = container.add_face edge.start.position, edge.end.position, apex
              container.each do |entity|
              if entity.is_a? Sketchup::Face
              entity.reverse!
              end #if
              end #do
              end #for`

              Sorry, I can't seem to get the code to indent here, which makes it a bit harder to read.

              1 Reply Last reply Reply Quote 0
              • D Offline
                driven
                last edited by

                @johnwmcc said:

                Many thanks to all respondents.

                I am a good deal clearer now about what's happening.

                I found a workaround before I saw the responses, but they will stand me in good stead for future work.

                I iterated on the base edges instead of separate edge1, edge2, and this worked:

                Sorry, I can't seem to get the code to indent here, which makes it a bit harder to read.

                use the code box

                # Draw base and define apex point
                  base_down_by = -radius/3.0
                  triangle = container.add_ngon [0,0, base_down_by], Z_AXIS, radius * COS_ASIN_0333, 3
                  # Reverse to get front face outside
                  triangle.reverse!
                  base = container.add_face triangle
                  base_edges = base.edges
                
                  # Create the sides
                  apex = [0,0,radius]
                
                  for i in 0..2
                    edge = base_edges[i] 
                    tetrahedron = container.add_face edge.start.position, edge.end.position, apex
                    container.each do |entity|
                      if entity.is_a? Sketchup;;Face
                        entity.reverse!
                      end #if
                    end #do
                  end #for
                

                learn from the mistakes of others, you may not live long enough to make them all yourself...

                1 Reply Last reply Reply Quote 0
                • J Offline
                  johnwmcc
                  last edited by

                  I'd been wrapping the code in Ruby tags, which I thought would give syntax highlighting, but it doesn't seem to here.

                  I didn't see the meaning of the icon for Code box, and hadn't happened to hover the mouse over it, so didn't see the tooltip either.

                  What's the purpose of the Ruby tags, then?

                  1 Reply Last reply Reply Quote 0
                  • D Offline
                    driven
                    last edited by

                    differentiation...

                    Sketchup.version
                    

                    on my mac returns this, 14.0.4899 try it on yours by selecting all, copy/paste ...etc...etc

                    but, mainly it was first kid on the block so it got kept...

                    john

                    learn from the mistakes of others, you may not live long enough to make them all yourself...

                    1 Reply Last reply Reply Quote 0
                    • J Offline
                      Jim
                      last edited by

                      The advantage of code tags is they can easily be copied and pasted in a code editor, or one of the SketchUp console dialogs.

                      I have my editor and SketchUp set up[1] where I can run the pasted code in SketchUp with the push of a key. So testing posted code is fast and easy - copy, paste, run.

                      That's why it's important to post "run-able" code - leaving variables and constants undefined makes it harder to help.

                      [1] https://github.com/noelwarr/su-tunnel

                      Hi

                      1 Reply Last reply Reply Quote 0
                      • 1 / 1
                      • First post
                        Last post
                      Buy SketchPlus
                      Buy SUbD
                      Buy WrapR
                      Buy eBook
                      Buy Modelur
                      Buy Vertex Tools
                      Buy SketchCuisine
                      Buy FormFonts

                      Advertisement