I'm developing a flight simulator and have come across the problem of animating the individual pieces of the airplane (i.e. propeller, elevator, rudder, etc...). I created a class that stores the parts of the planes, which contains GeometryModel and a ModelVisual3D that is constructed from an STL file. When I apply the rotation to the specific part, nothing happens in the application. Full code can be found at: https://github.com/espina7/CSProblems/blob/main/MainWindow.xaml.cs\
public Part RotatePart()
{
//Console.WriteLine("Rotating Part");
Part temp;
temp = this;
AxisAngleRotation3D axisAngle = new AxisAngleRotation3D(new Vector3D(1, 0, 0), 10);
RotateTransform3D myRotate = new RotateTransform3D(axisAngle);
Vector3DAnimation myVectorAnimation = new Vector3DAnimation(new Vector3D(-1, -1, -1), new Duration(TimeSpan.FromMilliseconds(500)));
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever;
myRotate.Rotation.BeginAnimation(AxisAngleRotation3D.AxisProperty, myVectorAnimation);
Transform3DGroup partGroup = new Transform3DGroup();
partGroup.Children.Add(this.part.Transform);
partGroup.Children.Add(myRotate);
temp.part.Transform = partGroup;
temp.recalculateNormals();
return temp;
}
Related
I have a question about multipage FixedPage. I have a Grid created programmatically and the Grid exceeds one A4 page. Now I want to print the Grid in several FixedPage with print margin. But on my way, I create the Grid repeatedly and offset the LeftTop point in the fixedPage Arrange function. I meet a problem that I cannot set print margin in fixedPage, because I set the print margin to the fixedPage and then the first page will have print margin and the next pages will be blank.
How do print multipage of FixedDocument for a large grid want to print?
PrintDialog pd = new System.Windows.Controls.PrintDialog();
if (pd.ShowDialog() == false)
{
return;
}
var pageSize = new Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight);
var document = new FixedDocument();
document.DocumentPaginator.PageSize = pageSize;
for (int nPage = 0; nPage < MaxPage; nPage++)
{
Grid tempGrid = LoadControlMotherInit();
tempGrid.Width = GridWidth;
tempGrid.Height = GridActualHeight;
Point leftTop = new Point();
leftTop.X = 10;
leftTop.Y = -nPage * pageSize.Height;
// Create FixedPage
var fixedPage = new FixedPage();
fixedPage.Width = pageSize.Width;
fixedPage.Height = pageSize.Height;
fixedPage.Margin = new Thickness(0, 0, 0, 96);
fixedPage.Children.Add((UIElement)tempGrid);
fixedPage.Measure(pageSize);
fixedPage.Arrange(new Rect(leftTop, pageSize));
fixedPage.UpdateLayout();
// Add page to document
var pageContent = new PageContent();
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
document.Pages.Add(pageContent);
}
pd.PrintDocument(document.DocumentPaginator, "My Document");
From looking at your example,
PrintDialog.PrintDocument method takes in a DocumentPaginator, which could come from a multitude of source.
that being said, you can inherit from DocumentPaginator and take control of everything from PageSize, PageCount to the actual DocumentPage being returned.
Imagine your DocumentPage as a sliding window over your UIElement; but instead of sliding your DocumentPage, you slide your UIElement using its RenderTransform.
I have written the folowing code to populate the data from a object in a tablelayoutpanel control. It works Smile | :) , but when its loading the data onto the table, it flickers/jumps for few seconds and then after 2-3 seconds when its done processing the data it populates the data Frown | :( . I believe this behaviour is because of the code written for dynamically processing & drawing of the various controls in the table based on the object data.
I need your help in optimising the code/improving the performance of this code so that the table can load smoothly and fast. Please help. Thanks.
PS: This code is written for a table containing small amount of data. But going forward the same is planned for populating table with 4X more data. If this is the case, then performance will be very poor, which worries me. Please suggest some ideas.
private void button1_Click(object sender, EventArgs e)
{
Common obj = new Common();
obj.CreateDeserializedXmlObject(#"E:\TestReport.xml");
var v = obj.GetAdminData();
tableLayoutPanel1.ColumnCount = 4;
tableLayoutPanel1.RowCount = ((v.DOCREVISIONS.Length * 4) + 1 + (v.USEDLANGUAGES.L10.Length));
Label labelLanguage = new Label();
Label labelUsedLanguage = new Label();
Label labelDocRevisions = new Label();
labelLanguage.Text = "Language:";
labelUsedLanguage.Text = "Used Language:";
labelDocRevisions.Text = "Doc-Revisions:";
ComboBox comboBoxLanguage = new ComboBox();
comboBoxLanguage.Items.Add(v.LANGUAGE.Value.ToString());
comboBoxLanguage.SelectedIndex = 0;
ComboBox comboBoxUsedLanguage = new ComboBox();
foreach (LPLAINTEXT Lang in v.USEDLANGUAGES.L10)
{
comboBoxUsedLanguage.Items.Add(Lang.L.ToString());
}
comboBoxUsedLanguage.SelectedIndex = 0;
int index = 0;
Label[] labelDocRevision = new Label[v.DOCREVISIONS.Length];
Label[] labelRevision = new Label[v.DOCREVISIONS.Length];
Label[] labelState = new Label[v.DOCREVISIONS.Length];
Label[] labelTeamMember = new Label[v.DOCREVISIONS.Length];
Label[] labelDate = new Label[v.DOCREVISIONS.Length];
TextBox[] textBoxRevision = new TextBox[v.DOCREVISIONS.Length];
TextBox[] textBoxState = new TextBox[v.DOCREVISIONS.Length];
TextBox[] textBoxTeamMember = new TextBox[v.DOCREVISIONS.Length];
TextBox[] textBoxDate = new TextBox[v.DOCREVISIONS.Length];
foreach (DOCREVISION dcr in v.DOCREVISIONS)
{
labelDocRevision[index] = new Label();
labelRevision[index] = new Label();
labelState[index] = new Label();
labelTeamMember[index] = new Label();
labelDate[index] = new Label();
textBoxRevision[index] = new TextBox();
textBoxState[index] = new TextBox();
textBoxTeamMember[index] = new TextBox();
textBoxDate[index] = new TextBox();
labelDocRevision[index].Text = "DOCREVISION["+index.ToString()+"]:";
labelRevision[index].Text = "Revision:";
labelState[index].Text = "State:";
labelTeamMember[index].Text = "TeamMemberRef:";
labelDate[index].Text = "Date:";
textBoxRevision[index].Text = dcr.REVISIONLABEL.Value.ToString();
textBoxState[index].Text = dcr.STATE.Value.ToString();
textBoxTeamMember[index].Text = dcr.TEAMMEMBERREF.Value.ToString();
textBoxDate[index].Text = dcr.DATE.Value.ToString();
index++;
}
// Add child controls to TableLayoutPanel and specify rows and column
tableLayoutPanel1.Controls.Add(labelLanguage, 0, 0);
tableLayoutPanel1.Controls.Add(labelUsedLanguage, 0, 1);
tableLayoutPanel1.Controls.Add(labelDocRevisions, 0, 2);
tableLayoutPanel1.Controls.Add(comboBoxLanguage, 1, 0);
tableLayoutPanel1.Controls.Add(comboBoxUsedLanguage, 1, 1);
int docRevRowSpacing = 2;
for (int loop = 0; loop < index; loop++)
{
tableLayoutPanel1.Controls.Add(labelDocRevision[loop], 1, docRevRowSpacing);
tableLayoutPanel1.Controls.Add(labelRevision[loop], 2, docRevRowSpacing);
tableLayoutPanel1.Controls.Add(labelState[loop], 2, docRevRowSpacing+1);
tableLayoutPanel1.Controls.Add(labelTeamMember[loop], 2, docRevRowSpacing+2);
tableLayoutPanel1.Controls.Add(labelDate[loop], 2, docRevRowSpacing+3);
tableLayoutPanel1.Controls.Add(textBoxRevision[loop], 3, docRevRowSpacing);
tableLayoutPanel1.Controls.Add(textBoxState[loop], 3, docRevRowSpacing+1);
tableLayoutPanel1.Controls.Add(textBoxTeamMember[loop],3 , docRevRowSpacing+2);
tableLayoutPanel1.Controls.Add(textBoxDate[loop], 3, docRevRowSpacing+3);
docRevRowSpacing += 4;
}
tableLayoutPanel1.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
Controls.Add(this.tableLayoutPanel1);
}
There are two minor changes that helps a little bit.
At the start of your code you can call SuspendLayout. This prevents the TableLayoutPanel to redraw itself every time you add a control to it. When you're done adding all controls at the end you call ResumeLayout. At that moment the TableLayoutPanel will redraw only once. It still takes time but at least most the flickering is gone. At the end of your example code you add the tableLayoutPanel1 again to the forms control collection. If the TableLayoutPanel is on your form designer you don't need that and by doing it you make your performance worse because now you have two tableLayoutPanels that need to be painted.
private void button1_Click(object sender, EventArgs e)
{
tableLayoutPanel1.SuspendLayout();
// all your other code goes here
// not sure why you add the tableLayouyPanel AGAIN to the
// form control collection.
// Controls.Add(this.tableLayoutPanel1);
tableLayoutPanel1.ResumeLayout();
}
I noticed in my testing that resizing the form gives the same flickering effect. I used the ResizeBegin and ResizeEnd events to do the same Suspend and Resume layout trick:
private void Form1_ResizeBegin(object sender, EventArgs e)
{
tableLayoutPanel1.SuspendLayout();
}
private void Form1_ResizeEnd(object sender, EventArgs e)
{
tableLayoutPanel1.ResumeLayout();
}
This as much as you can do with your current code (except maybe the use of all those arrays with controls but their overhead is not the major issue here).
The TableLayoutPanel is maybe not the best control for what you want to achieve. It lacks for example VirtualMode support, something the DataGridView does. That would enable you to only load and show data that is visible on the form (and therefor create controls for it). Adapting your code to use that control is left as an exercise for the reader and if new issues pop-up feel free to start a new question.
I need to calculate the intersection between two geometries to check if one is fully inside the other or not.
The Geometry "container", based on a System.Windows.Shapes.Polygon, is created as follows:
List<PathSegment> basePolygonSegments = new List<PathSegment> {
new PolyLineSegment(basePolygon.Points, true) };
PathGeometry baseGeometry = new PathGeometry();
baseGeometry.Figures.Add(
new PathFigure(basePolygon.Points[0], basePolygonSegments, true));
The Geometry "contained" can be:
another System.Windows.Shapes.Polygon
a System.Windows.Shapes.Polyline, that can have only one line or three lines (the shape is a |_|, or U)
The Polyline is created as follows:
Polyline bracketDrawingPolyline = new Polyline();
foreach(Point p in listOfPoints)
bracketDrawingPolyline.Points.Add(p);
LineGeometry lineGeometry =
new LineGeometry(
bracketDrawingPolyline.Points[0],
bracketDrawingPolyline.Points[bracketDrawingPolyline.Points.Count - 1]);
PathGeometry bracketGeometry = new PathGeometry();
bracketGeometry = lineGeometry.GetWidenedPathGeometry(
new Pen(Brushes.Black, 1.0));
To understand if the "contained" Geometry is contained in the "container", I do the following:
CombinedGeometry intersectionGeometry =
new CombinedGeometry(GeometryCombineMode.Intersect,
baseGeometry, bracketGeometry);
double intersectionArea =
intersectionGeometry.GetArea(0.0001, ToleranceType.Absolute);
double bracketArea = bracketGeometry.GetArea(0.0001, ToleranceType.Absolute);
if (intersectionArea < bracketArea)
{
//the second Geometry is not fully contained in the "container" Geometry
}
else
//it is fully contained
....
In case of Polygon or Polyline with only one line everything works as expected. But with Polyline U, intersectionArea and bracketArea are always the same.
I've also tried to perform the following checks:
bool result = baseGeometry.FillContains(bracketGeometry);
IntersectionDetail idtl =
baseGeometry.FillContainsWithDetail(bracketGeometry);
but I have the same results.
I've found a solution on my own, but I don't know if it is the best one.
Considered that with a single line everything works well, I just do the check for each line of the polyline, that is:
for (int i = 1; i < bracketDrawingPolyline.Points.Count; i++)
{
LineGeometry lineGeometry =
new LineGeometry(bracketDrawingPolyline.Points[i - 1],
bracketDrawingPolyline.Points[i]);
...//continue with the check of the line as described in the post...
}
My program shows a static scene containing several instances, at different places, of a 3d model, for example a tree. This model can be 'heavy', between 50000 and 100000 triangles, and the performance degrade quickly with the number of instances (performance is unacceptable with more than 10 instances).
My first code, without optimizations, looks like this :
public partial class Vue3D : Window
{
public ModelVisual3D modelVisual = new ModelVisual3D();
public Model3DGroup model3DGroup = new Model3DGroup();
public Vue3D()
{
...
modelVisual.Content = model3DGroup;
view1.Children.Add(modelVisual); // view1 = viewport3D
...
BuildScene();
}
void BuildScene()
{
Model3DGroup model = GetModel("tree");
foreach (Point3D pnt in <point collection>)
{
Model3DGroup modelClone = model.Clone();
Transform3DGroup tg = new Transform3DGroup();
tg.Children.Add(new TranslateTransform3D(pnt.X, pnt.Y, pnt.Z>));
modelClone.Transform = tg;
model3DGroup.Children.Add(modelClone);
}
}
}
For each instance i clone the complete model, and add the clone to the viewport after transformation.
Let's say the tree model contains 2 GeometryModel3D :
{mesh1 (20000 triangles), texture1} and {mesh2 (40000 triangles), texture2}.
If i show 10 trees, i'm adding 20 GeometryModel3D.
Since all these instances share the same 2 textures, i thought i could speed up things by creating only 2 GeometryModel3D : one with all the triangles associated with texture1, one with all the triangles associated with texture2. That's what i tried in this code :
void BuildScene()
{
List<Transform3DGroup>> listTg = new List<Transform3DGroup>();
foreach (Point3D pnt in <point collection>)
{
Transform3DGroup tg = new Transform3DGroup();
tg.Children.Add(new TranslateTransform3D(pnt.X, pnt.Y, pnt.Z>));
listTg.Add(tg);
}
Model3DGroup model = GetModel("tree");
foreach (GeometryModel3D gmodel in model.Children)
{
MeshGeometry3D mesh = gmodel.Geometry as MeshGeometry3D;
GeometryModel3D newgmodel = new GeometryModel3D();
newgmodel.Material = gmodel.Material;
newgmodel.BackMaterial = gmodel.BackMaterial;
MeshGeometry3D newmesh = new MeshGeometry3D();
newgmodel.Geometry = newmesh;
foreach (Transform3DGroup tg in listTg)
{
foreach (int indice in mesh.TriangleIndices)
newmesh.TriangleIndices.Add(indice + newmesh.Positions.Count);
foreach (Point3D p3 in mesh.Positions)
newmesh.Positions.Add(tg.Transform(p3));
if (mesh.TextureCoordinates != null)
{
foreach (System.Windows.Point p in mesh.TextureCoordinates)
newmesh.TextureCoordinates.Add(p);
}
}
newmesh.TriangleIndices.Freeze();
newmesh.TextureCoordinates.Freeze();
newmesh.Positions.Freeze();
newgmodel.Material.Freeze();
newgmodel.BackMaterial.Freeze();
newgmodel.Freeze();
model3DGroup.Children.Add(newgmodel);
}
}
And the performance is not better, in fact it's rather worse ... What am I missing here ? It seems that my assumption, i.e. minimizing the number GeometryModel3D would be beneficial, is false. I have read somewhere that in wpf 3d, the number of triangles has no big impact on performance, but that the number of textures was more critical. Here i have a big number of triangles but only 2 textures, only one ModelVisual3D, and all is frozen... Any suggestion ?
I have had good luck with detaching the mesh applying any transformations and then reattaching the mesh afterward. I got the idea from here: http://msdn.microsoft.com/en-us/library/bb613553.aspx
I have the need for drawing in the same drawing with lines of different color, thickness etc.
I can create two instances of PathGeometry, but I can't set color on them.
I can create two instances of Path, but can't get them displayed in my control.
What am I doing wrong?
Thanks for any comments!
Anders, Denmark.
Code below only displays "collection" in my control, but I thought it could be a starting point for answers...
var pathFigure1 = new PathFigure(new Point(0, 0),
new List<PathSegment> {new LineSegment(new Point(10, 10), true)}, false);
var pathFigure2 = new PathFigure(new Point(20, 20),
new List<PathSegment> {new LineSegment(new Point(30, 30), true)}, false);
var g1 = new PathGeometry(new List<PathFigure> {pathFigure1});
var g2 = new PathGeometry(new List<PathFigure> {pathFigure2});
var p1 = new System.Windows.Shapes.Path
{
Data = g1,
Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0))
};
var p2 = new System.Windows.Shapes.Path
{
Data = g2,
Stroke = new SolidColorBrush(Color.FromRgb(170, 87, 170))
};
var content = new Canvas();
content.Children.Add(p1);
content.Children.Add(p2);
Content = content;
You have started on the right approach, a geometry defines a 'shape', so don;t worry that you cannot set its colour. A Path turns the geometry into a visual representation on the screen, so here you can set the color and stroke thickness.
Your problem is at the very last step, you are setting the content property of your control. Typically this property is used to associate some data object with a control, you then supply a template which is its visual representation.
What you need to do is add your paths as children of a panel.
For example, add a Canvas, or a Grid to your control. Then add your two paths to the Grid / Canvas via their Children collection property.