def recursive_intersect(self, p, tmin=0):
        """
        binary recursion stack starts unwinding when
        reach bileaf node p

        * p.l.is_leaf and p.r.is_leaf
        
        recursive argument changes:
        
        * p <- p.l  tmin <- tminL
        * p <- p.r  tmin <- tminR


        * http://stackoverflow.com/questions/12468251/convert-recursion-to-iteration
        * http://stackoverflow.com/questions/7548026/convert-recursive-binary-tree-traversal-to-iterative

        """ 
        assert p.is_operation
        miss =  intersect_miss(p, self.ray, tmin)
        tminL = tmin
        tminR = tmin
        loopcount = 0 
        ctrl = (CtrlLoopLeft | CtrlLoopRight)

        while ctrl & (CtrlLoopLeft | CtrlLoopRight ):
            if ctrl & CtrlLoopLeft: 
                if p.l.is_leaf:
                    left = intersect_primitive(p.l, self.ray, tminL)
                else:
                    left = self.recursive_intersect(p.l, tmin=tminL)
                pass
            pass
            if ctrl & CtrlLoopRight: 
                if p.r.is_leaf:
                    right = intersect_primitive(p.r, self.ray, tminR)
                else:
                    right = self.recursive_intersect(p.r, tmin=tminR)
                pass
            pass
            ctrl = self.binary_ctrl(p.operation, left, right, tminL, tminR)    

            if ctrl == CtrlLoopLeft:
                tminL = left.t + self.epsilon
            elif ctrl == CtrlLoopRight:
                tminR = right.t + self.epsilon
            else:
                pass # will fall out the ctrl loop
            pass 
            loopcount += 1 
            assert loopcount < 10  
        pass  #  end while ctrl loop

        assert ctrl in [CtrlReturnMiss, CtrlReturnLeft, CtrlReturnRight, CtrlReturnFlipRight ]
        result = self.binary_result(ctrl, miss, left, right, tmin)
        if self.debug:
            p.recursive = result

        return result
    def recursive_intersect_2(self, p, tmin=0):

        if p.is_leaf:
            return intersect_primitive(p, self.ray, tmin)
        pass
        miss =  intersect_miss(p, self.ray, tmin)
        tminL = tmin
        tminR = tmin

        loopcount = 0 
        ctrl = (CtrlLoopLeft | CtrlLoopRight)
        while ctrl & (CtrlLoopLeft | CtrlLoopRight ):
            if ctrl & CtrlLoopLeft: 
                left = self.recursive_intersect_2(p.l, tmin=tminL)
            pass
            if ctrl & CtrlLoopRight: 
                right = self.recursive_intersect_2(p.r, tmin=tminR)
            pass
            ctrl = self.binary_ctrl(p.operation, left, right, tminL, tminR)    
            if ctrl == CtrlLoopLeft:
                tminL = left.t + self.epsilon
            elif ctrl == CtrlLoopRight:
                tminR = right.t + self.epsilon
            else:
                pass # will fall out the ctrl loop
            pass 
            loopcount += 1 
            assert loopcount < 10  
        pass  #  end while ctrl loop
        assert ctrl in [CtrlReturnMiss, CtrlReturnLeft, CtrlReturnRight, CtrlReturnFlipRight ]
        result = self.binary_result(ctrl, miss, left, right, tmin)
        if self.debug:
            p.recursive = result
        return result
