<commit_before>from __future__ import absolute_import

from django.core.urlresolvers import reverse

from sentry.models import Organization, OrganizationMemberTeam
from sentry.testutils import APITestCase

class CreateOrganizationMemberTeamTest(APITestCase):
    def test_can_join_as_owner_without_open_membership(self):
        organization = self.create_organization(
            name='foo',
            owner=self.user,
            flags=0,
        )
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='owner',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.post(path)

        assert resp.status_code == 201

    def test_cannot_join_as_member_without_open_membership(self):
        organization = self.create_organization(
            name='foo',
            owner=self.user,
            flags=0,
        )
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.post(path)

        assert resp.status_code == 202

        assert not OrganizationMemberTeam.objects.filter(
            team=team,
            organizationmember=member_om,
        ).exists()

    def test_can_join_as_member_with_open_membership(self):
        organization = self.create_organization(
            name='foo',
            owner=self.user,
            flags=Organization.flags.allow_joinleave,
        )
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.post(path)

        assert resp.status_code == 201

        omt = OrganizationMemberTeam.objects.get(
            team=team,
            organizationmember=member_om,
        )
        assert omt.is_active

class DeleteOrganizationMemberTeamTest(APITestCase):
    def test_can_leave_as_member(self):
        organization = self.create_organization(name='foo', owner=self.user)
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[team],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.delete(path)

        assert resp.status_code == 200

        assert OrganizationMemberTeam.objects.filter(
            team=team,
            organizationmember=member_om,
            is_active=False,
        ).exists()

    def test_can_leave_as_non_member(self):
        organization = self.create_organization(name='foo', owner=self.user)
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.delete(path)

        assert resp.status_code == 200

        assert not OrganizationMemberTeam.objects.filter(
            team=team,
            organizationmember=member_om,
            is_active=True,
        ).exists()
<commit_msg>Expand test for access request<commit_after>from __future__ import absolute_import

from django.core.urlresolvers import reverse

from sentry.models import (
    Organization, OrganizationAccessRequest, OrganizationMemberTeam
)
from sentry.testutils import APITestCase

class CreateOrganizationMemberTeamTest(APITestCase):
    def test_can_join_as_owner_without_open_membership(self):
        organization = self.create_organization(
            name='foo',
            owner=self.user,
            flags=0,
        )
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='owner',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.post(path)

        assert resp.status_code == 201

    def test_cannot_join_as_member_without_open_membership(self):
        organization = self.create_organization(
            name='foo',
            owner=self.user,
            flags=0,
        )
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.post(path)

        assert resp.status_code == 202

        assert not OrganizationMemberTeam.objects.filter(
            team=team,
            organizationmember=member_om,
        ).exists()
        assert OrganizationAccessRequest.objects.filter(
            team=team,
            member=member_om,
        ).exists()

    def test_can_join_as_member_with_open_membership(self):
        organization = self.create_organization(
            name='foo',
            owner=self.user,
            flags=Organization.flags.allow_joinleave,
        )
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.post(path)

        assert resp.status_code == 201

        omt = OrganizationMemberTeam.objects.get(
            team=team,
            organizationmember=member_om,
        )
        assert omt.is_active

class DeleteOrganizationMemberTeamTest(APITestCase):
    def test_can_leave_as_member(self):
        organization = self.create_organization(name='foo', owner=self.user)
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[team],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.delete(path)

        assert resp.status_code == 200

        assert OrganizationMemberTeam.objects.filter(
            team=team,
            organizationmember=member_om,
            is_active=False,
        ).exists()

    def test_can_leave_as_non_member(self):
        organization = self.create_organization(name='foo', owner=self.user)
        team = self.create_team(name='foo', organization=organization)
        user = self.create_user('dummy@example.com')
        member_om = self.create_member(
            organization=organization,
            user=user,
            role='member',
            teams=[],
        )

        path = reverse('sentry-api-0-organization-member-team-details', args=[
            organization.slug, member_om.id, team.slug,
        ])

        self.login_as(user)

        resp = self.client.delete(path)

        assert resp.status_code == 200

        assert not OrganizationMemberTeam.objects.filter(
            team=team,
            organizationmember=member_om,
            is_active=True,
        ).exists()
<|endoftext|>


<commit_before>from sympy.core import Basic, S, Function, diff, Tuple
from sympy.core.relational import Equality, Relational
from sympy.logic.boolalg import And, Boolean
from sympy.core.sets import Set
from sympy.core.symbol import Dummy

class ExprCondPair(Tuple):
    """Represents an expression, condition pair."""

    true_sentinel = Dummy('True')

    def __new__(cls, expr, cond):
        if cond is True:
            cond = ExprCondPair.true_sentinel
        return Tuple.__new__(cls, expr, cond)

    @property
    def expr(self):
        """
        Returns the expression of this pair.
        """
        return self.args[0]

    @property
    def cond(self):
        """
        Returns the condition of this pair.
        """
        if self.args[1] == ExprCondPair.true_sentinel:
            return True
        return self.args[1]

    @property
    def free_symbols(self):
        """
        Return the free symbols of this pair.
        """
        # Overload Basic.free_symbols because self.args[1] may contain non-Basic
        result = self.expr.free_symbols
        if hasattr(self.cond, 'free_symbols'):
            result |= self.cond.free_symbols
        return result

    def __iter__(self):
        yield self.expr
        yield self.cond

