FBX_LIGHT_PHOTOMETRIC_FILE, absolute IES path issue

FBX_LIGHT_PHOTOMETRIC_FILE, absolute IES path issue

Revitalizer
Advisor Advisor
2,675 Views
9 Replies
Message 1 of 10

FBX_LIGHT_PHOTOMETRIC_FILE, absolute IES path issue

Revitalizer
Advisor
Advisor

Hi Jeremy,

I've faced a very different behavior when setting the "Photometric File"/BuiltInParameter.FBX_LIGHT_PHOTOMETRIC_FILE parameter via API or GUI.

When setting it via GUI, I use to set the file path to an *ies file.

The data of the ies file is stored in another parameter, BuiltInParameter.FBX_LIGHT_PHOTOMETRIC_FILE_CACHE, as you have already documented:
http://thebuildingcoder.typepad.com/blog/2016/01/loading-an-ies-photometric-web-and-exciting-times.h...

In the blog posting, it is mentioned that setting the parameter will update the buffer parameter.

I myself don't use a FamilySymbol's parameter but the built-in *FamilyParameter*, but that should not make a difference.
Also, the behavior is the same in Revit 2015 and 2017.

When setting the parameter via API, the result is completely different.
I set the parameter using the full ies file path.
This value is also displayed when opening the family manually.

The problem is when the family is ported from one computer to another one.
I deliver the family but not the ies file.
In this case the stored (absolute) file path does not point to a valid ies file on the customer's computer.

The then visible ies data, that means the light source geometry made of the ies data stored in the family, differs from the original ies file's content.
Seems that it is reset to a former state.

Also, the family cannot be opened again if the ies file defined in the parameter does not exist.

That's a bug.

To work around this, I use Journal files to set the IES Parameter since it simulates the manual user input.

Since I need to set the  parameter with several thousand Families, this is not an acceptable solution.

 

By the way, what is that, Autodesk?

 

Autodesk joke.png

 

Regards,

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Accepted solutions (1)
2,676 Views
9 Replies
Replies (9)
Message 2 of 10

jeremytammik
Autodesk
Autodesk

Dear Revitalizer,

 

Thank you for your query and sorry you have not received any answer yet to this.

 

Is this still an issue for you?

 

Have you made any progress on implementing a workaround?

 

I just saw that a new ADN case was raised that refers to this thread: 14390212 [IES-File und Revit Familien], raised by Contelos GmbH.

 

Do you know that company?

 

Best regards from Brassac in Occitanie,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 10

Revitalizer
Advisor
Advisor
Accepted solution

Hi Jeremy,

 

the issue is solved.

 

All I needed was to search for "*IES*" in the RevitAPI.chm.

The IES parameter must be set in an indirect way.

In the LightFamily.SetLightDistributionStyle page, there is a code sample:

 

public void ModifyLightDistributionStyle(Document familyDoc)
{
    // Get the light family from the static method.
    LightFamily lightFamily = LightFamily.GetLightFamily(familyDoc);

    // Set the light distribution style to PhotometricWeb
    lightFamily.SetLightDistributionStyle(LightDistributionStyle.PhotometricWeb);

    // After light shape style set to PhotometricWeb, each tyoe returns a CircleLightShape instance,
    for (int index = 0; index < lightFamily.GetNumberOfLightTypes(); index++)
    {
        LightType lightData = lightFamily.GetLightType(index);
        PhotometricWebLightDistribution lightDistribution = 
            lightData.GetLightDistribution() as PhotometricWebLightDistribution;
        lightDistribution.PhotometricWebFile = @"C:\IES\1x4 2Lamp.ies"; // input a full file path here.
        lightDistribution.TiltAngle = Math.PI / 6;    // use radian value to set
        lightData.SetLightDistribution(lightDistribution);  // set back
    }
}

So, in fact, it was a self-RTFM.

 

By the way, I don't know why the BuiltInParameter can be set, it should be readonly if setting it does not reflect UI behavior.

Currently, it is misleading.

 

Happy holidays,

Rudi

 




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 4 of 10

Anonymous
Not applicable

Hi Revitalizer,

 

I'm currently struggling with the same issue that you managed to solve (ies file path instead of file name for "Photometric Web File" parameter).

I've tried to use the solution you posted, but unfortunately it is still not working for me.

 

Here is my piece of code:

 