Example #3
0
    def Intersect(self):
        """
        # the below handling of a operation holding primitives 
        # initially seems a special case cop out, subverting the iterative approach, 
        # that is liable to to work for simple trees, but not for complex ones 
        # 
        # BUT on deeper refeclection that isnt the case, need to allow to keep going left until 
        # find primitives one level below in order to get the ball rolling 
        # and start filling the primStack, as go back upwards
        """
        action = self.action
        assert action in [GotoLft, GotoRgh]

        if self.node.is_primitive:

            tt, nn, name, act = intersect_primitive(self.node, self.ray,
                                                    self.tmin)
            if action == GotoLft:
                self.tl = tt
                self.nl = nn
                self.lname = name
                self.lact = act
                if self.debug > 3:
                    log.info("pr.Intersect.GotoLft %s tl %5.2f lname %s " %
                             (self.node.name, self.tl if self.tl else -1,
                              self.lname))
                pass
            elif action == GotoRgh:
                self.tr = tt
                self.nr = nn
                self.rname = name
                self.ract = act
                if self.debug > 3:
                    log.info("pr.Intersect.GotoRgh %s tr %5.2f rname %s " %
                             (self.node.name, self.tr if self.tr else -1,
                              self.rname))
                pass
            pass
            self.action = Compute
            self.node = self.node.parent

        elif self.node.is_operation:

            gotoL = intersectBox(self.node.left)
            gotoR = intersectBox(self.node.right)

            if gotoL and self.node.left.is_primitive:
                self.record_traversal(self.node.left)
                tt, nn, name, act = intersect_primitive(
                    self.node.left, self.ray, self.tmin)
                self.tl = tt
                self.nl = nn
                self.lname = name
                self.lact = act
                gotoL = False

                if self.debug > 3:
                    log.info("op.Intersect.gotoL %s tl %5.2f lname %s " %
                             (self.node.left.name, self.tl, self.lname))

            if gotoR and self.node.right.is_primitive:
                self.record_traversal(self.node.right)
                tt, nn, name, act = intersect_primitive(
                    self.node.right, self.ray, self.tmin)
                self.tr = tt
                self.nr = nn
                self.rname = name
                self.ract = act
                gotoR = False

                if self.debug > 3:
                    log.info("op.Intersect.gotoR %s tr %5.2f rname %s " %
                             (self.node.right.name, self.tr, self.rname))

            # immediate right/left primitives are not stacked, as are ready for compute
            if gotoL or gotoR:
                if gotoL:
                    # non-primitive subtree intersect
                    self.primStack.push(
                        (self.tl, self.nl, self.lname, self.lact),
                        debug=self.debug > 1)
                    self.actionStack.push(LoadLft, debug=self.debug > 1)
                elif gotoR:
                    self.primStack.push(
                        (self.tr, self.nr, self.rname, self.ract),
                        debug=self.debug > 1)
                    self.actionStack.push(LoadRgh, debug=self.debug > 1)
                pass
            else:
                # both gotoL and gotoR False means miss OR both prim intersects done, so are ready for compute
                self.tminStack.push(self.tmin, debug=self.debug > 1)
                self.actionStack.push(LoadLft, debug=self.debug > 1)
                self.actionStack.push(SaveLft, debug=self.debug > 1)
            pass
            # NB not the same as doing this interleaved within the above, as this places
            # no demands on (gotoL or gotoR)
            if gotoL:
                self.action = GotoLft
            elif gotoR:
                self.action = GotoRgh
            else:
                self.action = Compute
            pass

            if self.debug > 3:
                log.info(
                    "Intersect -> %s  tr/tl %5.2f/%5.2f rname/lname %s/%s " %
                    (desc_action(self.action), self.tr if self.tr else -1,
                     self.tl if self.tl else -1, self.rname, self.lname))

        else:
            assert 0
Example #4
0
    def iterative_intersect(self, root):
        """
        Iterative CSG boolean intersection

        * https://www.hackerearth.com/practice/notes/iterative-tree-traversals/

        """
        assert self.typ == "ITERATIVE"
        self.top = root
        self.node = root

        if self.node.is_primitive:
            return intersect_primitive(self.node, self.ray, self.tmin)

        self.count = 0
        limit = 10

        self.actionStack.push(Compute)
        #self.actionStack.push(GotoLft)

        self.action = GotoLft

        do_goto = False
        # ignoring the first GotoLft avoids the virtual root and associated termination complications

        while self.actionStack.count() > 0:
            self.count += 1

            #self.action = self.actionStack.pop(debug=self.debug > 2)

            if self.action == SaveLft:
                self.SaveLft_()
                self.action = GotoRgh

            if self.action == GotoLft or self.action == GotoRgh:
                if do_goto:
                    self.GoTo()
                pass
                do_goto = True

            if self.action == GotoLft or self.action == GotoRgh:
                self.Intersect()

            if self.action == LoadLft or self.action == LoadRgh:
                self.Load_()
                self.action = Compute

            if self.action == Compute:
                self.Compute_()
            pass

            if self.action == Return:
                break

            if self.count == limit:
                log.fatal("iray %d ray %s count %d reaches limit %d " %
                          (self.iray, self.ray, self.count, limit))
                assert 0

        pass
        return self.Return_()
