应用程序:SharedCoordinateSystem

Revit平台:全部

Revit版本:2011.0

首次发布时间:9.1

编程语言:C#

技能水平:中等

类别:元素

类型:ExternalCommand(外部命令)

主题:获取和设置项目的地点、位置。

概述:

本示例演示了如何获取项目的位置和地点,并更改它们的值。

相关类:

Autodesk.Revit.UI.IExternalCommand

Autodesk.Revit.DB.Element

Autodesk.Revit.DB.GeometryElement

Autodesk.Revit.DB.Parameter

Autodesk.Revit.DB.GeometryObject

Autodesk.Revit.DB.Transform

Autodesk.Revit.DB.Structure.AnalyticalModel

Autodesk.Revit.DB.SiteLocation

Autodesk.Revit.DB.CitySet

项目文件:

Command.cs

该文件包含继承自IExternalCommand”接口并实现“Execute”方法的“Command”类。

 

CoordinateSystemData.cs

该文件包含了一个名为CoordinateSystemData”的类,用于处理位置信息,如“获取”、“更改”和“复制”位置。

 

CoordinateSystemDataForm.cs

该文件包含了一个名为CoordinateSystemDataForm”的类,用于在具有两个选项卡“Locations”和“Place”的TabControl中显示和设置位置和地点信息。

 

DuplicateForm.cs

该文件包含了一个名为DuplicateForm”的类,用于复制位置信息。

 

PlaceInfo.cs

该文件由以下组成:

一个名为PlaceInfo”的类,用于存储所有城市的信息,包括其名称、纬度、经度和时区;

一个名为CityInfo”的结构体,用于描述有关城市的信息;

一个名为CityInfoString”的结构体,用于描述城市信息,其所有成员均为字符串类型。

 

UnitConversion.cs

该文件包含了一个名为UnitConversion”的类,它是一个实用程序类,提供单位信息和一些单位转换函数,如将字符串转换为双精度浮点数。

描述:

本示例演示了以下功能:

- 获取当前文档的地点信息,并从地点信息中获取以下数据:

- 城市名称。

- 纬度。

- 经度。

- 时区。

- 获取当前文档的位置信息,并从位置信息中获取以下数据:

- 名称

- 转换(从此点到原点)

- 提供对话框以显示当前文档的地点和位置数据,并修改以下信息:

- 活动地点的纬度、经度和时区

- 活动文档的活动地点(城市名称、纬度和经度)到定义的磁盘上的AR-CITY.UNI文件

- 当前位置的转换

- 从定义的位置列表中获取当前位置

- 向列表中添加新位置。

 

实施:

- 可以使用“Document.ActiveProjectLocation”属性检索活动项目的位置。

- 可以使用“Document.SiteLocation”属性检索活动项目的地点。可以通过“Autodesk.Revit.Site.SiteLocation”类的“Latitude”、“Longitude”和“TimeZone”属性检索纬度、经度和时区信息。

说明:

1. 将项目文件夹中的“timezone.txt”文件复制到“SharedCoordinateSystem.dll”文件所在的同一文件夹目录中,然后运行命令。

2. 一个带有选项卡控件的对话框将被显示,用于显示有关地点和位置的信息,允许设置或更改位置和地点的值。

3. 此外,此示例类似于Revit“设置”下的菜单命令“管理地点和位置”,前者几乎可以执行后者可以执行的所有操作。

源代码:

完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

