Я все еще работаю над этим, поэтому я не буду публиковать весь исходный код. Но я дам вам концептуальное решение.
В качестве входных данных (для обеих камер) вам понадобятся следующие данные:
Вы можете сами измерить последний, разместив камеру на листе бумаги и рисуя две линии и измеряя угол между этими линиями.
Камеры не обязательно должны быть выровнены, вам нужно только увидеть свой объект в обеих камерах.
Теперь вычислите вектор от каждой камеры к вашему объекту. У вас есть (X, Y) пиксельные координаты объекта с каждой камеры, и вам нужно вычислить вектор (X, Y, Z). Обратите внимание, что в простом случае, когда объект отображается прямо посередине камеры, решение будет просто (camera.PointOfInterest - camera.Position).
Как только у вас есть оба вектора, указывающие на ваш цель, линии, определяемые этими векторами, должны пересекаться в одной точке в идеальном мире. В реальном мире они не будут из-за небольших ошибок измерения и ограниченного разрешения камер. Поэтому используйте ссылку ниже, чтобы рассчитать вектор расстояния между двумя линиями.
Расстояние между двумя линиями
В этой ссылке: P0 - это ваша первая позиция кулачка, Q0 - это ваша вторая позиция кулачка, а u и v - векторы, начинающиеся с положения камеры и указывающие на вашу цель.
Вас не интересует фактическое расстояние, которое они хотят рассчитать. Вам нужен вектор Wc - мы можем предположить, что объект находится в середине Wc. После того, как у вас есть позиция вашего объекта в 3D-пространстве, вы также получите любое расстояние, которое вам нравится.
Я скоро опубликую весь исходный код.
Все разные.
typeof
принимает имя типа (которое вы указываете во время компиляции) . GetType
получает тип среды выполнения экземпляра. is
возвращает истину, если экземпляр находится в дереве наследования. class Animal { }
class Dog : Animal { }
void PrintTypes(Animal a) {
Console.WriteLine(a.GetType() == typeof(Animal)); // false
Console.WriteLine(a is Animal); // true
Console.WriteLine(a.GetType() == typeof(Dog)); // true
Console.WriteLine(a is Dog); // true
}
Dog spot = new Dog();
PrintTypes(spot);
А как насчет
typeof (T)
? Это также разрешено во время компиляции?
Да. T всегда соответствует типу выражения. Помните, что универсальный метод - это, по сути, целый набор методов соответствующего типа. Пример:
string Foo<T>(T parameter) { return typeof(T).Name; }
Animal probably_a_dog = new Dog();
Dog definitely_a_dog = new Dog();
Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.
Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal".
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
Используйте typeof
, если вы хотите получить тип во время компиляции . Используйте GetType
, если вы хотите получить тип во время выполнения . is
редко используются, поскольку он выполняет приведение, и в большинстве случаев вы все равно приводите переменную.
Есть четвертый вариант, который вы не рассматривали (особенно если вы также собираетесь привести объект к найденному вами типу); то есть использовать как
.
Foo foo = obj as Foo;
if (foo != null)
// your code here
Здесь используется только одно преобразование, тогда как этот подход:
if (obj is Foo)
Foo foo = (Foo)obj;
требует двух .
Я предпочитаю is
Тем не менее, если вы используете is , вы, скорее всего, не правильно используете наследование.
Предположим, что это лицо: сущность, а животное: сущность. Feed - это виртуальный метод в Entity (чтобы сделать Нила счастливым)
class Person
{
// A Person should be able to Feed
// another Entity, but they way he feeds
// each is different
public override void Feed( Entity e )
{
if( e is Person )
{
// feed me
}
else if( e is Animal )
{
// ruff
}
}
}
Скорее
class Person
{
public override void Feed( Person p )
{
// feed the person
}
public override void Feed( Animal a )
{
// feed the animal
}
}
1.
Type t = typeof(obj1);
if (t == typeof(int))
Это незаконно, потому что typeof работает только с типы, а не переменные. Я предполагаю, что obj1 - это переменная. Таким образом, typeof статичен и выполняет свою работу во время компиляции, а не во время выполнения.
2.
if (obj1.GetType() == typeof(int))
Это верно, если obj1 имеет именно тип int. Если obj1 является производным от int, условие if будет ложным.
3.
if (obj1 is int)
Это верно, если obj1 является int, или если он является производным от класса с именем int, или если он реализует интерфейс с именем int.
Я считаю, что последний также учитывает наследование (например, Dog is Animal == true), что в большинстве случаев лучше.
Это зависит от того, что я делаю. Если мне нужно значение типа bool (скажем, чтобы определить, приведу ли я к int), я буду использовать is
. Если мне действительно нужен тип по какой-то причине (например, для перехода к другому методу), я буду использовать GetType ()
.
Последний более понятен, более очевиден и также проверяет наличие подтипов. Остальные не проверяют полиморфизм.
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Это ошибка. Оператор typeof в C # может принимать только имена типов, но не объекты.
if (obj1.GetType() == typeof(int))
// Some code here
Это будет работать, но, возможно, не так, как вы ожидали. Для типов значений, как вы показали здесь, это приемлемо, но для ссылочных типов оно вернет истину только в том случае, если тип точно такой же , а не что-то еще в иерархии наследования. Например:
class Animal{}
class Dog : Animal{}
static void Foo(){
object o = new Dog();
if(o.GetType() == typeof(Animal))
Console.WriteLine("o is an animal");
Console.WriteLine("o is something else");
}
Это напечатает «o - это что-то еще»
, потому что тип o
- Dog
, а не Animal
. Однако вы можете справиться с этой задачей, если используете метод IsAssignableFrom
класса Type
.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Однако этот метод все еще оставляет серьезную проблему. Если ваша переменная равна нулю, вызов GetType ()
вызовет исключение NullReferenceException. Итак, чтобы он работал правильно, вы должны сделать:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
Таким образом, у вас есть эквивалентное поведение ключевого слова is
. Следовательно, если это именно то поведение, которое вам нужно, вам следует использовать ключевое слово is
, которое более читабельно и более эффективно.
if(o is Animal)
Console.WriteLine("o is an animal");
Однако в большинстве случаев ключевое слово is
по-прежнему это не то, что вам действительно нужно, потому что обычно недостаточно просто знать, что объект относится к определенному типу. Обычно вы хотите на самом деле использовать этот объект как экземпляр этого типа, что тоже требует его приведения. И поэтому вы можете написать такой код:
if(o is Animal)
((Animal)o).Speak();
Но это заставляет CLR проверять тип объекта до двух раз. Он проверит его один раз, чтобы удовлетворить оператору is
, и если o
действительно является Animal
, мы снова проверяем приведение, чтобы подтвердить приведение.
Это более эффективно:
Animal a = o as Animal;
if(a != null)
a.Speak();
Оператор as
- это приведение, которое не генерирует исключение в случае сбоя, вместо этого возвращает ноль
. Таким образом, CLR проверяет тип объекта только один раз, а после этого нам просто нужно выполнить нулевую проверку, что более эффективно.
Но будьте осторожны: многие люди попадают в ловушку с как
. Поскольку он не генерирует исключений, некоторые люди думают о нем как о «безопасном» приведении и используют исключительно его, избегая обычных приведений. Это приводит к следующим ошибкам:
(o as Animal).Speak();
В этом случае разработчик явно предполагает, что o
всегда будет Animal
, и пока их предположение верное, все работает нормально. Но если они ошибаются, то в итоге они получают NullReferenceException
. При обычном приведении они получили бы вместо этого InvalidCastException
, что позволило бы более правильно определить проблему.
Иногда эту ошибку бывает трудно найти:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
Это еще один случай, когда ошибка разработчик явно ожидает, что o
каждый раз будет Animal
, но это не очевидно в конструкторе, где используется приведение as
. Это не очевидно, пока вы не дойдете до метода Interact
, где ожидается, что поле animal
будет положительно присвоено. В этом случае вы не только получите вводящее в заблуждение исключение, но и не сгенерируете его до тех пор, пока возможно намного позже, чем когда произошла фактическая ошибка.
В итоге:
Если вам нужно только знать, относится ли объект к какому-либо типу, используйте равно
.
Если вам нужно рассматривать объект как экземпляр определенного типа, но вы этого не делаете Чтобы точно знать, что объект будет этого типа, используйте как
и проверьте null
.
Если вам нужно рассматривать объект как экземпляр определенного типа, и объект должен быть этого типа, используйте обычное приведение.