sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Loops

    Scheduled Pinned Locked Moved Developers' Forum
    15 Posts 4 Posters 860 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.
    • A Offline
      ahjkuipers
      last edited by

      Still not happy with your answers.
      Take a look at the next method, based on my old one.

      ` def helpme(a0, a1, a2, a3)
      ents = Sketchup.active_model.entities
      face = ents.add_face(a0, a1, a2, a3)
      for i in 0..3
      puts face.vertices[i].position
      end

      dosomething

      end`

      There are eight possibilities to define the rectangle but the output of the method will give seven times the same answer and exactly once a different one. I need all eight different answers. The dependency of clockwise/ccw is not really the problem because the method 'dosomething' already copes with this item.

      1 Reply Last reply Reply Quote 0
      • TIGT Offline
        TIG Moderator
        last edited by

        Aren't you making this harder than it needs to be?
        You already have the 4 original points.
        Those can be put into an array [called ' points'].
        You can reverse the face if it's at z=0 and the loop is c/cw...
        You then have an array of the face.vertices [called ' verts']...
        You then extract an array of the vertices' points [called ' vpoints'].
        You iterate the ' points' and compare them with the elements of ' vpoints'.
        When you have a match you know the index of the ' vpoints' match then rearrange ' verts' into the same order as ' points'.
        e.g. something like this...
        ` points=[a0,a1,a2,a3]

        fix face.normal if z==0

        verts=[va,vb,vc,vd]
        pverts=[va.position,vb.position,vc.position,vd.position]
        indx=0
        points.each_with_index{|p,i|
        if p==pverts[i]
        indx=i
        break
        end
        }
        verts_sorted=verts[indx..-1]
        verts.sorted=verts_sorted+verts[0..indx-1] if indx>0`

        TIG

        1 Reply Last reply Reply Quote 0
        • A Offline
          ahjkuipers
          last edited by

          Thanks TIG
          I think the solution indeed lies in matching - what you called - points and vpoints. I'm going to give it a try. It is a lot of work because my method 'dosomething' really exists of a couple of tranformations that required already all my knowledge of maths!!!

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

            @ahjkuipers said:

            Still not happy with your answers.
            Take a look at the next method, based on my old one.

            ` def helpme(a0, a1, a2, a3)
            ents = Sketchup.active_model.entities
            face = ents.add_face(a0, a1, a2, a3)
            for i in 0..3
            puts face.vertices[i].position
            end

            dosomething

            end`

            There are eight possibilities to define the rectangle but the output of the method will give seven times the same answer and exactly once a different one. I need all eight different answers. The dependency of clockwise/ccw is not really the problem because the method 'dosomething' already copes with this item.

            There are eight possible ways to list the points of the rectangle, but since Entities#add_face will force the normal to be downward when z==0, there are actually only four possible returns in that case. All eight can only occur when the Face is not at z==0 so you can get both upward and downward normals.

            However, Entities#add_face does a lot of work behind the scenes. In addition to forcing a downward normal at z==0, it checks for duplication and intersection of Entities and edits both existing Entities and your new Face to account for them. If you run helpme two times in a row without deleting the Face between, add_face will detect that the two Faces are geometrically the same (despite the original point ordering) and will return the pre-existing Face. You can add 'puts face' in your code to confirm this - same object ID! That is probably why you are seeing the same results seven times (did you delete the Face before the eighth?). I tried it while deleting the Face between cases, and I got four distinct results as expected at z==0.

            You don't say anything about how dosomething works or why the Vertex ordering matters, so the best advice we can offer is something like TIG provides above, which remembers the original ordering of the points and uses this to sort the Vertices. It is possible there is a different, better way to accomplish dosomething's purpose.

            1 Reply Last reply Reply Quote 0
            • A Offline
              ahjkuipers
              last edited by

              Thank for your help. I think your answers bring the solution within sight. My apologies for the rather stupid 'dosomething' method. At least I should have written 'dosomething(face, ..)'. And there exactly lies the bottleneck. Even if all the entities are erased at the very beginning of 'helpme' the problem still occurs in the method 'dosomething(face, ..)'. But I can smell the scent of a solution.

              1 Reply Last reply Reply Quote 0
              • A Offline
                ahjkuipers
                last edited by

                Finally: the solution

                The face I used was part of another face. And in that case it seems that the control over the order in which the vertices of the smaller face appear is taken over by the other face. Your answers helped me to discover that phenomenon. Is this assumption correct?

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

                  @ahjkuipers said:

                  Finally: the solution

                  The face I used was part of another face. And in that case it seems that the control over the order in which the vertices of the smaller face appear is taken over by the other face. Your answers helped me to discover that phenomenon. Is this assumption correct?

                  There are situations in which add_face will reverse the Vertex ordering of a Face to keep it consistent with other Faces that it touches or intersects. That is probably what you are seeing.

                  My experience has been that the operation of add_face is so loaded with undocumented special cases (and some bugs) that there are only two safe ways to deal with it: either make no assumptions at all and search or test the Entities collection after it completes, or very carefully try all possible test cases to make sure that you know what it does for all of them. When user input is involved, it is very hard to be certain there are no remaining bugs...

                  1 Reply Last reply Reply Quote 0
                  • tt_suT Offline
                    tt_su
                    last edited by

                    There is no guaranty in the API that the order of the vertices of the face is the same as the input points. As slbaumgartner mentions, there is a lot that goes on when you call add_face - SketchUp invokes it's merge operation that may create additional entities as it merges vertices and splits edges etc.

                    What are you doing to the vertices afterward that require the same order?

                    1 Reply Last reply Reply Quote 0
                    • A Offline
                      ahjkuipers
                      last edited by

                      The troubles appear in the following simplified case.

                      def example
                        ents = Sketchup.active_model.entities
                        ents.clear!
                        # body
                        pt0 = [0, 0, 0]
                        pt1 = [10, 0, 0]
                        pt2 = [10, 6, 0]
                        pt3 = [0, 6, 0]
                        ents.add_face(pt0, pt1, pt2, pt3).pushpull(-8)
                        # protrusion 1
                        pt0 = [2, 2, 8]
                        pt1 = [4, 2, 8]
                        pt2 = [4, 4, 8]
                        pt3 = [2, 4, 8]
                        ents.add_face(pt0, pt1, pt2, pt3).pushpull(6)
                        center = [3, 2, 10]
                        ents.add_circle(center, [0, 1, 0], 0.5)
                        # protrusion 2
                        pt0 = [7, 2, 8]
                        pt1 = [9, 2, 8]
                        pt2 = [9, 4, 8]
                        pt3 = [7, 4, 8]
                        ents.add_face(pt0, pt1, pt2, pt3).pushpull(6)
                        center = [9, 3, 10]
                        ents.add_circle(center, [1, 0, 0], 0.5)
                      end
                      

                      I succeeded in writing a method that is able to place the spikes at all six (maybe more) sides of the body, no matter how the body is transformed in 3D. The problem is how to determine the face on which the circles (drilling holes) are placed. In the mean time I have found a solution that exists of an extra boolean parameter in the parameterlist of the method. But that's not a satisfactory solution: the choice of the parametervalue is a matter of trial and error (not such an attempt with just two possibilities). The method that generates the spikes now is something as 'dosomething(face, extrusion, semaphoor = true)'. I was hoping that all your answers lead me to the conclusion that the trial and error parameter 'semaphoor' is redundant.

                      1 Reply Last reply Reply Quote 0
                      • TIGT Offline
                        TIG Moderator
                        last edited by

                        def example
                          ents = Sketchup.active_model.entities
                          ents.clear!
                          # body
                          pt0 = [0, 0, 0]
                          pt1 = [10, 0, 0]
                          pt2 = [10, 6, 0]
                          pt3 = [0, 6, 0]
                          ents.add_face(pt0, pt1, pt2, pt3).pushpull(-8)
                          # protrusion 1
                          pt0 = [2, 2, 8]
                          pt1 = [4, 2, 8]
                          pt2 = [4, 4, 8]
                          pt3 = [2, 4, 8]
                          ents.add_face(pt0, pt1, pt2, pt3).pushpull(6)
                          center = [3, 2, 10]
                          fas=ents.grep(Sketchup;;Face)
                          cir=ents.add_circle(center, [0, 1, 0], 0.5)
                          ents.add_face(cir)
                          fa=(ents.grep(Sketchup;;Face)-fas)[0]
                          fa.material='red' if fa
                          fa.pushpull(-2) if fa
                          # protrusion 2
                          pt0 = [7, 2, 8]
                          pt1 = [9, 2, 8]
                          pt2 = [9, 4, 8]
                          pt3 = [7, 4, 8]
                          ents.add_face(pt0, pt1, pt2, pt3).pushpull(6)
                          center = [9, 3, 10]
                          fas=ents.grep(Sketchup;;Face)
                          cir=ents.add_circle(center, [1, 0, 0], 0.5)
                          ents.add_face(cir)
                          fa=(ents.grep(Sketchup;;Face)-fas)[0]
                          fa.material='green' if fa
                          fa.pushpull(-2) if fa
                        end
                        

                        This works.
                        get all of the faces in 'ents' before adding the new face based on the circular edges.
                        Then 'fa' is the new face...
                        I colored them red & green so you can see which is which...

                        TIG

                        1 Reply Last reply Reply Quote 0
                        • A Offline
                          ahjkuipers
                          last edited by

                          Problem solved!!!
                          It's all about vectors. One of the arguments of the method that is resposable for creating the protrusions must be a vector or the order of the four given points of the rectangle must choosen in a way that the vector can be derived as the difference between the first two points of de rectangle.

                          ` def findface(pt)
                          arr = Sketchup.active_model.entities.grep(Sketchup::Face)
                          arr.each {|f| return f if f.classify_point(pt) == Sketchup::Face::PointInside}
                          return nil
                          end

                          def body
                          ents = Sketchup.active_model.entities
                          ents.clear!
                          f = ents.add_face([0, 0, 0], [60, 0, 0], [60, 40, 0], [0, 40, 0])
                          f.pushpull(-30)
                          end

                          def protr(array, extrusion)
                          ents = Sketchup.active_model.entities
                          base = ents.add_face(array)
                          arcvector = array[1].vector_to(array[0])
                          basenormal = base.normal
                          depthvector = basenormal.cross(arcvector).reverse
                          width = array[1].distance(array[0])
                          depth = array[2].distance(array[1])
                          basenormal.length = extrusion - width/2
                          basecenter = Geom::Point3d.new
                          basecenter.x = (array[0].x + array[1].x)/2
                          basecenter.y = (array[0].y + array[1].y)/2
                          basecenter.z = (array[0].z + array[1].z)/2
                          center = basecenter + basenormal
                          base.pushpull(extrusion + 1)
                          ents.add_arc(center, arcvector, depthvector, width/2, 0, Math::PI)
                          basenormal.length = extrusion + 0.5
                          findface(basecenter + basenormal).pushpull(-depth)
                          ents.add_circle(center, depthvector, 1)
                          findface(center).pushpull(-depth)
                          end

                          def test
                          body
                          protr [[22.0, 8.0, 30.0], [22.0, 20.0, 30.0], [10.0, 20.0, 30.0], [10.0, 8.0, 30.0]], 14.0
                          protr [[35.0, 8.0, 30.0], [47.0, 8.0, 30.0], [47.0, 20.0, 30.0], [35.0, 20.0, 30.0]], 14.0
                          end`

                          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