class Piecewise(Function):
    """
    Represents a piecewise function.

    Usage:

      Piecewise( (expr,cond), (expr,cond), ... )
        - Each argument is a 2-tuple defining a expression and condition
        - The conds are evaluated in turn returning the first that is True.
          If any of the evaluated conds are not determined explicitly False,
          e.g. x < 1, the function is returned in symbolic form.
        - If the function is evaluated at a place where all conditions are False,
          a ValueError exception will be raised.
        - Pairs where the cond is explicitly False, will be removed.

    Examples
    ========

      >>> from sympy import Piecewise, log
      >>> from sympy.abc import x
      >>> f = x**2
      >>> g = log(x)
      >>> p = Piecewise( (0, x<-1), (f, x<=1), (g, True))
      >>> p.subs(x,1)
      1
      >>> p.subs(x,5)
      log(5)

    See Also
    ========

    piecewise_fold
    """

    nargs = None
    is_Piecewise = True

    def __new__(cls, *args, **options):
        # (Try to) sympify args first
        newargs = []
        for ec in args:
            pair = ExprCondPair(*ec)
            cond = pair.cond
            if cond is False:
                continue
            if not isinstance(cond, (bool, Relational, Set, Boolean)):
                raise TypeError(
                    "Cond %s is of type %s, but must be a bool," \
                    " Relational, Number or Set" % (cond, type(cond)))
            newargs.append(pair)
            if cond is ExprCondPair.true_sentinel:
                break

        if options.pop('evaluate', True):
            r = cls.eval(*newargs)
        else:
            r = None

        if r is None:
            return Basic.__new__(cls, *newargs, **options)
        else:
            return r

    @classmethod
    def eval(cls, *args):
        from sympy import Or
        # Check for situations where we can evaluate the Piecewise object.
        # 1) Hit an unevaluable cond (e.g. x<1) -> keep object
        # 2) Hit a true condition -> return that expr
        # 3) Remove false conditions, if no conditions left -> raise ValueError
        all_conds_evaled = True    # Do all conds eval to a bool?
        piecewise_again = False    # Should we pass args to Piecewise again?
        non_false_ecpairs = []
        or1 = Or(*[cond for (_, cond) in args if cond is not True])
        for expr, cond in args:
            # Check here if expr is a Piecewise and collapse if one of
            # the conds in expr matches cond. This allows the collapsing
            # of Piecewise((Piecewise(x,x<0),x<0)) to Piecewise((x,x<0)).
            # This is important when using piecewise_fold to simplify
            # multiple Piecewise instances having the same conds.
            # Eventually, this code should be able to collapse Piecewise's
            # having different intervals, but this will probably require
            # using the new assumptions.
            if isinstance(expr, Piecewise):
                or2 = Or(*[c for (_, c) in expr.args if c is not True])
                for e, c in expr.args:
                    # Don't collapse if cond is "True" as this leads to
                    # incorrect simplifications with nested Piecewises.
                    if c == cond and (or1 == or2 or cond is not True):
                        expr = e
                        piecewise_again = True
            cond_eval = cls.__eval_cond(cond)
            if cond_eval is None:
                all_conds_evaled = False
                non_false_ecpairs.append( (expr, cond) )
            elif cond_eval:
                if all_conds_evaled:
                    return expr
                non_false_ecpairs.append( (expr, cond) )
        if len(non_false_ecpairs) != len(args) or piecewise_again:
            return Piecewise(*non_false_ecpairs)

        return None

    def doit(self, **hints):
        """
        Evaluate this piecewise function.
        """
        newargs = []
        for e, c in self.args:
            if hints.get('deep', True):
                if isinstance(e, Basic):
                    e = e.doit(**hints)
                if isinstance(c, Basic):
                    c = c.doit(**hints)
            newargs.append((e, c))
        return Piecewise(*newargs)

    @property
    def is_commutative(self):
        return all(expr.is_commutative for expr, _ in self.args)

    def _eval_integral(self,x):
        from sympy.integrals import integrate
        return Piecewise(*[(integrate(e, x), c) for e, c in self.args])

    def _eval_interval(self, sym, a, b):
        """Evaluates the function along the sym in a given interval ab"""
        # FIXME: Currently complex intervals are not supported.  A possible
        # replacement algorithm, discussed in issue 2128, can be found in the
        # following papers;
        #     http://portal.acm.org/citation.cfm?id=281649
        #     http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf
        mul = 1
        if (a == b) is True:
            return S.Zero
        elif (a > b) is True:
            a, b, mul = b, a, -1
        elif (a <= b) is not True:
            newargs = []
            for e, c in self.args:
                intervals = self._sort_expr_cond(sym, S.NegativeInfinity, S.Infinity, c)
                values = []
                for lower, upper in intervals:
                    if (a < lower) is True:
                        mid = lower
                        rep = b
                        val = e.subs(sym, b) - e.subs(sym, mid)
                        val += self._eval_interval(sym, a, mid)
                    elif (a > upper) is True:
                        mid = upper
                        rep = b
                        val = e.subs(sym, b) - e.subs(sym, mid)
                        val += self._eval_interval(sym, a, mid)
                    elif (a >= lower) is True and (a <= upper) is True:
                        rep = b
                        val = e.subs(sym, b) - e.subs(sym, a)
                    elif (b < lower) is True:
                        mid = lower
                        rep = a
                        val = e.subs(sym, mid) - e.subs(sym, a)
                        val += self._eval_interval(sym, mid, b)
                    elif (b > upper) is True:
                        mid = upper
                        rep = a
                        val = e.subs(sym, mid) - e.subs(sym, a)
                        val += self._eval_interval(sym, mid, b)
                    elif ((b >= lower) is True) and ((b <= upper) is True):
                        rep = a
                        val = e.subs(sym, b) - e.subs(sym, a)
                    else:
                        raise NotImplementedError(
                            """The evaluation of a Piecewise interval when both the lower
                            and the upper limit are symbolic is not yet implemented.""")
                    values.append(val)
                if len(set(values)) == 1 :
                    try:
                        c = c.subs(sym, rep)
                    except AttributeError:
                        pass
                    e = values[0]
                    newargs.append((e, c))
                else:
                    for i in range(len(values)):
                        newargs.append((values[i],
                            intervals[i][0] <= rep and rep <= intervals[i][1]))
            return Piecewise(*newargs)

        # Determine what intervals the expr,cond pairs affect.
        int_expr = self._sort_expr_cond(sym, a, b)

        # Finally run through the intervals and sum the evaluation.
        ret_fun = 0
        for int_a, int_b, expr in int_expr:
            ret_fun += expr._eval_interval(sym,  max(a, int_a), min(b, int_b))
        return mul * ret_fun

    def _sort_expr_cond(self, sym, a, b, targetcond = None):
        """Determine what intervals the expr, cond pairs affect.

        1) If cond is True, then log it as default
        1.1) Currently if cond can't be evaluated, throw NotImplementedError.
        2) For each inequality, if previous cond defines part of the interval
           update the new conds interval.
           -  eg x < 1, x < 3 -> [oo,1],[1,3] instead of [oo,1],[oo,3]
        3) Sort the intervals to make it easier to find correct exprs

        Under normal use, we return the expr,cond pairs in increasing order
        along the real axis corresponding to the symbol sym.  If targetcond
        is given, we return a list of (lowerbound, upperbound) pairs for
        this condition."""
        default = None
        int_expr = []
        for expr, cond in self.args:
            if cond is True:
                default = expr
                break
            elif isinstance(cond, Equality):
                continue
            elif isinstance(cond, And):
                lower = S.NegativeInfinity
                upper = S.Infinity
                for cond2 in cond.args:
                    if cond2.lts.has(sym):
                        upper = min(cond2.gts, upper)
                    elif cond2.gts.has(sym):
                        lower = max(cond2.lts, lower)
            else:
                lower, upper = cond.lts, cond.gts # part 1: initialize with givens
                if cond.lts.has(sym):     # part 1a: expand the side ...
                    lower = S.NegativeInfinity   # e.g. x <= 0 ---> -oo <= 0
                elif cond.gts.has(sym):   # part 1a: ... that can be expanded
                    upper = S.Infinity           # e.g. x >= 0 --->  oo >= 0
                else:
                    raise NotImplementedError(
                        "Unable to handle interval evaluation of expression.")

            # part 1b: Reduce (-)infinity to what was passed in.
            lower, upper = max(a, lower), min(b, upper)

            for n in xrange(len(int_expr)):
                # Part 2: remove any interval overlap.  For any conflicts, the
                # iterval already there wins, and the incoming interval updates
                # its bounds accordingly.
                if self.__eval_cond(lower < int_expr[n][1]) and \
                        self.__eval_cond(lower >= int_expr[n][0]):
                    lower = int_expr[n][1]
                if self.__eval_cond(upper > int_expr[n][0]) and \
                        self.__eval_cond(upper <= int_expr[n][1]):
                    upper = int_expr[n][0]
            if self.__eval_cond(lower < upper):  # Is it still an interval?
                int_expr.append((lower, upper, expr))
            if cond is targetcond:
                return [(lower, upper)]
        int_expr.sort(key=lambda x:x[0])

        # Add holes to list of intervals if there is a default value,
        # otherwise raise a ValueError.
        holes = []
        curr_low = a
        for int_a, int_b, expr in int_expr:
            if curr_low < int_a:
                holes.append([curr_low, min(b, int_a), default])
            curr_low = int_b
            if curr_low > b:
                break
        if curr_low < b:
            holes.append([curr_low, b, default])

        if holes and default is not None:
            int_expr.extend(holes)
            if targetcond is True:
                return [(h[0], h[1]) for h in holes]
        elif holes and default == None:
            raise ValueError("Called interval evaluation over piecewise " \
                             "function on undefined intervals %s" % \
                             ", ".join([str((h[0], h[1])) for h in holes]))

        return int_expr

    def _eval_derivative(self, s):
        return Piecewise(*[(diff(e, s), c) for e, c in self.args])

    def _eval_subs(self, old, new):
        """
        Piecewise conditions may contain Sets whose modifications
        requires the use of contains rather than substitution. They
        may also contain bool which are not of Basic type.
        """
        args = list(self.args)
        for i, (e, c) in enumerate(args):
            e = e._subs(old, new)

            if isinstance(c, bool):
                pass
            elif isinstance(c, Set):
                # What do we do if there are more than one symbolic
                # variable. Which do we put pass to Set.contains?
                c = c.contains(new)
            elif isinstance(c, Basic):
                c = c._subs(old, new)

            args[i] = e, c

        return Piecewise(*args)

    def _eval_nseries(self, x, n, logx):
        args = map(lambda ec: (ec.expr._eval_nseries(x, n, logx), ec.cond), \
                   self.args)
        return self.func(*args)

    def _eval_as_leading_term(self, x):
        # This is completely wrong, cf. issue 3110
        return self.args[0][0].as_leading_term(x)

    @classmethod
    def __eval_cond(cls, cond):
        """Return the truth value of the condition."""
        if cond is True:
            return True
        return None

