Expalanation about WPF concept in unleashed WPF 4.0 book - wpf

Can anyone expalin what does the point ( 0,0) refers to within the CompositionTarget_Rendering . I could understand that the cube rotates around the Y axis, but what I cannot understand how could it be that the 2D point 0,0 always relates to the same corner of the cube while it's rotating. In terms of objects, we have the big cube, the small cube, and, as per my undesrtanding, we have a button that is interactive but at the end of the day is USED as brush (not as an object in the 3D sense). I envision a space where a cube stands up and rotates around a vertical axis Y, but how the placement of the scaled down purple cube winds up with the same relative position with respect to the big cube, namely, one particular top corner of the big cube. The book says "the Point (0,0) from the Viewport2DVisual3D’s hosted Button
is mapped into 3D space, and a purple cube is drawn where that Point3D lies in 3D space"
and I am confused because the sentence implies that the button is situated somewhere on a 2d layer (supposedly behaind the 3D space) but the button is EVERYWHERE in that it is used to "paint" each of the side of the cubes. What is the best way to envision this 3D space in relation to the 2D layer and the button?
It will also be good to know why the purple small cube revolves around itself, as I could only see the that the trigger rotates the big cube, and the rendering event places the small cube at a fixed position WITHOUT rotating it.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Name="myGrid">
<Viewport3D Panel.ZIndex="0">
<Viewport3D.Camera>
<PerspectiveCamera Position="3,3,4" LookDirection="-1,-1,-1" FieldOfView="60"/>
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Direction="-0.3,-0.4,-0.5" />
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D x:Name="Container">
<Viewport2DVisual3D >
<Viewport2DVisual3D.Transform>
<Transform3DGroup>
<TranslateTransform3D OffsetX="1.5" />
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="rotationY" Axis="0,1,0" Angle="0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Transform3DGroup>
</Viewport2DVisual3D.Transform>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D Positions="1,1,-1 1,-1,-1 -1,-1,-1 -1,1,-1 1,1,1 -1,1,1 -1,-1,1 1,-1,1 1,1,-1 1,1,1 1,-1,1 1,-1,-1 1,-1,-1 1,-1,1 -1,-1,1 -1,-1,-1 -1,-1,-1 -1,-1,1 -1,1,1 -1,1,-1 1,1,1 1,1,-1 -1,1,-1 -1,1,1"
TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7 8 9 10 8 10 11 12 13 14 12 14 15 16 17 18 16 18 19 20 21 22 20 22 23"
TextureCoordinates="0,1 0,0 1,0 1,1 1,1 -0,1 0,-0 1,0 1,1 -0,1 0,-0 1,0 1,0 1,1 -0,1 0,-0 -0,0 1,-0 1,1 0,1 1,-0 1,1 0,1 -0,0"/>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/>
</Viewport2DVisual3D.Material>
<Button Name="TestButton">
<Button.RenderTransform>
<ScaleTransform ScaleY="-1" />
</Button.RenderTransform>
Hello, 3D
</Button>
</Viewport2DVisual3D>
</ModelVisual3D>
<ModelUIElement3D>
<ModelUIElement3D.Transform>
<Transform3DGroup>
<ScaleTransform3D ScaleX="0.2" ScaleY="0.2" ScaleZ="0.2" />
<TranslateTransform3D x:Name="cube_translation" />
</Transform3DGroup>
</ModelUIElement3D.Transform>
<ModelUIElement3D.Model>
<GeometryModel3D>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Purple" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="1,1,-1 1,-1,-1 -1,-1,-1 -1,1,-1 1,1,1 -1,1,1 -1,-1,1 1,-1,1 1,1,-1 1,1,1 1,-1,1 1,-1,-1 1,-1,-1 1,-1,1 -1,-1,1 -1,-1,-1 -1,-1,-1 -1,-1,1 -1,1,1 -1,1,-1 1,1,1 1,1,-1 -1,1,-1 -1,1,1"
TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7 8 9 10 8 10 11 12 13 14 12 14 15 16 17 18 16 18 19 20 21 22 20 22 23"
TextureCoordinates="0,1 0,0 1,0 1,1 1,1 -0,1 0,-0 1,0 1,1 -0,1 0,-0 1,0 1,0 1,1 -0,1 0,-0 -0,0 1,-0 1,1 0,1 1,-0 1,1 0,1 -0,0"/>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelUIElement3D.Model>
</ModelUIElement3D>
</Viewport3D.Children>
</Viewport3D>
</Grid>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded" >
<BeginStoryboard>
<Storyboard Name="myStoryBoardY">
<DoubleAnimation
Storyboard.TargetName="rotationY"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:12" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
static TimeSpan lastRenderTime = new TimeSpan();
void CompositionTarget_Rendering(object sender, EventArgs e)
{
// Ensure we only do this once per frame
if (lastRenderTime == ((RenderingEventArgs)e).RenderingTime)
return;
lastRenderTime = ((RenderingEventArgs)e).RenderingTime;
GeneralTransform2DTo3D transform = TestButton.TransformToAncestor(Container);
Point3D point = transform.Transform(new Point(0, 0));
cube_translation.OffsetX = point.X;
cube_translation.OffsetY = point.Y;
cube_translation.OffsetZ = point.Z;
}
}

