|
Does anyone know of a way to combine geometries of DrawingVisuals? For example, say you have a DrawingVisual that renders a rectangle, and another DrawingVisual that overlaps it that renders an ellipse. How would you combine (union) the two geometries to produce a new DrawingVisual that combines the rectangle of the first with the ellipse of the second? I know this can easily be done with XAML and CombinedGeometry, but I am doing this in code using DrawingVisuals. Any help would be appreciated. | | dmikon | DrawingVisual will not handle those types of operations. If you need to do intersections, xors, etc, you'll need something heavier weight. DrawingVisual is meant to be a very low level, very fast building block for creating drawings. It is not a full fledged image composition engine, with geometric intersection routines. From the docs : "DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text." If you want to do xors/intersections/etc, you'll need to use Geometry objects instead of DrawingVisual objects. In particular, the CombinedGeometry object allows you to combine multiple Geometry primitives, and specify how they are combined, using any of the GeometryCombineMode options, which include Union, Intersect, Xor, and Exclude.
Reed Copsey, Jr. - http://reedcopsey.com- Proposed As Answer byReed Copsey, Jr. Wednesday, September 23, 2009 5:07 PM
- Marked As Answer byZhi-Xin YeMSFT, ModeratorThursday, September 24, 2009 5:52 AM
-
| | Reed Copsey, Jr. | For those interested, here's a potential solution for this issue. The idea is basically to extract the underlying geometries from two DrawingVisuals and then use CombinedGeometry (as Reed has mentioned) to produce a combined geometry that can then be rendered in a DrawingVisual.
private void foo()
{
// dvOne and dvTwo are DrawingVisuals
// assume dvOne and dvTwo have been defined...
CombinedGeometry combGeo = new CombinedGeometry();
// add the first visual to the geometry
CombineGeometries(dvOne.Drawing, GeometryCombineMode.Union, ref combGeo);
// exclude the second visual's geometry from the first
CombineGeometries(dvTwo.Drawing, GeometryCombineMode.Exclude, ref combGeo);
// create a new DrawingVisual based on the new geometry
DrawingVisual dv = new DrawingVisual();
using (DrawingContext DC = dv.RenderOpen())
{
DC.DrawGeometry(someBrush, somePen, combGeo);
DC.Close();
}
}
private void CombineGeometries(DrawingGroup p_DrawingGroup, GeometryCombineMode p_CombineMode, ref CombinedGeometry p_CombinedGeometry)
{
if (p_CombinedGeometry == null)
p_CombinedGeometry = new CombinedGeometry();
DrawingCollection drawingCollection = p_DrawingGroup.Children;
foreach (Drawing drawing in drawingCollection)
{
if (drawing is DrawingGroup)
{
CombineGeometries((DrawingGroup)drawing, p_CombineMode, ref p_CombinedGeometry);
}
else if (drawing is GeometryDrawing)
{
GeometryDrawing geoDrawing = drawing as GeometryDrawing;
p_CombinedGeometry = new CombinedGeometry(p_CombineMode, p_CombinedGeometry, geoDrawing.Geometry);
}
}
}
I have not tested this thoroughly yet, but it seems to work so far. - Proposed As Answer byReed Copsey, Jr. Wednesday, September 23, 2009 5:07 PM
- Marked As Answer byZhi-Xin YeMSFT, ModeratorThursday, September 24, 2009 5:52 AM
-
| | dmikon | You can put both DrawingVisual instances into a single VisualCollection instance, and then use that. I believe this is done as part of the Hit Test Using Drawing Visuals sample on MSDN. Alternatively, you can just make a single DrawingVisual that does both of the renderings (ie: DrawRectangle(..) then DrawEllipse(..) in it's DrawingContext).
Reed Copsey, Jr. - http://reedcopsey.com- Edited byReed Copsey, Jr. Wednesday, September 23, 2009 12:10 AMAdded alternative
-
| | Reed Copsey, Jr. | Thanks for the suggestion, Reed. The problem is that I really do need to combine the two DrawingVisuals into one, so the first approach would not work. The problem with the second approach is that one DrawingVisual has already been rendered, and when I need to combine it with the second DrawingVisual, I have no idea what's been rendered within that visual. To give you an example, imagine you're trying to design a selection tool (similar to one found in most drawing programs such as Photoshop). The user creates a rectangular selection (as an example). Then, the user holds the shift key, and selects a circle, the idea being that when the user lets go of the mouse, the resulting selection will be the combination of the two. | | dmikon | VisualCollection should work perfectly for that. It will be a single Visual that contains both of the original DrawingVisual elements. Another option would be to just make a new DrawingVisual, and add the other two drawing visual's as child visual elements. DrawingVisual derives from ContainerVisual, which means it can have child visual elements. DrawingVisual compositeDV = new DrawingVisual(); compositeDV.Children.Add(ellipseVisual); compositeDV.Children.Add(rectangleVisual);
Reed Copsey, Jr. - http://reedcopsey.com | | Reed Copsey, Jr. | How would you handle other geometry operations in that case, such as Xor, exclude, and intercept? | | dmikon | DrawingVisual will not handle those types of operations. If you need to do intersections, xors, etc, you'll need something heavier weight. DrawingVisual is meant to be a very low level, very fast building block for creating drawings. It is not a full fledged image composition engine, with geometric intersection routines. From the docs : "DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text." If you want to do xors/intersections/etc, you'll need to use Geometry objects instead of DrawingVisual objects. In particular, the CombinedGeometry object allows you to combine multiple Geometry primitives, and specify how they are combined, using any of the GeometryCombineMode options, which include Union, Intersect, Xor, and Exclude.
Reed Copsey, Jr. - http://reedcopsey.com- Proposed As Answer byReed Copsey, Jr. Wednesday, September 23, 2009 5:07 PM
- Marked As Answer byZhi-Xin YeMSFT, ModeratorThursday, September 24, 2009 5:52 AM
-
| | Reed Copsey, Jr. | For those interested, here's a potential solution for this issue. The idea is basically to extract the underlying geometries from two DrawingVisuals and then use CombinedGeometry (as Reed has mentioned) to produce a combined geometry that can then be rendered in a DrawingVisual.
private void foo()
{
// dvOne and dvTwo are DrawingVisuals
// assume dvOne and dvTwo have been defined...
CombinedGeometry combGeo = new CombinedGeometry();
// add the first visual to the geometry
CombineGeometries(dvOne.Drawing, GeometryCombineMode.Union, ref combGeo);
// exclude the second visual's geometry from the first
CombineGeometries(dvTwo.Drawing, GeometryCombineMode.Exclude, ref combGeo);
// create a new DrawingVisual based on the new geometry
DrawingVisual dv = new DrawingVisual();
using (DrawingContext DC = dv.RenderOpen())
{
DC.DrawGeometry(someBrush, somePen, combGeo);
DC.Close();
}
}
private void CombineGeometries(DrawingGroup p_DrawingGroup, GeometryCombineMode p_CombineMode, ref CombinedGeometry p_CombinedGeometry)
{
if (p_CombinedGeometry == null)
p_CombinedGeometry = new CombinedGeometry();
DrawingCollection drawingCollection = p_DrawingGroup.Children;
foreach (Drawing drawing in drawingCollection)
{
if (drawing is DrawingGroup)
{
CombineGeometries((DrawingGroup)drawing, p_CombineMode, ref p_CombinedGeometry);
}
else if (drawing is GeometryDrawing)
{
GeometryDrawing geoDrawing = drawing as GeometryDrawing;
p_CombinedGeometry = new CombinedGeometry(p_CombineMode, p_CombinedGeometry, geoDrawing.Geometry);
}
}
}
I have not tested this thoroughly yet, but it seems to work so far. - Proposed As Answer byReed Copsey, Jr. Wednesday, September 23, 2009 5:07 PM
- Marked As Answer byZhi-Xin YeMSFT, ModeratorThursday, September 24, 2009 5:52 AM
-
| | dmikon |
|