Hello,
I am currently trying to create an add-in that will allow me to perform a calculation on various points on a duct face.
For now, the user is selecting the face, but in the future, I plan to process the top face of each duct in the view.
I am following along with the RvtFader example project.
A reference to my face is passed into the SpatialFieldManager, exactly like in the RvtFader example.
The UpdateSpatialFieldPrimiate method runs without error, and my duct is shaded with a single solid color.
I believe my issue is that I am feeding the FieldDomainPointsByUV with UV points that are in the global coordinate system instead of the local coordinates system to the face. I suspect because create a BoundingBoxUV of my face, and supplying the bb.Min and bb.Max, along with 0, 10 as FieldValues, I get a correctly shaded (using a gradient) duct.
Is there a way to convert WCS XYZ points to local UV points?
I assume I don't care about the z coordinate...
What am I missing here?
Here is my relevant code:
static SpatialFieldManager SetUpAvfSfm(View view, Reference faceReference, Face face)
{
if (view.AnalysisDisplayStyleId == ElementId.InvalidElementId)
{
SetAvfDisplayStyle(view);
}
SpatialFieldManager _sfm = SpatialFieldManager.GetSpatialFieldManager(view);
if (null == _sfm)
{
_sfm = SpatialFieldManager.CreateSpatialFieldManager(view, 1);
}
else if (0 < _sfp_index)
{
_sfm.RemoveSpatialFieldPrimitive(_sfp_index);
}
_sfp_index = _sfm.AddSpatialFieldPrimitive(faceReference);
if (_schemaId != -1)
{
List<int> results = _sfm.GetRegisteredResults().ToList();
foreach (int idx in results)
{
}
if (!results.Contains(_schemaId))
{
_schemaId = -1;
}
}
if (_schemaId == -1)
{
AnalysisResultSchema schema = new AnalysisResultSchema("Test", "Test Description");
//List<string> unitNames = new List<string>(new string[1] { "Score" });
//List<double> unitFactors = new List<double>(new double[1] { 1.0 });
//schema.SetUnits(unitNames, unitFactors);
if (_sfm.IsResultSchemaNameUnique("Test", -1))
_schemaId = _sfm.RegisterResult(schema);
else
{
List<int> existing = _sfm.GetRegisteredResults().ToList();
foreach (int idx in existing)
{
if (_sfm.GetResultSchema(idx).Name == "Test")
{
_schemaId = idx;
break;
}
}
}
}
return _sfm;
}
private void PaintFace(Document doc, SpatialFieldManager sfm, Element element, Face face, Dictionary<XYZ, double> ductMap)
{
//BoundingBoxUV bb = face.GetBoundingBox();
//UV min = bb.Min;
//UV max = bb.Max;
IList<UV> uvPts = new List<UV>();
//uvPts.Add(bb.Min); // adding these points created a successful gradient
//uvPts.Add(bb.Max); // adding these points created a successful gradient
IList<ValueAtPoint> uvValues = new List<ValueAtPoint>();
//uvValues.Add(new ValueAtPoint(new List<double> { 0.0 })); // adding these values created a successful gradient
//uvValues.Add(new ValueAtPoint(new List<double> { 10.0 })); // adding these values created a successful gradient
List<double> vals = new List<double>(1);
vals.Add(0);
foreach (KeyValuePair<XYZ, double> kvp in ductMap)
{
UV pt = new UV(kvp.Key.X, kvp.Key.Y);
uvPts.Add(new UV(kvp.Key.X, kvp.Key.Y));
vals[0] = kvp.Value;
uvValues.Add(new ValueAtPoint(vals));
}
FieldDomainPointsByUV pnts = new FieldDomainPointsByUV(uvPts);
FieldValues fVals = new FieldValues(uvValues);
sfm.UpdateSpatialFieldPrimitive(_sfp_index, pnts, fVals, _schemaId);
}
Solved! Go to Solution.
Solved by jeremy_tammik. Go to Solution.
Normally, the UV coordinates depend on the face. Simply converting the XYZ X and Y values directly to UV will not work.
To convert a XYZ point to the face UV space, you can use the Project method to project it from global 3D space onto the face 2D:
https://www.revitapidocs.com/2023/4bee3e30-74fa-3103-c2f4-d07618fbcedf.htm
Can't find what you're looking for? Ask the community or share your knowledge.