The (0,0) here refers to the 2D coordinates in the Button referential. It is the top left corner of the button. There 6 different visualisations of the same button here but it seems that WPF assumes that the real one is on the first triangle that contains this point of the button.
In this case it is actually the first triangle of the first face. This face is pointing to the negative Z direction (1,1,-1 1,-1,-1 -1,-1,-1 -1,1,-1).
To actually see this you can setup the camera to point to the positive direction so you can see this face of the cube:
<PerspectiveCamera Position="0,0,-10" LookDirection="0,0,1" FieldOfView="60"/>
Set the light to point in positive direction:
<DirectionalLight Direction="-0.3,-0.4,0.5" />
Remove the triger to avoid animation and replace (0,0) in with (27, 12) (it is about the center of the button).
You should see the red cube in the middle of the face pointing towards the camera (the neagtive Z face).
You can also try to remove the first triangle (remove just the first 3 triangle indices). In this case the red cube will move to the positive Z face.

Related

IndexedFaceSet creates extra faces in x3d file

I have created an x3d file using x3dom. Following is the structure of the file. Copy the following code into text editor and save it as .x3d file. For imgage texture you can consider any jpg file and place it at the same location as x3d.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN"
"http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D profile='Interchange' version='3.0'
xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance'
xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.0.xsd'>
<Scene>
<NavigationInfo type='"EXAMINE" "WALK" "FLY" "ANY"'/>
<DirectionalLight intensity="0.8" direction="0 1 0"/>
<DirectionalLight intensity="0.9" direction="0 -1 0"/>
<DirectionalLight intensity="0.6" direction="1 0 -1"/>
<DirectionalLight intensity="0.6" direction="-1 0 -1"/>
<DirectionalLight intensity="0.6" direction="-1 0 1"/>
<DirectionalLight intensity="0.6" direction="1 0 1"/>
<Shape>
<Appearance>
<Material ambientIntensity="0.2" diffuseColor="0.004 0.004 0.004" emissiveColor="0 0 0" shininess="0.2" specularColor="0 0 0" transparency="0"/>
<ImageTexture url="Penguins.jpg"/>
</Appearance>
<IndexedFaceSet convex="true" coordIndex="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -1 " ccw="true">
<Coordinate point="132.2349 0 329.9732 123.0347 0 336.9273 109.9391 0 350.0229 102.985 0 359.223 82.26761 0 386.6317 69.30841 0 436.438 74.03987 0 470.4683 78.77134 0 504.4987 104.8261 0 548.8805 132.2349 0 569.598 191.8598 0 569.598 191.8598 0 689.9727 911.8589 0 689.9727 1032.234 0 569.598 1032.234 0 270.3483 852.2339 0 270.3483 852.2339 0 210.7232 371.8596 0 210.7232 371.8596 0 329.9732"/>
</IndexedFaceSet>
</Shape>
<Viewpoint description="Center of Space" fieldOfView="0.785" position="553.1368 60 450.348"/>
</Scene>
</X3D>
Looking it from the top view the 3D object looks like this,
enter image description here
And from the bottom view it looks like this,
enter image description here
I have checked all the points and they are in proper sequence but not sure why these two extra faces are created. Anything I am doing wrong here?
You draw a non-convex shape, therefor you need to set convex to false, in addition if you want to see your shape from "behind" you need to set solid to false.
This works:
<IndexedFaceSet convex="false" solid="false" coordIndex="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -1">
(you dont need ccw, its true by default)