Example #5
0
    def recursive_intersect(self, root, depth=0, tmin=0):
        """
        * minimizing use of member vars makes recursive algorithm easier to understand
        * instead use local vars, which will have different existance at the 
          different levels of the recursion
        * can think of member vars as effective globals wrt the recursion

        * loopers result in recursive call repeating the same node, with tmin advanced 
        * recursively never traverse the root again ? are always going down with root.left root.right
          never going up ?

        * although the traverse never goes up, completion of the recursive instance calls 
          does go back up once hitting primitives in the leaves 

        """
        assert root
        assert self.typ == "RECURSIVE"
        if depth == 0:
            self.top = root
        pass
        self.node = root
        # above are just for debug comparison against iterative algo, not used below

        if root.is_primitive:
            return intersect_primitive(root, self.ray, tmin)

        elif root.is_operation:

            tl, nl, lname, lact = self.recursive_intersect(root.left,
                                                           depth=depth + 1,
                                                           tmin=tmin)
            tr, nr, rname, ract = self.recursive_intersect(root.right,
                                                           depth=depth + 1,
                                                           tmin=tmin)

            root.rstack = (tl, nl, lname, lact, tr, nr, rname, ract
                           )  # for debug comparison with iterative

            loopcount = 0
            looplimit = 10
            while loopcount < looplimit:
                loopcount += 1

                stateL = self.classify(tl, nl, tmin)  # tmin_l tmin_r ?
                stateR = self.classify(tr, nr, tmin)

                acts = boolean_table(root.operation, stateL, stateR)

                opr = "%s(%s:%s,%s:%s)" % (desc[root.operation], lname,
                                           desc_state[stateL], rname,
                                           desc_state[stateR])

                act_RetMiss = (RetMiss & acts)
                act_RetL = (RetL & acts)
                act_RetR = (RetR & acts)
                act_LoopL = (LoopL & acts)
                act_LoopR = (LoopR & acts)
                act_RetLIfCloser = ((RetLIfCloser & acts) and tl <= tr)
                act_LoopLIfCloser = ((LoopLIfCloser & acts) and tl <= tr)
                act_RetRIfCloser = ((RetRIfCloser & acts) and tr < tl)
                act_LoopRIfCloser = ((LoopRIfCloser & acts) and tr < tl)

                trep = self.trep_fmt(tmin, tl, tr)
                ret = ()
                if act_RetMiss:
                    act = RetMiss
                    ret = None, None, None, act

                elif act_RetL or act_RetLIfCloser:
                    act = RetLIfCloser if act_RetLIfCloser else RetL
                    ret = tl, nl, lname, act

                elif act_RetR or act_RetRIfCloser:
                    act = RetRIfCloser if act_RetRIfCloser else RetR
                    if (FlipR & acts): nr = -nr
                    ret = tr, nr, rname, act

                elif act_LoopL or act_LoopLIfCloser:
                    act = LoopLIfCloser if act_LoopLIfCloser else LoopL
                    tl, nl, lname, _ = self.recursive_intersect(root.left,
                                                                depth=depth +
                                                                1,
                                                                tmin=tl)

                elif act_LoopR or act_LoopRIfCloser:
                    act = LoopRIfCloser if act_LoopRIfCloser else LoopR
                    tr, nr, rname, _ = self.recursive_intersect(root.right,
                                                                depth=depth +
                                                                1,
                                                                tmin=tr)

                else:
                    log.fatal("[%d] RECURSIVE UNHANDLED acts " % (loopcount))
                    assert 0

                self.act = act

                if self.debug > 1:
                    log.info("(%d)[%d] RECURSIVE %s : %s -> %s : %s " %
                             (self.iray, loopcount, root.name, opr,
                              desc_acts(self.act), trep))

                if len(ret) > 0:

                    return ret
                else:
                    # only Loop-ers hang aroud here to intersect again with advanced tmin, the rest return up to caller
                    assert act in [LoopLIfCloser, LoopL, LoopRIfCloser, LoopR]
                pass

            else:
                log.fatal(
                    " depth %d root %s root.is_operation %d root.is_primitive %d "
                    % (depth, root, root.is_operation, root.is_primitive))
                assert 0
        pass
        log.fatal("[%d] RECURSIVE count EXCEEDS LIMIT %d " %
                  (loopcount, looplimit))
        assert 0
        return None, None, None, 0