CoordinateSystemData.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//  
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.SharedCoordinateSystem.CS
{
    /// <summary>
    /// this class is used to get, set and manage information about Location
    /// </summary>
    public class CoordinateSystemData
   {
      ExternalCommandData m_command; // the ExternalCommandData reference
      Autodesk.Revit.UI.UIApplication m_application; //the revit application reference
      const double Modulus = 0.0174532925199433; //a modulus for degree convert to pi 
      const int Precision = 3; //default precision 
      string m_currentLocationName;   //the location of the active project;
      List<string> m_locationnames = new List<string>(); //a list to store all the location name
      double m_angle;        //Angle from True North
      double m_eastWest;     //East to West offset
      double m_northSouth;   //North to South offset
      double m_elevation;    //Elevation above ground level
      /// <summary>
      /// the value of the angle form true north
      /// </summary>
      public double AngleOffset
      {
         get
         {
            return m_angle;
         }
      }
      /// <summary>
      /// return the East to West offset
      /// </summary>
      public double EastWestOffset
      {
         get
         {
            return m_eastWest;
         }
      }
      /// <summary>
      /// return the North to South offset
      /// </summary>
      public double NorthSouthOffset
      {
         get
         {
            return m_northSouth;
         }
      }
      /// <summary>
      /// return the Elevation above ground level
      /// </summary>
      public double PositionElevation
      {
         get
         {
            return m_elevation;
         }
      }
      /// <summary>
      /// get and set the current project location name of the project
      /// </summary>
      public string LocationName
      {
         get
         {
            return m_currentLocationName;
         }
         set
         {
            m_currentLocationName = value;
         }
      }
      /// <summary>
      /// get all the project locations' name of the project
      /// </summary>
      public List<string> LocationNames
      {
         get
         {
            return m_locationnames;
         }
      }
      /// <summary>
      /// constructor
      /// </summary>
      /// <param name="commandData">the ExternalCommandData reference</param>
      public CoordinateSystemData(ExternalCommandData commandData)
      {
         m_command = commandData;
         m_application = m_command.Application;
      }
      /// <summary>
      /// get the shared coordinate system data of the project 
      /// </summary>
      public void GatData()
      {
         this.GetLocationData();
      }
      /// <summary>
      /// get the information of all the project locations associated with this project
      /// </summary>
      public void GetLocationData()
      {
         m_locationnames.Clear();
         ProjectLocation currentLocation = m_application.ActiveUIDocument.Document.ActiveProjectLocation;
         //get the current location name
         m_currentLocationName = currentLocation.Name;
         //Retrieve all the project locations associated with this project
         ProjectLocationSet locations = m_application.ActiveUIDocument.Document.ProjectLocations;
         ProjectLocationSetIterator iter = locations.ForwardIterator();
         iter.Reset();
         while (iter.MoveNext())
         {
            ProjectLocation locationTransform = iter.Current as ProjectLocation;
            string transformName = locationTransform.Name;
            m_locationnames.Add(transformName); //add the location's name to the list
         }
      }
      /// <summary>
      /// duplicate a new project location
      /// </summary>
      /// <param name="locationName">old location name</param>
      /// <param name="newLocationName">new location name</param>
      public void DuplicateLocation(string locationName, string newLocationName)
      {
         ProjectLocationSet locationSet = m_application.ActiveUIDocument.Document.ProjectLocations;
         foreach (ProjectLocation projectLocation in locationSet)
         {
            if (projectLocation.Name == locationName ||
                        projectLocation.Name + " (current)" == locationName)
            {
               //duplicate a new project location
               projectLocation.Duplicate(newLocationName);
               break;
            }
         }
      }
      /// <summary>
      /// change the current project location
      /// </summary>
      /// <param name="locationName"></param>
      public void ChangeCurrentLocation(string locationName)
      {
         ProjectLocationSet locations = m_application.ActiveUIDocument.Document.ProjectLocations;
         foreach (ProjectLocation projectLocation in locations)
         {
            //find the project location which is selected by user and
            //set it to the current projecte location 
            if (projectLocation.Name == locationName)
            {
               m_application.ActiveUIDocument.Document.ActiveProjectLocation = projectLocation;
               m_currentLocationName = locationName;
               break;
            }
         }
      }
      /// <summary>
      /// get the offset values of the project position 
      /// </summary>
      /// <param name="locationName"></param>
      public void GetOffset(string locationName)
      {
         ProjectLocationSet locationSet = m_application.ActiveUIDocument.Document.ProjectLocations;
         foreach (ProjectLocation projectLocation in locationSet)
         {
            if (projectLocation.Name == locationName ||
                        projectLocation.Name + " (current)" == locationName)
            {
               Autodesk.Revit.DB.XYZ origin = new Autodesk.Revit.DB.XYZ (0, 0, 0);
               //get the project position
               ProjectPosition pp = projectLocation.GetProjectPosition(origin);
               m_angle = (pp.Angle /= Modulus); //convert to unit degree  
               m_eastWest = pp.EastWest;     //East to West offset
               m_northSouth = pp.NorthSouth; //north to south offset
               m_elevation = pp.Elevation;   //Elevation above ground level
               break;
            }
         }
         this.ChangePrecision();
      }
      /// <summary>
      /// change the offset value for the project position
      /// </summary>
      /// <param name="locationName">location name</param>
      /// <param name="newAngle">angle from true north</param>
      /// <param name="newEast">East to West offset</param>
      /// <param name="newNorth">north to south offset</param>
      /// <param name="newElevation">Elevation above ground level</param>
      public void EditPosition(string locationName, double newAngle, double newEast,
                                       double newNorth, double newElevation)
      {
         ProjectLocationSet locationSet = m_application.ActiveUIDocument.Document.ProjectLocations;
         foreach (ProjectLocation location in locationSet)
         {
            if (location.Name == locationName ||
                        location.Name + " (current)" == locationName)
            {
               //get the project position
               Autodesk.Revit.DB.XYZ origin = new Autodesk.Revit.DB.XYZ (0, 0, 0);
               ProjectPosition projectPosition = location.GetProjectPosition(origin);
               //change the offset value of the project position
               projectPosition.Angle = newAngle * Modulus; //convert the unit 
               projectPosition.EastWest = newEast;
               projectPosition.NorthSouth = newNorth;
               projectPosition.Elevation = newElevation;
               //set the value of the project position
               location.SetProjectPosition(origin, projectPosition);
            }
         }
      }
      /// <summary>
      /// change the Precision of the value
      /// </summary>
      private void ChangePrecision()
      {
         m_angle = UnitConversion.DealPrecision(m_angle, Precision);
         m_eastWest = UnitConversion.DealPrecision(m_eastWest, Precision);
         m_northSouth = UnitConversion.DealPrecision(m_northSouth, Precision);
         m_elevation = UnitConversion.DealPrecision(m_elevation, Precision);
      }
   }
}