def piecewise_fold(expr):
    """
    Takes an expression containing a piecewise function and returns the
    expression in piecewise form.

    Examples
    ========

    >>> from sympy import Piecewise, piecewise_fold, sympify as S
    >>> from sympy.abc import x
    >>> p = Piecewise((x, x < 1), (1, S(1) <= x))
    >>> piecewise_fold(x*p)
    Piecewise((x**2, x < 1), (x, 1 <= x))

    See Also
    ========

    Piecewise
    """
    if not isinstance(expr, Basic) or not expr.has(Piecewise):
        return expr
    new_args = map(piecewise_fold, expr.args)
    if expr.func is ExprCondPair:
        return ExprCondPair(*new_args)
    piecewise_args = []
    for n, arg in enumerate(new_args):
        if arg.func is Piecewise:
            piecewise_args.append(n)
    if len(piecewise_args) > 0:
        n = piecewise_args[0]
        new_args = [(expr.func(*(new_args[:n] + [e] + new_args[n+1:])), c) \
                        for e, c in new_args[n].args]
        if len(piecewise_args) > 1:
            return piecewise_fold(Piecewise(*new_args))
    return Piecewise(*new_args)
<commit_msg>Remove unneeded if: block in Piecewise.<commit_after>from sympy.core import Basic, S, Function, diff, Tuple
from sympy.core.relational import Equality, Relational
from sympy.logic.boolalg import And, Boolean
from sympy.core.sets import Set
from sympy.core.symbol import Dummy

class ExprCondPair(Tuple):
    """Represents an expression, condition pair."""

    true_sentinel = Dummy('True')

    def __new__(cls, expr, cond):
        if cond is True:
            cond = ExprCondPair.true_sentinel
        return Tuple.__new__(cls, expr, cond)

    @property
    def expr(self):
        """
        Returns the expression of this pair.
        """
        return self.args[0]

    @property
    def cond(self):
        """
        Returns the condition of this pair.
        """
        if self.args[1] == ExprCondPair.true_sentinel:
            return True
        return self.args[1]

    @property
    def free_symbols(self):
        """
        Return the free symbols of this pair.
        """
        # Overload Basic.free_symbols because self.args[1] may contain non-Basic
        result = self.expr.free_symbols
        if hasattr(self.cond, 'free_symbols'):
            result |= self.cond.free_symbols
        return result

    def __iter__(self):
        yield self.expr
        yield self.cond

class Piecewise(Function):
    """
    Represents a piecewise function.

    Usage:

      Piecewise( (expr,cond), (expr,cond), ... )
        - Each argument is a 2-tuple defining a expression and condition
        - The conds are evaluated in turn returning the first that is True.
          If any of the evaluated conds are not determined explicitly False,
          e.g. x < 1, the function is returned in symbolic form.
        - If the function is evaluated at a place where all conditions are False,
          a ValueError exception will be raised.
        - Pairs where the cond is explicitly False, will be removed.

    Examples
    ========

      >>> from sympy import Piecewise, log
      >>> from sympy.abc import x
      >>> f = x**2
      >>> g = log(x)
      >>> p = Piecewise( (0, x<-1), (f, x<=1), (g, True))
      >>> p.subs(x,1)
      1
      >>> p.subs(x,5)
      log(5)

    See Also
    ========

    piecewise_fold
    """

    nargs = None
    is_Piecewise = True

    def __new__(cls, *args, **options):
        # (Try to) sympify args first
        newargs = []
        for ec in args:
            pair = ExprCondPair(*ec)
            cond = pair.cond
            if cond is False:
                continue
            if not isinstance(cond, (bool, Relational, Set, Boolean)):
                raise TypeError(
                    "Cond %s is of type %s, but must be a bool," \
                    " Relational, Number or Set" % (cond, type(cond)))
            newargs.append(pair)
            if cond is ExprCondPair.true_sentinel:
                break

        if options.pop('evaluate', True):
            r = cls.eval(*newargs)
        else:
            r = None

        if r is None:
            return Basic.__new__(cls, *newargs, **options)
        else:
            return r

    @classmethod
    def eval(cls, *args):
        from sympy import Or
        # Check for situations where we can evaluate the Piecewise object.
        # 1) Hit an unevaluable cond (e.g. x<1) -> keep object
        # 2) Hit a true condition -> return that expr
        # 3) Remove false conditions, if no conditions left -> raise ValueError
        all_conds_evaled = True    # Do all conds eval to a bool?
        piecewise_again = False    # Should we pass args to Piecewise again?
        non_false_ecpairs = []
        or1 = Or(*[cond for (_, cond) in args if cond is not True])
        for expr, cond in args:
            # Check here if expr is a Piecewise and collapse if one of
            # the conds in expr matches cond. This allows the collapsing
            # of Piecewise((Piecewise(x,x<0),x<0)) to Piecewise((x,x<0)).
            # This is important when using piecewise_fold to simplify
            # multiple Piecewise instances having the same conds.
            # Eventually, this code should be able to collapse Piecewise's
            # having different intervals, but this will probably require
            # using the new assumptions.
            if isinstance(expr, Piecewise):
                or2 = Or(*[c for (_, c) in expr.args if c is not True])
                for e, c in expr.args:
                    # Don't collapse if cond is "True" as this leads to
                    # incorrect simplifications with nested Piecewises.
                    if c == cond and (or1 == or2 or cond is not True):
                        expr = e
                        piecewise_again = True
            cond_eval = cls.__eval_cond(cond)
            if cond_eval is None:
                all_conds_evaled = False
                non_false_ecpairs.append( (expr, cond) )
            elif cond_eval:
                if all_conds_evaled:
                    return expr
                non_false_ecpairs.append( (expr, cond) )
        if len(non_false_ecpairs) != len(args) or piecewise_again:
            return Piecewise(*non_false_ecpairs)

        return None

    def doit(self, **hints):
        """
        Evaluate this piecewise function.
        """
        newargs = []
        for e, c in self.args:
            if hints.get('deep', True):
                if isinstance(e, Basic):
                    e = e.doit(**hints)
                if isinstance(c, Basic):
                    c = c.doit(**hints)
            newargs.append((e, c))
        return Piecewise(*newargs)

    @property
    def is_commutative(self):
        return all(expr.is_commutative for expr, _ in self.args)

    def _eval_integral(self,x):
        from sympy.integrals import integrate
        return Piecewise(*[(integrate(e, x), c) for e, c in self.args])

    def _eval_interval(self, sym, a, b):
        """Evaluates the function along the sym in a given interval ab"""
        # FIXME: Currently complex intervals are not supported.  A possible
        # replacement algorithm, discussed in issue 2128, can be found in the
        # following papers;
        #     http://portal.acm.org/citation.cfm?id=281649
        #     http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf
        mul = 1
        if (a == b) is True:
            return S.Zero
        elif (a > b) is True:
            a, b, mul = b, a, -1
        elif (a <= b) is not True:
            newargs = []
            for e, c in self.args:
                intervals = self._sort_expr_cond(sym, S.NegativeInfinity, S.Infinity, c)
                values = []
                for lower, upper in intervals:
                    if (a < lower) is True:
                        mid = lower
                        rep = b
                        val = e.subs(sym, b) - e.subs(sym, mid)
                        val += self._eval_interval(sym, a, mid)
                    elif (a > upper) is True:
                        mid = upper
                        rep = b
                        val = e.subs(sym, b) - e.subs(sym, mid)
                        val += self._eval_interval(sym, a, mid)
                    elif (a >= lower) is True and (a <= upper) is True:
                        rep = b
                        val = e.subs(sym, b) - e.subs(sym, a)
                    elif (b < lower) is True:
                        mid = lower
                        rep = a
                        val = e.subs(sym, mid) - e.subs(sym, a)
                        val += self._eval_interval(sym, mid, b)
                    elif (b > upper) is True:
                        mid = upper
                        rep = a
                        val = e.subs(sym, mid) - e.subs(sym, a)
                        val += self._eval_interval(sym, mid, b)
                    elif ((b >= lower) is True) and ((b <= upper) is True):
                        rep = a
                        val = e.subs(sym, b) - e.subs(sym, a)
                    else:
                        raise NotImplementedError(
                            """The evaluation of a Piecewise interval when both the lower
                            and the upper limit are symbolic is not yet implemented.""")
                    values.append(val)
                if len(set(values)) == 1 :
                    try:
                        c = c.subs(sym, rep)
                    except AttributeError:
                        pass
                    e = values[0]
                    newargs.append((e, c))
                else:
                    for i in range(len(values)):
                        newargs.append((values[i],
                            intervals[i][0] <= rep and rep <= intervals[i][1]))
            return Piecewise(*newargs)

        # Determine what intervals the expr,cond pairs affect.
        int_expr = self._sort_expr_cond(sym, a, b)

        # Finally run through the intervals and sum the evaluation.
        ret_fun = 0
        for int_a, int_b, expr in int_expr:
            ret_fun += expr._eval_interval(sym,  max(a, int_a), min(b, int_b))
        return mul * ret_fun

    def _sort_expr_cond(self, sym, a, b, targetcond = None):
        """Determine what intervals the expr, cond pairs affect.

        1) If cond is True, then log it as default
        1.1) Currently if cond can't be evaluated, throw NotImplementedError.
        2) For each inequality, if previous cond defines part of the interval
           update the new conds interval.
           -  eg x < 1, x < 3 -> [oo,1],[1,3] instead of [oo,1],[oo,3]
        3) Sort the intervals to make it easier to find correct exprs

        Under normal use, we return the expr,cond pairs in increasing order
        along the real axis corresponding to the symbol sym.  If targetcond
        is given, we return a list of (lowerbound, upperbound) pairs for
        this condition."""
        default = None
        int_expr = []
        for expr, cond in self.args:
            if cond is True:
                default = expr
                break
            elif isinstance(cond, Equality):
                continue
            elif isinstance(cond, And):
                lower = S.NegativeInfinity
                upper = S.Infinity
                for cond2 in cond.args:
                    if cond2.lts.has(sym):
                        upper = min(cond2.gts, upper)
                    elif cond2.gts.has(sym):
                        lower = max(cond2.lts, lower)
            else:
                lower, upper = cond.lts, cond.gts # part 1: initialize with givens
                if cond.lts.has(sym):     # part 1a: expand the side ...
                    lower = S.NegativeInfinity   # e.g. x <= 0 ---> -oo <= 0
                elif cond.gts.has(sym):   # part 1a: ... that can be expanded
                    upper = S.Infinity           # e.g. x >= 0 --->  oo >= 0
                else:
                    raise NotImplementedError(
                        "Unable to handle interval evaluation of expression.")

            # part 1b: Reduce (-)infinity to what was passed in.
            lower, upper = max(a, lower), min(b, upper)

            for n in xrange(len(int_expr)):
                # Part 2: remove any interval overlap.  For any conflicts, the
                # iterval already there wins, and the incoming interval updates
                # its bounds accordingly.
                if self.__eval_cond(lower < int_expr[n][1]) and \
                        self.__eval_cond(lower >= int_expr[n][0]):
                    lower = int_expr[n][1]
                if self.__eval_cond(upper > int_expr[n][0]) and \
                        self.__eval_cond(upper <= int_expr[n][1]):
                    upper = int_expr[n][0]
            if self.__eval_cond(lower < upper):  # Is it still an interval?
                int_expr.append((lower, upper, expr))
            if cond is targetcond:
                return [(lower, upper)]
        int_expr.sort(key=lambda x:x[0])

        # Add holes to list of intervals if there is a default value,
        # otherwise raise a ValueError.
        holes = []
        curr_low = a
        for int_a, int_b, expr in int_expr:
            if curr_low < int_a:
                holes.append([curr_low, min(b, int_a), default])
            curr_low = int_b
        if curr_low < b:
            holes.append([curr_low, b, default])

        if holes and default is not None:
            int_expr.extend(holes)
            if targetcond is True:
                return [(h[0], h[1]) for h in holes]
        elif holes and default == None:
            raise ValueError("Called interval evaluation over piecewise " \
                             "function on undefined intervals %s" % \
                             ", ".join([str((h[0], h[1])) for h in holes]))

        return int_expr

    def _eval_derivative(self, s):
        return Piecewise(*[(diff(e, s), c) for e, c in self.args])

    def _eval_subs(self, old, new):
        """
        Piecewise conditions may contain Sets whose modifications
        requires the use of contains rather than substitution. They
        may also contain bool which are not of Basic type.
        """
        args = list(self.args)
        for i, (e, c) in enumerate(args):
            e = e._subs(old, new)

            if isinstance(c, bool):
                pass
            elif isinstance(c, Set):
                # What do we do if there are more than one symbolic
                # variable. Which do we put pass to Set.contains?
                c = c.contains(new)
            elif isinstance(c, Basic):
                c = c._subs(old, new)

            args[i] = e, c

        return Piecewise(*args)

    def _eval_nseries(self, x, n, logx):
        args = map(lambda ec: (ec.expr._eval_nseries(x, n, logx), ec.cond), \
                   self.args)
        return self.func(*args)

    def _eval_as_leading_term(self, x):
        # This is completely wrong, cf. issue 3110
        return self.args[0][0].as_leading_term(x)

    @classmethod
    def __eval_cond(cls, cond):
        """Return the truth value of the condition."""
        if cond is True:
            return True
        return None

