model PlanarWorld 
  "world model for planar mechanics.World coordinate system + gravity field + default animation definition" 
  
  import SI = Modelica.SIunits;
  
  parameter Boolean enableAnimation=true 
    "= true, if animation of all components is enabled";
  parameter Boolean animateWorld=true 
    "= true, if world coordinate system shall be visualized";
  parameter Boolean animateGravity=true 
    "= true, if gravity field shall be visualized (acceleration vector or field center)";
  parameter Modelica.Mechanics.MultiBody.Types.AxisLabel label1="x" 
    "Label of horizontal axis in icon";
  parameter Modelica.Mechanics.MultiBody.Types.AxisLabel label2="y" 
    "Label of vertical axis in icon";
  parameter Modelica.Mechanics.MultiBody.Types.GravityTypes.Temp gravityType=
      Modelica.Mechanics.MultiBody.Types.GravityTypes.UniformGravity 
    "Type of gravity field"
  parameter SI.Acceleration g=9.81 " Constant gravity acceleration" 
  parameter Modelica.Mechanics.MultiBody.Types.Axis n={0,-1,0} 
    " Direction of gravity resolved in world frame (gravity = g*n/length(n))" 
  parameter Real mue(
    unit="m3/s2",
    min=0) = 3.986e14 
    " Gravity field constant (default = field constant of earth)" 
  parameter SI.Distance axisLength=nominalLength/2 
    "|Animation|if animateWorld = true| Length of world axes arrows";
  parameter SI.Distance axisDiameter=axisLength/defaultFrameDiameterFraction 
    "|Animation|if animateWorld = true| Diameter of world axes arrows";
  parameter Boolean axisShowLabels=true 
    "|Animation|if animateWorld = true| = true, if labels shall be shown";
  parameter Modelica.Mechanics.MultiBody.Types.Color axisColor_x=Modelica.Mechanics.MultiBody.Types.Defaults.
      FrameColor "|Animation|if animateWorld = true| Color of x-arrow";
  parameter Modelica.Mechanics.MultiBody.Types.Color axisColor_y=axisColor_x 
    "|Animation|if animateWorld = true| Color of y-arrow";
  parameter Modelica.Mechanics.MultiBody.Types.Color axisColor_z=axisColor_x 
    "|Animation|if animateWorld = true| Color of z-arrow";
  
  parameter SI.Position gravityArrowTail[3]={0,0,0} 
    "|Animation|if animateGravity = true and gravityType = UniformGravity| Position vector from origin of world frame to arrow tail, resolved in world frame";
  parameter SI.Length gravityArrowLength=axisLength/2 
    "|Animation|if animateGravity = true and gravityType = UniformGravity| Length of gravity arrow";
  parameter SI.Diameter gravityArrowDiameter=gravityArrowLength/
      defaultWidthFraction 
    "|Animation|if animateGravity = true and gravityType = UniformGravity| Diameter of gravity arrow";
  parameter Modelica.Mechanics.MultiBody.Types.Color gravityArrowColor={0,230,0} 
    "|Animation|if animateGravity = true and gravityType = UniformGravity| Color of gravity arrow";
  parameter SI.Diameter gravitySphereDiameter=12742000 
    "|Animation|if animateGravity = true and gravityType = PointGravity| Diameter of sphere representing gravity center (default = mean diameter of earth)";
  parameter Modelica.Mechanics.MultiBody.Types.Color gravitySphereColor={0,230,0} 
    "|Animation|if animateGravity = true and gravityType = PointGravity| Color of gravity sphere";
  
  parameter SI.Length nominalLength=1 
    "|Defaults|| \"Nominal\" length of multi-body system";
  parameter SI.Length defaultAxisLength=nominalLength/5 
    "|Defaults|| Default for length of a frame axis (but not world frame)";
  parameter SI.Length defaultJointLength=nominalLength/10 
    "|Defaults|| Default for the fixed length of a shape representing a joint";
  parameter SI.Length defaultJointWidth=nominalLength/20 
    "|Defaults|| Default for the fixed width of a shape representing a joint";
  parameter SI.Length defaultForceLength=nominalLength/10 
    "|Defaults|| Default for the fixed length of a shape representing a force (e.g. damper)";
  parameter SI.Length defaultForceWidth=nominalLength/20 
    "|Defaults|| Default for the fixed width of a shape represening a force (e.g. spring, bushing)";
  parameter SI.Length defaultBodyDiameter=nominalLength/9 
    "|Defaults|| Default for diameter of sphere representing the center of mass of a body";
  parameter Real defaultWidthFraction=20 
    "|Defaults|| Default for shape width as a fraction of shape length (e.g., for Parts.FixedTranslation)";
  parameter SI.Length defaultArrowDiameter=nominalLength/40 
    "|Defaults|| Default for arrow diameter (e.g., of forces, torques, sensors)";
  parameter Real defaultFrameDiameterFraction=40 
    "|Defaults|| Default for arrow diameter of a coordinate system as a fraction of axis length";
  
  parameter Modelica.Mechanics.MultiBody.Types.Color defaultJointColor={255,0,255} 
    "|Defaults|| Default color of a joint element";
  parameter Modelica.Mechanics.MultiBody.Types.Color defaultBodyColor={0,64,255} 
    "|Defaults|| Default color of a body element";
  parameter Modelica.Mechanics.MultiBody.Types.Color defaultRodColor={96,128,128} 
    "|Defaults|| Default color of a rod element";
  parameter Modelica.Mechanics.MultiBody.Types.Color defaultForceElementColor={0,64,255} 
    "|Defaults|| Default color of a rod element";
  
  /* The World object can only use the Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape model, but no
     other models in package Modelica.Mechanics.MultiBody.Visualizers, since the other models access
     data of the "outer Modelica.Mechanics.MultiBody.World world" object, i.e., there are
     mutually dependent classes. For this reason, the higher level visualization
     objects cannot be used.
  */
