Frame Selected Object

On 09/05/2014 at 15:06, xxxxxxxx wrote:

I'm trying to render the active object isolated from all other objects of the document.
To do so, from inside my plugin, I created a new document, created a clone of the intended object and inserted it in the new document. Then I performed a render of that object and finally, get rid of that document.
It all works fine, except that I can't seem to perform a "Frame Selected Object" on the object that is inside the new document. When I run that command, the current object, still in my current object gets framed.
I'm using this code:

doc = documents.GetActiveDocument()
new_doc=c4d.documents.BaseDocument()
rd = new_doc.GetActiveRenderData().GetData()
new_tree=node.GetClone()
new_doc.InsertObject(new_tree)
xres = 128
yres = 128
bmp = bitmaps.BaseBitmap()
bmp.Init(x=xres, y=yres, depth=24)
rd[c4d.RDATA_XRES]=xres
rd[c4d.RDATA_YRES]=yres
new_doc.SetSelection(new_tree,c4d.SELECTION_NEW)
c4d.CallCommand(12151) # Frame Selected Objects
res = documents.RenderDocument(new_doc, rd, bmp, c4d.RENDERFLAGS_EXTERNAL)
if res==c4d.RENDERRESULT_OK:
    bitmaps.ShowBitmap(bmp)
new_doc.Flush()

How can I frame just the cloned object, inside the new document?

On 10/05/2014 at 00:05, xxxxxxxx wrote:

How do you think the CallCommand would know that it should use your
new document? It operates always on the active scene only.

-Niklas

On 10/05/2014 at 01:11, xxxxxxxx wrote:

I thought it would operate like how you say, but I tried the "shot in the dark" of selecting the newly inserted object and hopped that it would affect the last selected object ;-)
So, it must be made by hand, adjusting the virtual camera of the new document?
Does anyone now how to calculate the placement and orientation of the camera to frame an object?

On 10/05/2014 at 03:15, xxxxxxxx wrote:

You didn't make the new_doc the current document. ;)
Insert it and make it the active document.

On 10/05/2014 at 03:54, xxxxxxxx wrote:

Thank you, Niklas. It worked!!!
However, the object is not being framed correctly.
My code is this:

doc = documents.GetActiveDocument()
new_doc=c4d.documents.BaseDocument()
rd = new_doc.GetActiveRenderData()
rdc = rd.GetData()
new_tree=node.GetClone()
new_doc.InsertObject(new_tree)
xres = 256
yres = 256
bmp = bitmaps.BaseBitmap()
bmp.Init(x=xres, y=yres, depth=24)
rdc[c4d.RDATA_XRES]=xres
rdc[c4d.RDATA_YRES]=yres
rd.SetData(rdc)
c4d.documents.SetActiveDocument(new_doc)
new_doc.SetActiveRenderData(rd)
c4d.EventAdd(c4d.EVENT_FORCEREDRAW)
new_doc.SetSelection(new_tree,c4d.SELECTION_NEW)
c4d.CallCommand(12151) # Frame Selected Objects
res = documents.RenderDocument(new_doc, rdc, bmp, c4d.RENDERFLAGS_EXTERNAL)
c4d.documents.SetActiveDocument(doc)
if res==c4d.RENDERRESULT_OK:
    bitmaps.ShowBitmap(bmp)
new_doc.Flush()

