Advertisement
Whiplash141

GASP Missile Systems 12-20-15

Dec 20th, 2015
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.27 KB | None | 0 0
  1.  
  2. /*
  3. Whip's GASP Missile System v23 - revised: 12/19/15
  4. /// PERSONAL VERSION ///
  5. /// Stable ///  
  6.     Missile 1
  7. ___________________________________________________________________  
  8. Description:  
  9.  
  10. This script handles the launch of the GASP Missile System  
  11.  
  12. - Whiplash141 :)    
  13. */  
  14.  
  15. /*  
  16. ___________________________________________________________________  
  17.  
  18. ========== You can edit these variables to your liking ============  
  19. ___________________________________________________________________  
  20. */  
  21.  
  22. //---Missile name  
  23.     static string missileNumber = "1";  
  24.     string missileTag = "Missile " + missileNumber; //unique id of the missile  
  25.     string sideThrustTag = "Side"; //tag on side thrusters  
  26.     string mainThrustTag = "Main"; //tag on main forward thrusters
  27.  
  28. //---Reference names      
  29.     string shooterReferenceName = "Shooter Reference"; //notice how this has no number  
  30.  
  31. //---Runtime vars  
  32.     double guidance_delay = 1; //time (in seconds) that the missile will delay guidance activation by
  33.     double main_ignition_delay = .5; //time (in seconds) that the missile will delay main engine activation
  34.     double max_rotation_degrees = 180; //in degrees per second (360 max for small ships, 180 max for large ships)
  35.     double max_distance = 10000; //maximum guidance distance in meters; don't enlarge it 10km is super far
  36.     static int tick_limit = 1; //change to higher for less precision (I do not reccomend this)
  37.  
  38. //---Control system
  39.     int controlMode = 4; //1 = bang bang, 2 = proportional, 3 = proportional with lower bound
  40.     double lowerAngleBoundDeg = 30;
  41.  
  42. /*  
  43. ___________________________________________________________________  
  44.  
  45. ============= Don't touch anything below this :) ==================  
  46. ___________________________________________________________________  
  47. */  
  48. //---So many lists...    
  49.     List<IMyTerminalBlock> missileBlocks = new List<IMyTerminalBlock>();    
  50.     List<IMyTerminalBlock> mainThrusters = new List<IMyTerminalBlock>();            
  51.     List<IMyTerminalBlock> artMasses = new List<IMyTerminalBlock>();          
  52.     List<IMyTerminalBlock> mergeBlocks = new List<IMyTerminalBlock>();          
  53.     List<IMyTerminalBlock> sideThrusters = new List<IMyTerminalBlock>();        
  54.     List<IMyTerminalBlock> batteries = new List<IMyTerminalBlock>();  
  55.     List<IMyTerminalBlock> remotes = new List<IMyTerminalBlock>();    
  56.     List<IMyTerminalBlock> shooterRefrenceList = new List<IMyTerminalBlock>();    
  57.     List<IMyTerminalBlock> gyros = new List<IMyTerminalBlock>();  
  58.     List<IMyTerminalBlock> timers = new List<IMyTerminalBlock>();  
  59.     List<IMyTerminalBlock> programs = new List<IMyTerminalBlock>();  
  60.     List<IMyTerminalBlock> importantBlocks = new List<IMyTerminalBlock>();  
  61.      
  62.     Vector3D targetVectorNorm;
  63.     Vector3D shooterLeftNorm;
  64.     Vector3D shooterUpNorm;
  65.     Vector3D originPos;
  66.     Vector3D currentMissilePos;
  67.     Vector3D headingVector;
  68.     Vector3D destination;
  69.     IMyRemoteControl shooterRefrence;    
  70.     IMyGyro missileRefrence;    
  71.     bool hasRun = false;  
  72.     bool isFired = false;  
  73.     bool shouldKill = false;  
  74.     bool firstGuidance = true;
  75.     bool hasPassed = false;
  76.     double distanceFromShooter;
  77.     double lowerAngleBoundRad;
  78.     int max_kill_time = 60 / tick_limit;  
  79.     int kill_time = 0;  
  80.     int current_tick = 0;    
  81.     int duration = 0;        
  82.     int timeElapsed = 0;  
  83.    
  84. void Main(string arg)    
  85. {    
  86.     if(arg == "kill" && isFired == true)  
  87.     {  
  88.         shouldKill = true;  
  89.         max_distance = double.PositiveInfinity;  
  90.     }  
  91.          
  92.    
  93.     Echo("Tick: " + current_tick.ToString());  
  94.     if (!hasRun)  
  95.     {  
  96.         GrabBlocks();  
  97.     }          
  98.     else //will not run or release missile until has run setup succesfully  
  99.     {  
  100.         MissileSystems();  
  101.         StatusCheck();  
  102.         if (duration < Math.Ceiling(guidance_delay * 60))  
  103.         {  
  104.             duration++;  
  105.             return;  
  106.         }  
  107.         else  
  108.         {  
  109.             if((current_tick % tick_limit) == 0)  
  110.             {  
  111.                 Echo("Guidance Active");    
  112.                 GuideMissile();    
  113.                 current_tick = 0;    
  114.             }  
  115.         }        
  116.         current_tick++;      
  117.     }  
  118.     Echo("Has run?: " + hasRun);  
  119. }        
  120.    
  121. void GrabBlocks()  
  122. {  
  123.     GridTerminalSystem.SearchBlocksOfName( missileTag, missileBlocks );  
  124.     GridTerminalSystem.SearchBlocksOfName( shooterReferenceName, shooterRefrenceList );  
  125.  
  126.     for( int i = 0; i < shooterRefrenceList.Count; i++ )  
  127.     {  
  128.         importantBlocks.Add( shooterRefrenceList[i] );  
  129.     }  
  130.      
  131.     for( int i = 0; i < missileBlocks.Count; i++ )  
  132.     {  
  133.         var thisBlock = missileBlocks[i] as IMyTerminalBlock;  
  134.          
  135.         if( thisBlock is IMyThrust )  
  136.         {  
  137.             if( thisBlock.CustomName.Contains( sideThrustTag ) )  
  138.             {  
  139.                 sideThrusters.Add( thisBlock );  
  140.             }  
  141.             else if( thisBlock.CustomName.Contains( mainThrustTag ) )  
  142.             {  
  143.                 mainThrusters.Add( thisBlock );  
  144.             }  
  145.         }  
  146.         else if( thisBlock is IMyVirtualMass )  
  147.         {  
  148.             artMasses.Add( thisBlock );  
  149.         }  
  150.         else if( thisBlock is IMyBatteryBlock )  
  151.         {  
  152.             batteries.Add( thisBlock );  
  153.         }  
  154.         else if( thisBlock is IMyGyro )  
  155.         {  
  156.             gyros.Add( thisBlock );  
  157.             thisBlock.ApplyAction("OnOff_On");  
  158.             importantBlocks.Add( thisBlock );  
  159.         }    
  160.         else if( thisBlock is IMyShipMergeBlock )  
  161.         {  
  162.             mergeBlocks.Add( thisBlock );  
  163.         }  
  164.         else if( thisBlock is IMyTimerBlock )  
  165.         {  
  166.             timers.Add( thisBlock );  
  167.             importantBlocks.Add( thisBlock );  
  168.         }  
  169.         else if( thisBlock is IMyProgrammableBlock )  
  170.         {  
  171.             programs.Add( thisBlock );  
  172.             importantBlocks.Add( thisBlock );  
  173.         }  
  174.     }  
  175.      
  176. //---Check if we do not have an shooter remote  
  177.     if( shooterRefrenceList.Count == 0 )    
  178.     {    
  179.         Echo("No shooter refrence block found");    
  180.         hasRun = false;    
  181.         return;    
  182.     }  
  183.  
  184. //---Check for control gyros      
  185.     else if( gyros.Count == 0 )  
  186.     {  
  187.         Echo("No control gyros found");  
  188.         hasRun = false;  
  189.         return;  
  190.     }  
  191.     else if( mainThrusters.Count == 0)  
  192.     {  
  193.         Echo("No main thrusters found");  
  194.         hasRun = false;  
  195.         return;  
  196.     }  
  197.     else if( sideThrusters.Count == 0)  
  198.     {  
  199.         Echo("No main thrusters found");  
  200.         //hasRun = false;  
  201.         //return;  
  202.     }  
  203.     else if( artMasses.Count == 0)  
  204.     {  
  205.         Echo("No artificial masses found");  
  206.         hasRun = false;  
  207.         return;  
  208.     }  
  209.     else if( batteries.Count == 0)  
  210.     {  
  211.         Echo("No batteries found");  
  212.         hasRun = false;  
  213.         return;  
  214.     }  
  215.     else if( mergeBlocks.Count == 0)  
  216.     {  
  217.         Echo("No merge blocks found");  
  218.         hasRun = false;  
  219.         return;  
  220.     }  
  221.     else  
  222.     {      
  223.         Echo("Ready to run");  
  224.         shooterRefrence = shooterRefrenceList[0] as IMyRemoteControl;    
  225.         missileRefrence = gyros[0] as IMyGyro;    
  226.         hasRun = true;    
  227.     }  
  228. }  
  229.  
  230. void StatusCheck()  
  231. {  
  232.     for (int k = 0; k < importantBlocks.Count; k++)  
  233.     {  
  234.         IMyTerminalBlock block = importantBlocks[k];  
  235.         IMySlimBlock slim = block.CubeGrid.GetCubeBlock(block.Position);  
  236.         if( slim.CurrentDamage > 0 )  
  237.         {  
  238.             Echo("Damage");  
  239.             kill_time = max_kill_time;  
  240.             KillGuidance( 0, 0 );  
  241.             return;  
  242.         }  
  243.     }  
  244. }  
  245.  
  246. void MissileSystems()
  247. {
  248.     if ( timeElapsed == 0 )
  249.     {
  250.         for(int i = 0 ; i < batteries.Count ; i++)
  251.         {
  252.             var thisBattery = batteries[i] as IMyBatteryBlock;
  253.             thisBattery.ApplyAction( "OnOff_On" ); //make sure our battery is on
  254.             thisBattery.SetValue( "Recharge", false );
  255.         }
  256.  
  257.     }
  258.     else if( timeElapsed == 60 )
  259.     {
  260.         for( int i = 0 ; i < artMasses.Count ; i++ )
  261.         {
  262.             var thisMass = artMasses[i] as IMyVirtualMass;
  263.             thisMass.ApplyAction( "OnOff_On" );
  264.         }
  265.  
  266.         for( int i = 0 ; i < mergeBlocks.Count ; i++ )
  267.         {
  268.             var thisMerge = mergeBlocks[i] as IMyShipMergeBlock;    
  269.             thisMerge.ApplyAction( "OnOff_Off" );    
  270.         }
  271.     }
  272.     else if( timeElapsed == 60 + Math.Round( main_ignition_delay * 60 ) )    
  273.     {
  274.         for( int i = 0 ; i < artMasses.Count ; i++ )  
  275.         {
  276.             var thisMass = artMasses[i] as IMyVirtualMass;  
  277.             thisMass.ApplyAction( "OnOff_Off" );  
  278.         }
  279.         ThrusterOverride();          
  280.         ManeuveringThrust();                
  281.         isFired = true;  
  282.     }
  283.  
  284.     if ( timeElapsed < 181 )  
  285.     {
  286.         timeElapsed++;    
  287.     }
  288. }
  289.      
  290. void GuideMissile()    
  291. {    
  292. //---Get positions of our blocks with relation to world center  
  293.     if( !shouldKill )  
  294.         originPos = shooterRefrence.GetPosition();  
  295.      
  296.     currentMissilePos = missileRefrence.GetPosition();  
  297.  
  298. //---Find current distance from shooter to missile  
  299.     distanceFromShooter = Vector3D.Distance( originPos, currentMissilePos );  
  300.  
  301. //---Check if we are in range      
  302.     if( distanceFromShooter > max_distance )  
  303.     {  
  304.         Echo( "Out of range" );  
  305.         shouldKill = true;  
  306.     }  
  307.  
  308. //---Get orientation vectors from our shooter vessel  
  309.     if( !shouldKill )  
  310.     {  
  311.         var shooterForwardGrid = shooterRefrence.Position + Base6Directions.GetIntVector( shooterRefrence.Orientation.TransformDirection( Base6Directions.Direction.Forward ) );    
  312.         var targetVector = shooterRefrence.CubeGrid.GridIntegerToWorld( shooterForwardGrid ) - originPos;    
  313.         targetVectorNorm = Vector3D.Normalize( targetVector );
  314.  
  315.         var shooterLeftGrid = shooterRefrence.Position + Base6Directions.GetIntVector( shooterRefrence.Orientation.TransformDirection( Base6Directions.Direction.Left ) );
  316.         var shooterLeftWorld = shooterRefrence.CubeGrid.GridIntegerToWorld( shooterLeftGrid ) - originPos;  
  317.         shooterLeftNorm = Vector3D.Normalize( shooterLeftWorld );
  318.  
  319.         var shooterUpGrid = shooterRefrence.Position + Base6Directions.GetIntVector( shooterRefrence.Orientation.TransformDirection( Base6Directions.Direction.Up ) );
  320.         var shooterUpWorld = shooterRefrence.CubeGrid.GridIntegerToWorld( shooterUpGrid ) - originPos;
  321.         shooterUpNorm = Vector3D.Normalize( shooterUpWorld );
  322.     }  
  323.  
  324. //---Find vector from shooter to missile  
  325.     var shooterToMissile = currentMissilePos - originPos;
  326.  
  327. //---Determine where missile is in relation to shooter
  328.     bool isLeft = checkDotPositive( shooterToMissile, shooterLeftNorm );
  329.     bool isUp = checkDotPositive( shooterToMissile, shooterUpNorm );
  330.     int signLeft; int signUp;
  331.     if( isLeft )
  332.         signLeft = 1;
  333.     else
  334.         signLeft = -1;
  335.    
  336.     if( isUp )
  337.         signUp = 1;
  338.     else
  339.         signUp = -1;
  340.  
  341. //---Calculate angle between shooter vector and missile vector  
  342.     double rawDevAngle = Math.Acos( dotProduct( targetVectorNorm, Vector3D.Normalize( shooterToMissile ) ) ) * 180 / Math.PI; //angle between shooter vector and missile  
  343.  
  344. //---Calculate perpendicular distance from shooter vector  
  345.     var projectionVector = vectorProjection( shooterToMissile, targetVectorNorm );  
  346.     double deviationDistance = Vector3D.Distance( projectionVector, shooterToMissile );  
  347.      
  348.     Echo( "Angular Dev: " + rawDevAngle.ToString() );  
  349.  
  350. //---Find front left and top vectors of our missile  
  351.     var missileGridX = missileRefrence.Position + Base6Directions.GetIntVector( missileRefrence.Orientation.TransformDirection( Base6Directions.Direction.Forward ) );  
  352.     var missileWorldX = missileRefrence.CubeGrid.GridIntegerToWorld( missileGridX ) - currentMissilePos;  
  353.  
  354.     var missileGridY = missileRefrence.Position + Base6Directions.GetIntVector( missileRefrence.Orientation.TransformDirection( Base6Directions.Direction.Left ) );
  355.     var missileWorldY = missileRefrence.CubeGrid.GridIntegerToWorld( missileGridY ) - currentMissilePos;  
  356.  
  357.     var missileGridZ = missileRefrence.Position + Base6Directions.GetIntVector( missileRefrence.Orientation.TransformDirection( Base6Directions.Direction.Up ) );  
  358.     var missileWorldZ = missileRefrence.CubeGrid.GridIntegerToWorld( missileGridZ ) - currentMissilePos;  
  359.  
  360. //---Determine scaling factor  
  361.     double scalingFactor;  
  362.     if( rawDevAngle < 90 )
  363.     {
  364.         scalingFactor = projectionVector.Length() + 250; //travel approx. 250m from current position in direction of target vector
  365.         destination = shooterRefrence.GetPosition() + scalingFactor * targetVectorNorm;
  366.         if( !hasPassed )
  367.             hasPassed = true;
  368.     }
  369.     else if( hasPassed )
  370.     {
  371.         scalingFactor = -projectionVector.Length() + 250;
  372.         destination = shooterRefrence.GetPosition() + scalingFactor * targetVectorNorm + signLeft * 50 * shooterLeftNorm + signUp * 50 * shooterUpNorm;
  373.     }
  374.     else
  375.     {
  376.         scalingFactor = -projectionVector.Length() + 250;
  377.         destination = shooterRefrence.GetPosition() + scalingFactor * targetVectorNorm;
  378.     }
  379.  
  380. //---Find vector from missile to destination  
  381.     var shipToTarget = Vector3D.Subtract( destination, currentMissilePos );  
  382.  
  383. //---Calc our new heading based upon our travel vector  
  384.     headingVector = shipToTarget;
  385.  
  386. //---Project target vector onto our top left and up vectors  
  387.     var projTargetX = vectorProjection( headingVector, missileWorldX);  
  388.     var projTargetY = vectorProjection( headingVector, missileWorldY);  
  389.     var projTargetZ = vectorProjection( headingVector, missileWorldZ);  
  390.     var projTargetXYplane = projTargetX + projTargetY;  
  391.  
  392. //---Get Yaw and Pitch Angles  
  393.     double angleYaw = Math.Atan( projTargetY.Length() / projTargetX.Length() );  
  394.     double anglePitch = Math.Atan( projTargetZ.Length() / projTargetXYplane.Length() );
  395.  
  396. //---Check if x is positive or negative  
  397.     bool isPositiveX = checkDotPositive( missileWorldX, projTargetX );  
  398.     if( !isPositiveX )  
  399.         angleYaw += Math.PI/2; //we only change one value so it doesnt spaz                  
  400.  
  401. //---Check if yaw angle is left or right  
  402.     bool isPositiveY = checkDotPositive( missileWorldY, projTargetY );  
  403.     if( isPositiveY ) //yaw is backwards for what ever reason  
  404.         angleYaw = -angleYaw;  
  405.  
  406. //---Check if pitch angle is up or down  
  407.     bool isPositiveZ = checkDotPositive( missileWorldZ, projTargetZ );  
  408.     if( !isPositiveZ )  
  409.         anglePitch = -anglePitch;
  410.  
  411.     Echo("yaw: " + Math.Round(angleYaw,2).ToString());
  412.     Echo("pitch: " + Math.Round(anglePitch,2).ToString());    
  413.  
  414. //---Angle controller  
  415.  
  416.     double max_rotation_radians = max_rotation_degrees * ( Math.PI / 180 );  
  417.     double yawSpeed = 0;  
  418.     double pitchSpeed = 0;  
  419.  
  420.     switch( controlMode )
  421.     {
  422.         case 1:
  423.             yawSpeed = max_rotation_radians * angleYaw / Math.Abs( angleYaw );
  424.             pitchSpeed = max_rotation_radians * anglePitch / Math.Abs( anglePitch );
  425.             break;
  426.  
  427.         case 2:
  428.             yawSpeed = angleYaw / Math.PI * max_rotation_radians;
  429.             pitchSpeed = anglePitch / Math.PI * max_rotation_radians;
  430.             break;
  431.  
  432.         case 3:
  433.             lowerAngleBoundRad = lowerAngleBoundDeg * ( Math.PI / 180 );
  434.             if( Math.Abs( angleYaw ) < lowerAngleBoundRad )
  435.             {  
  436.                 yawSpeed = angleYaw / lowerAngleBoundRad * max_rotation_radians;
  437.             }
  438.             else  
  439.             {
  440.                 yawSpeed = max_rotation_radians * angleYaw / Math.Abs( angleYaw );
  441.             }
  442.  
  443.             if( Math.Abs( anglePitch ) < lowerAngleBoundRad )
  444.             {
  445.                 pitchSpeed = anglePitch / lowerAngleBoundRad * max_rotation_radians;
  446.             }
  447.             else  
  448.             {
  449.                 pitchSpeed = max_rotation_radians * anglePitch / Math.Abs( anglePitch );
  450.             }
  451.             break;
  452.            
  453.         case 4:
  454.             lowerAngleBoundRad = lowerAngleBoundDeg * ( Math.PI / 180 );
  455.             if( Math.Abs( angleYaw ) < lowerAngleBoundRad )
  456.             {  
  457.                 yawSpeed = max_rotation_radians / 4 * angleYaw / Math.Abs( angleYaw );
  458.             }
  459.             else  
  460.             {
  461.                 yawSpeed = max_rotation_radians * angleYaw / Math.Abs( angleYaw );
  462.             }
  463.  
  464.             if( Math.Abs( anglePitch ) < lowerAngleBoundRad )
  465.             {
  466.                 pitchSpeed = max_rotation_radians / 4 * anglePitch / Math.Abs( anglePitch );
  467.             }
  468.             else  
  469.             {
  470.                 pitchSpeed = max_rotation_radians * anglePitch / Math.Abs( anglePitch );
  471.             }
  472.             break;
  473.  
  474.         default:
  475.             yawSpeed = max_rotation_radians * angleYaw / Math.Abs( angleYaw );
  476.             pitchSpeed = max_rotation_radians * anglePitch / Math.Abs( anglePitch );
  477.             break;
  478.     }
  479.  
  480. //---Set appropriate gyro override
  481.     for( int i = 0; i < gyros.Count; i++ )
  482.     {
  483.         var thisGyro = gyros[i] as IMyGyro;
  484.         thisGyro.SetValue<float>( "Yaw", (float)yawSpeed );
  485.         thisGyro.SetValue<float>( "Pitch", (float)pitchSpeed );
  486.         thisGyro.SetValue( "Override", true );
  487.     }
  488.  
  489.     if( shouldKill )
  490.     {
  491.         KillGuidance( rawDevAngle, deviationDistance );  
  492.     }
  493. }
  494.  
  495. void ManeuveringThrust()          
  496. {            
  497.     for( int i = 0 ; i < sideThrusters.Count ; i++ )          
  498.     {          
  499.         IMyThrust Thrust = sideThrusters[i] as IMyThrust;  
  500.         Thrust.ApplyAction( "OnOff_On" );          
  501.     }          
  502. }          
  503.                
  504. void ThrusterOverride()          
  505. {                      
  506.     for( int i = 0; i < mainThrusters.Count; i++ )                
  507.     {                
  508.         IMyThrust Thrust = mainThrusters[i] as IMyThrust;  
  509.         Thrust.ApplyAction( "OnOff_On" );  
  510.         Thrust.SetValue<float>( "Override", float.MaxValue ); //not max b/c battery can't handle any more without an overload            
  511.     }            
  512. }  
  513.  
  514. void KillGuidance( double angleOfDeviation, double distanceOfDeviation )  
  515. {  
  516.     Echo("Kill command recieved");  
  517.     if( angleOfDeviation < 2.5 && distanceOfDeviation < 2.5 )  
  518.     {  
  519.         kill_time++;  
  520.     }else{  
  521.         kill_time = 0;  
  522.     }  
  523.      
  524.     if( kill_time > max_kill_time )  
  525.     {  
  526.         for( int i = 0; i < gyros.Count; i++ )  
  527.         {  
  528.             var thisGyro = gyros[i] as IMyGyro;  
  529.             thisGyro.SetValue<float>( "Yaw", 0f );  
  530.             thisGyro.SetValue<float>( "Pitch", 0f );  
  531.             thisGyro.SetValue( "Override", true );  
  532.         }  
  533.  
  534.         for( int i = 0; i < mainThrusters.Count; i++ )                
  535.         {  
  536.             var thisThruster = mainThrusters[i] as IMyThrust;  
  537.             thisThruster.ApplyAction( "OnOff_Off" );  
  538.         }  
  539.          
  540.         for( int i = 0; i < sideThrusters.Count; i++ )                
  541.         {  
  542.             var thisThruster = sideThrusters[i] as IMyThrust;  
  543.             thisThruster.ApplyAction( "OnOff_Off" );  
  544.         }  
  545.          
  546.         for( int i = 0; i < importantBlocks.Count; i++ )  
  547.         {  
  548.             var thisBlock = importantBlocks[i] as IMyTerminalBlock;  
  549.             if( !( thisBlock is IMyRemoteControl ) || !( thisBlock is IMyProgrammableBlock ) )  
  550.                 thisBlock.ApplyAction( "OnOff_Off" );  
  551.         }  
  552.     }  
  553. }  
  554.  
  555. Vector3D vectorProjection( Vector3D a, Vector3D b ) //proj a on b  
  556. {
  557.     Vector3D projection = dotProduct( a, b ) / b.Length() / b.Length() * b;
  558.     return projection;
  559. }
  560.  
  561. bool checkDotPositive( Vector3D vec1, Vector3D vec2 )  
  562. {  
  563.     double check = dotProduct( vec1, vec2 );  
  564.     if( check > 0 )  
  565.     {  
  566.         return true;  
  567.     }else{
  568.         return false;  
  569.     }  
  570. }  
  571.  
  572. double dotProduct( Vector3D v1, Vector3D v2 )  
  573. {  
  574.     double x;  
  575.     Vector3D.Dot( ref v1, ref v2, out x );  
  576.     return x;  
  577. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement