// Create the cap of primitive Polygon CreateCap(bool isLower) { Point3D[] centers = Centers; Vector3D[] horizontalVectors = HorizontalVectors; Vector3D[] verticalVectors = VerticalVectors; double halfWidth = 0.5 * Width; double halfHeight = 0.5 * Height; // Check the data of primitives if (!Tube.IsValid(centers, horizontalVectors, verticalVectors, halfWidth, halfHeight)) return null; // Create the cap int index = isLower ? 0 : centers.Length - 1; Point3D center = centers[index]; Vector3D horizontalVector = halfWidth * horizontalVectors[index]; Vector3D verticalVector = halfHeight * verticalVectors[index]; // Calculate positions Point3D[] positions = new Point3D[Tube.RadialSegementCount]; for (int i = 0; i < Tube.RadialSegementCount; i++) { double angle = i * 2 * Math.PI / Tube.RadialSegementCount; positions[i] = center + Math.Cos(angle) * horizontalVector + Math.Sin(angle) * verticalVector; } // Reverse points for upper cap if (!isLower) Array.Reverse(positions); Polygon result = new Polygon(); result.Positions = positions; // Set the same material result.Material = Material; return result; }
void UpdateShadow() { if (substance == null) return; if (style == null) return; Thread.Sleep(300); // Black material DiffuseMaterial material = new DiffuseMaterial(Brushes.Black); material.Freeze(); // Create molecules ModelVisual3D container = new ModelVisual3D(); foreach (Data.Molecule molecule in substance.Molecules) { foreach (Data.Atom atom in molecule.Atoms) { if (style.ColorStyle.ColorScheme[atom.Element].Diffuse.A < 5) continue; Sphere sphere = new Sphere(); sphere.Material = material; sphere.Radius = Atom.GetAtomRadius(atom, style.GeometryStyle); sphere.Center = atom.Position; container.Children.Add(sphere); } double bondRadius = Bond.GetBondRadius(style.GeometryStyle); foreach (Data.Bond bond in molecule.Bonds) { if (style.ColorStyle.UseSingleBondMaterial) { if (style.ColorStyle.BondMaterial.Diffuse.A < 5) continue; } else if (style.ColorStyle.ColorScheme[bond.Begin.Element].Diffuse.A < 5 || style.ColorStyle.ColorScheme[bond.End.Element].Diffuse.A < 5) continue; Cylinder cylinder = new Cylinder(bond.Begin.Position, bond.End.Position, bondRadius); cylinder.Material = material; container.Children.Add(cylinder); } #region Build approximation of ribbon double radius = 0.45; foreach (Data.Chain chain in molecule.Chains) { for (int i = 0; i < chain.Residues.Count; i++) { if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Helix) if (style.GeometryStyle.HelixHeight < 0.05 || style.GeometryStyle.HelixWidth < 0.05) continue; else radius = Residue.HelixWidth * ((style.GeometryStyle.HelixHeight + style.GeometryStyle.HelixWidth) / 2.0); if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Sheet) if (style.GeometryStyle.SheetHeight < 0.05 || style.GeometryStyle.SheetWidth < 0.05) continue; else radius = Residue.SheetWidth * ((style.GeometryStyle.SheetHeight + style.GeometryStyle.SheetWidth) / 2.0); if (chain.Residues[i].GetStructureType() == SecondaryStructureType.NotDefined) if (style.GeometryStyle.TurnHeight < 0.05 || style.GeometryStyle.TurnWidth < 0.05) continue; else radius = Residue.TurnWidth * ((style.GeometryStyle.TurnHeight + style.GeometryStyle.TurnWidth) / 2.0); if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Helix && style.ColorStyle.HelixMaterial.Diffuse.A < 5) continue; if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Sheet && style.ColorStyle.SheetMaterial.Diffuse.A < 5) continue; if (chain.Residues[i].GetStructureType() == SecondaryStructureType.NotDefined && style.ColorStyle.TurnMaterial.Diffuse.A < 5) continue; Data.Atom alfaCarbon = chain.Residues[i].AlfaCarbon; if (alfaCarbon != null) { Point3D begin = alfaCarbon.Position; alfaCarbon = null; for (int j = i + 1; j < chain.Residues.Count; j++) { alfaCarbon = chain.Residues[j].AlfaCarbon; if (alfaCarbon != null) break; } if (alfaCarbon != null) { Point3D end = alfaCarbon.Position; Cylinder cylinder = new Cylinder(begin, end, radius); container.Children.Add(cylinder); } } } } #endregion } // Get bounding box Rect3D boundingBox = VisualTreeHelper.GetDescendantBounds(container); if (boundingBox.IsEmpty) { shadowRefreshStarted = false; return; } #region Render Shadow const double blurSize = 25; const int renderTargetWidth = 200; int renderTargetHeight = (int)(200.0 * (boundingBox.SizeX / boundingBox.SizeY)); RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(renderTargetWidth, renderTargetHeight, 96, 96, PixelFormats.Pbgra32); Viewport3D shadowViewport3D = new Viewport3D(); Border border = new Border(); border.Padding = new Thickness(blurSize); border.Child = shadowViewport3D; // Change size of the visualizer border.Width = renderTargetBitmap.PixelWidth; border.Height = renderTargetBitmap.PixelHeight; border.Measure(new Size(renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight)); border.Arrange(new Rect(0, 0, renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight)); shadowViewport3D.Children.Add(container); // Create camera OrthographicCamera orthographicCamera = new OrthographicCamera(); #region Accomodate camera to fit content orthographicCamera.Position = new Point3D(boundingBox.Location.X + boundingBox.SizeX / 2.0, boundingBox.Location.Y, boundingBox.Location.Z + boundingBox.SizeZ / 2.0); orthographicCamera.LookDirection = new Vector3D(0, 1, 0); orthographicCamera.UpDirection = new Vector3D(-1, 0, 0); orthographicCamera.Width = boundingBox.SizeZ; #endregion orthographicCamera.NearPlaneDistance = 0; // Set the camera & correct lights shadowViewport3D.Camera = orthographicCamera; BlurEffect blurEffect = new BlurEffect(); blurEffect.Radius = blurSize; border.Effect = blurEffect; renderTargetBitmap.Render(border); renderTargetBitmap.Freeze(); #endregion // Invoke in main thread Dispatcher.BeginInvoke((Action) delegate { #region Create Plane Vector3D margin = new Vector3D(boundingBox.SizeX * 0.4, 0, boundingBox.SizeZ * 0.4); Point3D[] points = new Point3D[] { boundingBox.Location + new Vector3D(-margin.X, -margin.Y, -margin.Z), boundingBox.Location + new Vector3D(margin.X + boundingBox.SizeX, -margin.Y, -margin.Z), boundingBox.Location + new Vector3D(margin.X + boundingBox.SizeX, -margin.Y, margin.Z + boundingBox.SizeZ), boundingBox.Location + new Vector3D(-margin.X, -margin.Y, margin.Z + boundingBox.SizeZ) }; Polygon shadowPlane = new Polygon(); shadowPlane.Positions = points; shadowPlane.TextureCoordinates = new Point[] { new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(1, 0) }; #endregion shadowBrush.ImageSource = renderTargetBitmap; shadowBrush.Stretch = Stretch.Fill; shadowTargetOpacity = 0.8; shadowPlane.Material = new DiffuseMaterial(shadowBrush); shadowContainer.Children.Clear(); shadowContainer.Children.Add(shadowPlane); // Update shadow hash shadowRefreshStarted = false; }, DispatcherPriority.SystemIdle); }
// Create the cap of sheet primitive Polygon CreateCap(bool isLower) { Point3D[] centers = Centers; Vector3D[] horizontalVectors = HorizontalVectors; Vector3D[] verticalVectors = VerticalVectors; double halfWidth = 0.5 * Width; double halfHeight = 0.5 * Height; // Check the data of premitives if(!Sheet.IsValid(centers, horizontalVectors, verticalVectors, halfWidth, halfHeight)) return null; // Create the cap int index = isLower ? 0 : centers.Length - 1; Point3D center = centers[index]; Vector3D horizontalVector = halfWidth * horizontalVectors[index]; Vector3D verticalVector = halfHeight * verticalVectors[index]; Point3D[] positions = new Point3D[4]; positions[0] = center - horizontalVector + verticalVector; positions[1] = center - horizontalVector - verticalVector; positions[2] = center + horizontalVector - verticalVector; positions[3] = center + horizontalVector + verticalVector; // Reverse points for lower cap if (!isLower) Array.Reverse(positions); Polygon result = new Polygon(); result.Positions = positions; // Set the same material result.Material = Material; return result; }