xaml path data for arrow

I have trying to draw simple "up" arrow by this code:
<Canvas Width="500" Height="500">
<Path Height="120" Width="120" StrokeThickness="1" Stroke="Red" Data="M 60,60 L 60,0 L 50,10 L 60,0 L 70,10"/>
</Canvas>
And I don't see symmetric arrow on my screen.
I want to understand this "magic".
You have created a Path that is 120x120. Coordinate 0,0 is the upper-left corner.
M 60, 60 -> Move to the very center of the Path object x=60,y=60
L 60,0 -> Draw a Line from the last coordinate (60,60) to x=60,y=0 (straight up)
L 50,10 -> Draw a Line from the last coordinate (60,0) to x=50,y=10 (to the left 10 and down 10)
L 60, 0 -> Draw a Line from the last coordinate (50,10) to x=60, y=0 (retrace your line up and to the right by 10 each)
L 70,10 -> Draw a Line from the last coordinate (60,0) to x=70,y=10 ( to right 10 and down 10)
The reason that it is not symmetrical is because you are backtracking along the left arm of the arrow. This adds a join at that point, and essentially adds more to the line there because of your stroke thickness.
You can fix that like this:
<Path Height="120" Width="120"
StrokeThickness="1" Stroke="Red" Data="M 60,60 L 60,0 L 50,10 M60,0 L70,10"/>

Draw Cylinder Path in Expression Blend 4

I am trying to "draw" a simple cylinder path in Expression Blend 4, and I can't seem to get it quite right.
(1) I started out by adding two Ellipses and one Rectangle:
<Grid Background="Transparent">
<Ellipse Fill="Transparent" Height="13.25" Margin="352,0,352,227" Stroke="Black" VerticalAlignment="Bottom"/>
<Rectangle Fill="Transparent" Margin="352,216,352,233" Stroke="Black"/>
<Ellipse Fill="Transparent" Height="13.25" Margin="352,209.625,352,0" Stroke="Black" VerticalAlignment="Top"/>
</Grid>
(2) Next, I selected the bottom Ellipse and Rectangle, and performed a Combine -> Unite:
<Grid Background="Transparent">
<Path Data="M0.5,0.5 L47.5,0.5 47.5,47.375 47.5,47.5 47.493931,47.5 47.492325,47.533089 C47.170608,50.84277 36.775898,53.5 24,53.5 11.2241,53.5 0.82939076,50.84277 0.50767487,47.533089 L0.50606853,47.5 0.5,47.5 0.5,47.375 z" Fill="Transparent" Margin="352,216,352,227" Stretch="Fill" Stroke="Black"/>
<Ellipse Fill="Transparent" Height="13.25" Margin="352,209.625,352,0" Stroke="Black" VerticalAlignment="Top"/>
</Grid>
(3) Next, I selected the top Ellipse and the Path resulting from step 2 and then performed a Path -> Make Compound Path. Then with the direct selection tool, I removed the line cutting though the top Ellipse. It looks good until I try and apply a Fill="Green" to the Path.
<Grid Background="Transparent">
<Path Fill="Green" Data="M47.5,6.875 L47.5,53.75 47.5,53.875 47.493931,53.875 47.492325,53.908089 C47.170608,57.21777 36.775898,59.875 24,59.875 11.2241,59.875 0.82939076,57.21777 0.50767487,53.908089 L0.50606853,53.875 0.5,53.875 0.5,53.75 0.5,6.875 M47.5,6.625 C47.5,10.007744 36.978692,12.75 24,12.75 11.021308,12.75 0.5,10.007744 0.5,6.625 0.5,3.2422559 11.021308,0.5 24,0.5 36.978692,0.5 47.5,3.2422559 47.5,6.625 z" Margin="352,209.625,352,227" Stretch="Fill" Stroke="Black"/>
</Grid>
I've tried various operations, but I can't for the life of me figure out how to get a cylindrical Path where I can apply a Fill to the entire thing.
Don't know how to do that in Blend, but that figure could be made up of two arcs for (two halves of) the upper ellipse, one line down, one arc for the lower half ellipse, one line up and a final arc for half of the upper ellipse:
<Path Stroke="Black" Fill="LightGreen" Stretch="Fill" Data="
M0,0
A50,10 0 0 0 100,0
A50,10 0 0 0 0,0
M100,00 L100,100
A50,10 0 0 1 0,100
L0,0
A50,10 0 0 0 100,0" />
Is there a way to make it tilted tho? I am trying to shift this to give it an near-isometric look, but can't quite figure it out. Would the way to go be to have the circle shifted? So that the sides are at 10 and 4 or similar (as on a clock)?
Been working on this, but I either get an overlap in the bottom left, or some pixels outside of the circle.
<Path Stroke="Black" Fill="AliceBlue" Data="
M 0 0
A 45,40 0 0 0 100,0
A 45,40 0 0 0 0,0
L 15,-100
A 45,40 0 0 1 115,-100
L 100,0
A 45,40 0 0 0 0,0
"/>
EDIT: I more or less managed now, some minor tweaks and it should be there, the trick was to rotate the circles before adding the lines.
<Path Stroke="Black" Fill="AliceBlue" Data="
M 0 0
A 45,40 0 0 0 100,45
A 45,40 0 0 0 0,0
L 60,-100
A 45,40 0 0 1 160,-60
L 100,45
A 45,40 0 0 0 0,0
"/>