for (int index = 0; index < lightFamily.GetNumberOfLightTypes(); index++)
            {
                LightType lightData = lightFamily.GetLightType(index);
                string lightTypeName = lightFamily.GetLightTypeName(index);

                for (int k = 0; k < fileIesList.Count; k++)
                {
                    if (lightTypeName == typeName[k])
                    {
                        lightFamily.SetLightDistributionStyle(LightDistributionStyle.PhotometricWeb);
                        PhotometricWebLightDistribution lightDistribution = lightData.GetLightDistribution() as PhotometricWebLightDistribution;
                        lightDistribution.PhotometricWebFile = fileIesList[k];
                        //lightDistribution.TiltAngle = Math.PI / 6;    // use radian value to set
                        lightData.SetLightDistribution(lightDistribution);  // set back

                        InitialColor initColor = lightData.GetInitialColor();
                        CustomInitialColor customInitialColor = initColor as CustomInitialColor;
                        double colorTemperature = customInitialColor.Temperature;
                        customInitialColor.Temperature = Convert.ToDouble(initialColor[k]);
                        lightData.SetInitialColor(customInitialColor);

                        if (wattage[k] == 0)
                        {
                            wattage[k] = 1;
                        }

                        double efficacy = luminousFlux[k] / wattage[k];
                        lightData.SetInitialIntensity(new InitialWattageIntensity(efficacy, wattage[k]));
                        lightData.SetInitialIntensity(new InitialFluxIntensity(luminousFlux[k]));
                    }
                }
            }

PLEASE NOTE: in the code, the fileIesList[k] variable contains all the full paths of the .ies files.

 

Comparing my code to your I cannot see any difference...

But still the behaviour in my case is not fixed; this is in short how it works:

 

the plugin as a whole creates multiple types, starting from a "template" .rfa which doesn't contain any type.

For any type created in the .rfa, the plugin loads one .ies file (located in a folder chosen by the user) and sets the values of some parameters (including Initial Color, Wattage, Efficacy, Luminous Flux, etc...).

The values of the parameters are read from the .ies file itself. Then the .rfa file is saved.

 

HERE COMES THE ISSUE: in the saved .rfa, only the last type (the last created with the "for" loop) has the correct file name in the Photometric Web File parameter; all the others, instead, still present the full path.

Furthermore, the values of the other parameters (mentioned above) are set correctly only for the types which have the full path in the "Photometric Web File" parameter. In the only type for which the file name is set correctly, instead, the other parameters are left to the default values (as set in the "template" .rfa).

 

In attachment, a couple of screenshots to show the issue.

 

Can you help me to understand what I did wrong?

 

Let me know if you need more information from my side.

 

Any help will be greatly appreciated.

Thanks

 

 

0 Likes
Message 5 of 10

jeremytammik
Autodesk
Autodesk

It might help a lot if you clarify your data structures.

 

