コード例 #1
0
ファイル: Dynamics.py プロジェクト: Caian/Asparagus
 def simplify1DD(self, expr):
     # Place the offsets of the objects relative to their reference 
     # frame position, so constant position objects have a relative 
     # position of zero
     xb = 0 if isTimeConstant(self.objb['tr.x'], self.symbols) else self.objb['tr.x']
     xa = 0 if isTimeConstant(self.obja['tr.x'], self.symbols) else self.obja['tr.x']
     # b.x = a.x + (l + d)*sin(theta_a)
     # d = b.x - a.x
     return expr.subs(self.d, xb - xa)
コード例 #2
0
ファイル: T3Engine.py プロジェクト: Caian/Asparagus
    def assertPairAngle(self, dyn):
        x1 = dyn.obja["tr.x"]
        y1 = dyn.obja["tr.y"]
        x2 = dyn.objb["tr.x"]
        y2 = dyn.objb["tr.y"]
        a1 = dyn.obja["rt.angle"]
        a2 = dyn.objb["rt.angle"]
        thetaa = dyn.thetaa
        name = dyn.name

        if not isTimeConstant(thetaa, self.symbols):
            return True

        # Convert the attachments to polar, add the body angle
        # and then reconvert to rectangular

        att1 = dyn.getAttachment(dyn.obja, "p")
        if att1[0] != 0:
            att1 = (att1[0], a1 + att1[1], att1[2])
            i1, j1, m1 = Globals.convertAttachment(att1, "r")
        else:
            i1 = 0
            j1 = 0

        att2 = dyn.getAttachment(dyn.objb, "p")
        if att2[0] != 0:
            att2 = (att2[0], a2 + att2[1], att2[2])
            i2, j2, m2 = Globals.convertAttachment(att2, "r")
        else:
            i2 = 0
            j2 = 0

        dx = sympy.sympify((x2 + i2) - (x1 + i1))
        dy = sympy.sympify((y2 + j2) - (y1 + j1))

        if dx == 0 and sympy.simplify(sympy.Mod(thetaa, sympy.pi)) != 0:
            self.printer.print_diagnostic(
                2,
                "thetaa assertion failed for dynamic %s, set=%s, inferred=%s."
                % (name, str(thetaa), str(sympy.sympify(sympy.atan2(dx, dy)))),
            )
            return False
        elif dy == 0 and sympy.simplify(sympy.Mod(thetaa + sympy.pi / 2, sympy.pi)) != 0:
            self.printer.print_diagnostic(
                2,
                "thetaa assertion failed for dynamic %s, set=%s, inferred=%s."
                % (name, str(thetaa), str(sympy.sympify(sympy.atan2(dx, dy)))),
            )
            return False

        return True