WPF: is it possible to render a circle using GeometryDrawing?

I've got a GeometryDrawing similar like this:
<DrawingImage x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type wpfhlp:FokusGroupBox},ResourceId=IconTest}">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Black" Geometry="M0,260 L0,600 L110,670 L110,500 L190,550 L190,710 L300,775 L300,430 L150,175"/>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
Now I'd like to draw a circle instead, but I only can find commands to move, draw a line, nothing to draw a circle.
Is there some way to get the GeometryDrawing to draw a circle?
....
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<EllipseGeometry Center="0,0" RadiusX="1" RadiusY="1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
Alternatively, you can also use Path Markup Syntax to draw two elliptic arcs (upper and lower half of the circle):
<GeometryDrawing Brush="Black" Geometry="M -1,0 A 1,1 0 1 1 1,0 M -1,0 A 1,1 0 1 0 1,0" />
In case you're wondering, this is what those cryptic drawing instructions mean:
M -1,0: Start drawing at point (-1, 0).
A 1,1 0 1 1 1,0: Draw an elliptic arc with radius (1, 1) to point (1, 0). The single-digit flags in between mean: no rotation (0), angle 180° or larger (1), positive-angle direction (1, meaning clockwise). This yields the upper half of the circle.
M -1,0: Start drawing again at point (-1, 0)
A 1,1 0 1 0 1,0: Draw the same arc as before, only this time in negative-angle direction (0, meaning counter-clockwise).
<Path Stretch="Fill"
Fill="Transparent"
Stroke="Black"
StrokeThickness="5"
Data="M 0,0 A 180,180 180 1 1 1,1 Z"/>
Without second M (move) command:
Data="M0,5A5,5,0,1,0,10,5A5,5,0,1,0,0,5"
Radius: 5, Start (0,5)
Can omit the "z" at the end, and it is still a closed curve

How can I use SnapToDevicePixels and StrokeDashArray

I have the following XAML code:
<Path Data="M0,0 L 12 0 L 12 12 L 0 12 Z M 6 0 L 6 12 M 0 6 L 12 6" StrokeDashArray="1 1" Stroke="Black" StrokeThickness="1" SnapsToDevicePixels='True">
</Path>
However it looks horribly fuzzy on my screen.
Is there a solution?
If you just want a crisp, dashed path and you may be able to get the results you want by declaring the RenderOptions.EdgeMode as Aliased to prevent the framework from interpolating the path outline when a dash falls between pixel boundaries:
<Path Data="M0,0 L 12 0 L 12 12 L 0 12 Z M 6 0 L 6 12 M 0 6 L 12 6" StrokeDashArray="1 1" Stroke="Black" StrokeThickness="1" RenderOptions.EdgeMode="Aliased">
</Path>

Resources