protected 
  parameter Integer ndim=if enableAnimation and animateWorld then 1 else 0;
  parameter Integer ndim2=if enableAnimation and animateWorld and 
      axisShowLabels then 1 else 0;
  
  // Parameters to define axes
  parameter SI.Length headLength=min(axisLength, axisDiameter*Modelica.
      Mechanics.MultiBody.Types.Defaults.FrameHeadLengthFraction);
  parameter SI.Length headWidth=axisDiameter*Modelica.Mechanics.MultiBody.Types.
      Defaults.FrameHeadWidthFraction;
  parameter SI.Length lineLength=max(0, axisLength - headLength);
  parameter SI.Length lineWidth=axisDiameter;
  
  // Parameters to define axes labels
  parameter SI.Length scaledLabel=Modelica.Mechanics.MultiBody.Types.Defaults.
      FrameLabelHeightFraction                                           *
      axisDiameter;
  parameter SI.Length labelStart=1.05*axisLength;
  
  // x-axis
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape x_arrowLine[ndim](
    each shapeType="cylinder",
    each length=lineLength,
    each width=lineWidth,
    each height=lineWidth,
    each lengthDirection={1,0,0},
    each widthDirection={0,1,0},
    each color=axisColor_x,
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape x_arrowHead[ndim](
    each shapeType="cone",
    each length=headLength,
    each width=headWidth,
    each height=headWidth,
    each lengthDirection={1,0,0},
    each widthDirection={0,1,0},
    each color=axisColor_x,
    each r={lineLength,0,0},
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Internal.Lines x_label[ndim2](
    each lines=scaledLabel*{[0, 0; 1, 1],[0, 1; 1, 0]},
    each diameter=axisDiameter,
    each color=axisColor_x,
    each r_lines={labelStart,0,0},
    each n_x={1,0,0},
    each n_y={0,1,0},
    each specularCoefficient=0);
  
  // y-axis
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape y_arrowLine[ndim](
    each shapeType="cylinder",
    each length=lineLength,
    each width=lineWidth,
    each height=lineWidth,
    each lengthDirection={0,1,0},
    each widthDirection={1,0,0},
    each color=axisColor_y,
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape y_arrowHead[ndim](
    each shapeType="cone",
    each length=headLength,
    each width=headWidth,
    each height=headWidth,
    each lengthDirection={0,1,0},
    each widthDirection={1,0,0},
    each color=axisColor_y,
    each r={0,lineLength,0},
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Internal.Lines y_label[ndim2](
    each lines=scaledLabel*{[0, 0; 1, 1.5],[0, 1.5; 0.5, 0.75]},
    each diameter=axisDiameter,
    each color=axisColor_y,
    each r_lines={0,labelStart,0},
    each n_x={0,1,0},
    each n_y={-1,0,0},
    each specularCoefficient=0);
  
  // z-axis
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape z_arrowLine[ndim](
    each shapeType="cylinder",
    each length=lineLength,
    each width=lineWidth,
    each height=lineWidth,
    each lengthDirection={0,0,1},
    each widthDirection={0,1,0},
    each color=axisColor_z,
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape z_arrowHead[ndim](
    each shapeType="cone",
    each length=headLength,
    each width=headWidth,
    each height=headWidth,
    each lengthDirection={0,0,1},
    each widthDirection={0,1,0},
    each color=axisColor_z,
    each r={0,0,lineLength},
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Internal.Lines z_label[ndim2](
    each lines=scaledLabel*{[0, 0; 1, 0],[0, 1; 1, 1],[0, 1; 1, 0]},
    each diameter=axisDiameter,
    each color=axisColor_z,
    each r_lines={0,0,labelStart},
    each n_x={0,0,1},
    each n_y={0,1,0},
    each specularCoefficient=0);
  
  // Uniform gravity visualization
  parameter Integer ndim_uniformGravity=if enableAnimation and animateGravity
       and gravityType == 1 then 1 else 0;
  parameter SI.Length gravityHeadLength=min(gravityArrowLength,
      gravityArrowDiameter*Modelica.Mechanics.MultiBody.Types.Defaults.
      ArrowHeadLengthFraction);
  parameter SI.Length gravityHeadWidth=gravityArrowDiameter*Modelica.Mechanics.
      MultiBody.Types.Defaults.ArrowHeadWidthFraction;
  parameter SI.Length gravityLineLength=max(0, gravityArrowLength -
      gravityHeadLength);
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape gravityArrowLine[ndim_uniformGravity](
    each shapeType="cylinder",
    each length=gravityLineLength,
    each width=gravityArrowDiameter,
    each height=gravityArrowDiameter,
    each lengthDirection=n,
    each widthDirection={0,1,0},
    each color=gravityArrowColor,
    each r_shape=gravityArrowTail,
    each specularCoefficient=0);
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape gravityArrowHead[ndim_uniformGravity](
    each shapeType="cone",
    each length=gravityHeadLength,
    each width=gravityHeadWidth,
    each height=gravityHeadWidth,
    each lengthDirection=n,
    each widthDirection={0,1,0},
    each color=gravityArrowColor,
    each r_shape=gravityArrowTail + Modelica.Mechanics.MultiBody.Frames.normalize(
                                                     n)*gravityLineLength,
    each specularCoefficient=0);
  
  // Point gravity visualization
  parameter Integer ndim_pointGravity=if enableAnimation and animateGravity
       and gravityType == 2 then 1 else 0;
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape gravitySphere[ndim_pointGravity](
    each shapeType="sphere",
    each r_shape={-gravitySphereDiameter/2,0,0},
    each lengthDirection={1,0,0},
    each length=gravitySphereDiameter,
    each width=gravitySphereDiameter,
    each height=gravitySphereDiameter,
    each color=gravitySphereColor,
    each specularCoefficient=0);
  
  function gravityAcceleration = gravityAccelerationTypes (
      gravityType=gravityType,
      g=g*Modelica.Mechanics.MultiBody.Frames.normalize(
                                     n),
      mue=mue);
  
protected 
  function gravityAccelerationTypes 
    "Gravity field acceleration depending on field type and position" 
    
    extends Modelica.Icons.Function;
    input SI.Position r[3] 
      "Position vector from world frame to actual point, resolved in world frame";
    input Integer gravityType "Type of gravity field";
    input SI.Acceleration g[3] 
      "Constant gravity acceleration, resolved in world frame, if gravityType=1";
    input Real mue(unit="m3/s2") 
      "Field constant of point gravity field, if gravityType=2";
    output SI.Acceleration gravity[3] 
      "Gravity acceleration at point r, resolved in world frame";
  algorithm 
    gravity := if gravityType == 1 then g else if gravityType == 2 then -(mue/(
      r*r))*(r/Modelica.Mechanics.MultiBody.Frames.length(r)) else zeros(3);
  end gravityAccelerationTypes;
equation 
  
  assert(Modelica.Mechanics.MultiBody.Frames.length(n) > 1.e-10,
    "Parameter n of World object is wrong (lenght(n) > 0 required)");
end PlanarWorld;