コード例 #3
0
ファイル: T3Engine.py プロジェクト: Caian/Asparagus
    def solveEquations(self):
        # System of equations
        self.printer.print_diagnostic(3, "Finishing system of equations...")
        for ei, expr in enumerate(self.scene["fragments"]):

            obj = expr["object"]

            self.printer.print_diagnostic(3, "(%d/%d) %s..." % (ei + 1, len(self.scene["fragments"]), obj["$.name"]))

            rftmode, rfrmode, rfangle, rfdir = self.scene["refs"][obj["$.name"]]

            rhsx = 0
            rhsy = 0
            rhst = 0

            mxa = obj["tr.mass"] * sympy.Derivative(obj["tr.x"], Globals.time(self.symbols), Globals.time(self.symbols))
            mya = obj["tr.mass"] * sympy.Derivative(obj["tr.y"], Globals.time(self.symbols), Globals.time(self.symbols))
            mta = obj["rt.mass"] * sympy.Derivative(
                obj["rt.angle"], Globals.time(self.symbols), Globals.time(self.symbols)
            )

            cx = isTimeConstant(obj["tr.x"], self.symbols)
            cy = isTimeConstant(obj["tr.y"], self.symbols)
            ca = isTimeConstant(obj["rt.angle"], self.symbols)

            for i in expr["rhs"]:

                force = i[0]
                dyn = i[-1]
                roll = i[2] == "roll"
                angle = i[1]

                # Compute the force components
                if angle != None:
                    if rftmode == 1:
                        x = sympy.simplify(force * sympy.sin(i[1]))
                        rhsx += dyn.simplify1DD(x)

                        # Send expression to timemachine
                        if obj["tr.mass"] != 0 and not cx and not cy:
                            self.timemachine.add_highlight_eqn(obj, dyn, [sympy.Eq(mxa, rhsx)])

                    elif rftmode == 2:
                        if not cx:
                            x = sympy.simplify(force * sympy.sin(i[1]))
                            rhsx += x

                            # Send expression to timemachine
                            if obj["tr.mass"] != 0 and not cx:
                                self.timemachine.add_highlight_eqn(obj, dyn, [sympy.Eq(mxa, rhsx)])

                        if not cy:
                            y = sympy.simplify(force * sympy.cos(i[1]))
                            rhsy += y

                            # Send expression to timemachine
                            if obj["tr.mass"] != 0 and not cy:
                                self.timemachine.add_highlight_eqn(obj, dyn, [sympy.Eq(mya, rhsy)])

                    if rfrmode != 0 and not ca:
                        # Compute the torque components
                        atd, ata, atm = dyn.getAttachment(obj, "p")
                        if atd != 0:
                            # Roll dynamics will assume a force perpendicular to the radius vector
                            if not roll:
                                # Compute the torque angle
                                tangle = ata + sympy.pi / 2 + obj["rt.angle"]
                            else:
                                # Compute the torque angle without considering the body rotation
                                tangle = ata + sympy.pi / 2

                            # Compute the projection of the force onto the torque direction
                            torque = sympy.simplify(force * atd * sympy.cos(angle - tangle))
                            rhst += torque

                            # Send expression to timemachine
                            if obj["rt.mass"] != 0 and not ca:
                                self.timemachine.add_highlight_eqn(obj, dyn, [sympy.Eq(mta, rhst)])

                elif not ca:
                    # The force is actually a torque...
                    rhst += force

                    # Well this is weird...
                    if obj["rt.mass"] == 0:
                        self.printer.print_diagnostic(
                            2,
                            "pure torque from %s applied to %s which has no moment of inertia."
                            % (dyn.name, obj["$.name"]),
                        )

                    # Send expression to timemachine
                    if obj["rt.mass"] != 0 and not ca:
                        self.timemachine.add_highlight_eqn(obj, dyn, [sympy.Eq(mta, rhst)])

            # Prepare to show the final set of equations
            tmexprs = []

            # Append the translation equations
            if rftmode != 0:
                if obj["tr.mass"] == 0:
                    self.printer.print_diagnostic(
                        3, "ignoring translational equations for body %s bacause it has no mass." % obj["$.name"]
                    )
                else:
                    if rftmode == 1:
                        expr = sympy.Eq(mxa, rhsx)
                        self.scene["equations"].append(expr)
                        tmexprs.append(expr)
                    if rftmode == 2:
                        if cx:
                            self.printer.print_diagnostic(
                                3,
                                "ignoring x-axis translational equation for body %s bacause it is locked."
                                % obj["$.name"],
                            )
                        else:
                            expr = sympy.Eq(mxa, rhsx)
                            self.scene["equations"].append(expr)
                            tmexprs.append(expr)
                        if cy:
                            self.printer.print_diagnostic(
                                3,
                                "ignoring y-axis translational equation for body %s bacause it is locked."
                                % obj["$.name"],
                            )
                        else:
                            expr = sympy.Eq(mya, rhsy)
                            self.scene["equations"].append(expr)
                            tmexprs.append(expr)
                    else:
                        raise Exception("unknown reference frame mode")

            # Append the rotation equations
            if rfrmode != 0:
                if obj["rt.mass"] == 0:
                    self.printer.print_diagnostic(
                        3,
                        "ignoring rotational equations for body %s bacause it has no moment of inertia."
                        % obj["$.name"],
                    )
                else:
                    if rfrmode == 1:
                        if ca:
                            self.printer.print_diagnostic(
                                3, "ignoring rotational equation for body %s bacause it is locked." % obj["$.name"]
                            )
                        else:
                            expr = sympy.Eq(mta, rhst)
                            self.scene["equations"].append(expr)
                            tmexprs.append(expr)
                    else:
                        raise Exception("unknown reference frame mode")

            # Send expressions to timemachine
            self.timemachine.add_highlight_eqn(obj, None, tmexprs)

        # Finish with the link equations
        for di, dyn in enumerate(self.scene["dynamics"]):

            self.printer.print_diagnostic(3, "(%d/%d) %s..." % (di + 1, len(self.scene["dynamics"]), dyn.name))

            # Prepare to show the final set of link equations
            tmexprs = []

            les = dyn.getLEqns()
            for le in les:
                le = sympy.simplify(le)
                if le == True:
                    self.printer.print_diagnostic(
                        3, "link equation was reduced to 0 == 0 due to constraints and will be ignored."
                    )
                elif le == False:
                    raise Exception("inconsistent system detected while processing dynamic %s" % dyn.name)
                else:
                    self.scene["equations"].append(le)
                    tmexprs.append(le)

            # Send the system of link equations to timemachine
            self.timemachine.add_highlight_eqn(None, dyn, tmexprs)

        # Send the whole system to timemachine
        self.timemachine.add_highlight_eqn(None, None, self.scene["equations"])

        self.printer.print_diagnostic(3, "system ready.")