Example #6
0
def iterative_intersect(partBuffer, ray, tst):
    """  
    For following code paths its simpler to instrument rays, not intersects
    as isects keep getting created, pushed, popped, etc..
    """
    debug = tst.debug
    postorder_sequence = [0x1, 0x132, 0x1376254, 0x137fe6dc25ba498]
    ierr = 0
    abort_ = False
    instrument = True

    partOffset = 0
    numParts = len(partBuffer)
    primIdx = -1

    fullHeight = ffs_(numParts + 1) - 2
    height = fullHeight - 1

    postorder = postorder_sequence[height]
    numInternalNodes = (0x1 << (1 + height)) - 1

    _tmin = np.zeros((TRANCHE_STACK_SIZE), dtype=np.float32)
    _tranche = np.zeros((TRANCHE_STACK_SIZE), dtype=np.uint32)
    tranche = -1

    csg_ = [CSG_(), CSG_()]
    lhs = csg_[LHS]
    rhs = csg_[RHS]
    lhs.curr = -1
    rhs.curr = -1

    isect = np.zeros([4, 4, 4], dtype=np.float32)

    tranche = TRANCHE_PUSH0(_tranche, _tmin, tranche,
                            POSTORDER_SLICE(0, numInternalNodes), ray.tmin)

    while tranche >= 0:
        tranche, tmp, tmin = TRANCHE_POP0(_tranche, _tmin, tranche)
        begin = POSTORDER_BEGIN(tmp)
        end = POSTORDER_END(tmp)

        i = begin
        while i < end:

            nodeIdx = POSTORDER_NODE(postorder, i)
            leftIdx = nodeIdx * 2
            rightIdx = nodeIdx * 2 + 1
            depth = TREE_DEPTH(nodeIdx)
            subNodes = (0x1 << (1 + height - depth)) - 1
            halfNodes = (subNodes - 1) / 2
            bileaf = leftIdx > numInternalNodes

            operation = partBuffer[nodeIdx - 1, Q1, W].view(np.uint32)

            tX_min = np.zeros(2, dtype=np.float32)
            tX_min[LHS] = tmin
            tX_min[RHS] = tmin

            x_state = np.zeros(2, dtype=np.uint32)

            if bileaf:
                isect[LEFT, 0, W] = 0.
                isect[RIGHT, 0, W] = 0.
                isect[LEFT] = intersect_primitive(
                    Node.fromPart(partBuffer[partOffset + leftIdx - 1]), ray,
                    tX_min[LHS])
                isect[RIGHT] = intersect_primitive(
                    Node.fromPart(partBuffer[partOffset + rightIdx - 1]), ray,
                    tX_min[RHS])
            else:
                try:
                    isect[LEFT] = lhs.pop()
                except Error:
                    log_info("%s : ERROR_LHS_POP_EMPTY : ABORT  " %
                             (pfx("I0", tst.iray, nodeIdx, bileaf)))
                    ierr |= ERROR_LHS_POP_EMPTY
                    abort_ = True
                    break
                pass
                try:
                    isect[RIGHT] = rhs.pop()
                except Error:
                    log_info("%s : ERROR_RHS_POP_EMPTY : ABORT  " %
                             (pfx("I0", tst.iray, nodeIdx, bileaf)))
                    ierr |= ERROR_RHS_POP_EMPTY
                    abort_ = True
                    break
                pass
            pass

            x_state[LHS] = CSG_CLASSIFY(isect[LEFT][0], ray.direction,
                                        tX_min[LHS])
            x_state[RHS] = CSG_CLASSIFY(isect[RIGHT][0], ray.direction,
                                        tX_min[RHS])
            ctrl = boolean_ctrl_packed_lookup(
                operation, x_state[LHS], x_state[RHS],
                isect[LEFT][0][W] <= isect[RIGHT][0][W])

            if debug:
                log_info("%s :   %s   " %
                         (pfx("I0", tst.iray, nodeIdx, bileaf),
                          fmt(isect[LEFT], isect[RIGHT], x_state[LHS],
                              x_state[RHS], ctrl)))
            if instrument:
                ray.addseq(ctrl)
            pass

            reiterate = False
            if ctrl < CTRL_.LOOP_A:
                ## recursive return after first classify, needs an avenue to push
                pass
            else:
                side = ctrl - CTRL_.LOOP_A
                loop = -1

                while side > -1 and loop < 10:
                    if debug:
                        log_info(
                            "%s :  side %s loop %d " %
                            (pfx("I", tst.iray, nodeIdx, bileaf), side, loop))
                    loop += 1
                    THIS = side + LEFT
                    tX_min[side] = isect[THIS][0][W] + propagate_epsilon

                    if bileaf:
                        isect[THIS] = intersect_primitive(
                            Node.fromPart(partBuffer[partOffset + leftIdx +
                                                     side - 1]), ray,
                            tX_min[side])
                    else:
                        try:
                            isect[THIS] = csg_[side].pop()
                        except Error:
                            log_info("%s : ERROR_POP_EMPTY : ABORT : %s " %
                                     (pfx("I0", tst.iray, nodeIdx,
                                          bileaf), stk(csg_[LHS], csg_[RHS])))
                            ierr |= ERROR_POP_EMPTY
                            abort_ = True
                            break
                        pass
                    pass

                    x_state[side] = CSG_CLASSIFY(isect[THIS][0], ray.direction,
                                                 tX_min[side])
                    ctrl = boolean_ctrl_packed_lookup(
                        operation, x_state[LHS], x_state[RHS],
                        isect[LEFT][0][W] <= isect[RIGHT][0][W])
                    if debug:
                        log_info("%s :   %s   " %
                                 (pfx("I1", tst.iray, nodeIdx, bileaf),
                                  fmt(isect[LEFT], isect[RIGHT], x_state[LHS],
                                      x_state[RHS], ctrl)))

                    if instrument:
                        ray.addseq(ctrl)
                    pass
                    side = ctrl - CTRL_.LOOP_A  ## NB possibly changed side

                    if side > -1 and not bileaf:
                        other = 1 - side
                        tX_min[side] = isect[THIS][0][W] + propagate_epsilon
                        csg_[other].push(isect[other + LEFT])

                        leftTree = POSTORDER_SLICE(i - 2 * halfNodes,
                                                   i - halfNodes)
                        rightTree = POSTORDER_SLICE(i - halfNodes, i)
                        endTree = POSTORDER_SLICE(
                            i, end)  # FIX numInternalNodes -> end
                        sideTree = leftTree if side == LHS else rightTree

                        tranche = TRANCHE_PUSH(_tranche, _tmin, tranche,
                                               endTree, tmin)
                        tranche = TRANCHE_PUSH(_tranche, _tmin, tranche,
                                               sideTree, tX_min[side])
                        reiterate = True
                        break
                    pass
                pass  # side loop
            pass

            if reiterate or abort_:
                break
            pass

            isect[RFLIP] = isect[RIGHT]
            isect[RFLIP, 0, X] = -isect[RFLIP, 0, X]
            isect[RFLIP, 0, Y] = -isect[RFLIP, 0, Y]
            isect[RFLIP, 0, Z] = -isect[RFLIP, 0, Z]

            assert ctrl < CTRL_.LOOP_A
            result = isect[ctrl]
            nside = LHS if nodeIdx % 2 == 0 else RHS  # even on left

            csg_[nside].push(result)

            i += 1  # next postorder node in the tranche
        pass  # end traversal loop
        if abort_: break
    pass  # end tranch loop

    LHS_curr = csg_[LHS].curr
    RHS_curr = csg_[RHS].curr

    ierr |= ERROR_LHS_END_NONEMPTY if LHS_curr != -1 else 0
    ierr |= ERROR_RHS_END_EMPTY if RHS_curr != 0 else 0

    assert RHS_curr == 0 and ierr == 0
    assert RHS_curr == 0, RHS_curr

    ret = csg_[RHS].data[0]
    assert ret.shape == (4, 4)
    ret[0, W] = abs(ret[0, W])
    return ret