def piecewise_fold(expr):
    """
    Takes an expression containing a piecewise function and returns the
    expression in piecewise form.

    Examples
    ========

    >>> from sympy import Piecewise, piecewise_fold, sympify as S
    >>> from sympy.abc import x
    >>> p = Piecewise((x, x < 1), (1, S(1) <= x))
    >>> piecewise_fold(x*p)
    Piecewise((x**2, x < 1), (x, 1 <= x))

    See Also
    ========

    Piecewise
    """
    if not isinstance(expr, Basic) or not expr.has(Piecewise):
        return expr
    new_args = map(piecewise_fold, expr.args)
    if expr.func is ExprCondPair:
        return ExprCondPair(*new_args)
    piecewise_args = []
    for n, arg in enumerate(new_args):
        if arg.func is Piecewise:
            piecewise_args.append(n)
    if len(piecewise_args) > 0:
        n = piecewise_args[0]
        new_args = [(expr.func(*(new_args[:n] + [e] + new_args[n+1:])), c) \
                        for e, c in new_args[n].args]
        if len(piecewise_args) > 1:
            return piecewise_fold(Piecewise(*new_args))
    return Piecewise(*new_args)
<|endoftext|>


<commit_before>import ddapp.objectmodel as om
import ddapp.applogic as app
from ddapp import affordance
import ddapp.affordanceupdater as affup
from shallowCopy import shallowCopy
import ddapp.vtkAll as vtk
from ddapp.debugVis import DebugData
import numpy as np
from PythonQt import QtCore, QtGui

from ddapp.affordancelistener import listener as affListener

def computeAToB(a,b):

    t = vtk.vtkTransform()
    t.PostMultiply()
    t.Concatenate(b)
    t.Concatenate(a.GetLinearInverse())
    tt = vtk.vtkTransform()
    tt.SetMatrix(t.GetMatrix())
    return tt

class AffordanceItem(om.PolyDataItem):

    def __init__(self, name, polyData, view):
        om.PolyDataItem.__init__(self, name, polyData, view)
        self.baseTransform = None
        self.params = {}
        affup.updater.addCallback(self.onGroundTransform)
        affListener.registerAffordance(self)

    def publish(self):
        pass

    def getActionNames(self):
        actions = ['Publish affordance']
        return om.PolyDataItem.getActionNames(self) + actions

    def onAction(self, action):
        if action == 'Publish affordance':
            self.publish()
        else:
            om.PolyDataItem.onAction(self, action)

    def onServerAffordanceUpdate(self, serverAff):
        if not self.params.get('uid'):
            print 'assigning uid from server:', serverAff.uid
            self.params['uid'] = serverAff.uid

    def computeBaseTransform(self):
        self.baseTransform = computeAToB(self.groundTransform, self.actor.GetUserTransform())

    def onGroundTransform(self, newTransform, resetTime):

        if not self.baseTransform or resetTime > self.groundTransformResetTime:
            self.groundTransform = newTransform
            self.groundTransformResetTime = resetTime
            self.computeBaseTransform()
            return

        newUserTransform = vtk.vtkTransform()
        newUserTransform.PostMultiply()
        newUserTransform.Identity()
        newUserTransform.Concatenate(self.baseTransform)
        newUserTransform.Concatenate(newTransform)

        self.actor.GetUserTransform().SetMatrix(newUserTransform.GetMatrix())
        self._renderAllViews()

    def onRemoveFromObjectModel(self):
        om.PolyDataItem.onRemoveFromObjectModel(self)
        affListener.unregisterAffordance(self)