コード例 #4
0
ファイル: T3Engine.py プロジェクト: Caian/Asparagus
    def solveRefFrames(self):
        # Reference frames
        self.printer.print_diagnostic(3, "deducing reference frames...")
        for expr in self.scene["fragments"]:
            obj = expr["object"]
            if len(expr["rhs"]) == 0:
                self.printer.print_diagnostic(2, "%s has no dynamics associated." % obj["$.name"])
                rmode = 0
                tmode = 0
                angle = 0
                dir = 0
            else:
                cx = isTimeConstant(obj["tr.x"], self.symbols)
                cy = isTimeConstant(obj["tr.y"], self.symbols)
                ca = isTimeConstant(obj["rt.angle"], self.symbols)
                if cx and cy and ca:
                    # All axis of movement are locked (all motion variables are constants)
                    self.printer.print_diagnostic(2, "%s is fully locked." % obj["$.name"])
                    rmode = 0
                    tmode = 0
                    angle = 0
                    dir = 1
                else:
                    rmode = 1
                    tmode = 2
                    angle = 0
                    dir = 1
                    # See if rotation is locked
                    # if ca:
                    #    if obj['rt.mass'] != 0:
                    #        self.printer.print_diagnostic(2, '%s has no rotation but has moment of inertia.' % obj['$.name'])
                    #    rmode = 0
                    #    dir = 0
                    # else:
                    #    rmode = 1
                    #    dir = 1
                    ## Deduce translations
                    # if cx and cy:
                    #    if obj['tr.mass'] != 0:
                    #        self.printer.print_diagnostic(2, '%s has no translation but has mass.' % obj['$.name'])
                    #    tmode = 0
                    #    angle = 0
                    # elif cx:
                    #    # Translation along x axis
                    #    tmode = 1
                    #    angle = sympy.pi / 2
                    # elif cy:
                    #    # Translation along y axis
                    #    tmode = 1
                    #    angle = 0
                    # else:
                    #    # xy free, deduce from dynamics
                    #    # Check if a 2D ref frame is necessary
                    #    # for that all forces must be aligned on the same
                    #    # axis and the angle cannot vary with time
                    #    angle = expr['rhs'][0][1]
                    #    if not isTimeConstant(angle, self.symbols):
                    #        tmode = 2
                    #        angle = 0
                    #    else:
                    #        tmode = 1
                    #        for rhs in expr['rhs'][1:]:
                    #            # simplification of cross product for unit vectors
                    #            # to evaluate if two angles form parallel vectors
                    #            a = rhs[1]
                    #            if isTimeConstant(a, self.symbols) == False or sympy.sin(sympy.simplify(angle-a)) != 0:
                    #                angle = 0
                    #                tmode = 2
                    #                break

            self.printer.print_diagnostic(
                4,
                "%s - %d translation DOF (rotated by %s), %d rotation DOF (%s)."
                % (obj["$.name"], tmode, str(angle), rmode, "CCW" if dir == 1 else "CW"),
            )
            self.scene["refs"][obj["$.name"]] = (tmode, rmode, angle, dir)

            # Send the ref frame to timemachine
            self.timemachine.add_rf(
                obj, tmode, rmode, angle, dir, (str(obj["tr.x"]), str(obj["tr.y"]), str(obj["rt.angle"]))
            )
