sketchucation logo sketchucation
    • 登入
    Oops, your profile's looking a bit empty! To help us tailor your experience, please fill in key details like your SketchUp version, skill level, operating system, and more. Update and save your info on your profile page today!
    ⚠️ Important | Libfredo 15.6b introduces important bugfixes for Fredo's Extensions Update

    Iterating over the faces of a component - without exploding

    已排程 已置頂 已鎖定 已移動 Developers' Forum
    30 貼文 6 Posters 1.5k 瀏覽 6 Watching
    正在載入更多貼文
    • 從舊到新
    • 從新到舊
    • 最多點贊
    回覆
    • 在新貼文中回覆
    登入後回覆
    此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
    • T 離線
      talig
      最後由 編輯

      I've been trying to iterate over the faces of a component without
      exploding it, in the following manner:

      Let c be that component.
      Then d = c.definitions.entities
      for each entity in d - put in in an entities_array.
      iterate over the entities_array: If an entity is a group, take it's
      entities and add them to an entities_array
      if it's a face, add to a result array.

      I'm comparing the results of this to that of "Explode".
      I get the same number of faces, but the calculations I'm using them
      for later disagree.
      I was thinking it might be related to the face's Normal Vector, but
      that seems improbable to me that using the aforementioned method and
      "Explode" will differ in such a manner.

      Essentially, the calculation performed is "raytracing" - I'm checking
      if a point in a face is visible from another point in the model.

      Has anyone seen something like this? Tell me where's the error?
      Thanks

      • Tali

      Avatar: all rights reserved to Bryan Eppihimer

      1 條回覆 最後回覆 回覆 引用 0
      • thomthomT 離線
        thomthom
        最後由 編輯

        hm... not sure. can you post the iterating code snippet?

        Thomas Thomassen — SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 條回覆 最後回覆 回覆 引用 0
        • T 離線
          talig
          最後由 編輯

          Certainly. The point is to get an array of faces in the end of it all. I don't need the edges, and I don't count them even when I explode the component in advance.

          def get_faces(object)
          	entities = []
          	type = object.typename
          	if type == "Face"
          		return [object]
          	elsif type == "Loop"
          		return [object.face]
          	elsif type == "Group"
          		entities = to_array(object.entities)
          	elsif type == "ComponentInstance"
          		entities = to_array(object.definition.entities)
          	end
          	result = []
          	i = 0
          	while i<entities.length do
          		entity = entities[i]
          		type = entity.typename
          		if type == "Face"
          			result << entity
          		elsif type == "Loop"
          			result << entity.face
          		elsif type == "Group"
          			entities.concat(to_array(entity.entities))
          		elsif type == "ComponentInstance"
          			entities.concat(to_array(entity.definition.entities))
          		end
          		i+=1
          	end
          	return result
          end
          
          def to_array(entities)
          	result = []
          	entities.each { |entity| result << entity }
          	return result
          end
          
          def get_all_selected_faces(selection)
          	result = []
          	for selected in selection do
          		entities = get_faces(selected)
          		result.concat(entities)
          	end
          	return result
          end
          

          Avatar: all rights reserved to Bryan Eppihimer

          1 條回覆 最後回覆 回覆 引用 0
          • J 離線
            Jim
            最後由 編輯

            Did you know about the raytest method? It sounds like it could help you do a ray trace for visibility.

            Hi

            1 條回覆 最後回覆 回覆 引用 0
            • T 離線
              talig
              最後由 編輯

              Jim - Thanks.
              I'm using raytest. But I need a fine-grain detail.
              See, if I have a component - raytest will return the component as an answer for the ray hitting any of it's faces. I need to know which face in that component was intersected. More accurately, I need to know that a certain face that should have been intersected, isn't - because it's shaded.

              Thomthom - any thoughts?

              Thanks again guys,

              • Tali

              Avatar: all rights reserved to Bryan Eppihimer

              1 條回覆 最後回覆 回覆 引用 0
              • Chris FullmerC 離線
                Chris Fullmer
                最後由 編輯

                It also returns the 3dPoint that it hits. You could run that point against all planes of all the faces faces in the component with the .on_plane? method. If it truly hits something, there should be one plane in that compnent that would return true in that comparison.....right?

                Chris

                Lately you've been tan, suspicious for the winter.
                All my Plugins I've written

                1 條回覆 最後回覆 回覆 引用 0
                • T 離線
                  talig
                  最後由 編輯

                  Chris -
                  Thanks again. You are correct, but again - that is not my use case.

                  I repeat the question:
                  This code SHOULD work, it's unclear why whatever calculation I'm running on it, disagrees with the result on the exploded component.
                  Essentially - they both provide an array of faces, and it should be the same faces in both cases, but it seems like it isn't.
                  Why?

                  Avatar: all rights reserved to Bryan Eppihimer

                  1 條回覆 最後回覆 回覆 引用 0
                  • fredo6F 離線
                    fredo6
                    最後由 編輯

                    Talig

                    A few remarks on your script.

                    You must accumulate the transformations to get the real geometric coordinates of the elements you traverse. If your raytest hits a component 'cp3', embedded in 'cp2' and 'cp1', then you should use

                    
                    t = cp1.transformation * cp2.transformation * cp3.transformation
                    
                    

                    Then, you do as Chris suggests, cycle through the faces of component3, and perform 2 tests with the point 'ptray' returned by model.raytest:

                    1. Check if on plane (fast test)
                    2. check within the face (more greedy, especially when face has holes)
                    
                    lfaces = []
                    cp3.definition.entities.each do |e|
                        if e.class == Sketchup;;Face
                           plane = [t * e.center, t * e.normal]
                           lfaces.push e if ptray.on_plane?(plane)
                        end
                    end
                    
                    myface = nil
                    tinv = t.inverse
                    ptlocal = tinv * ptray
                    lfaces.each do |face|
                       status = face.classify_point ptlocal
                       if status > 0 && status < 8
                          myface = face
                          break
                       end
                    end
                    #myface should contain your face
                    
                    #Note that if cp3 is a group, you should use cp3.entities instead of cp3.definition.entities.
                    
                    

                    The list [cp3, cp2, cp1] is returned by the raytestmethod.

                    As a side remark, you can get an array of entities by using the standard Ruby method: entities.to_areturns a list of entities (this also works on a selection).

                    Fredo

                    1 條回覆 最後回覆 回覆 引用 0
                    • Chris FullmerC 離線
                      Chris Fullmer
                      最後由 編輯

                      How large of a component does it take for this to break? I just tried it on a simple group of 5 faces and it returned an array 5 of faces. Are you experiencing problems only on large, multiple nested components?

                      Chris

                      Lately you've been tan, suspicious for the winter.
                      All my Plugins I've written

                      1 條回覆 最後回覆 回覆 引用 0
                      • fredo6F 離線
                        fredo6
                        最後由 編輯

                        I did not test the code (just wrote it on the fly).
                        The question is whether Raytest returns the point hit in absolute model coordinates, or in local coordinates of the component or group hit. The doc is unclear. In either case, I wanted just to tell Talig that he should use Transformations to cycle through the model.

                        Fredo

                        1 條回覆 最後回覆 回覆 引用 0
                        • T 離線
                          talig
                          最後由 編輯

                          Chris - that's what I said: I get the correctnumber of faces. But I make some calculation about them, and I get a different result when I use explode - though I should get the same one. Even a plain box is not working properly.

                          Fredo - I'm a female 😄
                          About the coordinates: What you're saying is interesting. I assumed I get the absolute model coordinates in any case. That's obviously true in the exploded case, but possibly the cause of the problem in what I'm trying to do. I'll check it out. Thanks! 👍 (and thanks for the to_a tip!)

                          I already have everything else up and running, so thanks for trying to help - but really, no call for that.
                          All I need is an array of faces equivalent to that of an exploded component. Nothing more, nothing less. 😄

                          Avatar: all rights reserved to Bryan Eppihimer

                          1 條回覆 最後回覆 回覆 引用 0
                          • Chris FullmerC 離線
                            Chris Fullmer
                            最後由 編輯

                            @talig said:

                            Chris - that's what I said: I get the correctnumber of faces. But I make some calculation about them, and I get a different result when I use explode - though I should get the same one. Even a plain box is not working properly.

                            Heehe, yeah, I noticed that after I was re-reading some of Fredo's posts. I went back and re-read your post and realized that you already were getting the number of faces correct. My mistake.

                            @talig said:

                            All I need is an array of faces equivalent to that of an exploded component. Nothing more, nothing less. 😄

                            I see what your saying now. Makes sense.

                            So what is the calculations you're trying to run on the faces? Or maybe you've already got it working with Fredo's great explanation?

                            Chris

                            Lately you've been tan, suspicious for the winter.
                            All my Plugins I've written

                            1 條回覆 最後回覆 回覆 引用 0
                            • thomthomT 離線
                              thomthom
                              最後由 編輯

                              Have you checked that the list of faces you get is the same as if you exploded them? Not just the number.

                              Thomas Thomassen — SketchUp Monkey & Coding addict
                              List of my plugins and link to the CookieWare fund

                              1 條回覆 最後回覆 回覆 引用 0
                              • T 離線
                                talig
                                最後由 編輯

                                thomthom - I don't know how I can check that they are the same.
                                I mean, I can work something out and save the array before explosion, then explode it and compare, but will the object comparison be good enough? Do I need to compare certain fields? I'll obviously need to sort them both to have them in the same order - which may also be non-trivial...
                                Ideas?

                                Avatar: all rights reserved to Bryan Eppihimer

                                1 條回覆 最後回覆 回覆 引用 0
                                • thomthomT 離線
                                  thomthom
                                  最後由 編輯

                                  The .to_s method of entities returns something like: #<Sketchup::Face:0xae3ce28>
                                  You could sort the results of each method, exploded and un-exploded, and write it out to two files. When you have your array just use the .sort method. Then you can compare them for differences. For short lists you can do it yourself. For larger lists if you need to test more complex models you can try with some software that compares two files.

                                  Thomas Thomassen — SketchUp Monkey & Coding addict
                                  List of my plugins and link to the CookieWare fund

                                  1 條回覆 最後回覆 回覆 引用 0
                                  • Chris FullmerC 離線
                                    Chris Fullmer
                                    最後由 編輯

                                    I don't think you can .sort a selection set. It always comes back with undefined method '<=>' so I'm guessing they have not built in a way to compare the values of faces to know how to sort them. Even if they implemented sort to work with just the ObjectID string would suffice.

                                    Chris

                                    Lately you've been tan, suspicious for the winter.
                                    All my Plugins I've written

                                    1 條回覆 最後回覆 回覆 引用 0
                                    • Chris FullmerC 離線
                                      Chris Fullmer
                                      最後由 編輯

                                      @chris fullmer said:

                                      Even if they implemented sort to work with just the ObjectID string would suffice.

                                      Oh, that works to do that: selection.to_a.to_s.sort

                                      That will sort it by turning all face ID's into a simple string. Then it can sort them. That will come in handy,

                                      Chris

                                      Lately you've been tan, suspicious for the winter.
                                      All my Plugins I've written

                                      1 條回覆 最後回覆 回覆 引用 0
                                      • thomthomT 離線
                                        thomthom
                                        最後由 編輯

                                        @chris fullmer said:

                                        Oh, that works to do that: selection.to_a.to_s.sort

                                        I was thinking more like selection.to_a.sort
                                        Is there a .sort method for a string?

                                        Thomas Thomassen — SketchUp Monkey & Coding addict
                                        List of my plugins and link to the CookieWare fund

                                        1 條回覆 最後回覆 回覆 引用 0
                                        • T 離線
                                          talig
                                          最後由 編輯

                                          Thanks thomthom, but who promises that that string is a good identifier, when you run different instances of the program, possibly different files (same model saved under different names), if you have the same component twice in the model? Is it documented anywhere what that hex sequence is? (I'm guessing hash, but even so it matters what it takes into account)

                                          Avatar: all rights reserved to Bryan Eppihimer

                                          1 條回覆 最後回覆 回覆 引用 0
                                          • thomthomT 離線
                                            thomthom
                                            最後由 編輯

                                            You're right. Didn't think of that. The Hash, and .entityID changes, also if you explode the groups.

                                            But, another method: You could make a list of the areas of all faces and compare them. Mind you, if any of your groups/components are scaled you have to take that into account.

                                            Thomas Thomassen — SketchUp Monkey & Coding addict
                                            List of my plugins and link to the CookieWare fund

                                            1 條回覆 最後回覆 回覆 引用 0
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • 第一個貼文
                                              最後的貼文
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement