Planar

model Planar "Planar joint (3 degrees-of-freedom, 6 potential states)"
    extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;

    parameter Boolean animation = true "= true, if animation shall be enabled";
    parameter Modelica.Mechanics.MultiBody.Types.Axis n = {0, 0, 1} "Axis orthogonal to unconstrained plane, resolved in frame_a (= same as in frame_b)"
        annotation (Evaluate = true);
    parameter Modelica.Mechanics.MultiBody.Types.Axis n_x = {1, 0, 0} "Vector in direction of x-axis of plane, resolved in frame_a (n_x shall be orthogonal to n)"
        annotation (Evaluate = true);
    parameter SI.Distance cylinderLength = world.defaultJointLength "Length of revolute cylinder"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter SI.Distance cylinderDiameter = world.defaultJointWidth "Diameter of revolute cylinder"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    input Types.Color cylinderColor = Modelica.Mechanics.MultiBody.Types.Defaults.JointColor "Color of revolute cylinder"
        annotation (Dialog(
            colorSelector = true,
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter SI.Distance boxWidth = 0.3 * cylinderDiameter "Width of prismatic joint boxes"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter SI.Distance boxHeight = boxWidth "Height of prismatic joint boxes"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    input Types.Color boxColor = Modelica.Mechanics.MultiBody.Types.Defaults.JointColor "Color of prismatic joint boxes"
        annotation (Dialog(
            colorSelector = true,
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter StateSelect stateSelect = StateSelect.prefer "Priority to use joint coordinates (s_x, s_y, phi, v_x, v_y, w) as states"
        annotation (Dialog(tab = "Advanced"));
    Prismatic prismatic_x(stateSelect = StateSelect.never, n = cross(cross(n, n_x), n), animation = false) annotation (Placement(transformation(extent = {
        {-69, -20}, 
        {-29, 20}})));
    Prismatic prismatic_y(stateSelect = StateSelect.never, n = cross(n, n_x), animation = false) annotation (Placement(transformation(
        origin = {0, 50},
        extent = {
            {-20, -20}, 
            {20, 20}},
        rotation = 90)));
    Revolute revolute(stateSelect = StateSelect.never, n = n, animation = false) annotation (Placement(transformation(extent = {
        {41, -20}, 
        {81, 20}})));
    SI.Position s_x(start = 0, stateSelect = stateSelect) "Relative distance along first prismatic joint starting at frame_a";
    SI.Position s_y(start = 0, stateSelect = stateSelect) "Relative distance along second prismatic joint starting at first prismatic joint";
    SI.Angle phi(start = 0, stateSelect = stateSelect) "Relative rotation angle from frame_a to frame_b";
    SI.Velocity v_x(start = 0, stateSelect = stateSelect) "First derivative of s_x (relative velocity in s_x direction)";
    SI.Velocity v_y(start = 0, stateSelect = stateSelect) "First derivative of s_y (relative velocity in s_y direction)";
    SI.AngularVelocity w(start = 0, stateSelect = stateSelect) "First derivative of angle phi (relative angular velocity)";
    SI.Acceleration a_x(start = 0) "Second derivative of s_x (relative acceleration in s_x direction)";
    SI.Acceleration a_y(start = 0) "Second derivative of s_y (relative acceleration in s_y direction)";
    SI.AngularAcceleration wd(start = 0) "Second derivative of angle phi (relative angular acceleration)";
protected
    parameter Integer ndim = if world.enableAnimation and animation then 1 else 0;
    parameter Real e[3](each final unit = "1") = Modelica.Math.Vectors.normalize(n);
    Visualizers.Advanced.Shape box_x[ndim](each shapeType = "box", each color = boxColor, each length = prismatic_x.s, each width = boxWidth, each height = boxWidth, each lengthDirection = prismatic_x.e, each widthDirection = {0, 1, 0}, each r = frame_a.r_0, each R = frame_a.R) annotation (Placement(transformation(extent = {
        {-80, 30}, 
        {-60, 50}})));
    Visualizers.Advanced.Shape box_y[ndim](each shapeType = "box", each color = boxColor, each length = prismatic_y.s, each width = boxWidth, each height = boxWidth, each lengthDirection = prismatic_y.e, each widthDirection = {1, 0, 0}, each r = prismatic_y.frame_a.r_0, each R = prismatic_y.frame_a.R) annotation (Placement(transformation(extent = {
        {-46, 69}, 
        {-26, 89}})));
    Visualizers.Advanced.Shape cylinder[ndim](each shapeType = "cylinder", each color = cylinderColor, each length = cylinderLength, each width = cylinderDiameter, each height = cylinderDiameter, each lengthDirection = n, each widthDirection = {0, 1, 0}, each r_shape = -e * (0.5 * cylinderLength), each r = revolute.frame_b.r_0, each R = revolute.frame_b.R) annotation (Placement(transformation(extent = {
        {50, 30}, 
        {70, 50}})));
equation
    connect(frame_a,prismatic_x.frame_a) annotation (Line(
        points = {
            {-100, 0}, 
            {-84, 0}, 
            {-84, 0}, 
            {-69, 0}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(revolute.frame_b,frame_b) annotation (Line(
        points = {
            {81, 0}, 
            {92, 0}, 
            {92, 0}, 
            {100, 0}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(prismatic_x.frame_b,prismatic_y.frame_a) annotation (Line(
        points = {
            {-29, 0}, 
            {0, 0}, 
            {0, 30}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(prismatic_y.frame_b,revolute.frame_a) annotation (Line(
        points = {
            {0, 70}, 
            {0, 80}, 
            {30, 80}, 
            {30, 0}, 
            {41, 0}},
        color = {95, 95, 95},
        thickness = 0.5));
    w = der(phi);
    a_x = der(v_x);
    a_y = der(v_y);
    phi = revolute.phi;
    s_x = prismatic_x.s;
    s_y = prismatic_y.s;
    v_x = der(s_x);
    v_y = der(s_y);
    wd = der(w);

    annotation (
        Documentation(info = "<html>\n<p>\nJoint where frame_b can move in a plane and can rotate around an\naxis orthogonal to the plane. The plane is defined by\nvector n which is perpendicular to the plane and by vector n_x,\nwhich points in the direction of the x-axis of the plane.\nframe_a and frame_b coincide when s_x=prismatic_x.s=0,\ns_y=prismatic_y.s=0 and phi=revolute.phi=0. This joint has the following\npotential states:\n</p>\n<ul>\n<li> the relative distance s_x = prismatic_x.s [m] along axis n_x,</li>\n<li> the relative distance s_y = prismatic_y.s [m] along axis n_y = cross(n,n_x),</li>\n<li> the relative angle phi = revolute.phi [rad] around axis n,</li>\n<li> the relative velocity v_x (= der(s_x)).</li>\n<li> the relative velocity v_y (= der(s_y)).</li>\n<li> the relative angular velocity w (= der(phi))</li>\n</ul>\n<p>\nThey are used as candidates for automatic selection of states\nfrom the tool. This may be enforced by setting \"stateSelect=StateSelect.<strong>always</strong>\"\nin the <strong>Advanced</strong> menu. The states are usually selected automatically.\nIn certain situations, especially when closed kinematic loops are present,\nit might be slightly more efficient, when using the \"StateSelect.always\" setting.\n</p>\n<p>\nIn the following figure the animation of a planar\njoint is shown. The light blue coordinate system is\nframe_a and the dark blue coordinate system is\nframe_b of the joint. The black arrows are parameter\nvectors \"n\" and \"n_x\"\n(here: n = {0,1,0}, n_x = {0,0,1}, s_x.start = 0.5,\ns_y.start = 0.5, phi.start = 45<sup>o</sup>).\n</p>\n\n<p>\n<img src=\"modelica://Modelica/Resources/Images/Mechanics/MultiBody/Joints/Planar.png\">\n</p>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Rectangle(
                    extent = {
                        {-30, -60}, 
                        {-10, 60}},
                    pattern = LinePattern.None,
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {10, -60}, 
                        {30, 60}},
                    pattern = LinePattern.None,
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {-100, -10}, 
                        {-30, 10}},
                    pattern = LinePattern.None,
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {100, -10}, 
                        {30, 10}},
                    pattern = LinePattern.None,
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {-150, -75}, 
                        {150, -105}},
                    textString = "n=%n"), 
                Text(
                    extent = {
                        {-150, 110}, 
                        {150, 70}},
                    textString = "%name",
                    lineColor = {0, 0, 255})}));
end Planar;