class BlockAffordanceItem(AffordanceItem):

    def setAffordanceParams(self, params):
        self.params = params

    def updateParamsFromActorTransform(self):

        t = self.actor.GetUserTransform()

        xaxis = np.array(t.TransformVector([1,0,0]))
        yaxis = np.array(t.TransformVector([0,1,0]))
        zaxis = np.array(t.TransformVector([0,0,1]))
        self.params['xaxis'] = xaxis
        self.params['yaxis'] = yaxis
        self.params['zaxis'] = zaxis
        self.params['origin'] = t.GetPosition()

    def publish(self):
        self.updateParamsFromActorTransform()
        aff = affordance.createBoxAffordance(self.params)
        affordance.publishAffordance(aff)

        if hasattr(self, 'publishCallback'):
            self.publishCallback()

    def updateICPTransform(self, transform):
        delta = computeAToB(self.icpTransformInitial, transform)
        print 'initial:', self.icpTransformInitial.GetPosition(), self.icpTransformInitial.GetOrientation()
        print 'latest:', transform.GetPosition(), transform.GetOrientation()
        print 'delta:', delta.GetPosition(), delta.GetOrientation()
        newUserTransform = vtk.vtkTransform()
        newUserTransform.PostMultiply()
        newUserTransform.Identity()
        newUserTransform.Concatenate(self.baseTransform)
        newUserTransform.Concatenate(delta.GetLinearInverse())

        self.actor.SetUserTransform(newUserTransform)
        self._renderAllViews()

class FrameAffordanceItem(AffordanceItem):

    def setAffordanceParams(self, params):
        self.params = params
        assert 'otdf_type' in params

    def updateParamsFromActorTransform(self):

        t = self.actor.GetUserTransform()

        xaxis = np.array(t.TransformVector([1,0,0]))
        yaxis = np.array(t.TransformVector([0,1,0]))
        zaxis = np.array(t.TransformVector([0,0,1]))
        self.params['xaxis'] = xaxis
        self.params['yaxis'] = yaxis
        self.params['zaxis'] = zaxis
        self.params['origin'] = t.GetPosition()

    def publish(self):
        self.updateParamsFromActorTransform()
        aff = affordance.createFrameAffordance(self.params)
        affordance.publishAffordance(aff)

class CylinderAffordanceItem(AffordanceItem):

    def setAffordanceParams(self, params):
        self.params = params

    def updateParamsFromActorTransform(self):

        t = self.actor.GetUserTransform()

        xaxis = np.array(t.TransformVector([1,0,0]))
        yaxis = np.array(t.TransformVector([0,1,0]))
        zaxis = np.array(t.TransformVector([0,0,1]))
        self.params['axis'] = zaxis
        self.params['origin'] = t.GetPosition()

    def publish(self):
        self.updateParamsFromActorTransform()
        aff = affordance.createCylinderAffordance(self.params)
        affordance.publishAffordance(aff)

class FrameItem(om.PolyDataItem):

    def __init__(self, name, transform, view):

        scale = 1.0
        self.transform = transform
        polyData = self._createAxes(scale)

        om.PolyDataItem.__init__(self, name, polyData, view)

        self.colorBy('Axes')
        lut = self.mapper.GetLookupTable()
        lut.SetHueRange(0, 0.667)
        lut.Build()

        self.actor.SetUserTransform(transform)

        self.widget = vtk.vtkFrameWidget()
        self.widget.CreateDefaultRepresentation()
        self.widget.EnabledOff()
        self.rep = self.widget.GetRepresentation()
        self.rep.SetWorldSize(scale)
        self.rep.SetTransform(transform)

        self.addProperty('Scale', scale)
        self.addProperty('Edit', False)

    def _createAxes(self, scale):
        axes = vtk.vtkAxes()
        axes.SetComputeNormals(0)
        axes.SetScaleFactor(scale)
        axes.Update()

        #t = vtk.vtkTransformPolyDataFilter()
        #t.SetTransform(transform)
        #t.AddInputConnection(self.axes.GetOutputPort())
        #t.Update()

        return shallowCopy(axes.GetOutput())

    def addToView(self, view):
        om.PolyDataItem.addToView(self, view)

    def setFrame(self, transform):
        self.transform = transform
        polyData = self._createAxes(self.getProperty('Scale'))
        self.setPolyData(polyData)

    def _onPropertyChanged(self, propertyName):

        if propertyName == 'Scale':
            scale = self.getProperty(propertyName)
            self.rep.SetWorldSize(scale)
            self.setPolyData(self._createAxes(scale))
        elif propertyName == 'Edit':
            view = app.getCurrentRenderView()
            if view not in self.views:
                view = self.views[0]
            self.widget.SetInteractor(view.renderWindow().GetInteractor())
            self.widget.SetEnabled(self.getProperty(propertyName))

        om.PolyDataItem._onPropertyChanged(self, propertyName)

    def getPropertyAttributes(self, propertyName):

        if propertyName == 'Scale':
            return om.PropertyAttributes(decimals=2, minimum=0.01, maximum=100, singleStep=0.1, hidden=False)
        else:
            return om.PolyDataItem.getPropertyAttributes(self, propertyName)

    def onRemoveFromObjectModel(self):
        om.PolyDataItem.onRemoveFromObjectModel(self)

        self.widget.SetInteractor(None)
        self.widget.EnabledOff()
        for view in self.views:
            view.renderer().RemoveActor(self.actor)
            view.render()

def updatePolyData(polyData, name, **kwargs):

    obj = om.findObjectByName(name)
    obj = obj or showPolyData(polyData, name, **kwargs)
    obj.setPolyData(polyData)
    return obj

def updateFrame(frame, name, **kwargs):

    obj = om.findObjectByName(name)
    obj = obj or showFrame(frame, name, **kwargs)
    obj.setFrame(frame)
    return obj

def showFrame(frame, name, parent='segmentation', scale=0.35, visible=True):
    if isinstance(parent, str):
        parentObj = om.getOrCreateContainer(parent)
    else:
        parentObj = parent

    item = FrameItem(name, frame, app.getCurrentRenderView())
    om.addToObjectModel(item, parentObj)
    item.setProperty('Visible', visible)
    item.setProperty('Scale', scale)
    return item

def showPolyData(polyData, name, color=None, colorByName=None, colorByRange=None, alpha=1.0, visible=True, view=None, parent='segmentation', cls=None):

    view = view or app.getCurrentRenderView()
    if view is None:
        return

    cls = cls or om.PolyDataItem
    item = cls(name, polyData, view)

    if isinstance(parent, str):
        parentObj = om.getOrCreateContainer(parent)
    else:
        parentObj = parent

    om.addToObjectModel(item, parentObj)
    item.setProperty('Visible', visible)
    item.setProperty('Alpha', alpha)
    if color:
        color = [component * 255 for component in color]
        item.setProperty('Color', QtGui.QColor(*color))
        item.colorBy(None)
    else:
        item.colorBy(colorByName, colorByRange)
    return item

