Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Exporting Selections

    Scheduled Pinned Locked Moved PYTHON Development
    8 Posts 0 Posters 679 Views
    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.
    • H Offline
      Helper
      last edited by

      On 11/01/2017 at 07:54, xxxxxxxx wrote:

      Hi!

      I'm using C4D R16 and I'm trying to write a short script that goes through all edge and polygon selection tags in the selected objects and exports the data of the selected edges to an external file. The documentation however is very superficial.

      So far I have tried 2 approaches:
      The BaseSelect  object has a write method that uses a HyperFile. This output some data into a file. The file seemed to contain some extra information beyond the edges and polygons, as well as a large number of padding 0-s or 0-s that denoted who knows what. And not knowing how edge data is stored (I assumed originally that each edge would be 2 ints for the 2 end points' id-s, but the file didn't look like that, it contained too few non-zero words), I had no way of interpreting the data.

      The second approach was to use BaseSelect.GetAll() and output the data with the built in IO functions of Python as text. The latter part worked fine, but GetAll() returned a series of 0-s instead of useful data. For the edges it output twice the number of selected edges, for the polygons it output as many 0-s as the olygons selected. This suggests to me that my initial assumption on edges couldn't have been too far off and polygons are stored with id-s that can be used to look up their vertices in which case what was up with the HyperFile?

      My questions:
      - How does C4D store polygon and edge data?
      - Is there a more extensive documentation on the BaseSelect class than the one in the official documentation of the SDK? The official one is neat, but lacks any sort of information on data structures.
      - What's up with all the 0-s?
      - Is what I'm doing feasible at all and off only by overlooking a necessary step or two, or should I try a completely different approach? Is there one?

      Thanks,
      zoliking

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 12/01/2017 at 07:38, xxxxxxxx wrote:

        Hi zoliking,

        welcome to the Plugin Café forums 🙂

        Unfortunately you didn't tell us, what's your final use-case, so it's hard to tell, what's the optimal solution.

        - How does C4D store polygon and edge data?

        C4D doesn't store edge data at all. Edges are a result of the stored polygons, which are stored as an array of CPolygon. CPolygon then stores up to four point indices.

        - Is there a more extensive documentation on the BaseSelect class...?

        I like your paraphrase for "the docs suck!" 🙂
        Unfortunately there's currently no other documentation, than the one you already know. At least none that I know of. Often it can be a good idea to take a look at the C++ documentation, which might contain more information, especially because we are currently trying to extend it.

        - What's up with all the 0-s?

        Well, it's hard to tell without knowing your scenario, but I'd expect it to be a lot of zeros, depending on the selection state. After all a BaseSelect doesn't store anything but zeroes (false) and ones (true)...
        So, like in a famous German movie we could ask "What is a BaseSelect?"
        The BaseSelect class actually is nothing (well, almost nothing) more than an array of boolean values storing a selection state per index. While mostly used to store polygon or point selections, it can (and actually is internally) used to store all kinds of selections.

        I think, the index is the actual problem you are facing.
        When retrieving the BaseSelect from an Edge Selection tag, one might expect something like an edge index, but as said before, there are actually no edges in C4D. Instead the information is stored on a polygon/edge basis. For every polygon there are four entries (for every possible edge) in the BaseSelect.

        Four entries per polygon in the BaseSelect (this is only true for Edge selections!). So you can either index the BaseSelect via "poly index * 4 + edge index" or the other way round for a given BaseSelect index the polygon index will be "bsIdx / 4" and the edge index on this polygon "bsIdx % 4".

        Via the edge index you can get hold of the actual point indices via EdgePoints() function.

            baseSelect = tag.GetBaseSelect()
            obj = tag.GetObject()
            polyCount = obj.GetPolygonCount()
            
            for e in xrange(polyCount * 4) :
                if baseSelect.IsSelected(e) :
                    print "Poly: ", e/4, "Edge index:", e%4, "Edge point index a - b: ", obj.GetPolygon(e/4).EdgePoints(e%4)[0], " - ", obj.GetPolygon(e/4).EdgePoints(e%4)[1]
        

        Finally there's one more peculiarity you need to know. As the information is stored on a polygon basis, a edge may be "selected" several times, if it's shared by several polygons.

        - Is what I'm doing feasible at all...?

        This is probably a bit difficult to answer without knowing what you are trying to achieve in the end.

        If you are just trying to move the data out of and then back into C4D, I'd stick to the hyperfile approach. There you wouldn't have to care about the indices at all (and it should simply work out of the box). But as you already found out a hyperfile is not a plain file. There are data type IDs stored with every entry, for some data also length information. These files are not thought to be read by other applications.

        So, if you want to exchange data with another application, you are probably better off, getting the information in the way described above and then write it to your own file format in what ever way you need.

        I hope, I was able to shed some light.

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 16/01/2017 at 01:09, xxxxxxxx wrote:

          Thank you very much for that information, it sounds useful.

          My end goal is that I'm trying to write a proof of concept test program for a game idea I have and in that some edges and polygons in certain models are special, that's why I need to export selections from C4D.

          My "all the 0-s" question wasn't specific enough though, it related to the fact that all returned values were 0 when I worked with nonzero selections in my second attempt.

          Here is my code:

          def main() :
            objList = doc.GetActiveObjects(True)
            obj = objList[0]
           
            tag = obj.GetFirstTag()
           
            dataFile = open("Drive:/MyPath/MyFile.txt", "w")

          while tag:
                if (tag.GetType() == c4d.Tpolygonselection or tag.GetType() == c4d.Tedgeselection) :
                    selectionTag = tag.GetBaseSelect()
                    dataList = selectionTag.GetAll(selectionTag.GetCount())
                    for data in dataList:
                        dataFile.write(str(data))
                    dataFile.write('\n')
                tag = tag.GetNext()
           
            dataFile.close()

          if __name__=='__main__':
            main()

          Thanks again for the information!

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 19/01/2017 at 08:35, xxxxxxxx wrote:

            Any ideas anyone? GetAll() should return non zero integers for non zero selections ideally, right?

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 20/01/2017 at 00:56, xxxxxxxx wrote:

              Everything as been said above. Here is a working example.

              import c4d
                
              def main() :
                  objList = doc.GetActiveObjects(True)
                  obj = objList[0]
                  
                  tag = obj.GetFirstTag()
                  
                
                  poly_selected = list()
                  edge_selected = list()
                  if not isinstance(obj, c4d.PointObject) : #Mayvbe you should check PolygonObject depending of what you want to do
                      return
                  
                  while tag:
                      if tag.GetType() == c4d.Tpolygonselection:
                          points_count = obj.GetPolygonCount()
                          selectionTag = tag.GetBaseSelect()
                          
                          dataList = selectionTag.GetAll(points_count)
                          for i in xrange(points_count) :
                              if dataList[i]:
                                  poly_selected.append(i)
                      
                      elif tag.GetType() == c4d.Tedgeselection:
                          points_count = obj.GetPolygonCount() * 4 #Read Andreas post
                          selectionTag = tag.GetBaseSelect()
                          
                          dataList = selectionTag.GetAll(points_count)
                          for i in xrange(points_count) :
                              if dataList[i]:
                                  if i%4: #remove edge with id 0
                                      edge_selected.append(i%4)
                              
                      tag = tag.GetNext()
                      
                  print poly_selected
                  print list(set(edge_selected)) #Remove duplicate entry
                
                
              if __name__=='__main__':
                  main()
              

              You have wrote selectionTag.GetCount()) but the count have to be done on poly/point count not the count of the tag.

              It's look like edge 0 is always returned. Is it normal?

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 20/01/2017 at 08:53, xxxxxxxx wrote:

                What do you mean, edge 0 is always returned? I haven't seen anything special with edge 0, when doing my tests here.

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 20/01/2017 at 09:57, xxxxxxxx wrote:

                  Ok that was a miss understand from me.
                  I was thinking edge id are unique for each edge (as a point index).

                  But as you said they belong to a polygon id or two point id.
                  So the only way for checking if we got twice the same edge is by getting edge from 2 point id?

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 22/01/2017 at 10:42, xxxxxxxx wrote:

                    Thank you!

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post