Example #7
0
def evaluative_intersect(partBuffer, ray, tst):
    debug = tst.debug

    partOffset = 0
    numParts = len(partBuffer)
    primIdx = -1

    fullHeight = TREE_HEIGHT(numParts)
    height = fullHeight - 1
    numInternalNodes = TREE_NODES(height)
    numNodes = TREE_NODES(fullHeight)

    postorder_sequence = [0x1, 0x132, 0x1376254, 0x137fe6dc25ba498]

    try:
        postorder = postorder_sequence[fullHeight]
    except IndexError:
        postorder = getattr(tst.root, '_postorder_leaf', None)

    tr = Tranche()
    tr.push(POSTORDER_SLICE(0, numNodes), ray.tmin)

    csg = CSGD()
    csg.curr = -1

    tloop = -1

    while tr.curr > -1:
        tloop += 1
        assert tloop < 20  # wow root3 needs lots of loops

        slice_, tmin = tr.pop()
        begin = POSTORDER_BEGIN(slice_)
        end = POSTORDER_END(slice_)
        beginIdx = POSTORDER_NODE(postorder, begin)
        endIdx = POSTORDER_NODE(postorder, end - 1)

        #if debug:log.info("%6d E : tranche begin %d end %d  (nodeIdx %d:%d)tmin %5.2f tloop %d  %r " % (tst.iray, begin, end, beginIdx, endIdx,  tmin, tloop, csg))

        i = begin
        while i < end:
            nodeIdx = POSTORDER_NODE(postorder, i)

            depth = TREE_DEPTH(nodeIdx)
            subNodes = TREE_NODES(fullHeight - depth)
            halfNodes = (subNodes - 1) / 2
            primitive = nodeIdx > numInternalNodes

            operation = partBuffer[nodeIdx - 1, Q1, W].view(np.uint32)

            #print "(%d) depth %d subNodes %d halfNodes %d " % (nodeIdx, depth, subNodes, halfNodes )

            if primitive:
                isect = intersect_primitive(
                    Node.fromPart(partBuffer[partOffset + nodeIdx - 1]), ray,
                    tmin)
                isect[0, W] = math.copysign(isect[0, W],
                                            -1. if nodeIdx % 2 == 0 else 1.)
                csg.push(isect, nodeIdx)
            else:
                if csg.curr < 1:
                    raise Error(
                        "ERROR_POP_EMPTY : csg.curr < 1 when need two items to combine"
                    )

                firstLeft = signbit(csg.data[csg.curr, 0, W])
                secondLeft = signbit(csg.data[csg.curr - 1, 0, W])

                if not firstLeft ^ secondLeft:
                    raise Error("ERROR_XOR_SIDE")

                left = csg.curr if firstLeft else csg.curr - 1
                right = csg.curr - 1 if firstLeft else csg.curr

                l_state = CSG_CLASSIFY(csg.data[left, 0], ray.direction, tmin)
                r_state = CSG_CLASSIFY(csg.data[right, 0], ray.direction, tmin)

                t_left = abs(csg.data[left, 0, W])
                t_right = abs(csg.data[right, 0, W])

                ctrl = boolean_ctrl_packed_lookup(operation, l_state, r_state,
                                                  t_left <= t_right)
                ray.addseq(ctrl)

                if debug:
                    log_info("%s :   %s   " %
                             (pfx("E1", tst.iray, nodeIdx, None),
                              fmt(csg.data[left], csg.data[right], l_state,
                                  r_state, ctrl)))

                UNDEFINED = 0
                CONTINUE = 1
                BREAK = 2

                if ctrl < CTRL_.LOOP_A:
                    result = np.zeros((4, 4), dtype=np.float32)
                    if not ctrl == CTRL_.RETURN_MISS:
                        result[:] = csg.data[left if ctrl ==
                                             CTRL_.RETURN_A else right]
                    pass
                    if ctrl == CTRL_.RETURN_FLIP_B:
                        result[0, X] = -result[0, X]
                        result[0, Y] = -result[0, Y]
                        result[0, Z] = -result[0, Z]
                    pass
                    result[0,
                           W] = math.copysign(result[0, W],
                                              -1. if nodeIdx % 2 == 0 else 1.)

                    if debug:
                        log_info(
                            "%s :   %s " %
                            (pfx("E2", tst.iray, nodeIdx, None), f4(result)))

                    csg.pop()
                    csg.pop()
                    csg.push(result, nodeIdx)

                    act = CONTINUE
                else:
                    loopside = left if ctrl == CTRL_.LOOP_A else right
                    otherside = right if ctrl == CTRL_.LOOP_A else left

                    leftIdx = 2 * nodeIdx
                    rightIdx = leftIdx + 1
                    otherIdx = rightIdx if ctrl == CTRL_.LOOP_A else leftIdx

                    tminAdvanced = abs(csg.data[loopside, 0,
                                                W]) + propagate_epsilon

                    other = np.zeros(
                        (4, 4), dtype=np.float32
                    )  #  need tmp as pop about to invalidate indices
                    other[:] = csg.data[otherside]

                    csg.pop()
                    csg.pop()
                    csg.push(other, otherIdx)

                    endTree = POSTORDER_SLICE(i, end)  # fix numNodes -> end
                    leftTree = POSTORDER_SLICE(i - 2 * halfNodes,
                                               i - halfNodes)
                    rightTree = POSTORDER_SLICE(i - halfNodes, i)
                    loopTree = leftTree if ctrl == CTRL_.LOOP_A else rightTree

                    tr.push(endTree, tmin)
                    tr.push(loopTree, tminAdvanced)

                    act = BREAK
                pass  # return or "recursive" call
                if act == BREAK:
                    break
                pass
            pass
            i += 1  # next postorder node in the tranche
        pass  # end traversal loop
    pass  # end tranch loop
    assert csg.curr == 0, csg.curr
    ret = csg.data[0]
    assert ret.shape == (4, 4)
    ret[0, W] = abs(ret[0, W])
    return ret