def pickPoint(displayPoint, obj=None, view=None, pickType='points', tolerance=0.01):

    view = view or app.getCurrentRenderView()
    assert view

    picker = vtk.vtkPointPicker() if pickType == 'points' else vtk.vtkCellPicker()

    if isinstance(obj, str):
        obj = om.findObjectByName(objName)
        assert obj

    if obj:
        picker.AddPickList(obj.actor)
        picker.PickFromListOn()

    picker.SetTolerance(tolerance)
    picker.Pick(displayPoint[0], displayPoint[1], 0, view.renderer())
    pickPoints = picker.GetPickedPositions()
    pickedPoint = np.array(pickPoints.GetPoint(0)) if pickPoints.GetNumberOfPoints() else None
    pickedDataset = picker.GetDataSet()

    if obj:
        return pickedPoint
    else:
        return pickedDataset, pickedPoint

def mapMousePosition(widget, mouseEvent):
    mousePosition = mouseEvent.pos()
    return mousePosition.x(), widget.height - mousePosition.y()

def getObjectByDataSet(polyData):
    for item, obj in om.objects.iteritems():
        if isinstance(obj, om.PolyDataItem) and obj.polyData == polyData:
            return obj

def findPickedObject(displayPoint, view=None):

    view = view or app.getCurrentRenderView()
    assert view

    polyData, pickedPoint = pickPoint(displayPoint, view=view, pickType='cells')
    return getObjectByDataSet(polyData), pickedPoint
<commit_msg>fix typo in visualization.py<commit_after>import ddapp.objectmodel as om
import ddapp.applogic as app
from ddapp import affordance
import ddapp.affordanceupdater as affup
from shallowCopy import shallowCopy
import ddapp.vtkAll as vtk
from ddapp.debugVis import DebugData
import numpy as np
from PythonQt import QtCore, QtGui

from ddapp.affordancelistener import listener as affListener

def computeAToB(a,b):

    t = vtk.vtkTransform()
    t.PostMultiply()
    t.Concatenate(b)
    t.Concatenate(a.GetLinearInverse())
    tt = vtk.vtkTransform()
    tt.SetMatrix(t.GetMatrix())
    return tt

class AffordanceItem(om.PolyDataItem):

    def __init__(self, name, polyData, view):
        om.PolyDataItem.__init__(self, name, polyData, view)
        self.baseTransform = None
        self.params = {}
        affup.updater.addCallback(self.onGroundTransform)
        affListener.registerAffordance(self)

    def publish(self):
        pass

    def getActionNames(self):
        actions = ['Publish affordance']
        return om.PolyDataItem.getActionNames(self) + actions

    def onAction(self, action):
        if action == 'Publish affordance':
            self.publish()
        else:
            om.PolyDataItem.onAction(self, action)

    def onServerAffordanceUpdate(self, serverAff):
        if not self.params.get('uid'):
            print 'assigning uid from server:', serverAff.uid
            self.params['uid'] = serverAff.uid

    def computeBaseTransform(self):
        self.baseTransform = computeAToB(self.groundTransform, self.actor.GetUserTransform())

    def onGroundTransform(self, newTransform, resetTime):

        if not self.baseTransform or resetTime > self.groundTransformResetTime:
            self.groundTransform = newTransform
            self.groundTransformResetTime = resetTime
            self.computeBaseTransform()
            return

        newUserTransform = vtk.vtkTransform()
        newUserTransform.PostMultiply()
        newUserTransform.Identity()
        newUserTransform.Concatenate(self.baseTransform)
        newUserTransform.Concatenate(newTransform)

        self.actor.GetUserTransform().SetMatrix(newUserTransform.GetMatrix())
        self._renderAllViews()

    def onRemoveFromObjectModel(self):
        om.PolyDataItem.onRemoveFromObjectModel(self)
        affListener.unregisterAffordance(self)

class BlockAffordanceItem(AffordanceItem):

    def setAffordanceParams(self, params):
        self.params = params

    def updateParamsFromActorTransform(self):

        t = self.actor.GetUserTransform()

        xaxis = np.array(t.TransformVector([1,0,0]))
        yaxis = np.array(t.TransformVector([0,1,0]))
        zaxis = np.array(t.TransformVector([0,0,1]))
        self.params['xaxis'] = xaxis
        self.params['yaxis'] = yaxis
        self.params['zaxis'] = zaxis
        self.params['origin'] = t.GetPosition()

    def publish(self):
        self.updateParamsFromActorTransform()
        aff = affordance.createBoxAffordance(self.params)
        affordance.publishAffordance(aff)

        if hasattr(self, 'publishCallback'):
            self.publishCallback()

    def updateICPTransform(self, transform):
        delta = computeAToB(self.icpTransformInitial, transform)
        print 'initial:', self.icpTransformInitial.GetPosition(), self.icpTransformInitial.GetOrientation()
        print 'latest:', transform.GetPosition(), transform.GetOrientation()
        print 'delta:', delta.GetPosition(), delta.GetOrientation()
        newUserTransform = vtk.vtkTransform()
        newUserTransform.PostMultiply()
        newUserTransform.Identity()
        newUserTransform.Concatenate(self.baseTransform)
        newUserTransform.Concatenate(delta.GetLinearInverse())

        self.actor.SetUserTransform(newUserTransform)
        self._renderAllViews()

class FrameAffordanceItem(AffordanceItem):

    def setAffordanceParams(self, params):
        self.params = params
        assert 'otdf_type' in params

    def updateParamsFromActorTransform(self):

        t = self.actor.GetUserTransform()

        xaxis = np.array(t.TransformVector([1,0,0]))
        yaxis = np.array(t.TransformVector([0,1,0]))
        zaxis = np.array(t.TransformVector([0,0,1]))
        self.params['xaxis'] = xaxis
        self.params['yaxis'] = yaxis
        self.params['zaxis'] = zaxis
        self.params['origin'] = t.GetPosition()

    def publish(self):
        self.updateParamsFromActorTransform()
        aff = affordance.createFrameAffordance(self.params)
        affordance.publishAffordance(aff)

class CylinderAffordanceItem(AffordanceItem):

    def setAffordanceParams(self, params):
        self.params = params

    def updateParamsFromActorTransform(self):

        t = self.actor.GetUserTransform()

        xaxis = np.array(t.TransformVector([1,0,0]))
        yaxis = np.array(t.TransformVector([0,1,0]))
        zaxis = np.array(t.TransformVector([0,0,1]))
        self.params['axis'] = zaxis
        self.params['origin'] = t.GetPosition()

    def publish(self):
        self.updateParamsFromActorTransform()
        aff = affordance.createCylinderAffordance(self.params)
        affordance.publishAffordance(aff)

class FrameItem(om.PolyDataItem):

    def __init__(self, name, transform, view):

        scale = 1.0
        self.transform = transform
        polyData = self._createAxes(scale)

        om.PolyDataItem.__init__(self, name, polyData, view)

        self.colorBy('Axes')
        lut = self.mapper.GetLookupTable()
        lut.SetHueRange(0, 0.667)
        lut.Build()

        self.actor.SetUserTransform(transform)

        self.widget = vtk.vtkFrameWidget()
        self.widget.CreateDefaultRepresentation()
        self.widget.EnabledOff()
        self.rep = self.widget.GetRepresentation()
        self.rep.SetWorldSize(scale)
        self.rep.SetTransform(transform)

        self.addProperty('Scale', scale)
        self.addProperty('Edit', False)

    def _createAxes(self, scale):
        axes = vtk.vtkAxes()
        axes.SetComputeNormals(0)
        axes.SetScaleFactor(scale)
        axes.Update()

        #t = vtk.vtkTransformPolyDataFilter()
        #t.SetTransform(transform)
        #t.AddInputConnection(self.axes.GetOutputPort())
        #t.Update()

        return shallowCopy(axes.GetOutput())

    def addToView(self, view):
        om.PolyDataItem.addToView(self, view)

    def setFrame(self, transform):
        self.transform = transform
        polyData = self._createAxes(self.getProperty('Scale'))
        self.setPolyData(polyData)

    def _onPropertyChanged(self, propertyName):

        if propertyName == 'Scale':
            scale = self.getProperty(propertyName)
            self.rep.SetWorldSize(scale)
            self.setPolyData(self._createAxes(scale))
        elif propertyName == 'Edit':
            view = app.getCurrentRenderView()
            if view not in self.views:
                view = self.views[0]
            self.widget.SetInteractor(view.renderWindow().GetInteractor())
            self.widget.SetEnabled(self.getProperty(propertyName))

        om.PolyDataItem._onPropertyChanged(self, propertyName)

    def getPropertyAttributes(self, propertyName):

        if propertyName == 'Scale':
            return om.PropertyAttributes(decimals=2, minimum=0.01, maximum=100, singleStep=0.1, hidden=False)
        else:
            return om.PolyDataItem.getPropertyAttributes(self, propertyName)

    def onRemoveFromObjectModel(self):
        om.PolyDataItem.onRemoveFromObjectModel(self)

        self.widget.SetInteractor(None)
        self.widget.EnabledOff()
        for view in self.views:
            view.renderer().RemoveActor(self.actor)
            view.render()