コード例 #5
0
ファイル: T3Engine.py プロジェクト: Caian/Asparagus
    def loadDynamic(self, name, props, data, aliases):
        dyn = data["dynamic"]
        bodies = [self.getObject(n[0]) for n in data["attach"]]
        attmodes = [n[1] if len(n) > 1 else "p" for n in data["attach"]]
        attoffs = [n[2] if len(n) > 1 else None for n in data["attach"]]
        offs = data["offset"]
        showangles = props.get("showangles", False)

        # A few assert funtions...
        def assert_bodies(name, n):
            if len(bodies) != n:
                raise Exception("%s dynamic expects %d body, provided %d" % (name, n, len(bodies)))

        def assert_offs(name, n):
            if len(offs) != n:
                raise Exception("%s dynamic expects %d offsets, provided %d" % (name, n, len(offs)))

        def aliasify(s, p):
            alias = aliases.get(s, None)
            if alias != None:
                self.aliases[p] = alias
            return str(p)

        # Roll assertions

        def get0Rolls(what):
            roll = props.get("roll", None)
            if roll == None:
                roll = props.get("rolla", None)

            if roll == "1" or roll == "1":
                self.printer.print_diagnostic(2, "dynamic %s does not have roll because it is %s." % (name, what))

        def get1Roll():
            roll = props.get("roll", None)
            if roll == None:
                roll = props.get("rolla", None)

            if roll == "1" or roll == "1":
                self.printer.print_diagnostic(
                    3, "dynamic %s set to roll mode on body %s." % (name, bodies[0]["$.name"])
                )
                roll = True
            else:
                roll = False

            return roll

        def get2Rolls():
            rolla = props.get("rolla", None)
            if rolla == "1" or rolla == "1":
                self.printer.print_diagnostic(
                    3, "dynamic %s set to roll mode on body %s." % (name, bodies[0]["$.name"])
                )
                rolla = True
            else:
                rolla = False

            rollb = props.get("rollb", None)
            if rollb == "1" or rollb == "1":
                self.printer.print_diagnostic(
                    3, "dynamic %s set to roll mode on body %s." % (name, bodies[1]["$.name"])
                )
                rollb = True
            else:
                rollb = False

            return (rolla, rollb)

        # Resolve the attachments
        for b, m, o in zip(bodies, attmodes, attoffs):
            if o != None:
                if m == "p":
                    ata = Globals.getAttachProp(b["$.name"], "d")
                    atb = Globals.getAttachProp(b["$.name"], "theta")
                elif m == "r":
                    ata = Globals.getAttachProp(b["$.name"], "x")
                    atb = Globals.getAttachProp(b["$.name"], "y")

                self.symbols.addReplacement(name, ata, o[0])
                self.symbols.addReplacement(name, atb, o[1])

        # Switch the dynamic type
        if dyn == "force":
            assert_bodies("force", 1)
            assert_offs("force", 4)

            pos = (offs["x1"], offs["y1"], offs["x2"], offs["y2"])

            att = (bodies[0], attmodes[0])

            # Constant Force has only one roll
            roll = get1Roll()

            d = Dynamics.ForceDynamic(name, att, roll, self.symbols)

            t = aliasify("theta", d.theta)
            title = aliasify("F", d.getFSym())

        elif dyn == "weight":
            # TODO ignore offset and force it to center of mass
            assert_bodies("weight", 1)
            assert_offs("weight", 4)

            pos = (offs["x1"], offs["y1"], offs["x2"], offs["y2"])

            # Weight Force only has an att if the center of mass is different
            # from the fixture point, which means the translation axes MUST
            # be fixed, enforce this rule

            # By default the attachment must be zero even if nothing is
            # specified (center of mass assumed)
            mustlock = True

            # Enforce att lock if the axes are not
            if not isTimeConstant(bodies[0]["tr.x"], self.symbols) or not isTimeConstant(
                bodies[0]["tr.y"], self.symbols
            ):
                if attoffs[0] != None:
                    self.printer.print_diagnostic(
                        2,
                        "offset for %s will be ignored because the body %s is not locked in x and y."
                        % (name, bodies[0]["$.name"]),
                    )
            else:
                if attoffs[0] != None:
                    mustlock = False

            if mustlock:
                attmodes[0] = "p"
                ata = Globals.getAttachProp(b["$.name"], "d")
                atb = Globals.getAttachProp(b["$.name"], "theta")
                self.symbols.addReplacement(name, ata, 0)
                self.symbols.addReplacement(name, atb, 0)

            att = (bodies[0], attmodes[0])

            # Weight Force only has no rolls :/

            get0Rolls("weight")

            d = Dynamics.WeightDynamic(name, att, self.symbols)

            title = str(d.getFSym())
            showangles = False  # Do not show theta for gravity

        elif dyn == "rod":
            assert_bodies("rod", 2)
            assert_offs("rod", 4)

            pos = (offs["x1"], offs["y1"], offs["x2"], offs["y2"])

            att0 = (bodies[0], attmodes[0])
            att1 = (bodies[1], attmodes[1])

            # Rod has two rolls, for a and b points
            rolla, rollb = get2Rolls()

            d = Dynamics.RodDynamic(name, att0, rolla, att1, rollb, self.symbols)

            aliasify("l", d.l)
            t = aliasify("thetaa", d.thetaa)
            title = aliasify("T", d.getTSym())

        elif dyn == "spring":
            assert_bodies("spring", 2)
            assert_offs("spring", 4)

            pos = (offs["x1"], offs["y1"], offs["x2"], offs["y2"])

            att0 = (bodies[0], attmodes[0])
            att1 = (bodies[1], attmodes[1])

            # Spring has two rolls, for a and b points
            rolla, rollb = get2Rolls()

            d = Dynamics.SpringDynamic(name, att0, rolla, att1, rollb, self.symbols)

            aliasify("l", d.l)
            aliasify("d", d.d)
            aliasify("T", d.getTSym())
            t = aliasify("thetaa", d.thetaa)
            title = aliasify("k", d.k)

        elif dyn == "dampener":
            assert_bodies("dampener", 2)
            assert_offs("dampener", 4)

            pos = (offs["x1"], offs["y1"], offs["x2"], offs["y2"])

            att0 = (bodies[0], attmodes[0])
            att1 = (bodies[1], attmodes[1])

            # Dampener has two rolls, for a and b points
            rolla, rollb = get2Rolls()

            d = Dynamics.DampenerDynamic(name, att0, rolla, att1, rollb, self.symbols)

            aliasify("l", d.l)
            aliasify("d", d.d)
            aliasify("T", d.getTSym())
            t = aliasify("thetaa", d.thetaa)
            title = aliasify("b", d.b)

        elif dyn == "torque":
            assert_bodies("torque", 1)
            assert_offs("torque", 2)

            flipped = int(props.get("direction", 1))
            flipped = flipped != 0

            pos = (offs["x1"], offs["y1"])

            # Angular dynamics have no rolls
            get0Rolls()

            d = Dynamics.TorqueDynamic(name, obj, flipped, self.symbols)

            title = aliasify("k", d.k)

        elif dyn == "angularspring":
            assert_bodies("angularspring", 1)
            assert_offs("angularspring", 2)

            pos = (offs["x1"], offs["y1"])

            # Angular dynamics have no rolls
            get0Rolls()

            d = Dynamics.AngularSpringDynamic(name, obj, self.symbols)

            title = aliasify("k", d.k)

        elif dyn == "angulardampener":
            assert_bodies("angulardampener", 1)
            assert_offs("angulardampener", 2)

            pos = (offs["x1"], offs["y1"])

            # Angular dynamics have no rolls
            get0Rolls()

            d = Dynamics.AngularDampenerDynamic(name, obj, self.symbols)

            title = aliasify("b", d.b)

        elif dyn == "belt":
            assert_bodies("belt", 2)
            assert_offs("belt", 4)

            pos = (offs["x1"], offs["y1"], offs["x2"], offs["y2"])

            att0 = (bodies[0], attmodes[0])
            att1 = (bodies[1], attmodes[1])

            # Angular dynamics have no rolls
            get0Rolls()

            d = Dynamics.BeltDynamic(name, att0, att1, self.symbols)

            title = aliasify("b", d.b)

        else:
            raise Exception("unknown dynamic type %s" % dyn)

        # Add dynamic to the list of dynamic in the scene
        self.scene["dynamics"].append(d)

        # Add dynamic to the collection of dynamics of each body
        for body in bodies:
            self.scene["attachments"][body["$.name"]].append(d)

        # Draw the dynamic
        self.printer.print_dynamic(name, dyn, pos, title, props)

        # Draw the angle of the dynamic, if specified
        if showangles == "1" or showangles == True:
            self.printer.print_angle(name, t)