. Balusc дает очень полезный обзорный обзор по этому вопросу. Но есть одна альтернатива, которую он не представляет: Roll-your-общий универсальный конвертер, который обрабатывает сложные объекты как выбранный элемент. Это очень сложно сделать, если вы хотите обрабатывать все случаи, но довольно просто для простых случаев.
В приведенном ниже коде содержится пример такого конвертера. Он работает в том же духе, что и OmniFaces SelectItemsConverter , поскольку он просматривает дочерние элементы компонента для объектов, содержащихся в UISelectItem(s)
. Разница в том, что он обрабатывает привязки только к простым коллекциям объектов сущности или к строкам. Он не обрабатывает группы элементов, коллекции SelectItem
s, массивы и, возможно, много других вещей.
Сущности, к которым должен привязываться компонент, должны реализовать интерфейс IdObject
. (Это можно решить другим способом, например, с помощью toString
.)
Обратите внимание, что сущности должны реализовать equals
таким образом, чтобы два объекта с одинаковым идентификатором сравнивались равными.
Единственное, что вам нужно сделать, чтобы использовать его, - это указать его как конвертер на компоненте select, привязать его к свойству сущности и списку возможных объектов:
Конвертер:
/**
* A converter for select components (those that have select items as children).
*
* It convertes the selected value string into one of its element entities, thus allowing
* binding to complex objects.
*
* It only handles simple uses of select components, in which the value is a simple list of
* entities. No ItemGroups, arrays or other kinds of values.
*
* Items it binds to can be strings or implementations of the {@link IdObject} interface.
*/
@FacesConverter("selectListConverter")
public class SelectListConverter implements Converter {
public static interface IdObject {
public String getDisplayId();
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
return component.getChildren().stream()
.flatMap(child -> getEntriesOfItem(child))
.filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o))
.findAny().orElse(null);
}
/**
* Gets the values stored in a {@link UISelectItem} or a {@link UISelectItems}.
* For other components returns an empty stream.
*/
private Stream> getEntriesOfItem(UIComponent child) {
if (child instanceof UISelectItem) {
UISelectItem item = (UISelectItem) child;
if (!item.isNoSelectionOption()) {
return Stream.of(item.getValue());
}
} else if (child instanceof UISelectItems) {
Object value = ((UISelectItems) child).getValue();
if (value instanceof Collection) {
return ((Collection>) value).stream();
} else {
throw new IllegalStateException("Unsupported value of UISelectItems: " + value);
}
}
return Stream.empty();
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof String) return (String) value;
if (value instanceof IdObject) return ((IdObject) value).getDisplayId();
throw new IllegalArgumentException("Unexpected value type");
}
}
Умножение кватернионов собирается пострадать от накопления проблем округления с плавающей точкой (даже простые углы как 45 градусов не будут точны). Это - отличный способ составить вращения, но точность каждого из Ваших компонентов кватерниона идет в зону высадки пассажиров со временем. Проступание является одним побочным эффектом, визуально худший, хотя Ваш кватернион, мог начать включать масштабный коэффициент - для восстановления этого, необходимо будет повторно нормализовать назад к Euler углам в любом случае. Фиксированная точка Euler угол не собирается накапливать округление.
Перевычисление кватерниона на кадр минимально. Я не потрудился бы пытаться оптимизировать его. Вы могли, вероятно, позволить нескольким кватернионам накапливаться перед перенормализацией для возвращения точности, но это действительно не стоит усилия.
Накопление является неточным процессом. Накопление большого количества возрастающих вращений накопит ошибку округления, делаете ли Вы это с кватернионами или матрицами.
я воображаю что-то вроде этого: Вы разбудили свой код и выполнение, но заметили, что после определенного количества навигации Ваша камера кренилась раздражающе - нарушение инварианта, о котором Вы не думали заранее. Эффективно, Вы поняли, что не делаете , хотят накопить вращения; вместо этого Вы хотите сделать что-то еще.
можно посмотреть на это как на большее количество проблемы дизайна интерфейса, чем числовая проблема точности. В основном люди ожидают, что камера перейдет согласно подаче, отклонению от курса, и список, таким образом принимая решение управлять и представить углы непосредственно может избежать большого количества проблем.
неприятность здесь - то, что quaterions, кажется, стали избыточными (для этого конкретного использования, по крайней мере). Вы все еще хотите кватернионы, хотя - интерполирующий с необработанной подачей/отклонением от курса/углами вращения может быть ужасным. Снова, это - вопрос о дизайне интерфейса: необходимо выяснить, где Вам будут нужны кватернионы, и как вложить их и...
Я видел, что оба привели доводы. Я думаю реальный вопрос, с которым необходимо будет иметь дело, гибкость в системе камеры по линии; отклонение от курса IMO обычно более интересно в представлении третьего лица (потому что Вы собираетесь вращаться о вертикальной оси символа). В то время как можно возможно "отклоняться от курса" вокруг вертикали в первоклассном представлении также, я не уверен, что это - действительно то же самое.
Однако я действительно думаю, что это является своего рода ненужным для перевычисления кватернионов на кадр. Возможно, было бы лучше сохранить последние кватернионы и отметить их грязный, если Ваш кадр получает вход?