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.
    • S Offline
      slbaumgartner
      last edited by

      You provided the points in anti-clockwise order as seen from above, which means the normal vector to the face would point upward (+z). Entities#add_face automatically forces the normal of a face drawn at z=0 to point downward, which causes your vertices to be traced in the opposite (clockwise) order. You can reverse the face after drawing it to correct for this, but there is no option by which you can turn off this "feature".

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

        Try making the z=1 for all of those 4 points.
        You should then find that the vertices' points will now report in the same order.

        When you make a face the clockwise/counter-clockwise ordering of the points dictates the face.normal...
        When you get the face.outer_loop.vertices these are returned counter-clockwise around the face.normal [inner loops go the other way!].
        When you draw a flat face at z=0 it ALWAYS faces downwards - even when you order the points counter-clockwise and you'd expect it the look upwards.
        So in that unique case the points were given as if the face were to look up, BUT just as with a manual face creation at z=0, the face is made with its normal reversed.

        So when you return the points of that z=0 face they'll appear in reverse order compared to the original points.
        A simple trap to always end up with a face with face.normal==Z_AXIS - even when it's at z=0 - is to check thus:
        face.reverse! if face.vertices[0].z==0 && face.normal.parallel?(Z_AXIS) && face.normal==Z_AXIS.reverse

        TIG

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

          @slbaumgartner said:

          You provided the points in anti-clockwise order as seen from above, which means the normal vector to the face would point upward (+z). Entities#add_face automatically forces the normal of a face drawn at z=0 to point downward, which causes your vertices to be traced in the opposite (clockwise) order. You can reverse the face after drawing it to correct for this, but there is no option by which you can turn off this "feature".

          Thanks for your quick response! It helps a lot but still it is not the total solution. A clockwise definition with four points can take place in four different way's, depending on which point is the first one. I tried the four possibilities in my little method. The response is still a bit confusing!!! I need the exact order.

          1 Reply Last reply Reply Quote 0
          • 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