As you said, Revit doesn't expose the color scheme of a view. There is another "program" that "knows" the color of a Room, namely the computer / the screen. This means that you can find the color of the rooms visible in the active view.
Steps:
- isolate (and deselect) a room
- zoom to fit
- find a point in the room
- find the screen coordinate of that point
- get the color using the windows functions of user32.dll.
using System;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.IO;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Automation;
Room r;
Document doc;
UIDocument uiapp;
StringBuilder sb = new StringBuilder();
View activeView = doc.ActiveView;
uiapp.Selection.SetElementIds(new List<ElementId>());
Category roomCat = doc.Settings.Categories.get_Item("Rooms");
Category colorfill = roomCat.SubCategories.get_Item("Color Fill");
if (!activeView.GetVisibility(colorfill))
{
TaskDialog.Show("warning","room colorfill is not visible");
return;
}
using (TransactionGroup tg = new TransactionGroup(doc, "GetRoomColor"))
{
tg.Start();
using (Transaction t = new Transaction(doc, "isolate room"))
{
t.Start();
doc.ActiveView.IsolateElementTemporary(r.Id);
uiapp.ShowElements( r.Id);
uiapp.RefreshActiveView();
t.Commit();
}
using (Transaction t = new Transaction(doc, "regenerate"))
{
t.Start();
doc.Regenerate();
uiapp.RefreshActiveView();
t.Commit();
}
// find outer boundary points
List<XYZ> boundaryPoints = new List<XYZ>();
SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions();
opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;
opt.StoreFreeBoundaryFaces = true;
foreach(var segmList in r.GetBoundarySegments(opt))
{
foreach(var _boundarySegment in segmList)
{
boundaryPoints.AddRange(_boundarySegment.GetCurve().Tessellate());
boundaryPoints.Remove(boundaryPoints.Last());
}
break; // consider only outer boundary
}
XYZ pointinRoom = boundaryPoints[0].Add(boundaryPoints[2]).Multiply(0.5);
// corner of 180 degrees will fail!!!
XYZ corner = boundaryPoints[1];
while (!r.IsPointInRoom(pointinRoom))
{
pointinRoom = pointinRoom.Add(corner).Multiply(0.5);
}
List<UIView> uiViewsWithActiveView = new List<UIView>();
foreach (UIView uiv in uiapp.GetOpenUIViews())
{
if (uiv.ViewId.IntegerValue == activeView.Id.IntegerValue) uiViewsWithActiveView.Add(uiv);
}
UIView ActiveUIView = uiViewsWithActiveView.FirstOrDefault();
if (uiViewsWithActiveView.Count>1)
{
// 2 or more windows showing the same view
// use Automation to find the active window
IntPtr revitHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
AutomationElement root = AutomationElement.FromHandle(revitHandle);
// find the container control for the open views
PropertyCondition workSpaceCondition
= new PropertyCondition(
AutomationElement.ClassNameProperty,
"MDIClient");
AutomationElement workspace = root.FindFirst(TreeScope.Descendants,workSpaceCondition);
//find the active window in the workspace == first childwindow
AutomationElement firstviewWindow = workspace.FindFirst(TreeScope.Children,Condition.TrueCondition);
PropertyCondition classCondition
= new PropertyCondition(
AutomationElement.ClassNameProperty,
"AfxFrameOrView110u");
//get clientrectangle
AutomationElement viewPane = firstviewWindow.FindFirst(TreeScope.Children,classCondition);
System.Windows.Rect boundingRect1;
object boundingRectNoDefault =
viewPane.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty, true);
//select uiview with identical clientrectangle
boundingRect1 = (System.Windows.Rect)boundingRectNoDefault;
foreach(UIView uiv in uiViewsWithActiveView)
{
Rectangle r1 = uiv.GetWindowRectangle();
if( r1.Left == boundingRect1.Left && r1.Top==boundingRect1.Top
&& r1.Right == boundingRect1.Right && r1.Bottom == boundingRect1.Bottom)
{
ActiveUIView = uiv;
break;
}
}
}
if (ActiveUIView==null) return;
// get screen coordinates of active view
Rectangle rect = ActiveUIView.GetWindowRectangle();
// get cornerpoints of active view
IList<XYZ> corners = ActiveUIView.GetZoomCorners();
XYZ p = corners[0];
XYZ q = corners[1];
// find screencoordinate of pointinRoom
double dX = activeView.RightDirection.DotProduct(pointinRoom.Subtract(p))/activeView.RightDirection.DotProduct(q.Subtract(p));
double dY = activeView.UpDirection.DotProduct(pointinRoom.Subtract(p))/activeView.UpDirection.DotProduct(q.Subtract(p));
int screenX = (int) (rect.Left + dX*(rect.Right-rect.Left));
int screenY = (int) (rect.Top + dY*(rect.Bottom-rect.Top));
sb.AppendLine(string.Format("screencoordinates: {0}, {1}",screenX,screenY));
// getcolor
System.Drawing.Color color = WindowHelper.GetPixelColor(screenX,screenY);
sb.AppendLine("RoomColor = "+ WindowHelper.ToRGBString( WindowHelper.ToRevitColor( color)));
tg.RollBack();
}
TaskDialog.Show("debug", sb.ToString());
using this helper class
public class WindowHelper
{
// ******************************************************************
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
static public System.Drawing.Color GetPixelColor(int x, int y )
{
IntPtr hdc = GetDC(IntPtr.Zero);
uint value2 = GetPixel(hdc,x,y);
uint pixel =GetPixel(hdc,x,y);
bool condition = pixel.Equals(value2);
int aant=0;
while (!condition && aant<1000)
{
aant++;
value2 = pixel;
pixel = GetPixel(hdc,x,y);
condition = pixel.Equals(value2);
}
ReleaseDC(IntPtr.Zero, hdc);
System.Drawing.Color color = System.Drawing.Color.FromArgb(
(byte)(pixel & 0x000000FF),
(byte)((pixel & 0x0000FF00) >> 8),
(byte)((pixel & 0x00FF0000) >> 16));
return color;
}
Add References:
System.Windows.Forms
UIAutomationClient
UIAutomationTypes
WindowBase