Example #8
0
    def recursive_intersect_r(nodeIdx, tmin):
        """  
        :param nodeIdx: 1-based levelorder tree index
        """
        leftIdx = nodeIdx * 2
        rightIdx = nodeIdx * 2 + 1
        bileaf = leftIdx > numInternalNodes

        isect = np.zeros([4, 4, 4], dtype=np.float32)
        tX_min = np.zeros(2, dtype=np.float32)
        tX_min[LHS] = tmin
        tX_min[RHS] = tmin
        x_state = np.zeros(2, dtype=np.uint32)

        if bileaf:
            isect[LEFT, 0, W] = 0.
            isect[RIGHT, 0, W] = 0.
            isect[LEFT] = intersect_primitive(
                Node.fromPart(partBuffer[partOffset + leftIdx - 1]), ray,
                tX_min[LHS])
            isect[RIGHT] = intersect_primitive(
                Node.fromPart(partBuffer[partOffset + rightIdx - 1]), ray,
                tX_min[RHS])
        else:
            isect[LEFT] = recursive_intersect_r(leftIdx, tX_min[LHS])
            isect[RIGHT] = recursive_intersect_r(rightIdx, tX_min[RHS])
        pass

        x_state[LHS] = CSG_CLASSIFY(isect[LEFT][0], ray.direction, tX_min[LHS])
        x_state[RHS] = CSG_CLASSIFY(isect[RIGHT][0], ray.direction,
                                    tX_min[RHS])

        operation = partBuffer[nodeIdx - 1, Q1, W].view(np.uint32)
        ctrl = boolean_ctrl_packed_lookup(
            operation, x_state[LHS], x_state[RHS],
            isect[LEFT][0][W] <= isect[RIGHT][0][W])
        #if debug:log_info("%s :   %s   " % (pfx("R0",tst.iray,nodeIdx,bileaf), fmt(isect[LEFT],isect[RIGHT],x_state[LHS],x_state[RHS],ctrl)))

        if instrument:
            ray.addseq(ctrl)

        side = ctrl - CTRL_.LOOP_A

        loop = -1
        while side > -1 and loop < 10:
            loop += 1
            THIS = side + LEFT
            tX_min[side] = isect[THIS][0][W] + propagate_epsilon
            if bileaf:
                isect[THIS] = intersect_primitive(
                    Node.fromPart(partBuffer[partOffset + leftIdx + side - 1]),
                    ray, tX_min[side])
            else:
                isect[THIS] = slavish_intersect_r(leftIdx + side, tX_min[side])
            pass
            x_state[side] = CSG_CLASSIFY(isect[THIS][0], ray.direction,
                                         tX_min[side])
            ctrl = boolean_ctrl_packed_lookup(
                operation, x_state[LHS], x_state[RHS],
                isect[LEFT][0][W] <= isect[RIGHT][0][W])
            if instrument:
                ray.addseq(ctrl)
            pass
            side = ctrl - CTRL_.LOOP_A  ## NB possibly changed side
        pass

        isect[RFLIP] = isect[RIGHT]
        isect[RFLIP, 0, X] = -isect[RFLIP, 0, X]
        isect[RFLIP, 0, Y] = -isect[RFLIP, 0, Y]
        isect[RFLIP, 0, Z] = -isect[RFLIP, 0, Z]

        assert ctrl < CTRL_.LOOP_A

        # recursive return is equivalent to what gets popped ?
        if debug:
            log_info("%s :   %s   " % (pfx("R1", tst.iray, nodeIdx, bileaf),
                                       fmt(isect[LEFT], isect[RIGHT],
                                           x_state[LHS], x_state[RHS], ctrl)))
        return isect[ctrl]
    def iterative_intersect(self, root, depth=0, tmin=0, debug=1, icheck=True):
        """
        :param root:
        :return isect: I instance

        0-based postorder p-indices from p0 at leftmost to p14 at root, for height 4 tree, 
        excluding leaf nodes to make height 3 internal nodes::

            In [78]: root4.txt
            Out[78]: 
            root4                                                                                                                            
                                                                         14                                                                
                                                                          o                                                                
                                          6                                                              13                                
                                          o                                                               o                                
                          2                               5                               9                              12                
                          o                               o                               o                               o                
                  0               1               3               4               7               8              10              11        
                  o               o               o               o               o               o               o               o        
                                                                                                                                           
              o       o       o       o       o       o       o       o       o       o       o       o       o       o       o       o    



        Consider evaluating p13 subtree, of sub-height 2 (from full-height - depth = 3 - 1 = 2 )  

        * reiterate p13.left   (p9) ->  repeat p7,  p8, p9  [with live tree Node.leftmost(p13.l)->p7 ]
        * reiterate p13.right (p12) ->  repeat p10,p11,p12  [with live tree Node.leftmost(p13.r)->p10 ]

        Need to derive the p-indices that need to repeat based on the depth of p13 and
        the height of the tree.

        * sub-nodes 7,   l-nodes = r-nodes = (sub-nodes - 1)/2 = (7 - 1)/2 = 3 

        *   13-3   +0, +1, +2 =  10, 11, 12 
        *   13-3*2 +0, +1, +2 =  7, 8, 9  

        *  beneath p13 are two sub-subtrees 


        Operation height is 3,    2^(h+1) = 2^(3+1) - 1               = 15  nodes in total
        Subtree starting p13 is at depth 1,   2^(h-d+1) = 2^(2+1) - 1 =  7  nodes 
        Subtree starting p9 is at depth 2,    2^(h-d+1) = 2^(1+1) - 1 =  3  nodes

        """
        self.check_tree(root)

        lhs = []
        rhs = []


        tranche = []
        tranche.append([tmin,Node.leftmost(root),None])

        if icheck:
            # check using 0-based postorder indices
            i_height = root.maxdepth - 1   # excluding leaves
            numInternalNodes = Node.NumNodes(i_height)

            itranche = []
            itranche.append([tmin, 0, numInternalNodes])

            i_postorder = Node.postorder_r(root, nodes=[], leaf=False)
            assert len(i_postorder) == numInternalNodes

            lmo = Node.leftmost(root) 
            assert lmo.pidx == 0 and lmo is i_postorder[0] 
            assert i_postorder[numInternalNodes-1].next_ == None

        else:
            itranche = None
        pass


        tcount = 0 

        while len(tranche) > 0:

            assert len(tranche) <= 4

            tmin, begin, end = tranche.pop()
            
            if icheck:
                i_tmin, i_begin, i_end = itranche.pop()

                #print "icheck (%d,%d) [%s,%s] " % (i_begin, i_end, begin, end ) 

                assert len(itranche) == len(tranche)
                assert i_tmin == tmin
                assert i_postorder[i_begin] is begin 
                assert i_postorder[i_end-1].next_ == end 
            pass


            #log.info("%s : start tranche %d begin %s end %s " % (self.pfx, tcount, begin, end))
            tcount += 1    
            assert tcount < 10

            p = begin

            if icheck:
               i_pindex = i_begin

            while p is not end:

                if icheck:
                    assert i_postorder[i_pindex] is p 
                    i_depth = p.cdepth
                    i_subNodes = Node.NumNodes( i_height, i_depth )
                    i_halfNodes = (i_subNodes - 1)/2
                pass

                act = 0 
                left = None
                right = None
                miss =  intersect_miss(p, self.ray, tmin)
                result = None
    
                tminL = tmin
                tminR = tmin

                ctrl = (CtrlLoopLeft | CtrlLoopRight)
                log.debug("p loop %s : %s " % (desc_ctrl(ctrl), p))

                reiterate_ = False

                loopcount = 0 
                while ctrl & (CtrlLoopLeft | CtrlLoopRight ):

                    if ctrl & CtrlLoopLeft: 
                        if p.l.is_leaf:
                            left = intersect_primitive(p.l, self.ray, tminL)
                        else:
                            try:
                                left = lhs.pop()
                            except IndexError:
                                log.error("%s : lhs pop from empty" % self.pfx)
                                self.tst.ierr += 1
                                left = miss
                            pass
                        pass
                    pass
                    if ctrl & CtrlLoopRight: 
                        if p.r.is_leaf:
                            right = intersect_primitive(p.r, self.ray, tminR)
                        else:
                            try:
                                right = rhs.pop()
                            except IndexError:
                                log.error("%s : rhs pop from empty" % self.pfx)
                                self.tst.ierr += 1
                                right = miss
                            pass
                        pass
                    pass

                    ctrl = self.binary_ctrl(p.operation, left, right, tminL, tminR)    

                    if ctrl in [CtrlReturnMiss, CtrlReturnLeft, CtrlReturnRight, CtrlReturnFlipRight]:
                        pass # will fall out of the ctrl while as no longer loopers
                    elif ctrl == CtrlLoopLeft: 
                        if self.debug:
                            print "CtrlLoopLeft %s " % p.l
                        pass
                        tminL = left.t + self.epsilon
                        if not p.l.is_leaf:
                            rhs.append(right)

                            tranche.append([tmin,p,None])  # should this be tminL ? its for continuation
                            tranche.append([tminL,Node.leftmost(p.l),p.l.next_])

                            if icheck:
                                itranche.append([tmin,  i_index, numInternalNodes ])
                                itranche.append([tminL, i_index - i_halfNodes*2, i_index - i_halfNodes ])  
                                print "icheck lhs %r " % itranche
                            pass
                            reiterate_ = True 
                        pass
                    elif ctrl == CtrlLoopRight: 

                        tminR = right.t + self.epsilon
                        if self.debug:
                            print "CtrlLoopRight %s " % p.r
                        pass
                        if not p.r.is_leaf:
                            lhs.append(left)
                            tranche.append([tmin,p,None])  # should this be tminR ?
                            tranche.append([tminR,Node.leftmost(p.r),p.r.next_])   
                            if icheck:
                                assert p.r.next_ is p  # next on right is always self
                                itranche.append([tmin,  i_index, numInternalNodes ])
                                itranche.append([tminR, i_index - i_halfNodes, i_index ])  
                                print "icheck rhs %r " % itranche
                            pass
                            reiterate_ = True 
                        pass
                    else:
                         assert 0, desc_ctrl(ctrl) 
                    pass
                    if reiterate_:  # non-bileaf loopers have to break to traverse subtree
                        break 
                    pass
                    loopcount += 1 
                    assert loopcount < 10  
                    pass 
                pass  # end while ctrl loop   
          
                if reiterate_:  
                    #log.info("break out of postorder traversal, for re-iteration of subtree ntranche %d " % len(tranche))
                    break 

                assert ctrl in [CtrlReturnMiss, CtrlReturnLeft,CtrlReturnRight,CtrlReturnFlipRight]
                result = self.binary_result(ctrl, miss, left, right, tmin)

                if p.is_left:
                    if self.debug:
                        log.info("%s : lhs append %d : %s " % (self.pfx, len(lhs), lhs ))
                    lhs.append(result)
                else:
                    if self.debug:
                        log.info("%s : rhs append %d : %s " % (self.pfx, len(rhs), rhs ))
                    rhs.append(result)
                pass
                if self.debug:
                    p.iterative = result


                if icheck:
                    i_pindex += 1
                pass

                p = p.next_ 
            pass               # postorder tranche traversal while loop
        pass

        #assert len(lhs) == 0, lhs
        #assert len(rhs) == 1, rhs   # end with p.idx = 1 for the root

        if not len(lhs) == 0:
            log.error("%s : lhs has %d, expect 0 " % (self.pfx, len(lhs)) )
            self.tst.ierr += 1
        pass

        if not len(rhs) == 1:
            log.error("%s : rhs has %d, expect 1 " % (self.pfx, len(rhs)) )
            self.tst.ierr += 1
        pass

        return rhs[0]