The render shows a clipped object :-(

On 10/05/2014 at 05:33, xxxxxxxx wrote:

Already tried with:

c4d.CallCommand(12148) # Frame Geometry

and with

c4d.CallCommand(12288) # Frame All

To no avail :-(

On 10/05/2014 at 11:29, xxxxxxxx wrote:

Ok, never mind. I created my own framing code. It works for what I need.

On 11/05/2014 at 04:26, xxxxxxxx wrote:

Hi Rui,

# Copyright (c) 2014  Niklas Rosenstein
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
r"""
This script shows how to frame the current object and then render
it into a 256x256 image without loosing information such as the
object's materials. Absolutely non-destructive and memory-optimized.

Changelog:
v 0.1.0 (May 11, 2014)
    Initial version
"""

import c4d

class Remember(object) :
    r""" Remembers the hierarchy position of a node and can restore
    it at a later time. A ``root_routine`` is required when the node
    was the first and only node in the list. """

    def \__init\_\_(self, node) :
        super(Remember, self).\__init\_\_()
        self.parent = node.GetUp()
        self.pred = node.GetPred()

    def restore(self, node, root_routine) :
        node.Remove()
        if self.pred:
            node.InsertAfter(self.pred)
        elif self.parent:
            node.InsertUnder(self.parent)
        else:
            root_routine(node)

class DocumentContext(object) :
    r""" Context manager for a temporary document that will be inserted
    when entering the context and \*killed\* when leaving the context. The
    document can and must not be used after the context was left.

    Inside the context, the document is inserted and active. """

    def \__init\_\_(self, doc=None) :
        if not doc:
            doc = c4d.documents.BaseDocument()
        elif not isinstance(doc, c4d.documents.BaseDocument) :
            raise TypeError('expected BaseDocument')

        super(DocumentContext, self).\__init\_\_()
        self.doc = doc

    def \__enter\_\_(self) :
        c4d.documents.InsertBaseDocument(self.doc)
        c4d.documents.SetActiveDocument(self.doc)
        return self.doc

    def \__exit\_\_(self, exc_type, exc_value, exc_tb) :
        c4d.documents.KillDocument(self.doc)

def render_object(op, width, height) :
    r""" Renders the object \*op\* with the specified resolution. Returns
    the resulting :class:`c4d.bitmaps.BaseBitmap`. It tries to keep the
    memory overhead at a minimum by stripping down op's document before
    cloning it. """

    doc = op.GetDocument()
    if not doc:
        raise ValueError('op is not in a document')

    # Remember the original position of \*op\* in the hierarchy and
    # remove it from the tree.
    location = Remember(op)
    op.Remove()

    # Put all the objects in the document into a Null-Object that
    # we will keep separate.
    root_null = c4d.BaseObject(c4d.Onull)
    for obj in reversed(doc.GetObjects()) :
        obj.Remove()
        obj.InsertUnder(root_null)

    # Insert it into the document again. Then we clone it to get a 
    # document with all the materials that the object referenced.
    doc.InsertObject(op)
    new_doc = doc.GetClone(c4d.COPYFLAGS_0)

    # Restore the structure of the original document.
    for obj in reversed(root_null.GetChildren()) :
        obj.Remove()
        doc.InsertObject(obj)
    root_null.Remove()
    location.restore(op, root_routine=doc.InsertObject)

    # Frame the object and render the new document.
    with DocumentContext(new_doc) :
        new_doc.SetActiveObject(new_doc.GetFirstObject())
        force_redraw() # Redraw is required to create the Geometry
        c4d.CallCommand(12151) # Frame Selected Objects
        return render_document(new_doc, width, height)

def render_document(doc, width, height, depth=24) :
    r""" Renders \*doc\* with the specified width and height. """

    bmp = c4d.bitmaps.BaseBitmap()
    bmp.Init(x=width, y=width, depth=depth)
    
    rdc = doc.GetActiveRenderData().GetData()
    rdc[c4d.RDATA_XRES] = width
    rdc[c4d.RDATA_YRES] = height
    
    c4d.documents.RenderDocument(doc, rdc, bmp, c4d.RENDERFLAGS_EXTERNAL)
    return bmp

def force_redraw() :
    r""" Force a redraw for the current document. """

    flags = c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_FORCEFULLREDRAW
    c4d.DrawViews(flags) 

def main() :
    if not op:
        c4d.gui.MessageDialog("Please select one object.")
        return

    bmp = render_object(op, 256, 256)
    c4d.bitmaps.ShowBitmap(bmp)

main()

This should help you.
-Niklas

On 11/05/2014 at 06:49, xxxxxxxx wrote:

Thank you Niklas. I learned a lot with this code.