def updatePolyData(polyData, name, **kwargs):

    obj = om.findObjectByName(name)
    obj = obj or showPolyData(polyData, name, **kwargs)
    obj.setPolyData(polyData)
    return obj

def updateFrame(frame, name, **kwargs):

    obj = om.findObjectByName(name)
    obj = obj or showFrame(frame, name, **kwargs)
    obj.setFrame(frame)
    return obj

def showFrame(frame, name, parent='segmentation', scale=0.35, visible=True):
    if isinstance(parent, str):
        parentObj = om.getOrCreateContainer(parent)
    else:
        parentObj = parent

    item = FrameItem(name, frame, app.getCurrentRenderView())
    om.addToObjectModel(item, parentObj)
    item.setProperty('Visible', visible)
    item.setProperty('Scale', scale)
    return item

def showPolyData(polyData, name, color=None, colorByName=None, colorByRange=None, alpha=1.0, visible=True, view=None, parent='segmentation', cls=None):

    view = view or app.getCurrentRenderView()
    if view is None:
        return

    cls = cls or om.PolyDataItem
    item = cls(name, polyData, view)

    if isinstance(parent, str):
        parentObj = om.getOrCreateContainer(parent)
    else:
        parentObj = parent

    om.addToObjectModel(item, parentObj)
    item.setProperty('Visible', visible)
    item.setProperty('Alpha', alpha)
    if color:
        color = [component * 255 for component in color]
        item.setProperty('Color', QtGui.QColor(*color))
        item.colorBy(None)
    else:
        item.colorBy(colorByName, colorByRange)
    return item

def pickPoint(displayPoint, obj=None, view=None, pickType='points', tolerance=0.01):

    view = view or app.getCurrentRenderView()
    assert view

    picker = vtk.vtkPointPicker() if pickType == 'points' else vtk.vtkCellPicker()

    if isinstance(obj, str):
        obj = om.findObjectByName(obj)
        assert obj

    if obj:
        picker.AddPickList(obj.actor)
        picker.PickFromListOn()

    picker.SetTolerance(tolerance)
    picker.Pick(displayPoint[0], displayPoint[1], 0, view.renderer())
    pickPoints = picker.GetPickedPositions()
    pickedPoint = np.array(pickPoints.GetPoint(0)) if pickPoints.GetNumberOfPoints() else None
    pickedDataset = picker.GetDataSet()

    if obj:
        return pickedPoint
    else:
        return pickedDataset, pickedPoint

def mapMousePosition(widget, mouseEvent):
    mousePosition = mouseEvent.pos()
    return mousePosition.x(), widget.height - mousePosition.y()

def getObjectByDataSet(polyData):
    for item, obj in om.objects.iteritems():
        if isinstance(obj, om.PolyDataItem) and obj.polyData == polyData:
            return obj

def findPickedObject(displayPoint, view=None):

    view = view or app.getCurrentRenderView()
    assert view

    polyData, pickedPoint = pickPoint(displayPoint, view=view, pickType='cells')
    return getObjectByDataSet(polyData), pickedPoint
<|endoftext|>


<commit_before>#!/usr/bin/python

# TODO: tidy
# TODO: add logging
# TODO: get STATS_TYPES from statistics module.

"""Usage:
    assemble_quantification_stats [--log-level=<log-level>] [--out-dir=<out-dir>] [--run-dir=<run-dir>] --quant-methods=<quant-methods> --params=<param-values> --read-lengths=<read-lengths> --read-depths=<read-depths> --paired-ends=<paired-ends> --errors=<errors> --biases=<biases>

-h --help                           Show this message.
-v --version                        Show version.
--log-level=<log-level>             Set logging level (one of {log_level_vals}) [default: info].
--run-dir=<out-dir>                 Parent directory for quantification run directories [default: output].
--out-dir=<out-dir>                 Directory to output assembled stats files to [default: output/overall_stats].
-q --quant-methods=<quant-methods>  Comma-separated list of quantification methods to assemble stats for.
-l --read-lengths=<read-lengths>    Comma-separated list of read-lengths to assemble stats for.
-d --read-depths=<read-depths>      Comma-separated list of read-depths to assemble stats for.
-p --paired-ends=<paired-ends>      Comma-separated list of True/False strings indicating whether stats should be assembled for single or paired-end reads.
-e --errors=<errors>                Comma-separated list of True/False strings indicating whether stats should be assembled with or without read errors.
-b --biases=<biases>                Comma-separated list of True/False strings indicating whether stats should be assembled with or without read sequence bias.
"""

import docopt
import itertools
import ordutils.log as log
import ordutils.options as opt
import os.path
import pandas as pd
import quantifiers as qs
import schema
import sys

LOG_LEVEL = "--log-level"
LOG_LEVEL_VALS = str(log.LEVELS.keys())
OUTPUT_DIRECTORY = "--out-dir"
RUN_DIRECTORY = "--run-dir"
QUANT_METHODS = "--quant-methods"
READ_LENGTHS = "--read-lengths"
READ_DEPTHS = "--read-depths"
PAIRED_ENDS = "--paired-ends"
ERRORS = "--errors"
BIASES = "--biases"

STATS_TYPES = ["_stats", "_stats_by_gene_transcript_number", "_stats_by_log10_real_FPKM", "_stats_by_transcript_length", "_stats_by_unique_sequence_percentage", "_distribution_stats_asc_by_absolute_percent_error", "_distribution_stats_desc_by_absolute_percent_error"]

# Read in command-line options
__doc__ = __doc__.format(log_level_vals=LOG_LEVEL_VALS)
options = docopt.docopt(__doc__, version="assemble_quantification_stats v0.1")

# Validate command-line options

def validate_list_option(option, item_validator, separator=','):
    items = option.split(separator)
    return [schema.Schema(
        schema.Use(item_validator)).validate(i) for i in items]

def check_boolean_value(data):
    data = data.lower()
    if data in ["true", "t", "yes", "y"]:
        return True
    elif data in ["false", "f", "no", "n"]:
        return False
    else:
        raise Exception("Can't convert '{d}' to bool.".format(d=data))

def check_quantification_method(data):
    available_methods = qs.get_quantification_methods()
    return available_methods[data]
try:
    opt.validate_dict_option(
        options[LOG_LEVEL], log.LEVELS, "Invalid log level")
    options[QUANT_METHODS] = validate_list_option(
        options[QUANT_METHODS], check_quantification_method)
    options[READ_LENGTHS] = set(validate_list_option(
        options[READ_LENGTHS], int))
    options[READ_DEPTHS] = set(validate_list_option(
        options[READ_DEPTHS], int))
    options[PAIRED_ENDS] = set(validate_list_option(
        options[PAIRED_ENDS], check_boolean_value))
    options[ERRORS] = set(validate_list_option(
        options[ERRORS], check_boolean_value))
    options[BIASES] = set(validate_list_option(
        options[BIASES], check_boolean_value))
except schema.SchemaError as exc:
    exit(exc.code)

# Set up logger

logger = log.get_logger(sys.stderr, options[LOG_LEVEL])

def _get_reads_name(length, depth, paired_end, errors, bias):
    return "{d}x_{l}b_{p}_{e}_{b}".format(
        d=depth, l=length,
        p="pe" if paired_end else "se",
        e="errors" if errors else "no_errors",
        b="bias" if bias else "no_bias")

def _get_run_name(quant_method, length, depth, paired_end, errors, bias):
    return "{qm}_{r}".format(
        qm=quant_method.get_name(),
        r=_get_reads_name(length, depth, paired_end, errors, bias))