PlaceInfo.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;
using System.Windows.Forms;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace Revit.SDK.Samples.SharedCoordinateSystem.CS
{
/// <summary>
/// a struct used to describe information about city
/// </summary>
public struct CityInfo
{
double m_timeZone; //Timezone in which the city resides
double m_latitude; //Latitude of the city
double m_longitude; //Longitude of the city
string m_cityName; //name of city

/// <summary>
/// property used to get and set TimeZone
/// </summary>
public double TimeZone
{
get
{
return m_timeZone;
}
set
{
m_timeZone = value;
}
}

/// <summary>
/// property used to get and set Latitude
/// </summary>
public double Latitude
{
get
{
return m_latitude;
}
set
{
m_latitude = value;
}
}

/// <summary>
/// property used to get and set Longitude
/// </summary>
public double Longitude
{
get
{
return m_longitude;
}
set
{
m_longitude = value;
}
}

/// <summary>
/// property used to get and set city name
/// </summary>
public string CityName
{
get
{
return m_cityName;
}
set
{
m_cityName = value;
}
}

/// <summary>
/// class CityInfo's constructor
/// </summary>
/// <param name="latitude">latitude of city</param>
/// <param name="longitude">longitude of city</param>
public CityInfo(double latitude, double longitude)
{
m_latitude = latitude;
m_longitude = longitude;
m_timeZone = PlaceInfo.InvalidTimeZone;
m_cityName = null;
}

/// <summary>
/// class CityInfo's constructor
/// </summary>
/// <param name="latitude">latitude of city</param>
/// <param name="longitude">longitude of city</param>
/// <param name="timeZone">timezone of city</param>
/// <param name="cityName">city name</param>
public CityInfo(double latitude, double longitude, double timeZone, string cityName)
{
m_timeZone = timeZone;
m_latitude = latitude;
m_longitude = longitude;
m_cityName = cityName;
}
}

/// <summary>
/// a struct used to describe information about city
/// displayed in Form and it's members are string type
/// </summary>
public struct CityInfoString
{
string m_timeZone; //Timezone in which the city resides
string m_latitude; //Latitde of the city
string m_longitude; //Longitude of the city

/// <summary>
/// property used to get and set TimeZone
/// </summary>
public string TimeZone
{
get
{
return m_timeZone;
}
set
{
m_timeZone = value;
}
}

/// <summary>
/// property used to get and set Latitude
/// </summary>
public string Latitude
{
get
{
return m_latitude;
}
set
{
m_latitude = value;
}
}

/// <summary>
/// property used to get and set Longitude
/// </summary>
public string Longitude
{
get
{
return m_longitude;
}
set
{
m_longitude = value;
}
}

/// <summary>
/// class CityInfo's constructor
/// </summary>
/// <param name="latitude">latitude of city</param>
/// <param name="longitude">longitude of city</param>
public CityInfoString(string latitude, string longitude)
{
m_latitude = latitude;
m_longitude = longitude;
m_timeZone = null;
}

/// <summary>
/// class CityInfo's constructor
/// </summary>
/// <param name="latitude">latitude of city</param>
/// <param name="longitude">longitude of city</param>
/// <param name="timeZone">timezone of city</param>
public CityInfoString(string latitude, string longitude, string timeZone)
{
m_timeZone = timeZone;
m_latitude = latitude;
m_longitude = longitude;
}
}

/// <summary>
/// a class used to store information of all city
/// include it's name,Latitude,longitude,timezone
/// </summary>
public class PlaceInfo
{
private List<string> m_citiesName; //city's name
private List<CityInfo> m_citiesInfo; //information of all cities,such Latitude,longitude
private List<string> m_timeZones; //timezone information of all cities
private bool m_isTimeZonesValid; //figure out whether can get timezone information
private const double Diff = 0.0001; //used to check whether two double values are equal
private static readonly double m_invalidTimeZone = -13; //value used when can't get timezone

/// <summary>
/// property used to get and set all cities' name
/// </summary>
public List<string> CitiesName
{
get
{
return m_citiesName;
}
set
{
m_citiesName = value;
}
}

/// <summary>
/// property used to get and set all timezone
/// </summary>
public List<string> TimeZones
{
get
{
return m_timeZones;
}
set
{
m_timeZones = value;
}
}

/// <summary>
/// property used to get Invalid timezone
/// </summary>
public static double InvalidTimeZone
{
get
{
return m_invalidTimeZone;
}
}

/// <summary>
/// class PlaceInfo's constructor
/// </summary>
/// <param name="cities"></param>
public PlaceInfo(CitySet cities)
{
Initialize(cities);
}

/// <summary>
/// initialize function
/// </summary>
/// <param name="cities">a set store all cities</param>
/// <returns></returns>
public bool Initialize(CitySet cities)
{
m_citiesInfo = new List<CityInfo>();
m_citiesName = new List<string>();
m_timeZones = new List<string>();

if (InitCities(cities) && InitTimeZone())
{
return true;
}
return false;
}

/// <summary>
/// Add a city info to city info List
/// </summary>
/// <param name="cityInfo">the city info need to add</param>
public void AddCityInfo(CityInfo cityInfo)
{
if (m_citiesInfo.Contains(cityInfo))
{
return;
}
m_citiesInfo.Add(cityInfo);
}

/// <summary>
/// try to get city name according to CityInfo
/// </summary>
/// <param name="cityInfo">store information about city</param>
/// <param name="cityName">city's name</param>
/// <param name="timeZone">city's timezone</param>
/// <returns>figure out whether this function successful</returns>
public bool TryGetCityNameTimeZone(CityInfo cityInfo, out string cityName, out double timeZone)
{
cityName = null;
timeZone = m_invalidTimeZone;

//loop to find cityinfo matched
foreach (CityInfo temp in m_citiesInfo)
{
//compare Latitude and longitude,and if difference < Diff
// the two CityInfo are equal
if (Math.Abs(temp.Latitude - cityInfo.Latitude) < Diff &&
Math.Abs(temp.Longitude - cityInfo.Longitude) < Diff)
{
cityName = temp.CityName;
timeZone = temp.TimeZone;
return true;
}
}
return false;
}

/// <summary>
/// try to get city info according to city name
/// </summary>
/// <param name="cityName">city name</param>
/// <param name="cityInfo">city's information</param>
/// <returns>figure out whether this function successful</returns>
public bool TryGetCityInfo(string cityName, out CityInfo cityInfo)
{
//compare cityName with element's CityName of m_citiesInfo
//if they are equal, that element is matched
foreach (CityInfo temp in m_citiesInfo)
{
if (cityName == temp.CityName)
{
cityInfo = temp;
return true;
}
}
cityInfo = new CityInfo();
return false;
}

/// <summary>
/// try to get city's timezone
/// </summary>
/// <param name="timeZoneNumber">time zone</param>
/// <returns>figure out whether this function successful</returns>
public string TryGetTimeZoneString(double timeZoneNumber)
{
//if Initialize faied or timeZoneNumber is not in range -12 to 12, return null
if (!m_isTimeZonesValid || timeZoneNumber > 13 || timeZoneNumber < -12)
{
return null;
}
string timeZoneString = null;
string temp = null;

//try to get a string like "(GMT+08:00)",
//the number in string associate with timeZoneNumber
//first if timeZoneNumber is 0
if (0 == timeZoneNumber)
{
temp = "(GMT)";
}
else
{
//if timeZoneNumber > 0
if (timeZoneNumber > 0)
{
if (timeZoneNumber > 9)
{
temp = "(GMT+";
}
else
{
temp = "(GMT+0";
}
}
//if timeZoneNumber < 0
else
{
if (timeZoneNumber < -9)
{
temp = "(GMT-";
}
else
{
temp = "(GMT-0";
}
}

//if timeZoneNumber is not int, append ":30" to string
int intNumber = (int)timeZoneNumber;
if (0.5 == Math.Abs(timeZoneNumber - intNumber))
{
temp += Math.Abs(intNumber) + ":30)";
}
else
{
temp += Math.Abs(intNumber) + ":00)";
}
}

//try to find string in list m_timeZones contains string get above
for (int i = 0; i < m_timeZones.Count; i++)
{
if (m_timeZones[i].Contains(temp))
{
//here, use last member of list contains that string as result.
timeZoneString = m_timeZones[i];
}
}
return timeZoneString;
}

/// <summary>
/// try to get TimeZone's number from a string
/// </summary>
/// <param name="timeZoneString">a string store TimeZone</param>
/// <returns>result Parse from string</returns>
public double TryGetTimeZoneNumber(string timeZoneString)
{
bool isPlus;
double result = 0;
//check timezone is plus, zero or negative
if (timeZoneString.Contains("+"))
{
isPlus = true;
}
else if (timeZoneString.Contains("-"))
{
isPlus = false;
}
else
{
return result;
}

//get int and decimal part of timezone
string intString = timeZoneString.Substring(5, 2);
string decimalString = timeZoneString.Substring(8, 1);
double intNumber;
double decimalNumber;

//try to get double from string using method Double.TryParse
if (Double.TryParse(intString, out intNumber) &&
Double.TryParse(decimalString, out decimalNumber))
{
//if decimal part is not zero, add 0.5 after int part
if (0 != decimalNumber)
{
result = intNumber + 0.5;
}
else
{
result = intNumber;
}
}

//if timezone is negative, add minus
if (!isPlus)
{
result *= -1;
}
return result;
}

/// <summary>
/// initialize cities
/// </summary>
/// <param name="cities"></param>
/// <returns></returns>
private bool InitCities(CitySet cities)
{
if (null == cities)
{
return false;
}

//add all element of CitySet cities to List m_cities
CitySetIterator iter = cities.ForwardIterator();
iter.Reset();
for (; iter.MoveNext(); )
{
City city = iter.Current as City;
if (null == city)
{
continue;
}
m_citiesName.Add(city.Name);
m_citiesInfo.Add(new CityInfo(city.Latitude, city.Longitude, city.TimeZone, city.Name));
}
//sort list according to first char of element
m_citiesName.Sort();
return true;
}

/// <summary>
/// initialize timezone
/// </summary>
/// <returns></returns>
private bool InitTimeZone()
{
StreamReader streamReader = null;
try
{
//open file store timezone
string filepath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
if (!filepath.EndsWith("\\"))
{
filepath += "\\";
}
filepath += "timezone.txt";
streamReader = File.OpenText(filepath);

//add timezone to m_timeZones
while (!streamReader.EndOfStream)
{
string text = streamReader.ReadLine();
if (null != text)
{
m_timeZones.Add(text);
}
}
}
catch (Exception e)
{
m_isTimeZonesValid = false;

//show message to tell user that initialize failed
TaskDialog.Show("Revit", e.Message);
return false;
}
finally
{
//close file resource
if (null != streamReader)
{
streamReader.Close();
}
}
m_isTimeZonesValid = true;
return true;
}
}
}

