1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/pxr.h"
25 #include "pxr/usd/usdGeom/metrics.h"
26 #include "pxr/usd/usdGeom/tokens.h"
27 
28 #include "pxr/usd/sdf/schema.h"
29 #include "pxr/usd/usd/stage.h"
30 
31 #include "pxr/base/plug/plugin.h"
32 #include "pxr/base/plug/registry.h"
33 
34 #include "pxr/base/tf/diagnostic.h"
35 #include "pxr/base/tf/envSetting.h"
36 #include "pxr/base/tf/staticData.h"
37 #include "pxr/base/tf/staticTokens.h"
38 #include "pxr/base/tf/token.h"
39 
40 #include <cfloat>
41 
42 PXR_NAMESPACE_OPEN_SCOPE
43 
44 
45 TF_DEFINE_PRIVATE_TOKENS(
46     _tokens,
47     (UsdGeomMetrics)
48 );
49 
50 TfToken
UsdGeomGetStageUpAxis(const UsdStageWeakPtr & stage)51 UsdGeomGetStageUpAxis(const UsdStageWeakPtr &stage)
52 {
53     if (!stage){
54         TF_CODING_ERROR("Invalid UsdStage");
55         return TfToken();
56     }
57 
58     // Even after we remove backwards compatibility support, we will still
59     // need to know if upAxis has been authored, since we want to provide
60     // a potentially different fallback than that of the SdfSchema.
61     if (stage->HasAuthoredMetadata(UsdGeomTokens->upAxis)){
62         TfToken axis;
63         stage->GetMetadata(UsdGeomTokens->upAxis, &axis);
64         return axis;
65     }
66 
67     return UsdGeomGetFallbackUpAxis();
68 }
69 
70 bool
UsdGeomSetStageUpAxis(const UsdStageWeakPtr & stage,const TfToken & axis)71 UsdGeomSetStageUpAxis(const UsdStageWeakPtr &stage, const TfToken &axis)
72 {
73     if (!stage){
74         TF_CODING_ERROR("Invalid UsdStage");
75         return false;
76     }
77 
78     if (axis != UsdGeomTokens->y && axis != UsdGeomTokens->z){
79         TF_CODING_ERROR("UsdStage upAxis can only be set to \"Y\" or \"Z\", "
80                         "not attempted \"%s\" on stage %s.",
81                         axis.GetText(),
82                         stage->GetRootLayer()->GetIdentifier().c_str());
83         return false;
84     }
85 
86     return stage->SetMetadata(UsdGeomTokens->upAxis, VtValue(axis));
87 }
88 
TF_MAKE_STATIC_DATA(TfToken,_fallbackUpAxis)89 TF_MAKE_STATIC_DATA(TfToken, _fallbackUpAxis)
90 {
91     TfToken upAxis;
92     std::string definingPluginName;
93     TfToken schemaFallback =
94         SdfSchema::GetInstance().GetFallback(UsdGeomTokens->upAxis)
95         .Get<TfToken>();
96 
97     PlugPluginPtrVector plugs = PlugRegistry::GetInstance().GetAllPlugins();
98     TF_FOR_ALL(plugIter, plugs) {
99         PlugPluginPtr plug = *plugIter;
100         JsObject metadata = plug->GetMetadata();
101         JsValue metricsDictValue;
102         if (TfMapLookup(metadata, _tokens->UsdGeomMetrics, &metricsDictValue)){
103             if (!metricsDictValue.Is<JsObject>()) {
104                 TF_CODING_ERROR(
105                         "%s[%s] was not a dictionary in plugInfo.json file.",
106                         plug->GetName().c_str(),
107                         _tokens->UsdGeomMetrics.GetText());
108                 continue;
109             }
110 
111             JsObject metricsDict =
112                 metricsDictValue.Get<JsObject>();
113             JsValue upAxisValue;
114             if (TfMapLookup(metricsDict,
115                             UsdGeomTokens->upAxis,
116                             &upAxisValue)) {
117                 if (!upAxisValue.Is<std::string>()) {
118                     TF_CODING_ERROR(
119                         "%s[%s][%s] was not a string.",
120                         plug->GetName().c_str(),
121                         _tokens->UsdGeomMetrics.GetText(),
122                         UsdGeomTokens->upAxis.GetText());
123                     continue;
124                 }
125 
126                 std::string axisStr = upAxisValue.Get<std::string>();
127                 TfToken axisToken;
128                 if (axisStr == "Y"){
129                     axisToken = UsdGeomTokens->y;
130                 } else if (axisStr == "Z") {
131                     axisToken = UsdGeomTokens->z;
132                 } else {
133                     TF_CODING_ERROR(
134                         "%s[%s][%s] had value \"%s\", but only \"Y\" and"
135                         " \"Z\" are allowed.",
136                         plug->GetName().c_str(),
137                         _tokens->UsdGeomMetrics.GetText(),
138                         UsdGeomTokens->upAxis.GetText(),
139                         axisStr.c_str());
140                     continue;
141                 }
142 
143                 if (!upAxis.IsEmpty() && upAxis != axisToken) {
144                     TF_CODING_ERROR("Plugins %s and %s provided different"
145                                     " fallback values for %s.  Ignoring all"
146                                     " plugins and using schema fallback of"
147                                     " \"%s\"",
148                                     definingPluginName.c_str(),
149                                     plug->GetName().c_str(),
150                                     UsdGeomTokens->upAxis.GetText(),
151                                     schemaFallback.GetText());
152                     *_fallbackUpAxis = schemaFallback;
153                     return;
154                 } else if (upAxis.IsEmpty()) {
155                     definingPluginName = plug->GetName();
156                     upAxis = axisToken;
157                 }
158             }
159 
160         }
161     }
162 
163     *_fallbackUpAxis = upAxis.IsEmpty() ? schemaFallback : upAxis;
164 }
165 
166 TfToken
UsdGeomGetFallbackUpAxis()167 UsdGeomGetFallbackUpAxis()
168 {
169     return *_fallbackUpAxis;
170 }
171 
172 
173 constexpr double UsdGeomLinearUnits::nanometers;
174 constexpr double UsdGeomLinearUnits::micrometers;
175 constexpr double UsdGeomLinearUnits::millimeters;
176 constexpr double UsdGeomLinearUnits::centimeters;
177 constexpr double UsdGeomLinearUnits::meters;
178 constexpr double UsdGeomLinearUnits::kilometers;
179 constexpr double UsdGeomLinearUnits::lightYears;
180 constexpr double UsdGeomLinearUnits::inches;
181 constexpr double UsdGeomLinearUnits::feet;
182 constexpr double UsdGeomLinearUnits::yards;
183 constexpr double UsdGeomLinearUnits::miles;
184 
185 double
UsdGeomGetStageMetersPerUnit(const UsdStageWeakPtr & stage)186 UsdGeomGetStageMetersPerUnit(const UsdStageWeakPtr &stage)
187 {
188     double  units = UsdGeomLinearUnits::centimeters;
189     if (!stage){
190         TF_CODING_ERROR("Invalid UsdStage");
191         return units;
192     }
193 
194     stage->GetMetadata(UsdGeomTokens->metersPerUnit, &units);
195     return units;
196 }
197 
198 bool
UsdGeomStageHasAuthoredMetersPerUnit(const UsdStageWeakPtr & stage)199 UsdGeomStageHasAuthoredMetersPerUnit(const UsdStageWeakPtr &stage)
200 {
201     if (!stage){
202         TF_CODING_ERROR("Invalid UsdStage");
203         return false;
204     }
205     return stage->HasAuthoredMetadata(UsdGeomTokens->metersPerUnit);
206 }
207 
208 bool
UsdGeomSetStageMetersPerUnit(const UsdStageWeakPtr & stage,double metersPerUnit)209 UsdGeomSetStageMetersPerUnit(const UsdStageWeakPtr &stage,
210                              double metersPerUnit)
211 {
212     if (!stage){
213         TF_CODING_ERROR("Invalid UsdStage");
214         return false;
215     }
216 
217     return stage->SetMetadata(UsdGeomTokens->metersPerUnit, metersPerUnit);
218 }
219 
220 bool
UsdGeomLinearUnitsAre(double authoredUnits,double standardUnits,double epsilon)221 UsdGeomLinearUnitsAre(double authoredUnits, double standardUnits,
222                       double epsilon)
223 {
224     if (authoredUnits <= 0 || standardUnits <= 0){
225         return false;
226     }
227 
228     const double diff = GfAbs(authoredUnits - standardUnits);
229     return (diff / authoredUnits < epsilon) && (diff / standardUnits < epsilon);
230 }
231 
232 
233 PXR_NAMESPACE_CLOSE_SCOPE
234 
235