def _get_run_dir(output_dir, quant_method, length, depth,
                 paired_end, error, bias):
    return output_dir + os.path.sep + \
        _get_run_name(quant_method, length, depth, paired_end, error, bias)

for quant_method, length, depth, paired_end, error, bias in \
    itertools.product(
        options[QUANT_METHODS], options[READ_LENGTHS],
        options[READ_DEPTHS], options[PAIRED_ENDS],
        options[ERRORS], options[BIASES]):

    # Check all run directories exist
    run_dir = _get_run_dir(
        options[RUN_DIRECTORY], quant_method,
        length, depth, paired_end, error, bias)
    if not os.path.exists(run_dir):
        sys.exit("Run directory '{d}' should exist.")

for stats_type in STATS_TYPES:
    overall_stats_df = pd.DataFrame()

    for quant_method, length, depth, paired_end, error, bias in \
        itertools.product(
            options[QUANT_METHODS], options[READ_LENGTHS],
            options[READ_DEPTHS], options[PAIRED_ENDS],
            options[ERRORS], options[BIASES]):

        run_name = _get_run_name(
            quant_method, length, depth, paired_end, error, bias)
        run_dir = _get_run_dir(
            options[RUN_DIRECTORY], quant_method,
            length, depth, paired_end, error, bias)

        stats_file = run_dir + os.path.sep + run_name + stats_type + ".csv"
        stats_df = pd.read_csv(stats_file)
        overall_stats_df.append(stats_df)

    overall_stats_file = options[OUTPUT_DIRECTORY] + os.path.sep + \
        "overall" + stats_type + ".csv"
    overall_stats_df.to_csv(
        overall_stats_file, float_format="%.5f", index=False)
<commit_msg>Fix appending stats for a run to existing data frame.<commit_after>#!/usr/bin/python

# TODO: tidy
# TODO: add logging
# TODO: get STATS_TYPES from statistics module.

"""Usage:
    assemble_quantification_stats [--log-level=<log-level>] [--out-dir=<out-dir>] [--run-dir=<run-dir>] --quant-methods=<quant-methods> --read-lengths=<read-lengths> --read-depths=<read-depths> --paired-ends=<paired-ends> --errors=<errors> --biases=<biases>

-h --help                           Show this message.
-v --version                        Show version.
--log-level=<log-level>             Set logging level (one of {log_level_vals}) [default: info].
--run-dir=<out-dir>                 Parent directory for quantification run directories [default: output].
--out-dir=<out-dir>                 Directory to output assembled stats files to [default: output/overall_stats].
-q --quant-methods=<quant-methods>  Comma-separated list of quantification methods to assemble stats for.
-l --read-lengths=<read-lengths>    Comma-separated list of read-lengths to assemble stats for.
-d --read-depths=<read-depths>      Comma-separated list of read-depths to assemble stats for.
-p --paired-ends=<paired-ends>      Comma-separated list of True/False strings indicating whether stats should be assembled for single or paired-end reads.
-e --errors=<errors>                Comma-separated list of True/False strings indicating whether stats should be assembled with or without read errors.
-b --biases=<biases>                Comma-separated list of True/False strings indicating whether stats should be assembled with or without read sequence bias.
"""

import docopt
import itertools
import ordutils.log as log
import ordutils.options as opt
import os.path
import pandas as pd
import quantifiers as qs
import schema
import sys

LOG_LEVEL = "--log-level"
LOG_LEVEL_VALS = str(log.LEVELS.keys())
OUTPUT_DIRECTORY = "--out-dir"
RUN_DIRECTORY = "--run-dir"
QUANT_METHODS = "--quant-methods"
READ_LENGTHS = "--read-lengths"
READ_DEPTHS = "--read-depths"
PAIRED_ENDS = "--paired-ends"
ERRORS = "--errors"
BIASES = "--biases"

STATS_TYPES = ["_stats", "_stats_by_gene_transcript_number", "_stats_by_log10_real_FPKM", "_stats_by_transcript_length", "_stats_by_unique_sequence_percentage", "_distribution_stats_asc_by_absolute_percent_error", "_distribution_stats_desc_by_absolute_percent_error"]

# Read in command-line options
__doc__ = __doc__.format(log_level_vals=LOG_LEVEL_VALS)
options = docopt.docopt(__doc__, version="assemble_quantification_stats v0.1")

# Validate command-line options

def validate_list_option(option, item_validator, separator=','):
    items = option.split(separator)
    return [schema.Schema(
        schema.Use(item_validator)).validate(i) for i in items]

def check_boolean_value(data):
    data = data.lower()
    if data in ["true", "t", "yes", "y"]:
        return True
    elif data in ["false", "f", "no", "n"]:
        return False
    else:
        raise Exception("Can't convert '{d}' to bool.".format(d=data))

def check_quantification_method(data):
    available_methods = qs.get_quantification_methods()
    return available_methods[data]
try:
    opt.validate_dict_option(
        options[LOG_LEVEL], log.LEVELS, "Invalid log level")
    options[QUANT_METHODS] = validate_list_option(
        options[QUANT_METHODS], check_quantification_method)
    options[READ_LENGTHS] = set(validate_list_option(
        options[READ_LENGTHS], int))
    options[READ_DEPTHS] = set(validate_list_option(
        options[READ_DEPTHS], int))
    options[PAIRED_ENDS] = set(validate_list_option(
        options[PAIRED_ENDS], check_boolean_value))
    options[ERRORS] = set(validate_list_option(
        options[ERRORS], check_boolean_value))
    options[BIASES] = set(validate_list_option(
        options[BIASES], check_boolean_value))
except schema.SchemaError as exc:
    exit(exc.code)

# Set up logger

logger = log.get_logger(sys.stderr, options[LOG_LEVEL])

def _get_reads_name(length, depth, paired_end, errors, bias):
    return "{d}x_{l}b_{p}_{e}_{b}".format(
        d=depth, l=length,
        p="pe" if paired_end else "se",
        e="errors" if errors else "no_errors",
        b="bias" if bias else "no_bias")

def _get_run_name(quant_method, length, depth, paired_end, errors, bias):
    return "{qm}_{r}".format(
        qm=quant_method.get_name(),
        r=_get_reads_name(length, depth, paired_end, errors, bias))

def _get_run_dir(output_dir, quant_method, length, depth,
                 paired_end, error, bias):
    return output_dir + os.path.sep + \
        _get_run_name(quant_method, length, depth, paired_end, error, bias)

if not os.path.exists(options[OUTPUT_DIRECTORY]):
    os.mkdir(options[OUTPUT_DIRECTORY])

for quant_method, length, depth, paired_end, error, bias in \
    itertools.product(
        options[QUANT_METHODS], options[READ_LENGTHS],
        options[READ_DEPTHS], options[PAIRED_ENDS],
        options[ERRORS], options[BIASES]):

    # Check all run directories exist
    run_dir = _get_run_dir(
        options[RUN_DIRECTORY], quant_method,
        length, depth, paired_end, error, bias)
    if not os.path.exists(run_dir):
        sys.exit("Run directory '{d}' should exist.".format(d=run_dir))

for stats_type in STATS_TYPES:
    overall_stats_df = pd.DataFrame()

    for quant_method, length, depth, paired_end, error, bias in \
        itertools.product(
            options[QUANT_METHODS], options[READ_LENGTHS],
            options[READ_DEPTHS], options[PAIRED_ENDS],
            options[ERRORS], options[BIASES]):

        run_name = _get_run_name(
            quant_method, length, depth, paired_end, error, bias)
        run_dir = _get_run_dir(
            options[RUN_DIRECTORY], quant_method,
            length, depth, paired_end, error, bias)

        stats_file = run_dir + os.path.sep + run_name + stats_type + ".csv"
        stats_df = pd.read_csv(stats_file)
        overall_stats_df = overall_stats_df.append(stats_df)

    overall_stats_file = options[OUTPUT_DIRECTORY] + os.path.sep + \
        "overall" + stats_type + ".csv"
    overall_stats_df.to_csv(
        overall_stats_file, float_format="%.5f", index=False)
<|endoftext|>