UnitConversion.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Globalization;

namespace Revit.SDK.Samples.SharedCoordinateSystem.CS
{
/// <summary>
/// define type of value
/// </summary>
public enum ValueType
{
/// <summary>
/// general value
/// </summary>
General = 0,

/// <summary>
/// angle value
/// </summary>
Angle
}

/// <summary>
/// a class used to deal with converting operation
/// </summary>
public class UnitConversion
{
private static readonly int DefaultPrecision = 3; //default precision
private static readonly double AngleRatio = 0.0174532925199433; //ratio of Angle

/// <summary>
/// convert CityInfo into CityInfoString
/// </summary>
/// <param name="cityInfo">CityInfo need to convert</param>
/// <returns>conversion result</returns>
public static CityInfoString ConvertFrom(CityInfo cityInfo)
{
CityInfoString cityInfoString = new CityInfoString();
cityInfoString.Latitude = DoubleToString(cityInfo.Latitude, ValueType.Angle);
cityInfoString.Longitude = DoubleToString(cityInfo.Longitude, ValueType.Angle);
return cityInfoString;
}

/// <summary>
/// convert CityInfoString into CityInfo
/// </summary>
/// <param name="cityInfoString">CityInfoString need to convert</param>
/// <returns>conversion result</returns>
public static CityInfo ConvertTo(CityInfoString cityInfoString)
{
CityInfo cityInfo = new CityInfo();
double temp;

//convert Latitude
if (StringToDouble(cityInfoString.Latitude, ValueType.Angle, out temp))
{
cityInfo.Latitude = temp;
}
else
{
cityInfo.Latitude = Double.NaN;
}

//convert Longitude
if (StringToDouble(cityInfoString.Longitude, ValueType.Angle, out temp))
{
cityInfo.Longitude = temp;
}
else
{
cityInfo.Longitude = Double.NaN;
}

return cityInfo;
}

/// <summary>
/// deal with value according to precision
/// </summary>
/// <param name="value">original value will be dealed</param>
/// <param name="precision">precision wanted to be set</param>
/// <returns>return the dealed value</returns>
public static double DealPrecision(double value, int precision)
{
//first make sure 0 =< precision <= 15
if (precision < 0 && precision > 15)
{
return value;
}

//if >1 or < -1,just use Math.Round to deal with
double newValue;
if (value >= 1 || value <= -1 || 0 == value)
{
//Math.Round: returns the number with the specified precision
//nearest the specified value.
newValue = Math.Round(value, precision);
return newValue;
}

//if -1 < value < 1,
//find first number which is not "0"
//compare it with precision, then select
//min of them as final precision
int firstNumberPos = 0;
double temp = Math.Abs(value);
for (firstNumberPos = 1; ; firstNumberPos++)
{
temp *= 10;
if (temp >= 1)
{
break;
}
}

//make sure firstNumberPos <= 15
if (firstNumberPos > 15)
{
firstNumberPos = 15;
}

//Math.Round: returns the number with the specified precision
//nearest the specified value.
newValue = Math.Round(value, firstNumberPos > precision ? firstNumberPos : precision);
return newValue;
}

/// <summary>
/// convert double into string
/// </summary>
/// <param name="value">double value need to convert</param>
/// <param name="valueType">value type</param>
/// <returns>conversion result</returns>
public static string DoubleToString(double value, ValueType valueType)
{
string displayText = null; // string included value and unit of parameter
double newValue;
ValueConversion(value, ValueType.Angle, true, out newValue);
value = newValue;
newValue = DealPrecision(value, DefaultPrecision);

//calculate the number after ".",if less than DecimalNumber
// add some "0" after it
displayText = DealDecimalNumber(newValue.ToString(), DefaultPrecision);

if(ValueType.Angle == valueType)
{
char degree = (char)0xb0;
displayText += degree;
}

return displayText;
}

/// <summary>
/// deal with decimal number
/// </summary>
/// <param name="value">string wanted to deal with</param>
/// <param name="number">number of decimal</param>
/// <returns>result dealing with</returns>
public static string DealDecimalNumber(string value, int number)
{
string newValue = value;
int dist;
if (newValue.Contains("."))
{
int index = newValue.IndexOf(".");
dist = newValue.Length - (index + 1);
}
else
{
dist = 0;
newValue += ".";
}
if (dist < number)
{
for (int i = 0; i < number - dist; i++)
{
newValue += "0";
}
}
return newValue;
}

/// <summary>
/// convert string into double
/// </summary>
/// <param name="value">string value need to convert</param>
/// <param name="valueType">value type</param>
/// <param name="newValue">conversion result</param>
/// <returns>if success, return true; otherwise, return false</returns>
public static bool StringToDouble(string value, ValueType valueType, out double newValue)
{
newValue = 0;

if (null == value)
{
return false;
}

//try to Parse double from string
double result;
if (ParseFromString(value, valueType, out result))
{
//deal with ratio
ValueConversion(result, valueType, false, out newValue);
return true;
}
return false;
}

/// <summary>
/// Parse double from string
/// </summary>
/// <param name="value">string value</param>
/// <param name="valueType">value type</param>
/// <param name="result">conversion result</param>
/// <returns>if success, return true; otherwise, return false</returns>
private static bool ParseFromString(string value, ValueType valueType, out double result)
{
string newValue = null;
string degree = ((char)0xb0).ToString();

//if nothing, set result = 0;
if (value.Length == 0)
{
result = 0;
return true;
}
else if (ValueType.General == valueType)
{
}
//check if contain degree symbol
else if (value.Contains(degree))
{
int index = value.IndexOf(degree);
newValue = value.Substring(0, index);
}
//check if have string" " ,for there is string" "
//between value and unit when show in PropertyGrid
else if (value.Contains(" "))
{
int index = value.IndexOf(" ");
newValue = value.Substring(0, index);
}
//finally if don't have unit name in it
//other situation, set newValue = value
else
{
newValue = value;
}

//double.TryParse's return value:
//true if s is converted successfully; otherwise, false.
if (double.TryParse(newValue, out result))
{
return true;
}
return false;
}

/// <summary>
/// deal with ratio
/// </summary>
/// <param name="value">value need to deal with</param>
/// <param name="valueType">value type</param>
/// <param name="isDoubleToString">
/// figure out whether be called by function "DoubleToString"
/// </param>
/// <param name="newValue"></param>
private static void ValueConversion(double value, ValueType valueType,
bool isDoubleToString, out double newValue)
{
//ValueType.General == valueType,do nothing and return
if (ValueType.General == valueType)
{
newValue = value;
return;
}

//otherwise,check whether be called by function "DoubleToString"
if (isDoubleToString)
{
newValue = value / AngleRatio;
}
else
{
newValue = value * AngleRatio;
}
}
}
}