You inner loop looks rather suspicious to me.

 

  for (int k = 0; k < fileIesList.Count; k++)
  {
      if (lightTypeName == typeName[k]) ...

 

Where does the `typeName` array or list come from?

 

Why do you loop through the entire list each time to find the desired name? 

  

I would suggest that you restructure your data to enable a more efficient search.

 

If you need to search by type name, then implement a dictionary taking the type name as a key and returning the desired data object, e.g., Dictionary<string,string> mapping type name to file path or whatever it is you need.

 

That will make your code much easier to read and much more efficient to boot.

 

Cheers,

 

Jeremy

 

 

 

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 6 of 10

Anonymous
Not applicable

Hi Jeremy,

Thanks for your suggestion; it would definitely improve the performance this way.

In any case, I don't think that it would affect the behaviour for what concerns the mentioned issue...

 

I'll try to clarify the data structure I used for the part of code you highlighted:

1. lightTypeName is the list of all the types, which are created previously in the code;

2. typeName is another list, previously created, which has the same number of elements of lightTypeName, and contains all the strings of the names of the types.

 

The if (lightTypeName == typeName[k]) … statement you highlighted means that, when the statement is true, the plugin

writes the full path in the PhotometricWebFile parameter. The full path is taken from a third list, named fileIesList, which contains

all the full paths of the .ies files and obviously has the same number of elements of the other 2 lists.

 

In the specific case of the example I posted previously, the list values are the following:

typeName contains:

071451_BLIZ ROUND 40 40W 5000K 0÷10V

079421_MAGICLICK ROUND 25 LED 26W 4000K

079877_MIMIK 50 B TYPE II 39+39W 830 EM90' 0-10V / Main

079877_MIMIK 50 B TYPE II 39+39W 830 EM90' 0-10V / Battery

fileIesList contains:

C:\Plugin\PRODUCT\PIL_071451.IES

C:\Plugin\PRODUCT\PIL_079421.IES

C:\Plugin\PRODUCT\PIL_079877_MainsVoltage.IES

C:\Plugin\PRODUCT\PIL_079877_OnBattery.IES

 

PLEASE NOTE: In the screenshot uploaded in the previous post, you can see only 2 types instead of 4 because the plugin split

the types between two distinct files, according to the different shape of the Emitting surface (circle and rectangle).

 

 

I'll copy below a bigger part of the code, I hope this can help you better understand the data structure.

 

private void Create_rfa_files()
    {
        this.doc = application.OpenDocumentFile(get_rfa_template.rfaTemplateFile);
        //doc.Save();
        if (Get_family_types_in_family() > 0)
        {
            Reset_window();
            return;
        }

        folderName.Clear();
        shapeType.Clear();
        destinationFileList.Clear();

        foreach (DataGridViewRow item2 in (IEnumerable)this.dgv2.Rows)
        {
            folderName.Add(item2.Cells[0].Value.ToString());
            shapeType.Add(item2.Cells[2].Value.ToString());
        }

        Create_short_folder_list();

        this.int4 = int4 + 1;
        this.Progress_bar();

        for (int i = 0; i < shortFolderList.Count; i++)
        {
            this.int4 = int4 + 1;
            this.Progress_bar();

            this.doc = application.OpenDocumentFile(get_rfa_template.rfaTemplateFile);
            //doc.Save();

            //foreach (FileInfo fileInfo in new DirectoryInfo(get_rfa_template.rfaTemplatePath).GetFiles("*.00*.rfa"))
            //{
            //    fileInfo.Delete();
            //}

            Get_family_types_in_family();

            FamilyManager familyManager = this.doc.FamilyManager;
            FamilyTypeSet famTypes = familyManager.Types;

            Transaction transaction = new Transaction(doc);

            //Add_existing_family_param_names();

            transaction.Start("Add Type to Family");

            LightFamily lightFamily = LightFamily.GetLightFamily(doc);

            for (int j = 0; j < folderName.Count; j++)
            {
                this.int4 = int4 + 1;
                this.Progress_bar();

                if (shortFolderList[i] == folderName[j] && shortShapeList[i] == shapeType[j])
                {
                    if (familyManager.CurrentType.Name != typeName[j])
                    {
                        familyManager.NewType(typeName[j]);

                        if (dgv2.Rows[j].Cells[2].Value.ToString() == "Circle")
                        {
                            lightFamily.SetLightShapeStyle(LightShapeStyle.Circle);

                            FamilyParameter familyParam = familyManager.get_Parameter("Emit from Circle Diameter");
                            familyManager.Set(familyParam, (circleDiameter[j] / _feet_to_mm) * (-1000));
                        }

                        if (dgv2.Rows[j].Cells[2].Value.ToString() == "Rectangle")
                        {
                            lightFamily.SetLightShapeStyle(LightShapeStyle.Rectangle);

                            FamilyParameter familyParam = familyManager.get_Parameter("Emit from Rectangle Length");
                            familyManager.Set(familyParam, (rectangleLength[j] / _feet_to_mm) * 1000);

                            familyParam = familyManager.get_Parameter("Emit from Rectangle Width");
                            familyManager.Set(familyParam, (rectangleWidth[j] / _feet_to_mm) * 1000);
                        }

                        {
                            FamilyParameter familyParam = familyManager.get_Parameter("Lamp");
                            familyManager.Set(familyParam, sourceType[j]);
                        }

                        {
                            FamilyParameter familyParam = familyManager.get_Parameter("Emit Shape Visible in Rendering");
                            if (Convert.ToBoolean(dgv2.Rows[j].Cells[3].Value))
                            {
                                familyManager.Set(familyParam, 1);
                            }
                            else
                            {
                                familyManager.Set(familyParam, 0);
                            }
                        }

                        {
                            //FamilyParameter familyParam = familyManager.get_Parameter("Photometric Web File");
                            //familyManager.Set(familyParam, fileIesList[j]);
                        }
                    }
                }
            }

            for (int index = 0; index < lightFamily.GetNumberOfLightTypes(); index++)
            {
                LightType lightData = lightFamily.GetLightType(index);
                string lightTypeName = lightFamily.GetLightTypeName(index);

                for (int k = 0; k < fileIesList.Count; k++)
                {
                    if (lightTypeName == typeName[k])
                    {
                        lightFamily.SetLightDistributionStyle(LightDistributionStyle.PhotometricWeb);
                        PhotometricWebLightDistribution lightDistribution = lightData.GetLightDistribution() as PhotometricWebLightDistribution;
                        lightDistribution.PhotometricWebFile = fileIesList[k];
                        //lightDistribution.TiltAngle = Math.PI / 6;    // use radian value to set
                        lightData.SetLightDistribution(lightDistribution);  // set back

                        InitialColor initColor = lightData.GetInitialColor();
                        CustomInitialColor customInitialColor = initColor as CustomInitialColor;
                        double colorTemperature = customInitialColor.Temperature;
                        customInitialColor.Temperature = Convert.ToDouble(initialColor[k]);
                        lightData.SetInitialColor(customInitialColor);

                        if (wattage[k] == 0)
                        {
                            wattage[k] = 1;
                        }

                        double efficacy = luminousFlux[k] / wattage[k];
                        lightData.SetInitialIntensity(new InitialWattageIntensity(efficacy, wattage[k]));
                        lightData.SetInitialIntensity(new InitialFluxIntensity(luminousFlux[k]));
                    }
                }
            }

            familyManager.Dispose();
            transaction.Commit();

            //ModifyLightDistributionStyle(doc,i);

            string fileName = "";
            if (shortShapeList[i] == "Circle")
            {
                fileName = shortFolderList[i] + "_Photometrics_C";
            }
            if (shortShapeList[i] == "Rectangle")
            {
                fileName = shortFolderList[i] + "_Photometrics_R";
            }

            string destinationFile = select_destination_folder.destinationFolderName + "\\N1_" + fileName + ".rfa";

            if (File.Exists(destinationFile))
            {
                File.Delete(destinationFile);
            }

            doc.SaveAs(destinationFile);
            destinationFileList.Add(destinationFile);

            if (transaction != null)
            {
                ((IDisposable)transaction).Dispose();
            }
        }

Hope this can clarify… If necessary I'll give further explanation.

 

Thanks a lot.

 

 

 

0 Likes
Message 7 of 10

Anonymous
Not applicable

Hi Jeremy,

 

I see that trying to explain the complexity of my plugin as a whole is too difficult and time wasting both for me and for you…

So, I’ve simplified it the most I can. I’ve written a simple code in which there are no lists and variables but all the values to be set are explicit.

 

Here it is:

 

private void Create_rfa_files()
    {
        this.doc = application.OpenDocumentFile(@"C:\Users\bianc\Desktop\Template1.rfa");

        Transaction transaction = new Transaction(doc);
        transaction.Start("Set IES file");

        LightFamily lightFamily = LightFamily.GetLightFamily(doc);
        lightFamily.SetLightDistributionStyle(LightDistributionStyle.PhotometricWeb);

        for (int index = 0; index < lightFamily.GetNumberOfLightTypes(); index++)
        {
            LightType lightData = lightFamily.GetLightType(index);

            PhotometricWebLightDistribution lightDistribution = lightData.GetLightDistribution() as PhotometricWebLightDistribution;
            lightDistribution.PhotometricWebFile = @"C:\Users\bianc\Desktop\PIL_071451.IES";
            lightDistribution.TiltAngle = Math.PI / 2;    // use radian value to set
            lightData.SetLightDistribution(lightDistribution);  // set back

            InitialColor initColor = lightData.GetInitialColor();
            CustomInitialColor customInitialColor = initColor as CustomInitialColor;
            double colorTemperature = customInitialColor.Temperature;
            customInitialColor.Temperature = 2577;
            lightData.SetInitialColor(customInitialColor);

            double efficacy = 9387.55 / 123.33;
            lightData.SetInitialIntensity(new InitialWattageIntensity(efficacy, 123.33));
            lightData.SetInitialIntensity(new InitialFluxIntensity(9387.55));
        }

        transaction.Commit();

        string destinationFile = @"C:\Users\bianc\Desktop\familyTest.rfa";
        doc.SaveAs(destinationFile);
    }

 

As you can see, the code takes one .rfa file as a starting point (Template1.rfa).

The .rfa has already two types in it (see Template1.jpg as a reference)

For every type, the “for” cycle writes the same values for Initial Intensity, Initial Color, Tilt Angle and Photometric Web File parameters.

 

As you can see in the two attached files named Type1.jpg and Type2.jpg, the issue I mentioned in my first message is still the same:

  • For Type1, the values of the parameters Initial Intensity and Initial Color are set to their correct values, but the Photometric Web File parameter presents the full path;
  • For Type2, instead, the values of Initial Intensity and Initial Color are left to their default values, but the .IES file is loaded correctly.

Tilt Angle seems to be set correctly for both types.

 

As already said, if the file contains more than two types, only the last processed will behave like “Type2” in the example, while all the others will behave like “Type1” in the example.

 

Am I doing something wrong? Or this issue cannot be fixed (for the moment at least)?

 

PLEASE NOTE: I have tried it with Revit versions 2017, 2018, 2019 and 2020, and the behaviour is always the same.

 

 

Any help will be greatly appreciated.

Thanks in advance.

 

0 Likes
Message 8 of 10

franjavigarciavalencia
Enthusiast
Enthusiast

I had the same exact problem and it seems that setting the parameter with the FamilyManager afterward fixes the problem.

 

// The parameter's name will change depending on Revit's language

FamilyParameter familyParameter = doc.FamilyManager.get_Parameter("Photometric Web File");
doc.FamilyManager.Set(familyParameter, @"C:\Users\bianc\Desktop\PIL_071451.IES");

 

If it doesn't work straight away, try to doc.Regenerate() before setting the parameter.

0 Likes
Message 9 of 10

Anonymous
Not applicable

Thank you for you update.

Unfourtunately, your suggestion corresponds to what I'm already doing.

 

This way, in the "Photometric Web File" parameter is written the whole path of the folder from which the plugin uploads the .ies file itself.

 

This is exactly what I want to avoid, because this way the .ies file is referenced externally and whenever I move it from its original location (or if I send the .rfa file to another person), the .ies file is no more readable inside the .rfa file.

 

What I want to obtain is to reproduce exactly with the plugin the manual uploading of a .ies file inside the "Photometric Web File" parameter, which is: you do not see the complete path anymore, but only the name of the .ies file, which is this way "loaded" inside the .rfa file.

 

If you have further suggestions on this topic, please let me know.

 

Thanks a lot.

Bye

0 Likes
Message 10 of 10

franjavigarciavalencia
Enthusiast
Enthusiast

Hello

What I suggest is using both methods, not just one. That's what fixed my problem which seems to be the same as yours.

private void Create_rfa_files()
    {
        this.doc = application.OpenDocumentFile(@"C:\Users\bianc\Desktop\Template1.rfa");

        Transaction transaction = new Transaction(doc);
        transaction.Start("Set IES file");

        LightFamily lightFamily = LightFamily.GetLightFamily(doc);
        lightFamily.SetLightDistributionStyle(LightDistributionStyle.PhotometricWeb);

        for (int index = 0; index < lightFamily.GetNumberOfLightTypes(); index++)
        {
            LightType lightData = lightFamily.GetLightType(index);

            PhotometricWebLightDistribution lightDistribution = lightData.GetLightDistribution() as PhotometricWebLightDistribution;
            lightDistribution.PhotometricWebFile = @"C:\Users\bianc\Desktop\PIL_071451.IES";
            lightDistribution.TiltAngle = Math.PI / 2;    // use radian value to set
            lightData.SetLightDistribution(lightDistribution);  // set back

            InitialColor initColor = lightData.GetInitialColor();
            CustomInitialColor customInitialColor = initColor as CustomInitialColor;
            double colorTemperature = customInitialColor.Temperature;
            customInitialColor.Temperature = 2577;
            lightData.SetInitialColor(customInitialColor);

            double efficacy = 9387.55 / 123.33;
            lightData.SetInitialIntensity(new InitialWattageIntensity(efficacy, 123.33));
            lightData.SetInitialIntensity(new InitialFluxIntensity(9387.55));
        }
        doc.Regenerate();

        FamilyParameter familyParameter = doc.FamilyManager.get_Parameter("Photometric Web File");
        doc.FamilyManager.Set(familyParameter, @"C:\Users\bianc\Desktop\PIL_071451.IES");

        transaction.Commit();

        string destinationFile = @"C:\Users\bianc\Desktop\familyTest.rfa";
        doc.SaveAs(destinationFile);
    }

 

Cheers.

0 Likes