+398
@@ -0,0 +1,398 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
@@ -1,543 +0,0 @@
|
||||
<Activity mc:Ignorable="sad" x:Class="TfsBuild.Process" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mt="clr-namespace:Microsoft.TeamFoundation;assembly=Microsoft.TeamFoundation.Common" xmlns:mtbc="clr-namespace:Microsoft.TeamFoundation.Build.Client;assembly=Microsoft.TeamFoundation.Build.Client" xmlns:mtbw="clr-namespace:Microsoft.TeamFoundation.Build.Workflow;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwa="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Activities;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwt="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Tracking;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mttbb="clr-namespace:Microsoft.TeamFoundation.TestImpact.BuildIntegration.BuildActivities;assembly=Microsoft.TeamFoundation.TestImpact.BuildIntegration" xmlns:mtvc="clr-namespace:Microsoft.TeamFoundation.VersionControl.Client;assembly=Microsoft.TeamFoundation.VersionControl.Client" xmlns:mtvco="clr-namespace:Microsoft.TeamFoundation.VersionControl.Common;assembly=Microsoft.TeamFoundation.VersionControl.Common" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:sad="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:sad1="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:this="clr-namespace:TfsBuild;" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<x:Members>
|
||||
<x:Property Name="BuildSettings" Type="InArgument(mtbwa:BuildSettings)" />
|
||||
<x:Property Name="TestSpecs" Type="InArgument(mtbwa:TestSpecList)" />
|
||||
<x:Property Name="BuildNumberFormat" Type="InArgument(x:String)" />
|
||||
<x:Property Name="SolutionSpecificBuildOutputs" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="CleanWorkspace" Type="InArgument(mtbwa:CleanWorkspaceOption)" />
|
||||
<x:Property Name="RunCodeAnalysis" Type="InArgument(mtbwa:CodeAnalysisOption)" />
|
||||
<x:Property Name="SourceAndSymbolServerSettings" Type="InArgument(mtbwa:SourceAndSymbolServerSettings)" />
|
||||
<x:Property Name="AgentSettings" Type="InArgument(mtbwa:AgentSettings)" />
|
||||
<x:Property Name="AssociateChangesetsAndWorkItems" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="CreateWorkItem" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="MSBuildArguments" Type="InArgument(x:String)" />
|
||||
<x:Property Name="MSBuildPlatform" Type="InArgument(mtbwa:ToolPlatform)" />
|
||||
<x:Property Name="MSBuildMultiProc" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="PerformTestImpactAnalysis" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="CreateLabel" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="DisableTests" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="GetVersion" Type="InArgument(x:String)" />
|
||||
<x:Property Name="PrivateDropLocation" Type="InArgument(x:String)" />
|
||||
<x:Property Name="Verbosity" Type="InArgument(mtbw:BuildVerbosity)" />
|
||||
<x:Property Name="Metadata" Type="mtbw:ProcessParameterMetadataCollection" />
|
||||
<x:Property Name="SupportedReasons" Type="mtbc:BuildReason" />
|
||||
<x:Property Name="BuildProcessVersion" Type="x:String" />
|
||||
</x:Members>
|
||||
<this:Process.BuildSettings>[New Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings()]</this:Process.BuildSettings>
|
||||
<this:Process.DisableTests>[False]</this:Process.DisableTests>
|
||||
<this:Process.TestSpecs>[New Microsoft.TeamFoundation.Build.Workflow.Activities.TestSpecList(New Microsoft.TeamFoundation.Build.Workflow.Activities.AgileTestPlatformSpec("**\*test*.dll"))]</this:Process.TestSpecs>
|
||||
<this:Process.BuildNumberFormat>["$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)"]</this:Process.BuildNumberFormat>
|
||||
<this:Process.SolutionSpecificBuildOutputs>[False]</this:Process.SolutionSpecificBuildOutputs>
|
||||
<this:Process.AssociateChangesetsAndWorkItems>[True]</this:Process.AssociateChangesetsAndWorkItems>
|
||||
<this:Process.CreateWorkItem>[True]</this:Process.CreateWorkItem>
|
||||
<this:Process.CleanWorkspace>[Microsoft.TeamFoundation.Build.Workflow.Activities.CleanWorkspaceOption.All]</this:Process.CleanWorkspace>
|
||||
<this:Process.MSBuildArguments>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.MSBuildArguments>
|
||||
<this:Process.RunCodeAnalysis>[Microsoft.TeamFoundation.Build.Workflow.Activities.CodeAnalysisOption.AsConfigured]</this:Process.RunCodeAnalysis>
|
||||
<this:Process.MSBuildMultiProc>[True]</this:Process.MSBuildMultiProc>
|
||||
<this:Process.MSBuildPlatform>[Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto]</this:Process.MSBuildPlatform>
|
||||
<this:Process.PerformTestImpactAnalysis>[True]</this:Process.PerformTestImpactAnalysis>
|
||||
<this:Process.SourceAndSymbolServerSettings>[New Microsoft.TeamFoundation.Build.Workflow.Activities.SourceAndSymbolServerSettings(True, Nothing)]</this:Process.SourceAndSymbolServerSettings>
|
||||
<this:Process.CreateLabel>[True]</this:Process.CreateLabel>
|
||||
<this:Process.GetVersion>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.GetVersion>
|
||||
<this:Process.AgentSettings>[New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }]</this:Process.AgentSettings>
|
||||
<this:Process.Verbosity>[Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal]</this:Process.Verbosity>
|
||||
<this:Process.Metadata>
|
||||
<mtbw:ProcessParameterMetadataCollection>
|
||||
<mtbw:ProcessParameterMetadata BrowsableWhen="EditingDefinition" Category="#300 Advanced" DisplayName="MSBuild Multi-Proc" Description="Enable MSBuid Multi-proc to build your solutions' projects in parallel, when possible, using all available processors on the build server." ParameterName="MSBuildMultiProc" />
|
||||
<mtbw:ProcessParameterMetadata BrowsableWhen="EditingDefinition" Category="#300 Advanced" DisplayName="Solution Specific Build Outputs" Description="True will put build outputs into folders based on the solution name. False will put all build outputs into the same folder." ParameterName="SolutionSpecificBuildOutputs" />
|
||||
</mtbw:ProcessParameterMetadataCollection>
|
||||
</this:Process.Metadata>
|
||||
<this:Process.SupportedReasons>All</this:Process.SupportedReasons>
|
||||
<this:Process.BuildProcessVersion>11.0</this:Process.BuildProcessVersion>
|
||||
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
|
||||
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="BuildDetail" />
|
||||
<Variable x:TypeArguments="x:String" Name="DropLocation" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:GetBuildDetail DisplayName="Get the Build" Result="[BuildDetail]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<Sequence DisplayName="Update Drop Location" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<mtbwa:InvokeForReason DisplayName="Update Build Number for Triggered Builds" Reason="Triggered">
|
||||
<mtbwa:UpdateBuildNumber BuildNumberFormat="[BuildNumberFormat]" DisplayName="Update Build Number" />
|
||||
</mtbwa:InvokeForReason>
|
||||
<If Condition="[(Not String.IsNullOrEmpty(BuildDetail.DropLocationRoot)) AndAlso (BuildDetail.Reason And Microsoft.TeamFoundation.Build.Client.BuildReason.Triggered) = BuildDetail.Reason]" DisplayName="If Build Reason is Triggered" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<Assign x:TypeArguments="x:String" mtbwt:BuildTrackingParticipant.Importance="None" Value="[BuildDropProvider.CombinePaths(BuildDetail.DropLocationRoot, BuildDetail.BuildDefinition.Name, BuildDetail.BuildNumber)]" To="[DropLocation]" />
|
||||
<mtbwa:SetBuildProperties DisplayName="Set Drop Location" DropLocation="[DropLocation]" PropertiesToSet="DropLocation" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[(Not String.IsNullOrEmpty(PrivateDropLocation)) AndAlso BuildDetail.Reason = Microsoft.TeamFoundation.Build.Client.BuildReason.ValidateShelveset]" DisplayName="If Build Reason is ValidateShelveset" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<Assign x:TypeArguments="x:String" Value="[BuildDropProvider.CombinePaths(PrivateDropLocation, BuildDetail.BuildDefinition.Name, BuildDetail.BuildNumber)]" To="[DropLocation]" mtbwt:BuildTrackingParticipant.Importance="None" />
|
||||
<mtbwa:SetBuildProperties DisplayName="Set Drop Location for Private Build" DropLocation="[DropLocation]" PropertiesToSet="DropLocation" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
<mtbwa:AgentScope DisplayName="Run On Agent" MaxExecutionTime="[AgentSettings.MaxExecutionTime]" MaxWaitTime="[AgentSettings.MaxWaitTime]" ReservationSpec="[AgentSettings.GetAgentReservationSpec()]">
|
||||
<mtbwa:AgentScope.Variables>
|
||||
<Variable x:TypeArguments="mtbc:IBuildAgent" Name="BuildAgent" />
|
||||
<Variable x:TypeArguments="mtvc:Workspace" Name="Workspace" />
|
||||
<Variable x:TypeArguments="x:String" Name="BuildDirectory" />
|
||||
<Variable x:TypeArguments="x:String" Default="[BuildDetail.BuildNumber]" Name="LabelName" />
|
||||
<Variable x:TypeArguments="x:String" Name="WorkspaceName" />
|
||||
<Variable x:TypeArguments="x:String" Name="SourcesDirectory" />
|
||||
<Variable x:TypeArguments="x:String" Name="BinariesDirectory" />
|
||||
<Variable x:TypeArguments="x:String" Name="TestResultsDirectory" />
|
||||
</mtbwa:AgentScope.Variables>
|
||||
<Sequence DisplayName="Initialize Variables" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<mtbwa:GetBuildAgent DisplayName="Get the Agent" Result="[BuildAgent]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:GetBuildDirectory DisplayName="Get the Build Directory" Result="[BuildDirectory]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Initialize Workspace Name" To="[WorkspaceName]" Value="[String.Format("{0}_{1}_{2}", BuildDetail.BuildDefinition.Id, Microsoft.TeamFoundation.LinkingUtilities.DecodeUri(BuildAgent.Uri.AbsoluteUri).ToolSpecificId, BuildAgent.ServiceHost.Name)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Initialize Sources Directory" To="[SourcesDirectory]" Value="[String.Format("{0}\Sources", BuildDirectory)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Initialize Binaries Directory" To="[BinariesDirectory]" Value="[String.Format("{0}\Binaries", BuildDirectory)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Initialize TestResults Directory" To="[TestResultsDirectory]" Value="[String.Format("{0}\TestResults", BuildDirectory)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[Not BuildSettings.HasPlatformConfigurations]" DisplayName="If Not BuildSettings.HasPlatformConfigurations" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<AddToCollection x:TypeArguments="mtbwa:PlatformConfiguration" DisplayName="Use Default Platform Configuration" Collection="[BuildSettings.PlatformConfigurations]" Item="[Microsoft.TeamFoundation.Build.Workflow.Activities.PlatformConfiguration.Default]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[WorkspaceName.Length > Microsoft.TeamFoundation.VersionControl.Common.RepositoryConstants.MaxWorkspaceNameSize]" DisplayName="If WorkspaceName > MaxSize" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<mtbwa:WriteBuildWarning DisplayName="Write Workspace Size Warning" Message="[String.Format("The workspace name '{0}' exceeds the maximum allowed limit of '{1}' characters. Truncating it to match the maximum limit.", WorkspaceName, Microsoft.TeamFoundation.VersionControl.Common.RepositoryConstants.MaxWorkspaceNameSize)]" />
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Truncate WorkspaceName to MaxSize" To="[WorkspaceName]" Value="[WorkspaceName.Substring(0, Microsoft.TeamFoundation.VersionControl.Common.RepositoryConstants.MaxWorkspaceNameSize).TrimEnd()]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
<Sequence DisplayName="Initialize Workspace" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<mtbwa:DeleteDirectory Directory="[TestResultsDirectory]" DisplayName="Delete Test Results Directory" Recursive="[True]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[Not CleanWorkspace = Microsoft.TeamFoundation.Build.Workflow.Activities.CleanWorkspaceOption.None]" DisplayName="If Not CleanWorkspace = CleanWorkspaceOption.None" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:DeleteDirectory Directory="[BinariesDirectory]" DisplayName="Delete Binaries Directory" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[CleanWorkspace = Microsoft.TeamFoundation.Build.Workflow.Activities.CleanWorkspaceOption.All]" DisplayName="If CleanWorkspace = CleanWorkspaceOption.All" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Delete Workspace and Sources Directory" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<mtbwa:DeleteWorkspace DeleteLocalItems="[True]" DisplayName="Delete Workspace" Name="[WorkspaceName]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:DeleteDirectory Directory="[SourcesDirectory]" DisplayName="Delete Sources Directory" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:CreateWorkspace BuildDirectory="[BuildDirectory]" Comment="["Workspace Created by Team Build"]" DisplayName="Create Workspace" Name="[WorkspaceName]" Result="[Workspace]" SourcesDirectory="[SourcesDirectory]" />
|
||||
<If Condition="[CleanWorkspace = Microsoft.TeamFoundation.Build.Workflow.Activities.CleanWorkspaceOption.Outputs]" DisplayName="If CleanWorkspace = CleanWorkspaceOption.Outputs" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<ForEach x:TypeArguments="mtbwa:PlatformConfiguration" DisplayName="For Each Configuration in BuildSettings.PlatformConfigurations" Values="[BuildSettings.PlatformConfigurations]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<ActivityAction x:TypeArguments="mtbwa:PlatformConfiguration">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="mtbwa:PlatformConfiguration" Name="platformConfiguration" />
|
||||
</ActivityAction.Argument>
|
||||
<Sequence DisplayName="Clean Configuration">
|
||||
<If Condition="[BuildSettings.HasProjectsToBuild]" DisplayName="If BuildSettings.HasProjectsToBuild" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<ForEach x:TypeArguments="x:String" DisplayName="For Each Project in BuildSettings.ProjectsToBuild" Values="[BuildSettings.ProjectsToBuild]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<ActivityAction x:TypeArguments="x:String">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="x:String" Name="serverBuildProjectItem" />
|
||||
</ActivityAction.Argument>
|
||||
<Sequence DisplayName="Clean Project" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="x:String" Name="localBuildProjectItem" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:ConvertWorkspaceItem DisplayName="Convert Server Paths to Local Paths" Input="[serverBuildProjectItem]" Result="[localBuildProjectItem]" Workspace="[Workspace]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[System.IO.File.Exists(localBuildProjectItem)]" DisplayName="If File.Exists(Project)" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:MSBuild CommandLineArguments="[String.Format("/p:SkipInvalidConfigurations=true {0}", MSBuildArguments)]" Configuration="[platformConfiguration.Configuration]" DisplayName="Run MSBuild for Project" GenerateVSPropsFile="[True]" MaxProcesses="[If (MSBuildMultiProc, 0, 1)]" OutDir="[BinariesDirectory]" Platform="[platformConfiguration.Platform]" Project="[localBuildProjectItem]" Targets="[New String() { "Clean" }]" TargetsNotLogged="[New String() {"GetNativeManifest", "GetCopyToOutputDirectoryItems", "GetTargetPath"}]" ToolPlatform="[MSBuildPlatform]" Verbosity="[Verbosity]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</ActivityAction>
|
||||
</ForEach>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</ActivityAction>
|
||||
</ForEach>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:SyncWorkspace DisplayName="Get Workspace" VersionOverride="[GetVersion]" Workspace="[Workspace]">
|
||||
<mtbwa:SyncWorkspace.RequestsFailed>
|
||||
<ActivityAction x:TypeArguments="scg:ICollection(mtbc:IQueuedBuild)">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="scg:ICollection(mtbc:IQueuedBuild)" Name="failedRequests" />
|
||||
</ActivityAction.Argument>
|
||||
<mtbwa:RetryRequests Behavior="[Microsoft.TeamFoundation.Build.Workflow.Activities.RetryBehavior.DoNotBatch]" DisplayName="Mark Requests for Retry" Requests="[failedRequests]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</ActivityAction>
|
||||
</mtbwa:SyncWorkspace.RequestsFailed>
|
||||
</mtbwa:SyncWorkspace>
|
||||
</Sequence>
|
||||
<If Condition="[CreateLabel]" DisplayName="If CreateLabel" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:InvokeForReason DisplayName="Create and Set Label for non-Shelveset Builds" Reason="Manual, IndividualCI, BatchedCI, Schedule, ScheduleForced, UserCreated">
|
||||
<mtbwa:LabelWorkspace Comment="["Label Created by Team Build"]" DisplayName="Create Label" Name="[LabelName]" Scope="[String.Format("$/{0}", BuildDetail.BuildDefinition.TeamProject)]" Workspace="[Workspace]" />
|
||||
<mtbwa:SetBuildProperties DisplayName="Set Label on BuildDetail" LabelName="[String.Format("{0}@$/{1}", LabelName, BuildDetail.BuildDefinition.TeamProject)]" PropertiesToSet="LabelName" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</mtbwa:InvokeForReason>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<mtbwa:WriteBuildMessage DisplayName="Write Message" Message="Not Labeling sources" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High]" />
|
||||
</If.Else>
|
||||
</If>
|
||||
<TryCatch DisplayName="Try Compile, Test, and Associate Changesets and Work Items" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<TryCatch.Finally>
|
||||
<Sequence DisplayName="Revert Workspace and Copy Files to Drop Location" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<mtbwa:InvokeForReason DisplayName="Revert Workspace for Shelveset Builds" Reason="CheckInShelveset, ValidateShelveset">
|
||||
<mtbwa:RevertWorkspace DisplayName="Revert Workspace" Workspace="[Workspace]" />
|
||||
</mtbwa:InvokeForReason>
|
||||
<If Condition="[Not String.IsNullOrEmpty(DropLocation)]" DisplayName="If DropLocation is Set" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:CopyDirectory DisplayName="Drop Files to Drop Location" Source="[BinariesDirectory]" Destination="[DropLocation]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</TryCatch.Finally>
|
||||
<TryCatch.Try>
|
||||
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="s:Exception" Name="compilationException" />
|
||||
<Variable x:TypeArguments="scg:IList(mtvc:Changeset)" Name="associatedChangesets" />
|
||||
<Variable x:TypeArguments="s:Boolean" Name="treatTestFailureAsBuildFailure" />
|
||||
</Sequence.Variables>
|
||||
<Parallel DisplayName="Compile, Test, and Associate Changesets and Work Items">
|
||||
<TryCatch DisplayName="Try Compile and Test" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<TryCatch.Try>
|
||||
<Sequence DisplayName="Compile and Test">
|
||||
<ForEach x:TypeArguments="mtbwa:PlatformConfiguration" DisplayName="For Each Configuration in BuildSettings.PlatformConfigurations" Values="[BuildSettings.PlatformConfigurations]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<ActivityAction x:TypeArguments="mtbwa:PlatformConfiguration">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="mtbwa:PlatformConfiguration" Name="platformConfiguration" />
|
||||
</ActivityAction.Argument>
|
||||
<Sequence DisplayName="Compile and Test for Configuration" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="x:String" Name="outputDirectory" />
|
||||
<Variable x:TypeArguments="x:String" Name="logFileDropLocation" />
|
||||
</Sequence.Variables>
|
||||
<Sequence DisplayName="Initialize Variables" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Create OutputDirectory Per Platform and Configuration" To="[outputDirectory]" Value="[If (platformConfiguration.IsEmpty Or BuildSettings.PlatformConfigurations.Count = 1, BinariesDirectory, If (platformConfiguration.IsPlatformEmptyOrAnyCpu, BinariesDirectory + "\" + platformConfiguration.Configuration, BinariesDirectory + "\" + platformConfiguration.Platform + "\" + platformConfiguration.Configuration))]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[Not String.IsNullOrEmpty(DropLocation)]" DisplayName="If DropLocation is Set" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Initialize LogFile Drop Location" To="[logFileDropLocation]" Value="[If (platformConfiguration.IsEmpty Or BuildSettings.PlatformConfigurations.Count = 1, BuildDropProvider.CombinePaths(DropLocation, "logs"), If (platformConfiguration.IsPlatformEmptyOrAnyCpu, BuildDropProvider.CombinePaths(DropLocation, "logs", platformConfiguration.Configuration), BuildDropProvider.CombinePaths(DropLocation, "logs", platformConfiguration.Platform, platformConfiguration.Configuration)))]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
<If Condition="[BuildSettings.HasProjectsToBuild]" DisplayName="If BuildSettings.HasProjectsToBuild" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<ForEach x:TypeArguments="x:String" DisplayName="For Each Project in BuildSettings.ProjectsToBuild" Values="[BuildSettings.ProjectsToBuild]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<ActivityAction x:TypeArguments="x:String">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="x:String" Name="serverBuildProjectItem" />
|
||||
</ActivityAction.Argument>
|
||||
<TryCatch DisplayName="Try to Compile the Project" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<TryCatch.Try>
|
||||
<Sequence DisplayName="Compile the Project" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="x:String" Name="localProject" />
|
||||
<Variable x:TypeArguments="x:String" Name="outputDirectoryPerProject" Default="[outputDirectory]" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:ConvertWorkspaceItem DisplayName="Convert Server Path to Local Path" Input="[serverBuildProjectItem]" Result="[localProject]" Workspace="[Workspace]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[SolutionSpecificBuildOutputs]" DisplayName="If Build Outputs are Solution-Specific" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Update Output Directory" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Assign x:TypeArguments="x:String" DisplayName="Set Solution-Specific Output Directory" To="[outputDirectoryPerProject]" Value="[System.IO.Path.Combine(outputDirectory, System.IO.Path.GetFileNameWithoutExtension(localProject))]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If DisplayName="If Output Directory Exists" Condition="[System.IO.Directory.Exists(outputDirectoryPerProject)]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:WriteBuildWarning DisplayName="Write Duplicate Project Names Warning" Message="[String.Format("{0} conflicts with another solution/project. Build outputs for solutions/projects with the same name will be copied to the same directory. To separate the build outputs, change the name of one of the solutions/projects.", System.IO.Path.GetFileNameWithoutExtension(localProject))]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:MSBuild CommandLineArguments="[String.Format("/p:SkipInvalidConfigurations=true {0}", MSBuildArguments)]" Configuration="[platformConfiguration.Configuration]" DisplayName="Run MSBuild for Project" GenerateVSPropsFile="[True]" LogFileDropLocation="[logFileDropLocation]" MaxProcesses="[If (MSBuildMultiProc, 0, 1)]" OutDir="[outputDirectoryPerProject]" Platform="[platformConfiguration.Platform]" Project="[localProject]" RunCodeAnalysis="[RunCodeAnalysis]" TargetsNotLogged="[New String() {"GetNativeManifest", "GetCopyToOutputDirectoryItems", "GetTargetPath"}]" ToolPlatform="[MSBuildPlatform]" Verbosity="[Verbosity]" />
|
||||
</Sequence>
|
||||
</TryCatch.Try>
|
||||
<TryCatch.Catches>
|
||||
<Catch x:TypeArguments="s:Exception">
|
||||
<ActivityAction x:TypeArguments="s:Exception">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="s:Exception" Name="ex" />
|
||||
</ActivityAction.Argument>
|
||||
<Sequence DisplayName="Handle Exception">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="scg:ICollection(mtbc:IQueuedBuild)" Name="failedRequests" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:SetBuildProperties CompilationStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Failed]" DisplayName="Set CompilationStatus to Failed" PropertiesToSet="CompilationStatus" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[CreateWorkItem]" DisplayName="If CreateWorkItem" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:InvokeForReason DisplayName="Create Work Item for non-Shelveset Builds" Reason="Manual, IndividualCI, BatchedCI, Schedule, ScheduleForced, UserCreated">
|
||||
<mtbwa:OpenWorkItem AssignedTo="[BuildDetail.RequestedFor]" Comment="["This work item was created by TFS Build on a build failure."]" CustomFields="[New Dictionary(Of String, String) From { {"System.Reason", "Build Failure"}, {"Microsoft.VSTS.TCM.ReproSteps", "Start the build using TFS Build"}, {"Priority", "1"}, {"Severity", "1 - Critical"} }]" DisplayName="Create Work Item" Title="[String.Format("Build Failure in Build: {0}", BuildDetail.BuildNumber)]" Type="["Bug"]" />
|
||||
</mtbwa:InvokeForReason>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:GetApprovedRequests DisplayName="Get Requests Approved for Check In" Result="[failedRequests]" mtbwt:BuildTrackingParticipant.Importance="None" />
|
||||
<mtbwa:RetryRequests Behavior="[Microsoft.TeamFoundation.Build.Workflow.Activities.RetryBehavior.DoNotBatch]" DisplayName="Mark Requests for Retry" Requests="[failedRequests]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<Rethrow DisplayName="Rethrow the exception so the build will stop" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</Sequence>
|
||||
</ActivityAction>
|
||||
</Catch>
|
||||
</TryCatch.Catches>
|
||||
</TryCatch>
|
||||
</ActivityAction>
|
||||
</ForEach>
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[Not DisableTests]" DisplayName="If Not DisableTests" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Run Tests" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If Condition="[Not TestSpecs Is Nothing]" DisplayName="If Not TestSpecs Is Nothing" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<ForEach x:TypeArguments="mtbwa:TestSpec" DisplayName="For Each TestSpec in TestSpecs" Values="[TestSpecs]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<ActivityAction x:TypeArguments="mtbwa:TestSpec">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="mtbwa:TestSpec" Name="spec" />
|
||||
</ActivityAction.Argument>
|
||||
<TryCatch DisplayName="Try Run Tests" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<TryCatch.Try>
|
||||
<If Condition="[TypeOf spec Is Microsoft.TeamFoundation.Build.Workflow.Activities.AgileTestPlatformSpec]" DisplayName="If spec Is AgileTestPlatformSpec" mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Run Visual Studio Test Runner for Test Sources" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtbwa:AgileTestPlatformSpec" Name="agileTestPlatformAssembly" />
|
||||
<Variable x:TypeArguments="scg:IEnumerable(x:String)" Name="agileTestPlatformAssemblies" />
|
||||
</Sequence.Variables>
|
||||
<Assign x:TypeArguments="mtbwa:AgileTestPlatformSpec" DisplayName="Assign spec to agileTestPlatformAssembly" To="[agileTestPlatformAssembly]" Value="[DirectCast(spec, Microsoft.TeamFoundation.Build.Workflow.Activities.AgileTestPlatformSpec)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:FindMatchingFiles DisplayName="Find Visual Studio Test Platform Test Assemblies" MatchPattern="[String.Format("{0}\{1}", outputDirectory, agileTestPlatformAssembly.AssemblyFileSpec)]" Result="[agileTestPlatformAssemblies]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[agileTestPlatformAssemblies.Count() > 0]" DisplayName="If Visual Studio Test Platform Test Assemblies Found" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<If Condition="[agileTestPlatformAssembly.HasRunSettingsFile]" DisplayName="If agileTestPlatformAssembly.HasRunSettingsFile" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Find Run Settings File And Run Visual Studio Test Runner" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="x:String" Name="localRunSettings" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:GenerateRunSettings DisplayName="Generate Run Settings File" RunSettingsForTestRun="[agileTestPlatformAssembly.RunSettingsForTestRun]" Result="[localRunSettings]" Workspace="[Workspace]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:RunTests DisplayName="Run Visual Studio Test Runner for Test Sources" RunName="[agileTestPlatformAssembly.RunName]" Flavor="[platformConfiguration.Configuration]" Platform="[platformConfiguration.Platform]" TestSources="[agileTestPlatformAssemblies]" RunSettings="[localRunSettings]" TestCaseFilter="[agileTestPlatformAssembly.TestCaseFilter]" ExecutionPlatform="[agileTestPlatformAssembly.ExecutionPlatform]" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<mtbwa:RunTests DisplayName="Run Visual Studio Test Runner for Test Sources" RunName="[agileTestPlatformAssembly.RunName]" Flavor="[platformConfiguration.Configuration]" Platform="[platformConfiguration.Platform]" TestSources="[agileTestPlatformAssemblies]" TestCaseFilter="[agileTestPlatformAssembly.TestCaseFilter]" ExecutionPlatform="[agileTestPlatformAssembly.ExecutionPlatform]" />
|
||||
</If.Else>
|
||||
</If>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<If Condition="[TypeOf spec Is Microsoft.TeamFoundation.Build.Workflow.Activities.TestMetadataFileSpec]" DisplayName="If spec Is TestMetadataFileSpec" mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Run MSTest for Metadata File">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtbwa:TestMetadataFileSpec" Name="testMetadataFile" />
|
||||
<Variable x:TypeArguments="x:String" Name="localTestMetadata" />
|
||||
</Sequence.Variables>
|
||||
<Assign x:TypeArguments="mtbwa:TestMetadataFileSpec" DisplayName="Assign spec to testMetadataFile" To="[testMetadataFile]" Value="[DirectCast(spec, Microsoft.TeamFoundation.Build.Workflow.Activities.TestMetadataFileSpec)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:ConvertWorkspaceItem DisplayName="Convert Server Path to Local Path" Input="[testMetadataFile.MetadataFileName]" Result="[localTestMetadata]" Workspace="[Workspace]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:MSTest RunTitle="[testMetadataFile.RunName]" Category="[testMetadataFile.CategoryFilter]" DisplayName="Run MSTest for Metadata File" Flavor="[platformConfiguration.Configuration]" MaxPriority="[testMetadataFile.MaximumPriority]" MinPriority="[testMetadataFile.MinimumPriority]" PathToResultsFilesRoot="[TestResultsDirectory]" Platform="[platformConfiguration.Platform]" SearchPathRoot="[outputDirectory]" TestLists="[testMetadataFile.TestLists]" TestMetadata="[localTestMetadata]" TestSettings="[String.Empty]" CommandLineArguments="[testMetadataFile.MSTestCommandLineArgs]" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<Sequence DisplayName="Run MSTest for Test Assemblies" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtbwa:TestAssemblySpec" Name="testAssembly" />
|
||||
<Variable x:TypeArguments="scg:IEnumerable(x:String)" Name="testAssemblies" />
|
||||
<Variable x:TypeArguments="x:String" Default="[String.Empty]" Name="testFlavor" />
|
||||
<Variable x:TypeArguments="x:String" Default="[String.Empty]" Name="testPlatform" />
|
||||
</Sequence.Variables>
|
||||
<Assign x:TypeArguments="mtbwa:TestAssemblySpec" DisplayName="Assign spec to testAssembly" To="[testAssembly]" Value="[DirectCast(spec, Microsoft.TeamFoundation.Build.Workflow.Activities.TestAssemblySpec)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:FindMatchingFiles DisplayName="Find Test Assemblies" MatchPattern="[String.Format("{0}\{1}", outputDirectory, testAssembly.AssemblyFileSpec)]" Result="[testAssemblies]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[testAssemblies.Count() > 0]" DisplayName="If Test Assemblies Found" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<If Condition="[testAssembly.HasTestSettingsFile]" DisplayName="If testAssembly.HasTestSettingsFile" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Find Test Settings File And Run MSTest" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="x:String" Name="localTestSettings" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:ConvertWorkspaceItem DisplayName="Convert Server Path to Local Path" Input="[testAssembly.TestSettingsFileName]" Result="[localTestSettings]" Workspace="[Workspace]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mtbwa:MSTest RunTitle="[testAssembly.RunName]" Category="[testAssembly.CategoryFilter]" DisplayName="Run MSTest for Test Assemblies" Flavor="[platformConfiguration.Configuration]" MaxPriority="[testAssembly.MaximumPriority]" MinPriority="[testAssembly.MinimumPriority]" PathToResultsFilesRoot="[TestResultsDirectory]" Platform="[platformConfiguration.Platform]" SearchPathRoot="[outputDirectory]" TestContainers="[testAssemblies]" TestSettings="[localTestSettings]" CommandLineArguments="[testAssembly.MSTestCommandLineArgs]" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<mtbwa:MSTest RunTitle="[testAssembly.RunName]" Category="[testAssembly.CategoryFilter]" DisplayName="Run MSTest for Test Assemblies" Flavor="[platformConfiguration.Configuration]" MaxPriority="[testAssembly.MaximumPriority]" MinPriority="[testAssembly.MinimumPriority]" PathToResultsFilesRoot="[TestResultsDirectory]" Platform="[platformConfiguration.Platform]" SearchPathRoot="[outputDirectory]" TestContainers="[testAssemblies]" CommandLineArguments="[testAssembly.MSTestCommandLineArgs]" />
|
||||
</If.Else>
|
||||
</If>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Else>
|
||||
</If>
|
||||
</If.Else>
|
||||
</If>
|
||||
</TryCatch.Try>
|
||||
<TryCatch.Catches>
|
||||
<Catch x:TypeArguments="s:Exception">
|
||||
<ActivityAction x:TypeArguments="s:Exception">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="s:Exception" Name="testException" />
|
||||
</ActivityAction.Argument>
|
||||
<Sequence DisplayName="Handle Test Run Exception">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="scg:ICollection(mtbc:IQueuedBuild)" Name="failedRequests" />
|
||||
</Sequence.Variables>
|
||||
<If Condition="[Not (TypeOf testException Is Microsoft.TeamFoundation.Build.Workflow.Activities.TestFailureException)]" DisplayName="If testException is NOT TestFailureException" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:WriteBuildError DisplayName="Write Test Failure Message" Message="[testException.Message]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:SetBuildProperties DisplayName="Set TestStatus to Failed" PropertiesToSet="TestStatus" TestStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Failed]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[spec.FailBuildOnFailure]" DisplayName="If spec.FailBuildOnFailure" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Assign x:TypeArguments="s:Boolean" DisplayName="Set treatTestFailureAsBuildFailure to True" To="[treatTestFailureAsBuildFailure]" Value="[True]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:GetApprovedRequests DisplayName="Get Requests Approved for Check In" Result="[failedRequests]" mtbwt:BuildTrackingParticipant.Importance="None" />
|
||||
<mtbwa:RetryRequests Behavior="[Microsoft.TeamFoundation.Build.Workflow.Activities.RetryBehavior.DoNotBatch]" DisplayName="Mark Requests for Retry" Requests="[failedRequests]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</Sequence>
|
||||
</ActivityAction>
|
||||
</Catch>
|
||||
</TryCatch.Catches>
|
||||
</TryCatch>
|
||||
</ActivityAction>
|
||||
</ForEach>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<If Condition="[(Not TestSpecs Is Nothing) And (TestSpecs.Count > 0)]" DisplayName="If TestSpecs Is Not Nothing or Empty" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:WriteBuildWarning DisplayName="Write Warning" Message="No automated tests will be run for this build because tests have been disabled for this build definition. To enable these tests, edit this build definition and set the Disable Tests process parameter to false." />
|
||||
</If.Then>
|
||||
</If>
|
||||
</If.Else>
|
||||
</If>
|
||||
</Sequence>
|
||||
</ActivityAction>
|
||||
</ForEach>
|
||||
<If Condition="[BuildDetail.CompilationStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Unknown]" DisplayName="If CompilationStatus = Unknown" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:SetBuildProperties CompilationStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" DisplayName="Set CompilationStatus to Succeeded" PropertiesToSet="CompilationStatus" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[BuildDetail.TestStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Unknown]" DisplayName="If TestStatus = Unknown" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:SetBuildProperties DisplayName="Set TestStatus to Succeeded" PropertiesToSet="TestStatus" TestStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[treatTestFailureAsBuildFailure And (BuildDetail.TestStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Failed)]" DisplayName="If TreatTestFailureAsBuildFailure And (TestStatus = Failed)" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:SetBuildProperties DisplayName="Set Status to Failed" PropertiesToSet="Status" Status="[Microsoft.TeamFoundation.Build.Client.BuildStatus.Failed]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</TryCatch.Try>
|
||||
<TryCatch.Catches>
|
||||
<Catch x:TypeArguments="s:Exception">
|
||||
<ActivityAction x:TypeArguments="s:Exception">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="s:Exception" Name="compilationExceptionArgument" />
|
||||
</ActivityAction.Argument>
|
||||
<Assign x:TypeArguments="s:Exception" DisplayName="Save the Compilation Exception" To="[compilationException]" Value="[compilationExceptionArgument]" mtbwt:BuildTrackingParticipant.Importance="None" />
|
||||
</ActivityAction>
|
||||
</Catch>
|
||||
</TryCatch.Catches>
|
||||
</TryCatch>
|
||||
<If Condition="[AssociateChangesetsAndWorkItems]" DisplayName="If AssociateChangesetsAndWorkItems" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<If Condition="[CreateLabel]" DisplayName="If CreateLabel and AssociateChangesetsAndWorkItems" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:InvokeForReason DisplayName="Associate Changesets and Work Items for non-Shelveset Builds" Reason="Manual, IndividualCI, BatchedCI, Schedule, ScheduleForced, UserCreated">
|
||||
<mtbwa:AssociateChangesetsAndWorkItems DisplayName="Associate Changesets and Work Items" Result="[associatedChangesets]" />
|
||||
</mtbwa:InvokeForReason>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<mtbwa:WriteBuildWarning DisplayName="Write Associate Changesets and Work Items Warning" Message="Cannot Associate Changesets and Work Items because the Label Sources option is set to False." />
|
||||
</If.Else>
|
||||
</If>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Parallel>
|
||||
<If Condition="[Not compilationException Is Nothing]" DisplayName="If a Compilation Exception Occurred" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Throw DisplayName="Rethrow Compilation Exception" Exception="[compilationException]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<Parallel DisplayName="Get Impacted Tests, Index Sources and Publish Symbols">
|
||||
<If Condition="[PerformTestImpactAnalysis]" DisplayName="If PerformTestImpactAnalysis" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Get Impacted Tests" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="scg:IEnumerable(x:String)" Name="assemblies" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:FindMatchingFiles DisplayName="Find Build Outputs" MatchPattern="[String.Format("{0}\**\*.dll;{0}\**\*.exe", BinariesDirectory)]" Result="[assemblies]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<mttbb:GetImpactedTests Assemblies="[assemblies]" AssociatedChangesets="[associatedChangesets]" BinariesRoot="[BinariesDirectory]" Build="[BuildDetail]" CodeChanges="{x:Null}" DisplayName="Get Impacted Tests" ImpactedTests="{x:Null}" Workspace="[Workspace]" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[SourceAndSymbolServerSettings.IndexSources Or SourceAndSymbolServerSettings.HasSymbolStorePath]" DisplayName="If SourceAndSymbolServerSettings.IndexSources Or SourceAndSymbolServerSettings.HasSymbolStorePath" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<mtbwa:InvokeForReason DisplayName="Index Sources and Publish Symbols for Triggered Builds" Reason="Triggered">
|
||||
<mtbwa:InvokeForReason.Variables>
|
||||
<Variable x:TypeArguments="scg:IEnumerable(x:String)" Name="symbolFiles" />
|
||||
</mtbwa:InvokeForReason.Variables>
|
||||
<mtbwa:FindMatchingFiles DisplayName="Find Symbol Files" MatchPattern="[String.Format("{0}\**\*.pdb", BinariesDirectory)]" Result="[symbolFiles]" mtbwt:BuildTrackingParticipant.Importance="Low" />
|
||||
<If Condition="[SourceAndSymbolServerSettings.IndexSources]" DisplayName="If SourceAndSymbolServerSettings.IndexSources" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<TryCatch DisplayName="Try Index Sources" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<TryCatch.Try>
|
||||
<mtbwa:IndexSources DisplayName="Index Sources" FileList="[symbolFiles]" />
|
||||
</TryCatch.Try>
|
||||
<TryCatch.Catches>
|
||||
<Catch x:TypeArguments="s:Exception">
|
||||
<ActivityAction x:TypeArguments="s:Exception">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="s:Exception" Name="exception" />
|
||||
</ActivityAction.Argument>
|
||||
<mtbwa:WriteBuildError DisplayName="Write Indexing Sources Error" Message="[exception.Message]" />
|
||||
</ActivityAction>
|
||||
</Catch>
|
||||
</TryCatch.Catches>
|
||||
</TryCatch>
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[SourceAndSymbolServerSettings.HasSymbolStorePath]" DisplayName="If SourceAndSymbolServerSettings.HasSymbolStorePath" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<If.Then>
|
||||
<TryCatch DisplayName="Try Publish Symbols" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<TryCatch.Try>
|
||||
<mtbwa:SharedResourceScope DisplayName="Synchronize Access to Symbol Store" MaxExecutionTime="[TimeSpan.Zero]" MaxWaitTime="[New TimeSpan(1, 0, 0)]" ResourceName="[SourceAndSymbolServerSettings.SymbolStorePath]" mtbwt:BuildTrackingParticipant.Importance="Low">
|
||||
<mtbwa:PublishSymbols DisplayName="Publish Symbols" FileList="[symbolFiles]" ProductName="[BuildDetail.BuildDefinition.Name]" StorePath="[SourceAndSymbolServerSettings.SymbolStorePath]" Version="[BuildDetail.BuildNumber]" />
|
||||
</mtbwa:SharedResourceScope>
|
||||
</TryCatch.Try>
|
||||
<TryCatch.Catches>
|
||||
<Catch x:TypeArguments="s:Exception">
|
||||
<ActivityAction x:TypeArguments="s:Exception">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="s:Exception" Name="exception" />
|
||||
</ActivityAction.Argument>
|
||||
<mtbwa:WriteBuildError DisplayName="Write Publishing Symbols Error" Message="[exception.Message]" />
|
||||
</ActivityAction>
|
||||
</Catch>
|
||||
</TryCatch.Catches>
|
||||
</TryCatch>
|
||||
</If.Then>
|
||||
</If>
|
||||
</mtbwa:InvokeForReason>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Parallel>
|
||||
</Sequence>
|
||||
</TryCatch.Try>
|
||||
</TryCatch>
|
||||
</mtbwa:AgentScope>
|
||||
<mtbwa:InvokeForReason DisplayName="Check In Gated Changes for CheckInShelveset Builds" Reason="CheckInShelveset">
|
||||
<mtbwa:CheckInGatedChanges DisplayName="Check In Gated Changes" />
|
||||
</mtbwa:InvokeForReason>
|
||||
</Sequence>
|
||||
</Activity>
|
||||
@@ -1,208 +0,0 @@
|
||||
<Activity mc:Ignorable="sads sap" x:Class="TfsBuild.Process" this:Process.LabWorkflowParameters="[New Microsoft.TeamFoundation.Lab.Workflow.Activities.LabWorkflowDetails()]" this:Process.Verbosity="[Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal]" this:Process.BuildNumberFormat="["$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)"]" this:Process.SupportedReasons="Manual, BatchedCI, Schedule, ScheduleForced" this:Process.TimeoutForDeploymentScriptInMinutes="30" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mt="clr-namespace:Microsoft.TeamFoundation;assembly=Microsoft.TeamFoundation.Common" xmlns:mtbc="clr-namespace:Microsoft.TeamFoundation.Build.Client;assembly=Microsoft.TeamFoundation.Build.Client" xmlns:mtbc1="clr-namespace:Microsoft.TeamFoundation.Build.Common;assembly=Microsoft.TeamFoundation.Build.Common" xmlns:mtbp="clr-namespace:Microsoft.TeamFoundation.Build.ProcessComponents;assembly=Microsoft.TeamFoundation.Build.ProcessComponents" xmlns:mtbw="clr-namespace:Microsoft.TeamFoundation.Build.Workflow;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwa="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Activities;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbws="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Services;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtlc="clr-namespace:Microsoft.TeamFoundation.Lab.Client;assembly=Microsoft.TeamFoundation.Lab.Client" xmlns:mtltc="clr-namespace:Microsoft.TeamFoundation.Lab.TestIntegration.Client;assembly=Microsoft.TeamFoundation.Lab.TestIntegration.Client" xmlns:mtlwa="clr-namespace:Microsoft.TeamFoundation.Lab.Workflow.Activities;assembly=Microsoft.TeamFoundation.Lab.Workflow.Activities" xmlns:mtlwc="clr-namespace:Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client;assembly=Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client" xmlns:mttbb="clr-namespace:Microsoft.TeamFoundation.TestImpact.BuildIntegration.BuildActivities;assembly=Microsoft.TeamFoundation.TestImpact.BuildIntegration" xmlns:mttc="clr-namespace:Microsoft.TeamFoundation.TestManagement.Client;assembly=Microsoft.TeamFoundation.TestManagement.Client" xmlns:mtvc="clr-namespace:Microsoft.TeamFoundation.VersionControl.Client;assembly=Microsoft.TeamFoundation.VersionControl.Client" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Core" xmlns:s3="clr-namespace:System;assembly=System.ServiceModel" xmlns:s4="clr-namespace:System;assembly=System.ComponentModel.Composition" xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities" xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:sads="http://schemas.microsoft.com/netfx/2010/xaml/activities/debugger" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:this="clr-namespace:TfsBuild" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<x:Members>
|
||||
<x:Property Name="BuildProcessVersion" Type="x:String" />
|
||||
<x:Property Name="Metadata" Type="mtbw:ProcessParameterMetadataCollection" />
|
||||
<x:Property Name="LabWorkflowParameters" Type="InArgument(mtlwa:LabWorkflowDetails)" />
|
||||
<x:Property Name="Verbosity" Type="InArgument(mtbw:BuildVerbosity)" />
|
||||
<x:Property Name="BuildNumberFormat" Type="InArgument(x:String)" />
|
||||
<x:Property Name="SupportedReasons" Type="mtbc:BuildReason" />
|
||||
<x:Property Name="TimeoutForDeploymentScriptInMinutes" Type="InArgument(x:Int32)">
|
||||
<x:Property.Attributes>
|
||||
<RequiredArgumentAttribute />
|
||||
</x:Property.Attributes>
|
||||
</x:Property>
|
||||
</x:Members>
|
||||
<this:Process.BuildProcessVersion>11.0</this:Process.BuildProcessVersion>
|
||||
<this:Process.Metadata>
|
||||
<mtbw:ProcessParameterMetadataCollection>
|
||||
<mtbw:ProcessParameterMetadata BrowsableWhen="Always" Category="Misc" DisplayName="Timeout For Each Deployment Script (in Minutes)" ParameterName="TimeoutForDeploymentScriptInMinutes" />
|
||||
</mtbw:ProcessParameterMetadataCollection>
|
||||
</this:Process.Metadata>
|
||||
<sap:VirtualizedContainerService.HintSize>920,3702</sap:VirtualizedContainerService.HintSize>
|
||||
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
|
||||
<Sequence DisplayName="Application Deployment Workflow" sad:XamlDebuggerXmlReader.FileName="D:\VSTLM\src\vset\LabManager\LabCustomActivities\Templates\LabDefaultTemplate.xaml" sap:VirtualizedContainerService.HintSize="880,3662" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="BuildDetail" />
|
||||
<Variable x:TypeArguments="x:String" Name="LabEnvironmentUri" />
|
||||
<Variable x:TypeArguments="x:String" Name="BuildLocation" />
|
||||
<Variable x:TypeArguments="x:Int64" Name="SnapshotId" />
|
||||
<Variable x:TypeArguments="x:Int32" Name="QueueBuildId" />
|
||||
<Variable x:TypeArguments="mtbc:BuildStatus" Default="[Microsoft.TeamFoundation.Build.Client.BuildStatus.Succeeded]" Name="BuildStatus" />
|
||||
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="ChildBuildDetail" />
|
||||
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="SelectedBuildDetail" />
|
||||
<Variable x:TypeArguments="x:String" Name="BuildNumber" />
|
||||
<Variable x:TypeArguments="mtlc:LabEnvironment" Name="LabEnvironment" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:UpdateBuildNumber BuildNumberFormat="[BuildNumberFormat]" DisplayName="Update Build Number" sap:VirtualizedContainerService.HintSize="858,22" />
|
||||
<mtbwa:GetBuildDetail DisplayName="Get Build Details" sap:VirtualizedContainerService.HintSize="858,22" Result="[BuildDetail]" />
|
||||
<If Condition="[LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True AndAlso LabWorkflowParameters.BuildDetails.QueueNewBuild = True]" DisplayName="If Build is needed" sap:VirtualizedContainerService.HintSize="858,416">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Do Build" sap:VirtualizedContainerService.HintSize="301,308">
|
||||
<sap:WorkflowViewStateService.ViewState>
|
||||
<scg:Dictionary x:TypeArguments="x:String, x:Object">
|
||||
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
|
||||
</scg:Dictionary>
|
||||
</sap:WorkflowViewStateService.ViewState>
|
||||
<mtlwa:RunWorkflow BuildController="{x:Null}" LabEnvironmentUri="{x:Null}" BuildDefinition="[LabWorkflowParameters.BuildDetails.BuildDefinitionName]" DisplayName="Start Build Workflow" sap:VirtualizedContainerService.HintSize="242,22" ProjectName="[BuildDetail.TeamProject]" Result="[QueueBuildId]" />
|
||||
<mtlwa:WaitForWorkflow AllowPartiallySucceededBuild="True" BuildDetails="[ChildBuildDetail]" DisplayName="Wait For Build To Complete" sap:VirtualizedContainerService.HintSize="242,22" LabWorkflowType="[Microsoft.TeamFoundation.Lab.Workflow.Activities.WorkflowType.Build]" MaxConsecutiveFailuresToIgnoreDuringWaitForCompletion="[3]" MaxWaitTime="[TimeSpan.Zero]" QueueBuildId="[QueueBuildId]" RefreshInterval="[System.TimeSpan.FromMinutes(1)]" Result="[BuildStatus]" ThrowOnError="True" />
|
||||
<Assign DisplayName="Set Build Location" sap:VirtualizedContainerService.HintSize="242,60">
|
||||
<Assign.To>
|
||||
<OutArgument x:TypeArguments="x:Uri">[LabWorkflowParameters.BuildDetails.BuildUri]</OutArgument>
|
||||
</Assign.To>
|
||||
<Assign.Value>
|
||||
<InArgument x:TypeArguments="x:Uri">[ChildBuildDetail.Uri]</InArgument>
|
||||
</Assign.Value>
|
||||
</Assign>
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtlwa:WriteDeploymentInformation Url="{x:Null}" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Update Deployment Summary" sap:VirtualizedContainerService.HintSize="858,22" Message="[String.Format("Lab environment: {0}", LabWorkflowParameters.EnvironmentDetails.LabEnvironmentName)]" />
|
||||
<mtlwa:GetBuildLocationAndBuildNumber BuildDetails="[LabWorkflowParameters.BuildDetails]" BuildNumber="[BuildNumber]" DisplayName="Get Build Location And Build Number" sap:VirtualizedContainerService.HintSize="858,22" Result="[BuildLocation]" SelectedBuild="[SelectedBuildDetail]" />
|
||||
<If Condition="[LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True]" DisplayName="Compute build location needed" sap:VirtualizedContainerService.HintSize="858,208">
|
||||
<If.Then>
|
||||
<Assign DisplayName="Compute build path" sap:VirtualizedContainerService.HintSize="291,100">
|
||||
<Assign.To>
|
||||
<OutArgument x:TypeArguments="x:String">[BuildLocation]</OutArgument>
|
||||
</Assign.To>
|
||||
<Assign.Value>
|
||||
<InArgument x:TypeArguments="x:String">[If(LabWorkflowParameters.BuildDetails.Configuration Is Nothing, BuildLocation, If(LabWorkflowParameters.BuildDetails.Configuration.IsEmpty Or (SelectedBuildDetail.Information.GetNodesByType(Microsoft.TeamFoundation.Build.Common.InformationTypes.ConfigurationSummary, True)).Count = 1, BuildLocation, If(LabWorkflowParameters.BuildDetails.Configuration.IsPlatformEmptyOrAnyCpu, BuildLocation + "\" + LabWorkflowParameters.BuildDetails.Configuration.Configuration, BuildLocation + "\" + LabWorkflowParameters.BuildDetails.Configuration.Platform + "\" + LabWorkflowParameters.BuildDetails.Configuration.Configuration)))]</InArgument>
|
||||
</Assign.Value>
|
||||
</Assign>
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[LabWorkflowParameters.EnvironmentDetails.Disposition = Microsoft.TeamFoundation.Lab.Client.LabEnvironmentDisposition.Stored]" DisplayName="If user selected stored environment" sap:VirtualizedContainerService.HintSize="858,208">
|
||||
<If.Then>
|
||||
<Throw DisplayName="Indicate error" Exception="[New System.Exception("You have selected an environment that is stored in the library. Select an environment that is deployed on a team project host group.")]" sap:VirtualizedContainerService.HintSize="269,100" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<Assign DisplayName="Get Lab Environment Uri" sap:VirtualizedContainerService.HintSize="858,22" >
|
||||
<Assign.To>
|
||||
<OutArgument x:TypeArguments="x:String">[LabEnvironmentUri]</OutArgument>
|
||||
</Assign.To>
|
||||
<Assign.Value>
|
||||
<InArgument x:TypeArguments="x:String">[LabWorkflowParameters.EnvironmentDetails.LabEnvironmentUri.ToString()]</InArgument>
|
||||
</Assign.Value>
|
||||
</Assign>
|
||||
<mtlwa:GetLabEnvironment DisplayName="Get Lab Environment" LabEnvironmentUri="[LabEnvironmentUri]" Result="[LabEnvironment]" />
|
||||
<If Condition="[LabWorkflowParameters.EnvironmentDetails.RevertToSnapshot = True]" DisplayName=" If Restore Snapshot" sap:VirtualizedContainerService.HintSize="858,316">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Restore Snapshot" sap:VirtualizedContainerService.HintSize="231,208">
|
||||
<mtlwa:GetLabEnvironmentSnapshotId DisplayName="Get Snapshot Details" sap:VirtualizedContainerService.HintSize="200,22" LabEnvironmentUri="[LabEnvironmentUri]" Result="[SnapshotId]" SnapshotName="[LabWorkflowParameters.EnvironmentDetails.SnapshotName]" />
|
||||
<mtlwa:RestoreLabEnvironment DisplayName="Restore Lab Environment to Snapshot" sap:VirtualizedContainerService.HintSize="200,22" LabEnvironmentUri="[LabEnvironmentUri]" SnapshotId="[SnapshotId]" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<Sequence DisplayName="No Clean Snapshot" >
|
||||
<If Condition="[Not String.Equals(Microsoft.TeamFoundation.Lab.Client.LabEnvironment.UnmanagedProvider, labEnvironment.LabProvider)]" DisplayName= "If Virtual Environment">
|
||||
<If.Then>
|
||||
<mtlwa:WriteDeploymentInformation Url="{x:Null}" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Clean snapshot not specified " sap:VirtualizedContainerService.HintSize="208,208" Message="Build definition did not specify a clean snapshot. It is a best practice to use clean snapshot when running the lab workflow." />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Else>
|
||||
</If>
|
||||
<If Condition="[LabWorkflowParameters.DeploymentDetails.DeploymentNeeded = True or LabWorkflowParameters.TestParameters.RunTest = True]" DisplayName="If deployment or test needed" sap:VirtualizedContainerService.HintSize="858,1214">
|
||||
<If.Then>
|
||||
<mtlwa:WaitForEnvironmentReady DisplayName="Wait For Environment To Be Ready" sap:VirtualizedContainerService.HintSize="711,22" LabEnvironmentUri="[LabEnvironmentUri]" MaxWaitTime="[System.TimeSpan.FromMinutes(10)]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[LabWorkflowParameters.DeploymentDetails.DeploymentNeeded = True]" DisplayName="If deployment needed" sap:VirtualizedContainerService.HintSize="858,1214">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Do deployment" sap:VirtualizedContainerService.HintSize="733,1106">
|
||||
<mtlwa:ReserveEnvironmentForDeployment DisplayName="Reserve Environment For Deployment" sap:VirtualizedContainerService.HintSize="711,22" LabEnvironmentUri="[LabEnvironmentUri]" />
|
||||
<TryCatch DisplayName="Deploy Build on Environment">
|
||||
<TryCatch.Try>
|
||||
<Sequence DisplayName="Deploying Build">
|
||||
<ForEach x:TypeArguments="x:String" DisplayName="Run Deployment scripts" sap:VirtualizedContainerService.HintSize="711,254" Values="[LabWorkflowParameters.DeploymentDetails.Scripts]">
|
||||
<ActivityAction x:TypeArguments="x:String">
|
||||
<ActivityAction.Argument>
|
||||
<DelegateInArgument x:TypeArguments="x:String" Name="deploymentConfigurationPair" />
|
||||
</ActivityAction.Argument>
|
||||
<mtlwa:RunDeploymentTask BuildLocation="[BuildLocation]" DeploymentScriptDetails="[deploymentConfigurationPair]" DisplayName="Run Deployment Task" sap:VirtualizedContainerService.HintSize="200,22" LabEnvironmentUri="[LabEnvironmentUri]" MaxWaitTime="[TimeSpan.FromMinutes(TimeoutForDeploymentScriptInMinutes)]" ThrowOnError="True" UseRoleForDeployment="[LabWorkflowParameters.DeploymentDetails.UseRoleForDeployment]" />
|
||||
</ActivityAction>
|
||||
</ForEach>
|
||||
</Sequence>
|
||||
</TryCatch.Try>
|
||||
<TryCatch.Finally>
|
||||
<mtlwa:ReleaseEnvironmentFromDeployment DisplayName="Release Environment From Deployment" sap:VirtualizedContainerService.HintSize="711,22" LabEnvironmentUri="[LabEnvironmentUri]" />
|
||||
</TryCatch.Finally>
|
||||
</TryCatch>
|
||||
<mtlwa:WriteDeploymentInformation DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Application Deployment Succeeded" sap:VirtualizedContainerService.HintSize="711,22" Message="[String.Format("The application was deployed successfully from the following build location:")]" Url="[BuildLocation]" />
|
||||
<If Condition="[LabWorkflowParameters.DeploymentDetails.TakePostDeploymentSnapshot = True]" DisplayName="Post Deployment Snapshot" sap:VirtualizedContainerService.HintSize="711,626">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Take Post deployment Snapshot " sap:VirtualizedContainerService.HintSize="486,518">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="x:Int64" Name="PostDeploymentSnapshotChainId" />
|
||||
<Variable x:TypeArguments="x:String" Default="[String.Format("{0}_{1}", BuildDetail.BuildDefinition.Name, BuildDetail.BuildNumber)]" Name="PostDeploymentSnapshotName" />
|
||||
</Sequence.Variables>
|
||||
<If Condition="[String.IsNullOrEmpty(LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName) = False]" DisplayName="Check snapshot name" sap:VirtualizedContainerService.HintSize="464,208">
|
||||
<If.Then>
|
||||
<Assign sap:VirtualizedContainerService.HintSize="291,100">
|
||||
<Assign.To>
|
||||
<OutArgument x:TypeArguments="x:String">[PostDeploymentSnapshotName]</OutArgument>
|
||||
</Assign.To>
|
||||
<Assign.Value>
|
||||
<InArgument x:TypeArguments="x:String">[If(LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True,String.Format("{0}_{1}_{2}", LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildNumber,BuildDetail.BuildNumber),String.Format("{0}_{1}", LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildDetail.BuildNumber))]</InArgument>
|
||||
</Assign.Value>
|
||||
</Assign>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtlwa:SnapshotLabEnvironment DisplayName="Taking Post Deployment snapshot" sap:VirtualizedContainerService.HintSize="464,22" LabEnvironmentUri="[LabEnvironmentUri]" SnapshotChainId="[PostDeploymentSnapshotChainId]" SnapshotName="[PostDeploymentSnapshotName]" />
|
||||
<mtlwa:WriteDeploymentInformation Url="{x:Null}" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Taking Snapshot succeeded" sap:VirtualizedContainerService.HintSize="464,22" Message="[String.Format("The following snapshot was taken after the deployment was finished: {0}", PostDeploymentSnapshotName)]" />
|
||||
<mtlwa:WriteDeploymentInformation DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.ConnectToSnapshot]" DisplayName="Added connection link to the Snapshot" sap:VirtualizedContainerService.HintSize="464,22" Message="[PostDeploymentSnapshotName]" Url="[PostDeploymentSnapshotChainId.ToString()]" />
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<Sequence DisplayName = "No Post Deployment Snapshot">
|
||||
<If Condition="[Not String.Equals(Microsoft.TeamFoundation.Lab.Client.LabEnvironment.UnmanagedProvider, labEnvironment.LabProvider)]" DisplayName= "If Virtual Environment">
|
||||
<If.Then>
|
||||
<mtlwa:WriteDeploymentInformation Url="{x:Null}" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Post deployment snapshot not specified" sap:VirtualizedContainerService.HintSize="200,518" Message="Build definition did not specify a post deployment snapshot. It is a best practice to take post deployment snapshot when running the lab workflow." />
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Else>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[LabWorkflowParameters.TestParameters.RunTest = True]" DisplayName="Run Tests on Environment" sap:VirtualizedContainerService.HintSize="858,604">
|
||||
<If.Then>
|
||||
<Sequence DisplayName="Run Tests" sap:VirtualizedContainerService.HintSize="656,498">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtltc:TestingCapabilityInformation" Name="TestCapabilityInfo" />
|
||||
<Variable x:TypeArguments="x:String" Name="variable1" />
|
||||
<Variable x:TypeArguments="mtlwa:TestRunStatistics" Default="[New Microsoft.TeamFoundation.Lab.Workflow.Activities.TestRunStatistics()]" Name="TestResults" />
|
||||
</Sequence.Variables>
|
||||
<mtlwa:ExecuteRemoteTestRun2 MaxWaitTime="{x:Null}" TestEnvironment="{x:Null}" BuildNumber="[BuildNumber]" BuildDefinitionName="[LabWorkflowParameters.BuildDetails.BuildDefinitionName]" DisplayName="Running Tests" sap:VirtualizedContainerService.HintSize="634,22" LabEnvironmentUri="[LabEnvironmentUri]" MaxConsecutiveFailuresToIgnoreDuringWaitForCompletion="[3]" RefreshInterval="[System.TimeSpan.FromMinutes(1)]" Result="[TestResults]" TestDirectory="[BuildLocation]" TestParameters="[LabWorkflowParameters.TestParameters]" Title="[String.Format("{0}", BuildDetail.BuildNumber)]" />
|
||||
<If Condition="[TestResults.PassedTests <> TestResults.TotalTests Or TestResults.TestRunStatus <> TestManagement.Client.TestRunState.Completed]" DisplayName="If all tests have not passed" sap:VirtualizedContainerService.HintSize="634,312">
|
||||
<If.Then>
|
||||
<If Condition="[(LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True AndAlso LabWorkflowParameters.BuildDetails.QueueNewBuild = True) Or (LabWorkflowParameters.DeploymentDetails.DeploymentNeeded = True)]" DisplayName="Set build status" sap:VirtualizedContainerService.HintSize="509,206">
|
||||
<If.Then>
|
||||
<Assign DisplayName="Partially succeeded" sap:VirtualizedContainerService.HintSize="242,100">
|
||||
<Assign.To>
|
||||
<OutArgument x:TypeArguments="mtbc:BuildStatus">[BuildStatus]</OutArgument>
|
||||
</Assign.To>
|
||||
<Assign.Value>
|
||||
<InArgument x:TypeArguments="mtbc:BuildStatus">[Microsoft.TeamFoundation.Build.Client.BuildStatus.PartiallySucceeded]</InArgument>
|
||||
</Assign.Value>
|
||||
</Assign>
|
||||
</If.Then>
|
||||
<If.Else>
|
||||
<Assign DisplayName="Failed" sap:VirtualizedContainerService.HintSize="242,100">
|
||||
<Assign.To>
|
||||
<OutArgument x:TypeArguments="mtbc:BuildStatus">[BuildStatus]</OutArgument>
|
||||
</Assign.To>
|
||||
<Assign.Value>
|
||||
<InArgument x:TypeArguments="mtbc:BuildStatus">[Microsoft.TeamFoundation.Build.Client.BuildStatus.Failed]</InArgument>
|
||||
</Assign.Value>
|
||||
</Assign>
|
||||
</If.Else>
|
||||
</If>
|
||||
</If.Then>
|
||||
</If>
|
||||
</Sequence>
|
||||
</If.Then>
|
||||
</If>
|
||||
<mtbwa:SetBuildProperties DisplayName="Set build status" sap:VirtualizedContainerService.HintSize="858,22" PropertiesToSet="Status" Status="[BuildStatus]" />
|
||||
</Sequence>
|
||||
</Activity>
|
||||
@@ -1,76 +0,0 @@
|
||||
<Activity mc:Ignorable="sad" x:Class="TfsBuild.Process" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mtbc="clr-namespace:Microsoft.TeamFoundation.Build.Client;assembly=Microsoft.TeamFoundation.Build.Client" xmlns:mtbw="clr-namespace:Microsoft.TeamFoundation.Build.Workflow;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwa="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Activities;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwt="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Tracking;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtvc="clr-namespace:Microsoft.TeamFoundation.VersionControl.Client;assembly=Microsoft.TeamFoundation.VersionControl.Client" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:sad="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:sad1="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:this="clr-namespace:TfsBuild;" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<x:Members>
|
||||
<x:Property Name="ConfigurationFolderPath" Type="InArgument(x:String)" />
|
||||
<x:Property Name="AgentSettings" Type="InArgument(mtbwa:AgentSettings)" />
|
||||
<x:Property Name="MSBuildArguments" Type="InArgument(x:String)" />
|
||||
<x:Property Name="MSBuildPlatform" Type="InArgument(mtbwa:ToolPlatform)" />
|
||||
<x:Property Name="DoNotDownloadBuildType" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="LogFilePerProject" Type="InArgument(x:Boolean)" />
|
||||
<x:Property Name="SourcesSubdirectory" Type="InArgument(x:String)" />
|
||||
<x:Property Name="BinariesSubdirectory" Type="InArgument(x:String)" />
|
||||
<x:Property Name="TestResultsSubdirectory" Type="InArgument(x:String)" />
|
||||
<x:Property Name="RecursionType" Type="InArgument(mtvc:RecursionType)" />
|
||||
<x:Property Name="Verbosity" Type="InArgument(mtbw:BuildVerbosity)" />
|
||||
<x:Property Name="Metadata" Type="mtbw:ProcessParameterMetadataCollection" />
|
||||
<x:Property Name="SupportedReasons" Type="mtbc:BuildReason" />
|
||||
</x:Members>
|
||||
<this:Process.ConfigurationFolderPath>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.ConfigurationFolderPath>
|
||||
<this:Process.AgentSettings>[New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }]</this:Process.AgentSettings>
|
||||
<this:Process.MSBuildArguments>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.MSBuildArguments>
|
||||
<this:Process.MSBuildPlatform>[Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto]</this:Process.MSBuildPlatform>
|
||||
<this:Process.DoNotDownloadBuildType>[False]</this:Process.DoNotDownloadBuildType>
|
||||
<this:Process.LogFilePerProject>[False]</this:Process.LogFilePerProject>
|
||||
<this:Process.SourcesSubdirectory>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.SourcesSubdirectory>
|
||||
<this:Process.BinariesSubdirectory>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.BinariesSubdirectory>
|
||||
<this:Process.TestResultsSubdirectory>
|
||||
<InArgument x:TypeArguments="x:String" />
|
||||
</this:Process.TestResultsSubdirectory>
|
||||
<this:Process.RecursionType>[Microsoft.TeamFoundation.VersionControl.Client.RecursionType.OneLevel]</this:Process.RecursionType>
|
||||
<this:Process.Verbosity>[Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal]</this:Process.Verbosity>
|
||||
<this:Process.Metadata>
|
||||
<mtbw:ProcessParameterMetadataCollection />
|
||||
</this:Process.Metadata>
|
||||
<this:Process.SupportedReasons>All</this:Process.SupportedReasons>
|
||||
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
|
||||
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
|
||||
<Sequence.Variables>
|
||||
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="BuildDetail" />
|
||||
</Sequence.Variables>
|
||||
<mtbwa:GetBuildDetail DisplayName="Get the Build" Result="[BuildDetail]" />
|
||||
<mtbwa:InvokeForReason DisplayName="Update Build Number for Triggered Builds" Reason="Triggered">
|
||||
<mtbwa:UpdateBuildNumber BuildNumberFormat="["$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)"]" DisplayName="Update Build Number" />
|
||||
</mtbwa:InvokeForReason>
|
||||
<mtbwa:AgentScope DisplayName="Run On Agent" MaxExecutionTime="[AgentSettings.MaxExecutionTime]" MaxWaitTime="[AgentSettings.MaxWaitTime]" ReservationSpec="[AgentSettings.GetAgentReservationSpec()]">
|
||||
<mtbwa:AgentScope.Variables>
|
||||
<Variable x:TypeArguments="x:String" Name="buildDirectory" />
|
||||
</mtbwa:AgentScope.Variables>
|
||||
<mtbwa:GetBuildDirectory DisplayName="Get the Build Directory" Result="[buildDirectory]" />
|
||||
<If Condition="[Not String.IsNullOrEmpty(ConfigurationFolderPath)]" DisplayName="If Not String.IsNullOrEmpty(ConfigurationFolderPath)">
|
||||
<If.Then>
|
||||
<mtbwa:TfsBuild BinariesSubdirectory="[BinariesSubdirectory]" BuildDirectory="[buildDirectory]" CommandLineArguments="[MSBuildArguments]" ConfigurationFolderPath="[ConfigurationFolderPath]" DisplayName="Run TfsBuild for Configuration Folder" DoNotDownloadBuildType="[DoNotDownloadBuildType]" LogFilePerProject="[LogFilePerProject]" RecursionType="[RecursionType]" SourcesSubdirectory="[SourcesSubdirectory]" TargetsNotLogged="[New String() {"GetNativeManifest", "GetCopyToOutputDirectoryItems", "GetTargetPath"}]" TestResultsSubdirectory="[TestResultsSubdirectory]" ToolPlatform="[MSBuildPlatform]" Verbosity="[Verbosity]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[BuildDetail.CompilationStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Unknown]" DisplayName="If CompilationStatus = Unknown">
|
||||
<If.Then>
|
||||
<mtbwa:SetBuildProperties CompilationStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" DisplayName="Set CompilationStatus to Succeeded" PropertiesToSet="CompilationStatus" />
|
||||
</If.Then>
|
||||
</If>
|
||||
<If Condition="[BuildDetail.TestStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Unknown]" DisplayName="If TestStatus = Unknown">
|
||||
<If.Then>
|
||||
<mtbwa:SetBuildProperties DisplayName="Set TestStatus to Succeeded" PropertiesToSet="TestStatus" TestStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" />
|
||||
</If.Then>
|
||||
</If>
|
||||
</mtbwa:AgentScope>
|
||||
<mtbwa:InvokeForReason Reason="CheckInShelveset">
|
||||
<mtbwa:CheckInGatedChanges DisplayName="Check In Gated Changes" />
|
||||
</mtbwa:InvokeForReason>
|
||||
</Sequence>
|
||||
</Activity>
|
||||
@@ -1,198 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{336AAF8A-5316-4303-9E73-5E38BD0B28AF}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MeshExplorer</RootNamespace>
|
||||
<AssemblyName>Mesh Explorer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Controls\ColorScheme.cs" />
|
||||
<Compile Include="Controls\DarkButton.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkCheckBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\AngleHistogram.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkListBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkSlider.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkTabControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkTextBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkToolStripRenderer.cs" />
|
||||
<Compile Include="DarkMessageBox.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormExport.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormExport.Designer.cs">
|
||||
<DependentUpon>FormExport.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormGenerator.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormGenerator.Designer.cs">
|
||||
<DependentUpon>FormGenerator.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormLog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormLog.Designer.cs">
|
||||
<DependentUpon>FormLog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormMain.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormMain.Designer.cs">
|
||||
<DependentUpon>FormMain.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormTopology.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormTopology.Designer.cs">
|
||||
<DependentUpon>FormTopology.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Generators\BaseGenerator.cs" />
|
||||
<Compile Include="Generators\BoxWithHole.cs" />
|
||||
<Compile Include="Generators\CircleWithHole.cs" />
|
||||
<Compile Include="Generators\IGenerator.cs" />
|
||||
<Compile Include="Generators\RandomPoints.cs" />
|
||||
<Compile Include="Generators\RandomPointsCircle.cs" />
|
||||
<Compile Include="Generators\RingPolygon.cs" />
|
||||
<Compile Include="Generators\StarInBox.cs" />
|
||||
<Compile Include="GenericEventArgs.cs" />
|
||||
<Compile Include="IO\FileProcessor.cs" />
|
||||
<Compile Include="IO\Formats\JsonFile.cs" />
|
||||
<Compile Include="IO\Formats\TriangleFile.cs" />
|
||||
<Compile Include="IO\ImageWriter.cs" />
|
||||
<Compile Include="IO\IMeshFile.cs" />
|
||||
<Compile Include="IO\JsonParser.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Topology\TopologyControlView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Topology\TopologyControlView.Designer.cs">
|
||||
<DependentUpon>TopologyControlView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Topology\TopologyRenderControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Topology\TopologyRenderer.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<Compile Include="Views\AboutView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Views\AboutView.Designer.cs">
|
||||
<DependentUpon>AboutView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\IView.cs" />
|
||||
<Compile Include="Views\MeshControlView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Views\MeshControlView.Designer.cs">
|
||||
<DependentUpon>MeshControlView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\StatisticView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Views\StatisticView.Designer.cs">
|
||||
<DependentUpon>StatisticView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="FormExport.resx">
|
||||
<DependentUpon>FormExport.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="FormGenerator.resx">
|
||||
<DependentUpon>FormGenerator.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="FormLog.resx">
|
||||
<DependentUpon>FormLog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="FormMain.resx">
|
||||
<DependentUpon>FormMain.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="FormTopology.resx">
|
||||
<DependentUpon>FormTopology.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Topology\TopologyControlView.resx">
|
||||
<DependentUpon>TopologyControlView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Views\AboutView.resx">
|
||||
<DependentUpon>AboutView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Views\MeshControlView.resx">
|
||||
<DependentUpon>MeshControlView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Views\StatisticView.resx">
|
||||
<DependentUpon>StatisticView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle.Rendering\Triangle.Rendering.csproj">
|
||||
<Project>{41022e0e-bd0f-439e-bc3a-aabb1b43471b}</Project>
|
||||
<Name>Triangle.Rendering</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj">
|
||||
<Project>{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}</Project>
|
||||
<Name>Triangle</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,10 +0,0 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Mesh Explorer")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Mesh Explorer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("7368d676-5415-47a5-b1a7-3d517e418b21")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -1,68 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class BoundingBox
|
||||
{
|
||||
public float Left;
|
||||
public float Right;
|
||||
public float Bottom;
|
||||
public float Top;
|
||||
|
||||
public float Width
|
||||
{
|
||||
get { return this.Right - this.Left; }
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get { return this.Top - this.Bottom; }
|
||||
}
|
||||
|
||||
public BoundingBox()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public BoundingBox(float left, float right, float bottom, float top)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
this.Bottom = bottom;
|
||||
this.Top = top;
|
||||
}
|
||||
|
||||
public void Update(Point pt)
|
||||
{
|
||||
this.Update(pt.X, pt.Y);
|
||||
}
|
||||
|
||||
public void Update(PointF pt)
|
||||
{
|
||||
this.Update(pt.X, pt.Y);
|
||||
}
|
||||
|
||||
public void Update(double x, double y)
|
||||
{
|
||||
Update((float)x, (float)y);
|
||||
}
|
||||
|
||||
public void Update(float x, float y)
|
||||
{
|
||||
// Update bounding box
|
||||
if (this.Left > x) this.Left = x;
|
||||
if (this.Right < x) this.Right = x;
|
||||
if (this.Bottom > y) this.Bottom = y;
|
||||
if (this.Top < y) this.Top = y;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.Left = float.MaxValue;
|
||||
this.Right = -float.MaxValue;
|
||||
this.Bottom = float.MaxValue;
|
||||
this.Top = -float.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public abstract class BufferBase<T> : IBuffer<T> where T : struct
|
||||
{
|
||||
protected T[] data;
|
||||
protected int size;
|
||||
|
||||
public BufferBase(int capacity, int size)
|
||||
{
|
||||
this.data = new T[capacity];
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public BufferBase(T[] data, int size)
|
||||
{
|
||||
this.data = data;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public T[] Data
|
||||
{
|
||||
get { return data; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return data == null ? 0 : data.Length; }
|
||||
}
|
||||
|
||||
public abstract int Size
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract BufferTarget Target
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
public class ColorBuffer : BufferBase<Color>
|
||||
{
|
||||
public ColorBuffer(int capacity, int size)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
public ColorBuffer(Color[] data, int size)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
public override int Size
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override BufferTarget Target
|
||||
{
|
||||
get { return BufferTarget.ColorBuffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public class IndexBuffer : BufferBase<int>
|
||||
{
|
||||
public IndexBuffer(int capacity, int size)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
public IndexBuffer(int[] data, int size)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of indices for one element (i.e. 2 for segments
|
||||
/// or 3 for triangles).
|
||||
/// </summary>
|
||||
public override int Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override BufferTarget Target
|
||||
{
|
||||
get { return BufferTarget.IndexBuffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public class VertexBuffer : BufferBase<float>
|
||||
{
|
||||
public VertexBuffer(int capacity, int size = 2)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
public VertexBuffer(float[] data, int size = 2)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of coordinates of one vertex in the buffer (i.e. 2 for
|
||||
/// 2D points or 3D points).
|
||||
/// </summary>
|
||||
public override int Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override BufferTarget Target
|
||||
{
|
||||
get { return BufferTarget.VertexBuffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
public class ColorManager
|
||||
{
|
||||
Color background;
|
||||
SolidBrush point;
|
||||
SolidBrush steinerPoint;
|
||||
Pen line;
|
||||
Pen segment;
|
||||
Pen voronoiLine;
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public Color Background
|
||||
{
|
||||
get { return background; }
|
||||
set { background = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for points.
|
||||
/// </summary>
|
||||
public SolidBrush Point
|
||||
{
|
||||
get { return point; }
|
||||
set
|
||||
{
|
||||
if (point != null) point.Dispose();
|
||||
point = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for steiner points.
|
||||
/// </summary>
|
||||
public SolidBrush SteinerPoint
|
||||
{
|
||||
get { return steinerPoint; }
|
||||
set
|
||||
{
|
||||
if (steinerPoint != null) steinerPoint.Dispose();
|
||||
steinerPoint = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for mesh edges.
|
||||
/// </summary>
|
||||
public Pen Line
|
||||
{
|
||||
get { return line; }
|
||||
set
|
||||
{
|
||||
if (line != null) line.Dispose();
|
||||
line = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for mesh segments.
|
||||
/// </summary>
|
||||
public Pen Segment
|
||||
{
|
||||
get { return segment; }
|
||||
set
|
||||
{
|
||||
if (segment != null) segment.Dispose();
|
||||
segment = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for Voronoi edges.
|
||||
/// </summary>
|
||||
public Pen VoronoiLine
|
||||
{
|
||||
get { return voronoiLine; }
|
||||
set
|
||||
{
|
||||
if (voronoiLine != null) voronoiLine.Dispose();
|
||||
voronoiLine = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a dictionary which maps region ids (or partition indices) to a color.
|
||||
/// </summary>
|
||||
public Dictionary<int, Color> ColorDictionary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a colormap which is used for function plotting.
|
||||
/// </summary>
|
||||
public ColorMap ColorMap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="ColorManager"/> class with default (dark) color scheme.
|
||||
/// </summary>
|
||||
public static ColorManager Default()
|
||||
{
|
||||
var colors = new ColorManager();
|
||||
|
||||
colors.Background = Color.FromArgb(0, 0, 0);
|
||||
colors.Point = new SolidBrush(Color.Green);
|
||||
colors.SteinerPoint = new SolidBrush(Color.Peru);
|
||||
colors.Line = new Pen(Color.FromArgb(30, 30, 30));
|
||||
colors.Segment = new Pen(Color.DarkBlue);
|
||||
colors.VoronoiLine = new Pen(Color.FromArgb(40, 50, 60));
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
public void CreateColorDictionary(int length)
|
||||
{
|
||||
var keys = new int[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
keys[i] = i;
|
||||
}
|
||||
|
||||
CreateColorDictionary(keys, length);
|
||||
}
|
||||
|
||||
public void CreateColorDictionary(IEnumerable<int> keys, int length)
|
||||
{
|
||||
this.ColorDictionary = new Dictionary<int, Color>();
|
||||
|
||||
int i = 0, n = regionColors.Length;
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
this.ColorDictionary.Add(key, regionColors[i]);
|
||||
|
||||
i = (i + 1) % n;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Dispose(Dictionary<int, SolidBrush> brushes)
|
||||
{
|
||||
foreach (var brush in brushes.Values)
|
||||
{
|
||||
brush.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal Dictionary<int, SolidBrush> GetBrushDictionary()
|
||||
{
|
||||
var brushes = new Dictionary<int, SolidBrush>();
|
||||
|
||||
foreach (var item in ColorDictionary)
|
||||
{
|
||||
brushes.Add(item.Key, new SolidBrush(item.Value));
|
||||
}
|
||||
|
||||
return brushes;
|
||||
}
|
||||
|
||||
// Change or add as many colors as you like...
|
||||
private static Color[] regionColors = {
|
||||
Color.Transparent,
|
||||
Color.FromArgb(200, 0, 255, 0),
|
||||
Color.FromArgb(200, 255, 0, 0),
|
||||
Color.FromArgb(200, 0, 0, 255),
|
||||
Color.FromArgb(200, 0, 255, 255),
|
||||
Color.FromArgb(200, 255, 255, 0),
|
||||
Color.FromArgb(200, 255, 0, 255),
|
||||
Color.FromArgb(200, 127, 0, 255),
|
||||
Color.FromArgb(200, 0, 127, 255)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Enables rendering of polygons or meshes to a bitmap.
|
||||
/// </summary>
|
||||
public class ImageRenderer
|
||||
{
|
||||
ColorManager colors = LightScheme();
|
||||
|
||||
public ColorManager ColorScheme
|
||||
{
|
||||
get { return colors; }
|
||||
set { colors = value; }
|
||||
}
|
||||
|
||||
public bool EnableRegions { get; set; }
|
||||
|
||||
public bool EnablePoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Export the mesh to PNG format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <param name="file">The PNG filename.</param>
|
||||
/// <param name="regions">Enable rendering of regions.</param>
|
||||
/// <param name="points">Enable rendering of points.</param>
|
||||
public static void Save(IMesh mesh, string file = null, int width = 800,
|
||||
bool regions = false, bool points = true)
|
||||
{
|
||||
// Check file name
|
||||
if (string.IsNullOrWhiteSpace(file))
|
||||
{
|
||||
file = string.Format("mesh-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
// Ensure .png extension.
|
||||
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Path.ChangeExtension(file, ".png");
|
||||
}
|
||||
|
||||
var renderer = new ImageRenderer();
|
||||
|
||||
renderer.EnableRegions = regions;
|
||||
renderer.EnablePoints = points;
|
||||
|
||||
var bitmap = renderer.Render(mesh, width);
|
||||
|
||||
bitmap.Save(file, ImageFormat.Png);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the mesh to a bitmap.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <returns>The bitmap.</returns>
|
||||
/// <remarks>
|
||||
/// The width has to be at least 2 * sqrt(n), n the number of vertices.
|
||||
/// Otherwise, an empty bitmap
|
||||
/// </remarks>
|
||||
public Bitmap Render(IMesh mesh, int width = 800)
|
||||
{
|
||||
Bitmap bitmap;
|
||||
|
||||
// Check if the specified width is reasonable
|
||||
if (width < 2 * Math.Sqrt(mesh.Vertices.Count))
|
||||
{
|
||||
return new Bitmap(1, 1);
|
||||
}
|
||||
|
||||
var bounds = mesh.Bounds;
|
||||
|
||||
// World margin on each side
|
||||
float margin = (float)bounds.Height * 0.05f;
|
||||
float scale = width / ((float)bounds.Width + 2 * margin);
|
||||
|
||||
var target = new Rectangle(0, 0, width, (int)((bounds.Height + 2 * margin) * scale));
|
||||
|
||||
bitmap = new Bitmap(width, target.Height, PixelFormat.Format32bppPArgb);
|
||||
|
||||
using (var g = Graphics.FromImage(bitmap))
|
||||
{
|
||||
g.Clear(colors.Background);
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
var context = new RenderContext(new Projection(target), colors);
|
||||
context.Add(mesh, true);
|
||||
|
||||
if (EnableRegions)
|
||||
{
|
||||
context.Add(GetRegions(mesh));
|
||||
}
|
||||
|
||||
if (!EnablePoints)
|
||||
{
|
||||
context.Enable(3, false);
|
||||
}
|
||||
|
||||
var renderer = new LayerRenderer();
|
||||
renderer.Context = context;
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private int[] GetRegions(IMesh mesh)
|
||||
{
|
||||
mesh.Renumber();
|
||||
|
||||
var labels = new int[mesh.Triangles.Count];
|
||||
var regions = new SortedSet<int>();
|
||||
|
||||
foreach (var t in mesh.Triangles)
|
||||
{
|
||||
labels[t.ID] = t.Label;
|
||||
regions.Add(t.Label);
|
||||
}
|
||||
|
||||
if (colors.ColorDictionary == null)
|
||||
{
|
||||
colors.CreateColorDictionary(regions, regions.Count);
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public static ColorManager LightScheme()
|
||||
{
|
||||
var colors = new ColorManager();
|
||||
|
||||
colors.Background = Color.White;
|
||||
colors.Point = new SolidBrush(Color.FromArgb(60, 80, 120));
|
||||
colors.SteinerPoint = new SolidBrush(Color.DarkGreen);
|
||||
colors.Line = new Pen(Color.FromArgb(200, 200, 200));
|
||||
colors.Segment = new Pen(Color.SteelBlue);
|
||||
colors.VoronoiLine = new Pen(Color.FromArgb(160, 170, 180));
|
||||
|
||||
return colors;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Voronoi.Legacy;
|
||||
|
||||
public interface IRenderContext
|
||||
{
|
||||
ColorManager ColorManager { get; }
|
||||
|
||||
BoundingBox Bounds { get; }
|
||||
|
||||
IList<IRenderLayer> RenderLayers { get; }
|
||||
|
||||
Projection Zoom { get; }
|
||||
|
||||
IMesh Mesh { get; }
|
||||
|
||||
bool HasData { get; }
|
||||
|
||||
void Add(IPolygon data);
|
||||
void Add(IMesh data, bool reset);
|
||||
void Add(ICollection<Point> points, IEnumerable<IEdge> edges, bool reset);
|
||||
|
||||
void Add(float[] values);
|
||||
void Add(int[] partition);
|
||||
|
||||
void Enable(int layer, bool enabled);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
public interface IRenderLayer
|
||||
{
|
||||
int Count { get; }
|
||||
|
||||
// Points can be set, because layers may share vertices.
|
||||
IBuffer<float> Points { get; }
|
||||
IBuffer<int> Indices { get; }
|
||||
|
||||
bool IsEnabled { get; set; }
|
||||
|
||||
bool IsEmpty();
|
||||
|
||||
void Reset(bool clear);
|
||||
|
||||
// TODO: add boolean: reset
|
||||
BoundingBox SetPoints(IBuffer<float> buffer);
|
||||
BoundingBox SetPoints(IPolygon poly);
|
||||
BoundingBox SetPoints(IMesh mesh);
|
||||
BoundingBox SetPoints(ICollection<Point> points);
|
||||
void SetPolygon(IPolygon poly);
|
||||
void SetPolygon(IMesh mesh);
|
||||
void SetMesh(IMesh mesh, bool elements);
|
||||
void SetMesh(IEnumerable<IEdge> edges);
|
||||
|
||||
|
||||
// TODO: better put these into a subclass.
|
||||
IBuffer<int> Partition { get; }
|
||||
IBuffer<Color> Colors { get; }
|
||||
|
||||
void AttachLayerData(float[] values, ColorMap colormap);
|
||||
void AttachLayerData(int[] partition);
|
||||
}
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Projection.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Manages a world to screen transformation (2D orthographic projection).
|
||||
/// </summary>
|
||||
public class Projection
|
||||
{
|
||||
// The screen.
|
||||
Rectangle screen;
|
||||
|
||||
// The complete mesh.
|
||||
RectangleF world;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current viewport (visible mesh).
|
||||
/// </summary>
|
||||
public RectangleF Viewport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current scale.
|
||||
/// </summary>
|
||||
public float Scale
|
||||
{
|
||||
get { return screen.Width / Viewport.Width; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zoom level.
|
||||
/// </summary>
|
||||
public int Level { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a clip margin (default is 5% of viewport width on each side).
|
||||
/// </summary>
|
||||
public float ClipMargin { get; set; }
|
||||
|
||||
// The y-direction of windows screen coordinates is upside down,
|
||||
// so inverY must be set to true.
|
||||
bool invertY = false;
|
||||
|
||||
int maxZoomLevel = 100;
|
||||
|
||||
public Projection(Rectangle screen, bool invertY = true)
|
||||
{
|
||||
this.screen = screen;
|
||||
this.world = screen;
|
||||
this.Viewport = screen;
|
||||
|
||||
this.Level = 1;
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
this.invertY = invertY;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inititialize the projection.
|
||||
/// </summary>
|
||||
/// <param name="world">The world that should be transformed to screen coordinates.</param>
|
||||
public void Initialize(BoundingBox world)
|
||||
{
|
||||
this.Level = 1;
|
||||
|
||||
// Add a margin so there's some space around the border
|
||||
float worldMargin = (world.Width < world.Height) ? world.Height * 0.05f : world.Width * 0.05f;
|
||||
|
||||
// Get the initial viewport (complete mesh centered on the screen)
|
||||
float screenRatio = screen.Width / (float)screen.Height;
|
||||
float worldRatio = world.Width / world.Height;
|
||||
|
||||
float scale = (world.Width + worldMargin) / screen.Width;
|
||||
|
||||
if (screenRatio > worldRatio)
|
||||
{
|
||||
scale = (world.Height + worldMargin) / screen.Height;
|
||||
}
|
||||
|
||||
float centerX = world.Left + world.Width / 2;
|
||||
float centerY = world.Bottom + world.Height / 2;
|
||||
|
||||
// TODO: Add initial margin
|
||||
this.Viewport = new RectangleF(centerX - screen.Width * scale / 2,
|
||||
centerY - screen.Height * scale / 2,
|
||||
screen.Width * scale,
|
||||
screen.Height * scale);
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
this.world = this.Viewport;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle resize of the screen.
|
||||
/// </summary>
|
||||
/// <param name="newScreen">The new screen dimensions.</param>
|
||||
public void Resize(Rectangle newScreen)
|
||||
{
|
||||
// The viewport has to be updated, but we want to keep
|
||||
// the scaling and the center.
|
||||
|
||||
// Get the screen scaling.
|
||||
float scaleX = newScreen.Width / (float)screen.Width;
|
||||
float scaleY = newScreen.Height / (float)screen.Height;
|
||||
|
||||
this.screen = newScreen;
|
||||
|
||||
var view = this.Viewport;
|
||||
|
||||
// Center of the viewport
|
||||
float centerX = (view.Left + view.Right) / 2;
|
||||
float centerY = (view.Bottom + view.Top) / 2;
|
||||
|
||||
// The new viewport dimensions.
|
||||
float width = view.Width * scaleX;
|
||||
float height = view.Height * scaleY;
|
||||
|
||||
this.Viewport = new RectangleF(
|
||||
centerX - width / 2,
|
||||
centerY - height / 2,
|
||||
width, height);
|
||||
|
||||
// Do the same for the world:
|
||||
centerX = (world.Left + world.Right) / 2;
|
||||
centerY = (world.Bottom + world.Top) / 2;
|
||||
|
||||
width = world.Width * scaleX;
|
||||
height = world.Height * scaleY;
|
||||
|
||||
this.world = new RectangleF(
|
||||
centerX - width / 2,
|
||||
centerY - height / 2,
|
||||
width, height);
|
||||
}
|
||||
|
||||
public bool Translate(int dx, int dy)
|
||||
{
|
||||
if (Level == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var view = this.Viewport;
|
||||
|
||||
float x = view.X + dx * view.Width / 4;
|
||||
float y = view.Y + dy * view.Height / 4;
|
||||
|
||||
this.Viewport = new RectangleF(x, y, view.Width, view.Height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom in or out of the viewport.
|
||||
/// </summary>
|
||||
/// <param name="amount">Zoom amount</param>
|
||||
/// <param name="focusX">Relative x point position</param>
|
||||
/// <param name="focusY">Relative y point position</param>
|
||||
public bool Zoom(int amount, float focusX, float focusY)
|
||||
{
|
||||
float width, height;
|
||||
|
||||
if (invertY)
|
||||
{
|
||||
focusY = 1 - focusY;
|
||||
}
|
||||
|
||||
if (amount > 0) // Zoom in
|
||||
{
|
||||
this.Level++;
|
||||
|
||||
if (this.Level > maxZoomLevel)
|
||||
{
|
||||
this.Level = maxZoomLevel;
|
||||
return false;
|
||||
}
|
||||
|
||||
width = Viewport.Width / 1.1f;
|
||||
height = Viewport.Height / 1.1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Level--;
|
||||
|
||||
if (this.Level < 1)
|
||||
{
|
||||
this.Level = 1;
|
||||
this.Viewport = this.world;
|
||||
return false;
|
||||
}
|
||||
|
||||
width = Viewport.Width * 1.1f;
|
||||
height = Viewport.Height * 1.1f;
|
||||
}
|
||||
|
||||
// Current focus on viewport
|
||||
float x = Viewport.X + Viewport.Width * focusX;
|
||||
float y = Viewport.Y + Viewport.Height * focusY;
|
||||
|
||||
// New left and top positions
|
||||
x = x - width * focusX;
|
||||
y = y - height * focusY;
|
||||
|
||||
// Check if outside of world
|
||||
if (x < world.X)
|
||||
{
|
||||
x = world.X;
|
||||
}
|
||||
else if (x + width > world.Right)
|
||||
{
|
||||
x = world.Right - width;
|
||||
}
|
||||
|
||||
if (y < world.Y)
|
||||
{
|
||||
y = world.Y;
|
||||
}
|
||||
else if (y + height > world.Bottom)
|
||||
{
|
||||
y = world.Bottom - height;
|
||||
}
|
||||
|
||||
// Set new viewport
|
||||
this.Viewport = new RectangleF(x, y, width, height);
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.Viewport = this.world;
|
||||
this.Level = 1;
|
||||
}
|
||||
|
||||
public void WorldToScreen(ref PointF pt)
|
||||
{
|
||||
pt.X = (pt.X - Viewport.X) / Viewport.Width * screen.Width;
|
||||
pt.Y = (1 - (pt.Y - Viewport.Y) / Viewport.Height) * screen.Height;
|
||||
}
|
||||
|
||||
public void ScreenToWorld(ref PointF pt)
|
||||
{
|
||||
pt.X = Viewport.X + Viewport.Width * pt.X;
|
||||
pt.Y = Viewport.Y + Viewport.Height * (1 - pt.Y);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public PointF WorldToScreen(float x, float y)
|
||||
{
|
||||
return new PointF((x - Viewport.X) / Viewport.Width * screen.Width,
|
||||
(1 - (y - Viewport.Y) / Viewport.Height) * screen.Height);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public PointF ScreenToWorld(float x, float y)
|
||||
{
|
||||
return new PointF(Viewport.X + Viewport.Width * x,
|
||||
Viewport.Y + Viewport.Height * (1 - y));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Triangle.Rendering")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Triangle.Rendering")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("14f2491b-ee62-41e4-ab93-206540302ece")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,188 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
public class RenderLayer : IRenderLayer
|
||||
{
|
||||
int count;
|
||||
|
||||
protected IBuffer<float> points;
|
||||
protected IBuffer<int> indices;
|
||||
|
||||
protected IBuffer<int> partition;
|
||||
protected IBuffer<Color> colors;
|
||||
|
||||
public RenderLayer()
|
||||
{
|
||||
this.IsEnabled = false;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return count; }
|
||||
}
|
||||
|
||||
public IBuffer<float> Points
|
||||
{
|
||||
get { return points; }
|
||||
set { points = value; }
|
||||
}
|
||||
|
||||
public IBuffer<int> Indices
|
||||
{
|
||||
get { return indices; }
|
||||
}
|
||||
|
||||
public IBuffer<int> Partition
|
||||
{
|
||||
get { return partition; }
|
||||
}
|
||||
|
||||
public IBuffer<Color> Colors
|
||||
{
|
||||
get { return colors; }
|
||||
}
|
||||
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return (points == null || points.Count == 0);
|
||||
}
|
||||
|
||||
public void Reset(bool clear)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
count = 0;
|
||||
points = null;
|
||||
}
|
||||
|
||||
indices = null;
|
||||
partition = null;
|
||||
colors = null;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IBuffer<float> buffer)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
if (points != null && points.Count < buffer.Count)
|
||||
{
|
||||
count = points.Count / points.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = buffer.Count / buffer.Size;
|
||||
}
|
||||
|
||||
this.points = buffer;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IPolygon poly)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
points = BufferHelper.CreateVertexBuffer(poly.Points, ref bounds);
|
||||
count = points.Count / points.Size;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IMesh mesh)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
points = BufferHelper.CreateVertexBuffer(mesh.Vertices, ref bounds);
|
||||
count = points.Count / points.Size;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(ICollection<Point> vertices)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
points = BufferHelper.CreateVertexBuffer(vertices, ref bounds);
|
||||
count = points.Count / points.Size;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public void SetPolygon(IPolygon poly)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(poly.Segments, 2);
|
||||
}
|
||||
|
||||
public void SetPolygon(IMesh mesh)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(mesh.Segments, 2);
|
||||
}
|
||||
|
||||
public void SetMesh(IEnumerable<IEdge> edges)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(edges, 2);
|
||||
}
|
||||
|
||||
public void SetMesh(IMesh mesh, bool elements)
|
||||
{
|
||||
mesh.Renumber();
|
||||
|
||||
if (!elements)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(mesh.Edges, 2);
|
||||
}
|
||||
|
||||
if (elements || indices.Count == 0)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(mesh.Triangles, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove colormap argument
|
||||
public void AttachLayerData(float[] values, ColorMap colormap)
|
||||
{
|
||||
int length = values.Length;
|
||||
|
||||
Color[] data = new Color[length];
|
||||
|
||||
double min = double.MaxValue;
|
||||
double max = double.MinValue;
|
||||
|
||||
// Find min and max of given values.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (values[i] < min)
|
||||
{
|
||||
min = values[i];
|
||||
}
|
||||
|
||||
if (values[i] > max)
|
||||
{
|
||||
max = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
data[i] = colormap.GetColor(values[i], min, max);
|
||||
}
|
||||
|
||||
colors = new ColorBuffer(data, 1);
|
||||
}
|
||||
|
||||
public void AttachLayerData(int[] partition)
|
||||
{
|
||||
this.partition = new IndexBuffer(partition, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
static class EdgeIterator
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerate the edges of the mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="skipSegments"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// In contrast to the <see cref="TriangleNet.Meshing.Iterators.EdgeIterator"/> this
|
||||
/// method will return objects that include the vertex information (and not only the
|
||||
/// indices).
|
||||
/// </remarks>
|
||||
public static IEnumerable<ISegment> EnumerateEdges(Mesh mesh, bool skipSegments = true)
|
||||
{
|
||||
foreach (var t in mesh.Triangles)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int nid = t.GetNeighborID(i);
|
||||
|
||||
if ((t.ID < nid) || (nid < 0))
|
||||
{
|
||||
var s = t.GetSegment(i);
|
||||
|
||||
if (skipSegments && s == null)
|
||||
{
|
||||
// Since segments will be processed separately, don't
|
||||
// include them in the enumeration.
|
||||
yield return new Segment(
|
||||
t.GetVertex((i + 1) % 3),
|
||||
t.GetVertex((i + 2) % 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
yield return new Segment(
|
||||
t.GetVertex((i + 1) % 3),
|
||||
t.GetVertex((i + 2) % 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{41022E0E-BD0F-439E-BC3A-AABB1B43471B}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>TriangleNet.Rendering</RootNamespace>
|
||||
<AssemblyName>Triangle.Rendering</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BoundingBox.cs" />
|
||||
<Compile Include="Buffer\BufferBase.cs" />
|
||||
<Compile Include="Buffer\ColorBuffer.cs" />
|
||||
<Compile Include="Buffer\IBuffer.cs" />
|
||||
<Compile Include="Buffer\IndexBuffer.cs" />
|
||||
<Compile Include="Buffer\VertexBuffer.cs" />
|
||||
<Compile Include="ColorManager.cs" />
|
||||
<Compile Include="ExtensionMethods.cs" />
|
||||
<Compile Include="GDI\FunctionRenderer.cs" />
|
||||
<Compile Include="GDI\ImageRenderer.cs" />
|
||||
<Compile Include="GDI\LayerRenderer.cs" />
|
||||
<Compile Include="GDI\MeshRenderer.cs" />
|
||||
<Compile Include="GDI\Native\GradientFillMode.cs" />
|
||||
<Compile Include="GDI\Native\GradientRect.cs" />
|
||||
<Compile Include="GDI\Native\GradientTriangle.cs" />
|
||||
<Compile Include="GDI\Native\NativeMethods.cs" />
|
||||
<Compile Include="GDI\Native\TriVertex.cs" />
|
||||
<Compile Include="GDI\RenderControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="IRenderContext.cs" />
|
||||
<Compile Include="IRenderControl.cs" />
|
||||
<Compile Include="IRenderer.cs" />
|
||||
<Compile Include="IRenderLayer.cs" />
|
||||
<Compile Include="Projection.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RenderContext.cs" />
|
||||
<Compile Include="RenderLayer.cs" />
|
||||
<Compile Include="RenderManager.cs" />
|
||||
<Compile Include="Text\EdgeIterator.cs" />
|
||||
<Compile Include="Text\EpsDocument.cs" />
|
||||
<Compile Include="Text\EpsImage.cs" />
|
||||
<Compile Include="Text\FormattingStreamWriter.cs" />
|
||||
<Compile Include="Text\PageSize.cs" />
|
||||
<Compile Include="Text\SvgImage.cs" />
|
||||
<Compile Include="Util\BufferHelper.cs" />
|
||||
<Compile Include="Util\ColorMap.cs" />
|
||||
<Compile Include="Util\ReflectionHelper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj">
|
||||
<Project>{f7907a0a-b75f-400b-9e78-bfad00db4d6b}</Project>
|
||||
<Name>Triangle</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,10 +0,0 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Topology;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
|
||||
internal static class BufferHelper
|
||||
{
|
||||
public static IBuffer<float> CreateVertexBuffer(double[] points, ref BoundingBox bounds)
|
||||
{
|
||||
int length = points.Length;
|
||||
|
||||
var buffer = new VertexBuffer(length);
|
||||
|
||||
bounds.Reset();
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
float x, y;
|
||||
|
||||
length = length >> 1;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
x = (float)points[2 * i];
|
||||
y = (float)points[2 * i + 1];
|
||||
|
||||
data[2 * i] = x;
|
||||
data[2 * i + 1] = y;
|
||||
|
||||
bounds.Update(x, y);
|
||||
}
|
||||
|
||||
return buffer as IBuffer<float>;
|
||||
}
|
||||
|
||||
public static IBuffer<float> CreateVertexBuffer(ICollection<Point> points, ref BoundingBox bounds)
|
||||
{
|
||||
var buffer = new VertexBuffer(2 * points.Count);
|
||||
|
||||
bounds.Reset();
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
float x, y;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
x = (float)p.X;
|
||||
y = (float)p.Y;
|
||||
|
||||
data[2 * i] = x;
|
||||
data[2 * i + 1] = y;
|
||||
|
||||
bounds.Update(x, y);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<float>;
|
||||
}
|
||||
|
||||
public static IBuffer<float> CreateVertexBuffer(ICollection<Vertex> points, ref BoundingBox bounds)
|
||||
{
|
||||
var buffer = new VertexBuffer(2 * points.Count);
|
||||
|
||||
bounds.Reset();
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
data[2 * i] = (float)p.X;
|
||||
data[2 * i + 1] = (float)p.Y;
|
||||
|
||||
bounds.Update(p.X, p.Y);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<float>;
|
||||
}
|
||||
|
||||
public static IBuffer<int> CreateIndexBuffer(IList<IEdge> segments, int size)
|
||||
{
|
||||
var buffer = new IndexBuffer(size * segments.Count, size);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var e in segments)
|
||||
{
|
||||
data[size * i + 0] = e.P0;
|
||||
data[size * i + 1] = e.P1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<int>;
|
||||
}
|
||||
|
||||
public static IBuffer<int> CreateIndexBuffer(IEnumerable<IEdge> edges, int size)
|
||||
{
|
||||
var data = new List<int>();
|
||||
|
||||
foreach (var e in edges)
|
||||
{
|
||||
data.Add(e.P0);
|
||||
data.Add(e.P1);
|
||||
}
|
||||
|
||||
return new IndexBuffer(data.ToArray(), size) as IBuffer<int>;
|
||||
}
|
||||
|
||||
public static IBuffer<int> CreateIndexBuffer(ICollection<Triangle> elements, int size)
|
||||
{
|
||||
var buffer = new IndexBuffer(size * elements.Count, size);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var e in elements)
|
||||
{
|
||||
data[size * i + 0] = e.GetVertexID(0);
|
||||
data[size * i + 1] = e.GetVertexID(1);
|
||||
data[size * i + 2] = e.GetVertexID(2);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<int>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle", "Triangle\Triangle.csproj", "{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mesh Explorer", "TestApp\Mesh Explorer.csproj", "{336AAF8A-5316-4303-9E73-5E38BD0B28AF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle.Rendering", "Triangle.Rendering\Triangle.Rendering.csproj", "{41022E0E-BD0F-439E-BC3A-AABB1B43471B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 4
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs06
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = Triangle\\Triangle.csproj
|
||||
SccProjectName1 = Triangle
|
||||
SccLocalPath1 = Triangle
|
||||
SccProjectUniqueName2 = TestApp\\Mesh\u0020Explorer.csproj
|
||||
SccProjectName2 = TestApp
|
||||
SccLocalPath2 = TestApp
|
||||
SccProjectUniqueName3 = Triangle.Rendering\\Triangle.Rendering.csproj
|
||||
SccProjectName3 = Triangle.Rendering
|
||||
SccLocalPath3 = Triangle.Rendering
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|x86.Build.0 = Debug|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|x86.ActiveCfg = Release|x86
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|x86.Build.0 = Release|x86
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,10 +0,0 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Polygon.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// A polygon represented as a planar straight line graph.
|
||||
/// </summary>
|
||||
public class Polygon : IPolygon
|
||||
{
|
||||
List<Vertex> points;
|
||||
List<Point> holes;
|
||||
List<RegionPointer> regions;
|
||||
|
||||
List<ISegment> segments;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Vertex> Points
|
||||
{
|
||||
get { return points; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Point> Holes
|
||||
{
|
||||
get { return holes; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<RegionPointer> Regions
|
||||
{
|
||||
get { return regions; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<ISegment> Segments
|
||||
{
|
||||
get { return segments; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasPointMarkers { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasSegmentMarkers { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count
|
||||
{
|
||||
get { return points.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Polygon" /> class.
|
||||
/// </summary>
|
||||
public Polygon()
|
||||
: this(3, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Polygon" /> class.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The default capacity for the points list.</param>
|
||||
public Polygon(int capacity)
|
||||
: this(3, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Polygon" /> class.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The default capacity for the points list.</param>
|
||||
/// <param name="markers">Use point and segment markers.</param>
|
||||
public Polygon(int capacity, bool markers)
|
||||
{
|
||||
points = new List<Vertex>(capacity);
|
||||
holes = new List<Point>();
|
||||
regions = new List<RegionPointer>();
|
||||
|
||||
segments = new List<ISegment>();
|
||||
|
||||
HasPointMarkers = markers;
|
||||
HasSegmentMarkers = markers;
|
||||
}
|
||||
|
||||
[Obsolete("Use polygon.Add(contour) method instead.")]
|
||||
public void AddContour(IEnumerable<Vertex> points, int marker = 0,
|
||||
bool hole = false, bool convex = false)
|
||||
{
|
||||
this.Add(new Contour(points, marker, convex), hole);
|
||||
}
|
||||
|
||||
[Obsolete("Use polygon.Add(contour) method instead.")]
|
||||
public void AddContour(IEnumerable<Vertex> points, int marker, Point hole)
|
||||
{
|
||||
this.Add(new Contour(points, marker), hole);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Rectangle Bounds()
|
||||
{
|
||||
var bounds = new Rectangle();
|
||||
bounds.Expand(this.points);
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a vertex to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="vertex">The vertex to insert.</param>
|
||||
public void Add(Vertex vertex)
|
||||
{
|
||||
this.points.Add(vertex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a segment to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="segment">The segment to insert.</param>
|
||||
/// <param name="insert">If true, both endpoints will be added to the points list.</param>
|
||||
public void Add(ISegment segment, bool insert = false)
|
||||
{
|
||||
this.segments.Add(segment);
|
||||
|
||||
if (insert)
|
||||
{
|
||||
this.points.Add(segment.GetVertex(0));
|
||||
this.points.Add(segment.GetVertex(1));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a segment to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="segment">The segment to insert.</param>
|
||||
/// <param name="index">The index of the segment endpoint to add to the points list (must be 0 or 1).</param>
|
||||
public void Add(ISegment segment, int index)
|
||||
{
|
||||
this.segments.Add(segment);
|
||||
|
||||
this.points.Add(segment.GetVertex(index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a contour to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="contour">The contour to insert.</param>
|
||||
/// <param name="hole">Treat contour as a hole.</param>
|
||||
public void Add(Contour contour, bool hole = false)
|
||||
{
|
||||
if (hole)
|
||||
{
|
||||
this.Add(contour, contour.FindInteriorPoint());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.points.AddRange(contour.Points);
|
||||
this.segments.AddRange(contour.GetSegments());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a contour to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="contour">The contour to insert.</param>
|
||||
/// <param name="hole">Point inside the contour, making it a hole.</param>
|
||||
public void Add(Contour contour, Point hole)
|
||||
{
|
||||
this.points.AddRange(contour.Points);
|
||||
this.segments.AddRange(contour.GetSegments());
|
||||
|
||||
this.holes.Add(hole);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Log.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Logging;
|
||||
|
||||
/// <summary>
|
||||
/// A simple logger, which logs messages to a List.
|
||||
/// </summary>
|
||||
/// <remarks>Using singleton pattern as proposed by Jon Skeet.
|
||||
/// http://csharpindepth.com/Articles/General/Singleton.aspx
|
||||
/// </remarks>
|
||||
public sealed class Log : ILog<LogItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Log detailed information.
|
||||
/// </summary>
|
||||
public static bool Verbose { get; set; }
|
||||
|
||||
private List<LogItem> log = new List<LogItem>();
|
||||
|
||||
private LogLevel level = LogLevel.Info;
|
||||
|
||||
#region Singleton pattern
|
||||
|
||||
private static readonly Log instance = new Log();
|
||||
|
||||
// Explicit static constructor to tell C# compiler
|
||||
// not to mark type as beforefieldinit
|
||||
static Log() { }
|
||||
|
||||
private Log() { }
|
||||
|
||||
public static ILog<LogItem> Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Add(LogItem item)
|
||||
{
|
||||
log.Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
log.Clear();
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
{
|
||||
log.Add(new LogItem(LogLevel.Info, message));
|
||||
}
|
||||
|
||||
public void Warning(string message, string location)
|
||||
{
|
||||
log.Add(new LogItem(LogLevel.Warning, message, location));
|
||||
}
|
||||
|
||||
public void Error(string message, string location)
|
||||
{
|
||||
log.Add(new LogItem(LogLevel.Error, message, location));
|
||||
}
|
||||
|
||||
public IList<LogItem> Data
|
||||
{
|
||||
get { return log; }
|
||||
}
|
||||
|
||||
public LogLevel Level
|
||||
{
|
||||
get { return level; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ILog.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Logging
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
Info = 0,
|
||||
Warning = 1,
|
||||
Error = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A basic log interface.
|
||||
/// </summary>
|
||||
public interface ILog<T> where T : ILogItem
|
||||
{
|
||||
void Add(T item);
|
||||
void Clear();
|
||||
|
||||
void Info(string message);
|
||||
void Error(string message, string info);
|
||||
void Warning(string message, string info);
|
||||
|
||||
IList<T> Data { get; }
|
||||
|
||||
LogLevel Level { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ILogItem.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Logging
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// A basic log item interface.
|
||||
/// </summary>
|
||||
public interface ILogItem
|
||||
{
|
||||
DateTime Time { get; }
|
||||
LogLevel Level { get; }
|
||||
string Message { get; }
|
||||
string Info { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SimpleLogItem.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Logging
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an item stored in the log.
|
||||
/// </summary>
|
||||
public class LogItem : ILogItem
|
||||
{
|
||||
DateTime time;
|
||||
LogLevel level;
|
||||
string message;
|
||||
string info;
|
||||
|
||||
public DateTime Time
|
||||
{
|
||||
get { return time; }
|
||||
}
|
||||
|
||||
public LogLevel Level
|
||||
{
|
||||
get { return level; }
|
||||
}
|
||||
|
||||
public string Message
|
||||
{
|
||||
get { return message; }
|
||||
}
|
||||
|
||||
public string Info
|
||||
{
|
||||
get { return info; }
|
||||
}
|
||||
|
||||
public LogItem(LogLevel level, string message)
|
||||
: this(level, message, "")
|
||||
{ }
|
||||
|
||||
public LogItem(LogLevel level, string message, string info)
|
||||
{
|
||||
this.time = DateTime.Now;
|
||||
this.level = level;
|
||||
this.message = message;
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="EdgeEnumerator.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Meshing.Iterators
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Topology;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the edges of a triangulation.
|
||||
/// </summary>
|
||||
public class EdgeIterator : IEnumerator<Edge>
|
||||
{
|
||||
IEnumerator<Triangle> triangles;
|
||||
Otri tri = default(Otri);
|
||||
Otri neighbor = default(Otri);
|
||||
Osub sub = default(Osub);
|
||||
Edge current;
|
||||
Vertex p1, p2;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EdgeIterator" /> class.
|
||||
/// </summary>
|
||||
public EdgeIterator(Mesh mesh)
|
||||
{
|
||||
triangles = mesh.triangles.GetEnumerator();
|
||||
triangles.MoveNext();
|
||||
|
||||
tri.tri = triangles.Current;
|
||||
tri.orient = 0;
|
||||
}
|
||||
|
||||
public Edge Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.triangles.Dispose();
|
||||
}
|
||||
|
||||
object System.Collections.IEnumerator.Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (tri.tri == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
current = null;
|
||||
|
||||
while (current == null)
|
||||
{
|
||||
if (tri.orient == 3)
|
||||
{
|
||||
if (triangles.MoveNext())
|
||||
{
|
||||
tri.tri = triangles.Current;
|
||||
tri.orient = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Finally no more triangles
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tri.Sym(ref neighbor);
|
||||
|
||||
if ((tri.tri.id < neighbor.tri.id) || (neighbor.tri.id == Mesh.DUMMY))
|
||||
{
|
||||
p1 = tri.Org();
|
||||
p2 = tri.Dest();
|
||||
|
||||
tri.Pivot(ref sub);
|
||||
|
||||
// Boundary mark of dummysub is 0, so we don't need to worry about that.
|
||||
current = new Edge(p1.id, p2.id, sub.seg.boundary);
|
||||
}
|
||||
|
||||
tri.orient++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.triangles.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Triangle")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Triangle")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("96a540d0-1772-4bed-8d25-ef5fa23cd1bc")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,19 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ISmoother.cs">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Smoothing
|
||||
{
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for mesh smoothers.
|
||||
/// </summary>
|
||||
public interface ISmoother
|
||||
{
|
||||
void Smooth(IMesh mesh);
|
||||
void Smooth(IMesh mesh, int limit);
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
|
||||
namespace TriangleNet.Tools
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
public static class Interpolation
|
||||
{
|
||||
#if USE_ATTRIBS
|
||||
/// <summary>
|
||||
/// Linear interpolation of vertex attributes.
|
||||
/// </summary>
|
||||
/// <param name="vertex">The interpolation vertex.</param>
|
||||
/// <param name="triangle">The triangle containing the vertex.</param>
|
||||
/// <param name="n">The number of vertex attributes.</param>
|
||||
/// <remarks>
|
||||
/// The vertex is expected to lie inside the triangle.
|
||||
/// </remarks>
|
||||
public static void InterpolateAttributes(Vertex vertex, ITriangle triangle, int n)
|
||||
{
|
||||
Vertex org = triangle.GetVertex(0);
|
||||
Vertex dest = triangle.GetVertex(1);
|
||||
Vertex apex = triangle.GetVertex(2);
|
||||
|
||||
double xdo, ydo, xao, yao;
|
||||
double denominator;
|
||||
double dx, dy;
|
||||
double xi, eta;
|
||||
|
||||
// Compute the circumcenter of the triangle.
|
||||
xdo = dest.x - org.x;
|
||||
ydo = dest.y - org.y;
|
||||
xao = apex.x - org.x;
|
||||
yao = apex.y - org.y;
|
||||
|
||||
denominator = 0.5 / (xdo * yao - xao * ydo);
|
||||
|
||||
//dx = (yao * dodist - ydo * aodist) * denominator;
|
||||
//dy = (xdo * aodist - xao * dodist) * denominator;
|
||||
|
||||
dx = vertex.x - org.x;
|
||||
dy = vertex.y - org.y;
|
||||
|
||||
// To interpolate vertex attributes for the new vertex, define a
|
||||
// coordinate system with a xi-axis directed from the triangle's
|
||||
// origin to its destination, and an eta-axis, directed from its
|
||||
// origin to its apex.
|
||||
xi = (yao * dx - xao * dy) * (2.0 * denominator);
|
||||
eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
// Interpolate the vertex attributes.
|
||||
vertex.attributes[i] = org.attributes[i]
|
||||
+ xi * (dest.attributes[i] - org.attributes[i])
|
||||
+ eta * (apex.attributes[i] - org.attributes[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_Z
|
||||
/// <summary>
|
||||
/// Linear interpolation of a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="p">The interpolation point.</param>
|
||||
/// <param name="triangle">The triangle containing the point.</param>
|
||||
/// <remarks>
|
||||
/// The point is expected to lie inside the triangle.
|
||||
/// </remarks>
|
||||
public static void InterpolateZ(Point p, ITriangle triangle)
|
||||
{
|
||||
Vertex org = triangle.GetVertex(0);
|
||||
Vertex dest = triangle.GetVertex(1);
|
||||
Vertex apex = triangle.GetVertex(2);
|
||||
|
||||
double xdo, ydo, xao, yao;
|
||||
double denominator;
|
||||
double dx, dy;
|
||||
double xi, eta;
|
||||
|
||||
// Compute the circumcenter of the triangle.
|
||||
xdo = dest.x - org.x;
|
||||
ydo = dest.y - org.y;
|
||||
xao = apex.x - org.x;
|
||||
yao = apex.y - org.y;
|
||||
|
||||
denominator = 0.5 / (xdo * yao - xao * ydo);
|
||||
|
||||
//dx = (yao * dodist - ydo * aodist) * denominator;
|
||||
//dy = (xdo * aodist - xao * dodist) * denominator;
|
||||
|
||||
dx = p.x - org.x;
|
||||
dy = p.y - org.y;
|
||||
|
||||
// To interpolate z value for the given point inserted, define a
|
||||
// coordinate system with a xi-axis, directed from the triangle's
|
||||
// origin to its destination, and an eta-axis, directed from its
|
||||
// origin to its apex.
|
||||
xi = (yao * dx - xao * dy) * (2.0 * denominator);
|
||||
eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
|
||||
|
||||
p.z = org.z + xi * (dest.z - org.z) + eta * (apex.z - org.z);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>TriangleNet</RootNamespace>
|
||||
<AssemblyName>Triangle</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;USE_ATTRIBS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;USE_ATTRIBS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration.cs" />
|
||||
<Compile Include="Geometry\Contour.cs" />
|
||||
<Compile Include="Geometry\Edge.cs" />
|
||||
<Compile Include="Geometry\ExtensionMethods.cs" />
|
||||
<Compile Include="Geometry\IEdge.cs" />
|
||||
<Compile Include="Geometry\IPolygon.cs" />
|
||||
<Compile Include="Geometry\ISegment.cs" />
|
||||
<Compile Include="Geometry\ITriangle.cs" />
|
||||
<Compile Include="Geometry\Point.cs" />
|
||||
<Compile Include="Geometry\Polygon.cs" />
|
||||
<Compile Include="Geometry\Rectangle.cs" />
|
||||
<Compile Include="Geometry\RegionPointer.cs" />
|
||||
<Compile Include="Geometry\Segment.cs" />
|
||||
<Compile Include="Geometry\Vertex.cs" />
|
||||
<Compile Include="IO\DebugWriter.cs" />
|
||||
<Compile Include="IO\FileProcessor.cs" />
|
||||
<Compile Include="IO\IFileFormat.cs" />
|
||||
<Compile Include="IO\IMeshFormat.cs" />
|
||||
<Compile Include="IO\InputTriangle.cs" />
|
||||
<Compile Include="IO\IPolygonFormat.cs" />
|
||||
<Compile Include="IO\TriangleFormat.cs" />
|
||||
<Compile Include="IO\TriangleReader.cs" />
|
||||
<Compile Include="IO\TriangleWriter.cs" />
|
||||
<Compile Include="IPredicates.cs" />
|
||||
<Compile Include="Meshing\ConstraintMesher.cs" />
|
||||
<Compile Include="Meshing\ConstraintOptions.cs" />
|
||||
<Compile Include="Meshing\Converter.cs" />
|
||||
<Compile Include="Meshing\GenericMesher.cs" />
|
||||
<Compile Include="Meshing\IConstraintMesher.cs" />
|
||||
<Compile Include="Meshing\IMesh.cs" />
|
||||
<Compile Include="Meshing\IQualityMesher.cs" />
|
||||
<Compile Include="Meshing\Iterators\VertexCirculator.cs" />
|
||||
<Compile Include="Meshing\ITriangulator.cs" />
|
||||
<Compile Include="Meshing\QualityOptions.cs" />
|
||||
<Compile Include="Meshing\QualityMesher.cs" />
|
||||
<Compile Include="Meshing\Algorithm\Dwyer.cs" />
|
||||
<Compile Include="Meshing\Algorithm\Incremental.cs" />
|
||||
<Compile Include="Meshing\Algorithm\SweepLine.cs" />
|
||||
<Compile Include="Meshing\Data\BadSubseg.cs" />
|
||||
<Compile Include="Meshing\Data\BadTriangle.cs" />
|
||||
<Compile Include="Meshing\Data\BadTriQueue.cs" />
|
||||
<Compile Include="Meshing\Iterators\EdgeIterator.cs" />
|
||||
<Compile Include="Meshing\Iterators\RegionIterator.cs" />
|
||||
<Compile Include="Smoothing\VoronoiFactory.cs" />
|
||||
<Compile Include="Tools\AdjacencyMatrix.cs" />
|
||||
<Compile Include="Tools\CuthillMcKee.cs" />
|
||||
<Compile Include="Tools\Interpolation.cs" />
|
||||
<Compile Include="Tools\IntersectionHelper.cs" />
|
||||
<Compile Include="Tools\VertexSorter.cs" />
|
||||
<Compile Include="Tools\PolygonValidator.cs" />
|
||||
<Compile Include="Tools\QualityMeasure.cs" />
|
||||
<Compile Include="Tools\TriangleQuadTree.cs" />
|
||||
<Compile Include="Tools\Statistic.cs" />
|
||||
<Compile Include="Topology\Osub.cs" />
|
||||
<Compile Include="Topology\Otri.cs" />
|
||||
<Compile Include="Topology\SubSegment.cs" />
|
||||
<Compile Include="Topology\Triangle.cs" />
|
||||
<Compile Include="Topology\DCEL\DcelMesh.cs" />
|
||||
<Compile Include="Topology\DCEL\Face.cs" />
|
||||
<Compile Include="Topology\DCEL\HalfEdge.cs" />
|
||||
<Compile Include="Topology\DCEL\Vertex.cs" />
|
||||
<Compile Include="Smoothing\ISmoother.cs" />
|
||||
<Compile Include="Smoothing\SimpleSmoother.cs" />
|
||||
<Compile Include="TrianglePool.cs" />
|
||||
<Compile Include="Voronoi\BoundedVoronoi.cs" />
|
||||
<Compile Include="Voronoi\DefaultVoronoiFactory.cs" />
|
||||
<Compile Include="Voronoi\IVoronoiFactory.cs" />
|
||||
<Compile Include="Voronoi\StandardVoronoi.cs" />
|
||||
<Compile Include="Voronoi\VoronoiBase.cs" />
|
||||
<Compile Include="Voronoi\Legacy\BoundedVoronoiLegacy.cs" />
|
||||
<Compile Include="Voronoi\Legacy\IVoronoi.cs" />
|
||||
<Compile Include="Voronoi\Legacy\SimpleVoronoi.cs" />
|
||||
<Compile Include="Voronoi\Legacy\VoronoiRegion.cs" />
|
||||
<Compile Include="Logging\ILog.cs" />
|
||||
<Compile Include="Logging\ILogItem.cs" />
|
||||
<Compile Include="Logging\LogItem.cs" />
|
||||
<Compile Include="Behavior.cs" />
|
||||
<Compile Include="Log.cs" />
|
||||
<Compile Include="Enums.cs" />
|
||||
<Compile Include="Mesh.cs" />
|
||||
<Compile Include="MeshValidator.cs" />
|
||||
<Compile Include="NewLocation.cs" />
|
||||
<Compile Include="RobustPredicates.cs" />
|
||||
<Compile Include="TriangleSampler.cs" />
|
||||
<Compile Include="TriangleLocator.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,10 +0,0 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
using TriangleNet.Rendering.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Simple point set triangulation.
|
||||
/// </summary>
|
||||
public class Example1
|
||||
{
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
// Generate points.
|
||||
var points = Generate.RandomPoints(50, new Rectangle(0, 0, 100, 100));
|
||||
|
||||
// Choose triangulator: Incremental, SweepLine or Dwyer.
|
||||
var triangulator = new Dwyer();
|
||||
|
||||
// Generate a default mesher.
|
||||
var mesher = new GenericMesher(triangulator);
|
||||
|
||||
// Generate mesh.
|
||||
var mesh = mesher.Triangulate(points);
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-1.svg", 500);
|
||||
|
||||
return mesh.Triangles.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
using TriangleNet.Rendering.Text;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
/// <summary>
|
||||
/// Scattered data interpolation without USE_Z or USE_ATTRIBS.
|
||||
/// </summary>
|
||||
internal class Example10
|
||||
{
|
||||
// The function we are sampling.
|
||||
private static readonly Func<Point, double> F = p => Math.Sin(p.X) * Math.Cos(p.Y);
|
||||
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
// The input domain.
|
||||
var r = new Rectangle(0d, 0d, 10d, 10d);
|
||||
|
||||
var mesh = GetScatteredDataMesh(r, out double[] data);
|
||||
//var mesh = GetStructuredDataMesh(r, out double[] data);
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-10.svg", 500);
|
||||
|
||||
// The points to interpolate.
|
||||
var xy = Generate.RandomPoints(50, r);
|
||||
|
||||
var xyData = InterpolateData((Mesh)mesh, data, xy);
|
||||
|
||||
double error = xy.Max(p => Math.Abs(xyData[p.ID] - F(p)));
|
||||
|
||||
// L2 error
|
||||
// double error = Math.Sqrt(xy.Sum(p => Math.Pow(xyData[p.ID] - F(p), 2)));
|
||||
|
||||
return error < 0.5;
|
||||
}
|
||||
|
||||
private static IMesh GetStructuredDataMesh(Rectangle domain, out double[] data)
|
||||
{
|
||||
var mesh = GenericMesher.StructuredMesh(domain, 20, 20);
|
||||
|
||||
mesh.Renumber();
|
||||
|
||||
// Generate function values for mesh points.
|
||||
data = new double[mesh.Vertices.Count];
|
||||
|
||||
foreach (var item in mesh.Vertices)
|
||||
{
|
||||
data[item.ID] = F(item);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private static IMesh GetScatteredDataMesh(Rectangle domain, out double[] data)
|
||||
{
|
||||
var r = new Rectangle(domain);
|
||||
|
||||
double h = domain.Width / 20;
|
||||
|
||||
// Generate a rectangle boundary point set (20 points on each side).
|
||||
var input = Generate.Rectangle(r, 0.5);
|
||||
|
||||
// Making sure we add some margin to the boundary.
|
||||
h = -h / 2;
|
||||
r.Resize(h, h);
|
||||
|
||||
// Add more input points (more sampling points, better interpolation).
|
||||
input.Points.AddRange(Generate.RandomPoints(350, r));
|
||||
|
||||
var mesher = new GenericMesher(new Dwyer());
|
||||
|
||||
// Generate mesh.
|
||||
var mesh = mesher.Triangulate(input.Points);
|
||||
|
||||
mesh.Renumber();
|
||||
|
||||
// Generate function values for mesh points.
|
||||
data = new double[mesh.Vertices.Count];
|
||||
|
||||
foreach (var item in mesh.Vertices)
|
||||
{
|
||||
data[item.ID] = F(item);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private static double[] InterpolateData(Mesh mesh, double[] data, IEnumerable<Point> xy)
|
||||
{
|
||||
// The interpolated values.
|
||||
var values = new double[xy.Count()];
|
||||
|
||||
var qtree = new TriangleQuadTree(mesh);
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var p in xy)
|
||||
{
|
||||
var tri = qtree.Query(p.X, p.Y);
|
||||
|
||||
// For easy access of the interpolated values.
|
||||
p.ID = i;
|
||||
|
||||
if (tri == null)
|
||||
{
|
||||
values[i] = float.NaN;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[i] = Interpolation.InterpolatePoint(tri, p, data);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate a polygon with hole and set minimum angle constraint.
|
||||
/// </summary>
|
||||
public static class Example2
|
||||
{
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
// Generate the input geometry.
|
||||
var poly = CreatePolygon();
|
||||
|
||||
// Set minimum angle quality option.
|
||||
var quality = new QualityOptions() { MinimumAngle = 30.0 };
|
||||
|
||||
// Generate mesh using the polygons Triangulate extension method.
|
||||
var mesh = poly.Triangulate(quality);
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-2.svg", 500);
|
||||
|
||||
return mesh.Triangles.Count > 0;
|
||||
}
|
||||
|
||||
public static IPolygon CreatePolygon(double h = 0.2)
|
||||
{
|
||||
// Generate the input geometry.
|
||||
var poly = new Polygon();
|
||||
|
||||
// Center point.
|
||||
var center = new Point(0, 0);
|
||||
|
||||
// Inner contour (hole).
|
||||
poly.Add(Generate.Circle(1.0, center, h, 1), center);
|
||||
|
||||
// Internal contour.
|
||||
poly.Add(Generate.Circle(2.0, center, h, 2));
|
||||
|
||||
// Outer contour.
|
||||
poly.Add(Generate.Circle(3.0, center, h, 3));
|
||||
|
||||
return poly;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Text;
|
||||
using TriangleNet.Smoothing;
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate a polygon with hole with maximum area constraint, followed by mesh smoothing.
|
||||
/// </summary>
|
||||
public class Example3
|
||||
{
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
// Generate mesh.
|
||||
var mesh = CreateMesh();
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-3.svg", 500);
|
||||
|
||||
return mesh.Triangles.Count > 0;
|
||||
}
|
||||
|
||||
public static IMesh CreateMesh()
|
||||
{
|
||||
// Generate the input geometry.
|
||||
var poly = Example2.CreatePolygon();
|
||||
|
||||
// Since we want to do CVT smoothing, ensure that the mesh
|
||||
// is conforming Delaunay.
|
||||
var options = new ConstraintOptions() { ConformingDelaunay = true };
|
||||
|
||||
// Set maximum area quality option (we don't need to set a minimum
|
||||
// angle, since smoothing will improve the triangle shapes).
|
||||
var quality = new QualityOptions()
|
||||
{
|
||||
// The boundary segments have a length of 0.2, so we set a
|
||||
// maximum area constraint assuming equilateral triangles.
|
||||
MaximumArea = (Math.Sqrt(3) / 4 * 0.2 * 0.2) * 1.45
|
||||
};
|
||||
|
||||
// Generate mesh using the polygons Triangulate extension method.
|
||||
var mesh = poly.Triangulate(options, quality);
|
||||
|
||||
var smoother = new SimpleSmoother();
|
||||
|
||||
// Smooth mesh.
|
||||
smoother.Smooth(mesh, 25);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Text;
|
||||
using TriangleNet.Smoothing;
|
||||
|
||||
/// <summary>
|
||||
/// Refine only a part of a polygon mesh by using region pointers and an area constraint.
|
||||
/// </summary>
|
||||
public class Example4
|
||||
{
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
// Generate the input geometry.
|
||||
var poly = CreatePolygon();
|
||||
|
||||
// Define regions (first one defines the area constraint).
|
||||
poly.Regions.Add(new RegionPointer(1.5, 0.0, 1, 0.01));
|
||||
poly.Regions.Add(new RegionPointer(2.5, 0.0, 2));
|
||||
|
||||
// Set quality and constraint options.
|
||||
var options = new ConstraintOptions()
|
||||
{
|
||||
ConformingDelaunay = true
|
||||
};
|
||||
|
||||
var quality = new QualityOptions()
|
||||
{
|
||||
MinimumAngle = 25.0,
|
||||
VariableArea = true
|
||||
};
|
||||
|
||||
//quality.UserTest = (t, area) => t.Label == 1 && area > 0.01;
|
||||
|
||||
var mesh = poly.Triangulate(options, quality);
|
||||
|
||||
var smoother = new SimpleSmoother();
|
||||
|
||||
smoother.Smooth(mesh, 5);
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-4.svg", 500);
|
||||
|
||||
return mesh.Triangles.Count > 0;
|
||||
}
|
||||
|
||||
public static IPolygon CreatePolygon()
|
||||
{
|
||||
// Generate three concentric circles.
|
||||
var poly = new Polygon();
|
||||
|
||||
// Center point.
|
||||
var center = new Point(0, 0);
|
||||
|
||||
// Inner contour (hole).
|
||||
poly.Add(Generate.Circle(1.0, center, 0.1, 1), center);
|
||||
|
||||
// Internal contour.
|
||||
poly.Add(Generate.Circle(2.0, center, 0.1, 2));
|
||||
|
||||
// Outer contour.
|
||||
poly.Add(Generate.Circle(3.0, center, 0.3, 3));
|
||||
|
||||
// Note that the outer contour has a larger segment size!
|
||||
|
||||
return poly;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using TriangleNet.Rendering.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Two ways finding boundary triangles.
|
||||
/// </summary>
|
||||
public static class Example5
|
||||
{
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
var mesh = Example3.CreateMesh();
|
||||
|
||||
FindBoundary1(mesh);
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-5-1.svg", 500, true, false);
|
||||
|
||||
FindBoundary2(mesh);
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-5-2.svg", 500, true, false);
|
||||
|
||||
return mesh.Triangles.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find boundary triangles using segments.
|
||||
/// </summary>
|
||||
private static void FindBoundary1(IMesh mesh, bool neigbours = true)
|
||||
{
|
||||
mesh.Renumber();
|
||||
|
||||
var cache = new List<Vertex>(mesh.Segments.Count + 1);
|
||||
|
||||
var circulator = new VertexCirculator((Mesh)mesh);
|
||||
|
||||
foreach (var s in mesh.Segments)
|
||||
{
|
||||
int label = s.Label;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
var vertex = s.GetVertex(i);
|
||||
|
||||
// Check the vertex ID to see if it was processed already.
|
||||
if (vertex.ID >= 0)
|
||||
{
|
||||
var star = circulator.EnumerateTriangles(vertex);
|
||||
|
||||
foreach (var triangle in star)
|
||||
{
|
||||
triangle.Label = label;
|
||||
}
|
||||
|
||||
// Mark the vertex as "processed".
|
||||
vertex.ID = -vertex.ID;
|
||||
|
||||
cache.Add(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Undo the vertex ID changes.
|
||||
foreach (var vertex in cache)
|
||||
{
|
||||
vertex.ID = -vertex.ID;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find boundary triangles using vertices.
|
||||
/// </summary>
|
||||
private static void FindBoundary2(IMesh mesh)
|
||||
{
|
||||
var circulator = new VertexCirculator((Mesh)mesh);
|
||||
|
||||
foreach (var vertex in mesh.Vertices)
|
||||
{
|
||||
int label = vertex.Label;
|
||||
|
||||
if (label > 0)
|
||||
{
|
||||
var star = circulator.EnumerateTriangles(vertex);
|
||||
|
||||
foreach (var triangle in star)
|
||||
{
|
||||
triangle.Label = label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System.Linq;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using TriangleNet.Rendering.Text;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Boolean operations on mesh regions (intersection, difference, xor).
|
||||
/// </summary>
|
||||
public static class Example6
|
||||
{
|
||||
public static bool Run(bool print = true)
|
||||
{
|
||||
// Generate the input geometry.
|
||||
var polygon = new Polygon(8, true);
|
||||
|
||||
// Two intersecting rectangles.
|
||||
var A = Generate.Rectangle(0d, 0d, 4d, 4d, label: 1);
|
||||
var B = Generate.Rectangle(1d, 1d, 4d, 4d, label: 2);
|
||||
|
||||
polygon.Add(A);
|
||||
polygon.Add(B);
|
||||
|
||||
// Generate mesh.
|
||||
var mesh = (Mesh)polygon.Triangulate();
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-6.svg", 500);
|
||||
|
||||
// Find a seeding triangle (in this case, the point (2, 2) lies in
|
||||
// both rectangles).
|
||||
var seed = (new TriangleQuadTree(mesh)).Query(2.0, 2.0) as Triangle;
|
||||
|
||||
var iterator = new RegionIterator(mesh);
|
||||
|
||||
iterator.Process(seed, t => t.Label ^= 1, 1);
|
||||
iterator.Process(seed, t => t.Label ^= 2, 2);
|
||||
|
||||
// At this point, all triangles will have label 1, 2 or 3 (= 1 xor 2).
|
||||
|
||||
// The intersection of A and B.
|
||||
var intersection = mesh.Triangles.Where(t => t.Label == 3);
|
||||
|
||||
// The difference A \ B.
|
||||
var difference = mesh.Triangles.Where(t => t.Label == 1);
|
||||
|
||||
// The xor of A and B.
|
||||
var xor = mesh.Triangles.Where(t => t.Label == 1 || t.Label == 2);
|
||||
|
||||
return intersection.Any() && difference.Any() && xor.Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using TriangleNet.Rendering.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Using a user test function to define a maximum edge length constraint.
|
||||
/// </summary>
|
||||
public static class Example7
|
||||
{
|
||||
const double MAX_EDGE_LENGTH = 0.2;
|
||||
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
var poly = new Polygon();
|
||||
|
||||
// Generate the input geometry.
|
||||
poly.Add(Generate.Rectangle(0.0, 0.0, 1.0, 1.0));
|
||||
|
||||
// Set minimum angle quality option, ignoring holes.
|
||||
var quality = new QualityOptions()
|
||||
{
|
||||
UserTest = MaxEdgeLength
|
||||
};
|
||||
|
||||
// Generate mesh using the polygons Triangulate extension method.
|
||||
var mesh = (Mesh)poly.Triangulate(quality);
|
||||
|
||||
// Validate.
|
||||
foreach (var e in EdgeIterator.EnumerateEdges(mesh))
|
||||
{
|
||||
double length = Math.Sqrt(DistSqr(e.GetVertex(0), e.GetVertex(1)));
|
||||
|
||||
if (length > MAX_EDGE_LENGTH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (print) SvgImage.Save(mesh, "example-7.svg", 500);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool MaxEdgeLength(ITriangle tri, double area)
|
||||
{
|
||||
var p0 = tri.GetVertex(0);
|
||||
var p1 = tri.GetVertex(1);
|
||||
var p2 = tri.GetVertex(2);
|
||||
|
||||
var s1 = DistSqr(p0, p1);
|
||||
var s2 = DistSqr(p1, p2);
|
||||
var s3 = DistSqr(p2, p0);
|
||||
|
||||
// Comparing against squared max leg length.
|
||||
var maxlen = MAX_EDGE_LENGTH * MAX_EDGE_LENGTH;
|
||||
|
||||
return s1 > maxlen || s2 > maxlen || s3 > maxlen;
|
||||
}
|
||||
|
||||
static double DistSqr(Vertex a, Vertex b)
|
||||
{
|
||||
var dx = a.X - b.X;
|
||||
var dy = a.Y - b.Y;
|
||||
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Compute the adjacency matrix of the mesh vertices.
|
||||
/// </summary>
|
||||
public class Example8
|
||||
{
|
||||
public static bool Run()
|
||||
{
|
||||
var mesh = (Mesh)Example3.CreateMesh();
|
||||
|
||||
return FindAdjacencyMatrix(mesh);
|
||||
}
|
||||
|
||||
private static bool FindAdjacencyMatrix(Mesh mesh)
|
||||
{
|
||||
mesh.Renumber();
|
||||
|
||||
var ap = new List<int>(mesh.Vertices.Count); // Column pointers.
|
||||
var ai = new List<int>(4 * mesh.Vertices.Count); // Row indices.
|
||||
|
||||
var circulator = new VertexCirculator(mesh);
|
||||
|
||||
int k = 0;
|
||||
|
||||
foreach (var vertex in mesh.Vertices)
|
||||
{
|
||||
var star = circulator.EnumerateVertices(vertex);
|
||||
|
||||
ap.Add(k);
|
||||
|
||||
// Each vertex is adjacent to itself.
|
||||
ai.Add(vertex.ID);
|
||||
k++;
|
||||
|
||||
foreach (var item in star)
|
||||
{
|
||||
ai.Add(item.ID);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
ap.Add(k);
|
||||
|
||||
var matrix1 = new AdjacencyMatrix(ap.ToArray(), ai.ToArray());
|
||||
var matrix2 = new AdjacencyMatrix(mesh);
|
||||
|
||||
// Column pointers should be exactly the same.
|
||||
if (!CompareArray(matrix1.ColumnPointers, matrix2.ColumnPointers))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CompareArray(int[] a, int[] b)
|
||||
{
|
||||
int length = a.Length;
|
||||
|
||||
if (b.Length != length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Troubleshooting: finding degenerate boundary triangles.
|
||||
/// </summary>
|
||||
public class Example9
|
||||
{
|
||||
public static bool Run(bool print = false)
|
||||
{
|
||||
var pts = new List<Vertex>
|
||||
{
|
||||
// The 4 corners of the rectangle.
|
||||
new Vertex(1.5, 1.0),
|
||||
new Vertex(1.5, -1.0),
|
||||
new Vertex(-1.5, -1.0),
|
||||
new Vertex(-1.5, 1.0),
|
||||
|
||||
// The edge midpoints.
|
||||
new Vertex(0.0, 1.0),
|
||||
new Vertex(0.0, -1.0),
|
||||
new Vertex(1.5, 0.0),
|
||||
new Vertex(-1.5, 0.0)
|
||||
};
|
||||
|
||||
var r = new Random(78403);
|
||||
|
||||
// The original rectangle.
|
||||
var poly = Rotate(pts, 0);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var mesh = poly.Triangulate();
|
||||
|
||||
var list = MeshValidator.GetDegenerateBoundaryTriangles(mesh);
|
||||
|
||||
if (print && list.Any())
|
||||
{
|
||||
Console.WriteLine("Iteration {0}: found {1} degenerate triangle(s) of {2}.",
|
||||
i, list.Count(), mesh.Triangles.Count);
|
||||
|
||||
foreach (var t in list)
|
||||
{
|
||||
Console.WriteLine(" [{0} {1} {2}]",
|
||||
t.GetVertexID(0),
|
||||
t.GetVertexID(1),
|
||||
t.GetVertexID(2));
|
||||
}
|
||||
}
|
||||
|
||||
// Random rotation.
|
||||
poly = Rotate(pts, Math.PI * r.NextDouble());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate given point set around the origin.
|
||||
/// </summary>
|
||||
private static IPolygon Rotate(List<Vertex> points, double radians)
|
||||
{
|
||||
var poly = new Polygon(points.Count);
|
||||
|
||||
int id = 0;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
double x = p.X;
|
||||
double y = p.Y;
|
||||
|
||||
double s = Math.Sin(radians);
|
||||
double c = Math.Cos(radians);
|
||||
|
||||
double xr = c * x - s * y;
|
||||
double yr = s * x + c * y;
|
||||
|
||||
poly.Points.Add(new Vertex(xr, yr) { ID = id++ });
|
||||
}
|
||||
|
||||
return poly;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
namespace TriangleNet.Examples
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TriangleNet;
|
||||
using TriangleNet.IO;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Processing meshes in parallel.
|
||||
/// </summary>
|
||||
public class ExamplePar
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads all .poly files from given directory and processes them in parallel.
|
||||
/// </summary>
|
||||
public static bool Run(string dir)
|
||||
{
|
||||
var files = Directory.EnumerateFiles(dir, "*.poly", SearchOption.AllDirectories);
|
||||
|
||||
var queue = new ConcurrentQueue<string>(files);
|
||||
|
||||
int concurrencyLevel = Environment.ProcessorCount / 2;
|
||||
|
||||
var tasks = new Task<MeshResult>[concurrencyLevel];
|
||||
|
||||
for (int i = 0; i < concurrencyLevel; i++)
|
||||
{
|
||||
tasks[i] = Task.Run(() =>
|
||||
{
|
||||
// Each task has it's own triangle pool and predicates instance.
|
||||
var pool = new TrianglePool();
|
||||
var predicates = new RobustPredicates();
|
||||
|
||||
// The factory methods return the above instances.
|
||||
var config = new Configuration()
|
||||
{
|
||||
Predicates = () => predicates,
|
||||
TrianglePool = () => pool.Restart()
|
||||
};
|
||||
|
||||
var mesher = new GenericMesher(config);
|
||||
var result = new MeshResult();
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
if (queue.TryDequeue(out var file))
|
||||
{
|
||||
var poly = FileProcessor.Read(file);
|
||||
|
||||
var mesh = mesher.Triangulate(poly);
|
||||
|
||||
ProcessMesh(mesh, result);
|
||||
}
|
||||
}
|
||||
|
||||
pool.Clear();
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
|
||||
int numberOfTriangles = tasks.Sum(t => t.Result.NumberOfTriangles);
|
||||
int invalid = tasks.Sum(t => t.Result.Invalid);
|
||||
|
||||
Console.WriteLine("Total number of triangles processed: {0}", numberOfTriangles);
|
||||
|
||||
if (invalid > 0)
|
||||
{
|
||||
Console.WriteLine(" Number of invalid triangulations: {0}", invalid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void ProcessMesh(IMesh mesh, MeshResult result)
|
||||
{
|
||||
result.NumberOfTriangles += mesh.Triangles.Count;
|
||||
|
||||
if (!MeshValidator.IsConsistent((Mesh)mesh))
|
||||
{
|
||||
result.Invalid += 1;
|
||||
}
|
||||
}
|
||||
|
||||
class MeshResult
|
||||
{
|
||||
public int NumberOfTriangles;
|
||||
public int Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
static class Generate
|
||||
{
|
||||
private static readonly Random random = new Random(63841);
|
||||
|
||||
public static List<Vertex> RandomPoints(int n, Rectangle bounds)
|
||||
{
|
||||
var points = new List<Vertex>(n);
|
||||
|
||||
var xmin = bounds.Left;
|
||||
var ymin = bounds.Bottom;
|
||||
|
||||
var width = bounds.Width;
|
||||
var height = bounds.Height;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
double x = random.NextDouble();
|
||||
double y = random.NextDouble();
|
||||
points.Add(new Vertex(xmin + x * width, ymin + y * height));
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rectangle contour.
|
||||
/// </summary>
|
||||
public static Contour Rectangle(Rectangle rect, double size = 0d, int label = 0)
|
||||
{
|
||||
return Rectangle(rect.X, rect.Y, rect.Width, rect.Height, size, label);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rectangle contour.
|
||||
/// </summary>
|
||||
public static Contour Rectangle(double x, double y, double width, double height,
|
||||
double size = 0d, int label = 0)
|
||||
{
|
||||
// Horizontal and vertical step sizes.
|
||||
double stepH = 0d;
|
||||
double stepV = 0d;
|
||||
|
||||
int nH = 1;
|
||||
int nV = 1;
|
||||
|
||||
if (size > 0d)
|
||||
{
|
||||
size = Math.Min(size, Math.Min(width, height));
|
||||
|
||||
nH = (int)Math.Ceiling(width / size);
|
||||
nV = (int)Math.Ceiling(height / size);
|
||||
|
||||
stepH = width / nH;
|
||||
stepV = height / nV;
|
||||
}
|
||||
|
||||
var points = new List<Vertex>(2 * nH + 2 * nV);
|
||||
|
||||
double right = x + width;
|
||||
double top = y + height;
|
||||
|
||||
// Left box boundary points
|
||||
for (int i = 0; i < nV; i++)
|
||||
{
|
||||
points.Add(new Vertex(x, y + i * stepV, label));
|
||||
}
|
||||
|
||||
// Top box boundary points
|
||||
for (int i = 0; i < nH; i++)
|
||||
{
|
||||
points.Add(new Vertex(x + i * stepH, top, label));
|
||||
}
|
||||
|
||||
// Right box boundary points
|
||||
for (int i = 0; i < nV; i++)
|
||||
{
|
||||
points.Add(new Vertex(right, top - i * stepV, label));
|
||||
}
|
||||
|
||||
// Bottom box boundary points
|
||||
for (int i = 0; i < nH; i++)
|
||||
{
|
||||
points.Add(new Vertex(right - i * stepH, y, label));
|
||||
}
|
||||
|
||||
return new Contour(points, label, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a circular contour.
|
||||
/// </summary>
|
||||
/// <param name="r">The radius.</param>
|
||||
/// <param name="center">The center point.</param>
|
||||
/// <param name="h">The desired segment length.</param>
|
||||
/// <param name="label">The boundary label.</param>
|
||||
/// <returns>A circular contour.</returns>
|
||||
public static Contour Circle(double r, Point center, double h, int label = 0)
|
||||
{
|
||||
int n = (int)(2 * Math.PI * r / h);
|
||||
|
||||
var points = new List<Vertex>(n);
|
||||
|
||||
double x, y, dphi = 2 * Math.PI / n;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
x = center.X + r * Math.Cos(i * dphi);
|
||||
y = center.Y + r * Math.Sin(i * dphi);
|
||||
|
||||
points.Add(new Vertex(x, y, label));
|
||||
}
|
||||
|
||||
return new Contour(points, label, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Examples;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Check("Example 1", Example1.Run());
|
||||
Check("Example 2", Example2.Run());
|
||||
Check("Example 3", Example3.Run());
|
||||
Check("Example 4", Example4.Run());
|
||||
Check("Example 5", Example5.Run());
|
||||
Check("Example 6", Example6.Run());
|
||||
Check("Example 7", Example7.Run());
|
||||
Check("Example 8", Example8.Run());
|
||||
Check("Example 9", Example9.Run());
|
||||
Check("Example 10", Example10.Run());
|
||||
}
|
||||
|
||||
static void Check(string item, bool success)
|
||||
{
|
||||
var color = Console.ForegroundColor;
|
||||
|
||||
Console.Write(item + " ");
|
||||
Console.ForegroundColor = success ? ConsoleColor.DarkGreen : ConsoleColor.DarkRed;
|
||||
Console.WriteLine(success ? "OK" : "Failed");
|
||||
Console.ForegroundColor = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>TriangleNet</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj" />
|
||||
<ProjectReference Include="..\Triangle.Rendering\Triangle.Rendering.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+26
-26
@@ -1,26 +1,26 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if segment (a, b) intersects rectangle.
|
||||
/// </summary>
|
||||
public static bool Intersects(this RectangleF rect, PointF a, PointF b)
|
||||
{
|
||||
// TODO: implement intersection.
|
||||
return rect.Contains(a) || rect.Contains(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if triangle (a, b, c) intersects rectangle.
|
||||
/// </summary>
|
||||
public static bool Intersects(this RectangleF rect, PointF a, PointF b, PointF c)
|
||||
{
|
||||
// TODO: implement intersection.
|
||||
return rect.Contains(a) || rect.Contains(b) || rect.Contains(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if segment (a, b) intersects rectangle.
|
||||
/// </summary>
|
||||
public static bool Intersects(this RectangleF rect, PointF a, PointF b)
|
||||
{
|
||||
// TODO: implement intersection.
|
||||
return rect.Contains(a) || rect.Contains(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if triangle (a, b, c) intersects rectangle.
|
||||
/// </summary>
|
||||
public static bool Intersects(this RectangleF rect, PointF a, PointF b, PointF c)
|
||||
{
|
||||
// TODO: implement intersection.
|
||||
return rect.Contains(a) || rect.Contains(b) || rect.Contains(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
-101
@@ -1,101 +1,101 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.GDI.Native;
|
||||
|
||||
public class FunctionRenderer
|
||||
{
|
||||
TriVertex[] points;
|
||||
GradientTriangle[] elements;
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public void Render(IRenderLayer layer)
|
||||
{
|
||||
Create(layer);
|
||||
|
||||
var hdc = RenderTarget.GetHdc();
|
||||
|
||||
NativeMethods.GradientFill(hdc,
|
||||
points, (uint)points.Length, elements, (uint)elements.Length,
|
||||
GradientFillMode.GRADIENT_FILL_TRIANGLE);
|
||||
|
||||
RenderTarget.ReleaseHdc(hdc);
|
||||
}
|
||||
|
||||
private void Create(IRenderLayer layer)
|
||||
{
|
||||
var zoom = Context.Zoom;
|
||||
var colors = layer.Colors.Data;
|
||||
|
||||
int length = colors.Length;
|
||||
|
||||
int size = layer.Points.Size;
|
||||
var data = layer.Points.Data;
|
||||
|
||||
if (length != data.Length / size)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
this.points = new TriVertex[length];
|
||||
|
||||
TriVertex vertex;
|
||||
Color color;
|
||||
PointF p = new PointF((float)data[0], (float)data[1]);
|
||||
|
||||
zoom.WorldToScreen(ref p);
|
||||
|
||||
// Get correction distance
|
||||
float dx = (p.X - (int)p.X) * 2.0f;
|
||||
float dy = (p.Y - (int)p.Y) * 2.0f;
|
||||
|
||||
// Create vertices.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
p.X = (float)data[size * i];
|
||||
p.Y = (float)data[size * i + 1];
|
||||
|
||||
zoom.WorldToScreen(ref p);
|
||||
|
||||
color = colors[i];
|
||||
|
||||
vertex = new TriVertex();
|
||||
|
||||
vertex.x = (int)(p.X + dx);
|
||||
vertex.y = (int)(p.Y + dy);
|
||||
|
||||
vertex.Red = (ushort)(color.R << 8);
|
||||
vertex.Green = (ushort)(color.G << 8);
|
||||
vertex.Blue = (ushort)(color.B << 8);
|
||||
vertex.Alpha = (ushort)(color.A << 8);
|
||||
|
||||
this.points[i] = vertex;
|
||||
}
|
||||
|
||||
var triangles = layer.Indices.Data;
|
||||
|
||||
length = triangles.Length / 3;
|
||||
|
||||
this.elements = new GradientTriangle[length];
|
||||
|
||||
GradientTriangle e;
|
||||
|
||||
// Create triangles.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
e = new GradientTriangle();
|
||||
|
||||
e.Vertex1 = (uint)triangles[3 * i];
|
||||
e.Vertex2 = (uint)triangles[3 * i + 1];
|
||||
e.Vertex3 = (uint)triangles[3 * i + 2];
|
||||
|
||||
this.elements[i] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.GDI.Native;
|
||||
|
||||
public class FunctionRenderer
|
||||
{
|
||||
TriVertex[] points;
|
||||
GradientTriangle[] elements;
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public void Render(IRenderLayer layer)
|
||||
{
|
||||
Create(layer);
|
||||
|
||||
var hdc = RenderTarget.GetHdc();
|
||||
|
||||
NativeMethods.GradientFill(hdc,
|
||||
points, (uint)points.Length, elements, (uint)elements.Length,
|
||||
GradientFillMode.GRADIENT_FILL_TRIANGLE);
|
||||
|
||||
RenderTarget.ReleaseHdc(hdc);
|
||||
}
|
||||
|
||||
private void Create(IRenderLayer layer)
|
||||
{
|
||||
var zoom = Context.Zoom;
|
||||
var colors = layer.Colors.Data;
|
||||
|
||||
int length = colors.Length;
|
||||
|
||||
int size = layer.Points.Size;
|
||||
var data = layer.Points.Data;
|
||||
|
||||
if (length != data.Length / size)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
this.points = new TriVertex[length];
|
||||
|
||||
TriVertex vertex;
|
||||
Color color;
|
||||
PointF p = new PointF((float)data[0], (float)data[1]);
|
||||
|
||||
zoom.NdcToScreen(ref p);
|
||||
|
||||
// Get correction distance
|
||||
float dx = (p.X - (int)p.X) * 2.0f;
|
||||
float dy = (p.Y - (int)p.Y) * 2.0f;
|
||||
|
||||
// Create vertices.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
p.X = (float)data[size * i];
|
||||
p.Y = (float)data[size * i + 1];
|
||||
|
||||
zoom.NdcToScreen(ref p);
|
||||
|
||||
color = colors[i];
|
||||
|
||||
vertex = new TriVertex();
|
||||
|
||||
vertex.x = (int)(p.X + dx);
|
||||
vertex.y = (int)(p.Y + dy);
|
||||
|
||||
vertex.Red = (ushort)(color.R << 8);
|
||||
vertex.Green = (ushort)(color.G << 8);
|
||||
vertex.Blue = (ushort)(color.B << 8);
|
||||
vertex.Alpha = (ushort)(color.A << 8);
|
||||
|
||||
this.points[i] = vertex;
|
||||
}
|
||||
|
||||
var triangles = layer.Indices.Data;
|
||||
|
||||
length = triangles.Length / 3;
|
||||
|
||||
this.elements = new GradientTriangle[length];
|
||||
|
||||
GradientTriangle e;
|
||||
|
||||
// Create triangles.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
e = new GradientTriangle();
|
||||
|
||||
e.Vertex1 = (uint)triangles[3 * i];
|
||||
e.Vertex2 = (uint)triangles[3 * i + 1];
|
||||
e.Vertex3 = (uint)triangles[3 * i + 2];
|
||||
|
||||
this.elements[i] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
internal class Helper
|
||||
{
|
||||
public static void Dispose(Dictionary<int, SolidBrush> brushes)
|
||||
{
|
||||
foreach (var brush in brushes.Values)
|
||||
{
|
||||
brush.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<int, SolidBrush> GetBrushDictionary(Dictionary<int, Color> ColorDictionary)
|
||||
{
|
||||
var brushes = new Dictionary<int, SolidBrush>();
|
||||
|
||||
foreach (var item in ColorDictionary)
|
||||
{
|
||||
brushes.Add(item.Key, new SolidBrush(item.Value));
|
||||
}
|
||||
|
||||
return brushes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Enables rendering of polygons or meshes to a bitmap.
|
||||
/// </summary>
|
||||
public class ImageRenderer
|
||||
{
|
||||
ColorManager colors = LightScheme();
|
||||
|
||||
public ColorManager ColorScheme
|
||||
{
|
||||
get { return colors; }
|
||||
set { colors = value; }
|
||||
}
|
||||
|
||||
public bool EnableRegions { get; set; }
|
||||
|
||||
public bool EnablePoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Exports a polygon to PNG format.
|
||||
/// </summary>
|
||||
/// <param name="poly">The polygon.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <param name="file">The PNG filename.</param>
|
||||
/// <param name="regions">Enable rendering of regions.</param>
|
||||
/// <param name="points">Enable rendering of points.</param>
|
||||
public static void Save(Geometry.IPolygon poly, string file = null, int width = 800,
|
||||
bool points = true)
|
||||
{
|
||||
// Check file name
|
||||
if (string.IsNullOrWhiteSpace(file))
|
||||
{
|
||||
file = string.Format("poly-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
// Ensure .png extension.
|
||||
if (file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Path.ChangeExtension(file, ".png");
|
||||
}
|
||||
|
||||
var renderer = new ImageRenderer();
|
||||
|
||||
renderer.EnableRegions = false;
|
||||
renderer.EnablePoints = points;
|
||||
|
||||
var bitmap = renderer.Render(poly, width);
|
||||
|
||||
bitmap.Save(file, ImageFormat.Png);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports a mesh to PNG format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <param name="file">The PNG filename.</param>
|
||||
/// <param name="regions">Enable rendering of regions.</param>
|
||||
/// <param name="points">Enable rendering of points.</param>
|
||||
public static void Save(IMesh mesh, string file = null, int width = 800,
|
||||
bool regions = false, bool points = true)
|
||||
{
|
||||
// Check file name
|
||||
if (string.IsNullOrWhiteSpace(file))
|
||||
{
|
||||
file = string.Format("mesh-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
// Ensure .png extension.
|
||||
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Path.ChangeExtension(file, ".png");
|
||||
}
|
||||
|
||||
var renderer = new ImageRenderer();
|
||||
|
||||
renderer.EnableRegions = regions;
|
||||
renderer.EnablePoints = points;
|
||||
|
||||
var bitmap = renderer.Render(mesh, width);
|
||||
|
||||
bitmap.Save(file, ImageFormat.Png);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the polygon to a bitmap.
|
||||
/// </summary>
|
||||
/// <param name="poly">The polygon.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <returns>The bitmap.</returns>
|
||||
/// <remarks>
|
||||
/// The width has to be at least 2 * sqrt(n), n the number of vertices.
|
||||
/// Otherwise, an empty bitmap
|
||||
/// </remarks>
|
||||
public Bitmap Render(Geometry.IPolygon poly, int width = 800)
|
||||
{
|
||||
Bitmap bitmap;
|
||||
|
||||
// Check if the specified width is reasonable
|
||||
if (width < 2 * Math.Sqrt(poly.Points.Count))
|
||||
{
|
||||
return new Bitmap(1, 1);
|
||||
}
|
||||
|
||||
var bounds = poly.Bounds();
|
||||
|
||||
// World margin on each side
|
||||
float margin = (float)bounds.Height * 0.05f;
|
||||
float scale = width / ((float)bounds.Width + 2 * margin);
|
||||
|
||||
var target = new Rectangle(0, 0, width, (int)((bounds.Height + 2 * margin) * scale));
|
||||
|
||||
bitmap = new Bitmap(width, target.Height, PixelFormat.Format32bppPArgb);
|
||||
|
||||
using (var g = Graphics.FromImage(bitmap))
|
||||
{
|
||||
g.Clear(colors.Background);
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
var context = new RenderContext(new Projection(target), colors);
|
||||
context.Add(poly);
|
||||
|
||||
if (!EnablePoints)
|
||||
{
|
||||
context.Enable(3, false);
|
||||
}
|
||||
|
||||
var renderer = new LayerRenderer();
|
||||
renderer.Context = context;
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the mesh to a bitmap.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <returns>The bitmap.</returns>
|
||||
/// <remarks>
|
||||
/// The width has to be at least 2 * sqrt(n), n the number of vertices.
|
||||
/// Otherwise, an empty bitmap
|
||||
/// </remarks>
|
||||
public Bitmap Render(IMesh mesh, int width = 800)
|
||||
{
|
||||
Bitmap bitmap;
|
||||
|
||||
// Check if the specified width is reasonable
|
||||
if (width < 2 * Math.Sqrt(mesh.Vertices.Count))
|
||||
{
|
||||
return new Bitmap(1, 1);
|
||||
}
|
||||
|
||||
var bounds = mesh.Bounds;
|
||||
|
||||
// World margin on each side
|
||||
float margin = (float)bounds.Height * 0.05f;
|
||||
float scale = width / ((float)bounds.Width + 2 * margin);
|
||||
|
||||
var target = new Rectangle(0, 0, width, (int)((bounds.Height + 2 * margin) * scale));
|
||||
|
||||
bitmap = new Bitmap(width, target.Height, PixelFormat.Format32bppPArgb);
|
||||
|
||||
using (var g = Graphics.FromImage(bitmap))
|
||||
{
|
||||
g.Clear(colors.Background);
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
var context = new RenderContext(new Projection(target), colors);
|
||||
context.Add(mesh, true);
|
||||
|
||||
if (EnableRegions)
|
||||
{
|
||||
context.Add(GetRegions(mesh));
|
||||
}
|
||||
|
||||
if (!EnablePoints)
|
||||
{
|
||||
context.Enable(3, false);
|
||||
}
|
||||
|
||||
var renderer = new LayerRenderer();
|
||||
renderer.Context = context;
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public Bitmap Render(IMesh mesh, Topology.DCEL.DcelMesh dcel, int width = 800)
|
||||
{
|
||||
Bitmap bitmap;
|
||||
|
||||
// Check if the specified width is reasonable
|
||||
if (width < 2 * Math.Sqrt(mesh.Vertices.Count))
|
||||
{
|
||||
return new Bitmap(1, 1);
|
||||
}
|
||||
|
||||
var bounds = mesh.Bounds;
|
||||
|
||||
// World margin on each side
|
||||
float margin = (float)bounds.Height * 0.05f;
|
||||
float scale = width / ((float)bounds.Width + 2 * margin);
|
||||
|
||||
var target = new Rectangle(0, 0, width, (int)((bounds.Height + 2 * margin) * scale));
|
||||
|
||||
bitmap = new Bitmap(width, target.Height, PixelFormat.Format32bppPArgb);
|
||||
|
||||
using (var g = Graphics.FromImage(bitmap))
|
||||
{
|
||||
g.Clear(colors.Background);
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
var context = new RenderContext(new Projection(target), colors);
|
||||
context.Add(mesh, true);
|
||||
context.Add(dcel.Vertices.ToArray(), dcel.Edges, false);
|
||||
|
||||
if (EnableRegions)
|
||||
{
|
||||
context.Add(GetRegions(mesh));
|
||||
}
|
||||
|
||||
if (!EnablePoints)
|
||||
{
|
||||
context.Enable(3, false);
|
||||
}
|
||||
|
||||
var renderer = new LayerRenderer();
|
||||
renderer.Context = context;
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private int[] GetRegions(IMesh mesh)
|
||||
{
|
||||
mesh.Renumber();
|
||||
|
||||
var labels = new int[mesh.Triangles.Count];
|
||||
var regions = new SortedSet<int>();
|
||||
|
||||
foreach (var t in mesh.Triangles)
|
||||
{
|
||||
labels[t.ID] = t.Label;
|
||||
regions.Add(t.Label);
|
||||
}
|
||||
|
||||
if (colors.ColorDictionary == null)
|
||||
{
|
||||
colors.CreateColorDictionary(regions);
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public static ColorManager LightScheme()
|
||||
{
|
||||
var colors = new ColorManager();
|
||||
|
||||
colors.Background = Color.White;
|
||||
colors.Point = Color.FromArgb(60, 80, 120);
|
||||
colors.SteinerPoint = Color.DarkGreen;
|
||||
colors.Line = Color.FromArgb(200, 200, 200);
|
||||
colors.Segment = Color.SteelBlue;
|
||||
colors.VoronoiLine = Color.FromArgb(160, 170, 180);
|
||||
|
||||
return colors;
|
||||
}
|
||||
}
|
||||
}
|
||||
+124
-118
@@ -1,118 +1,124 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class LayerRenderer : IRenderer
|
||||
{
|
||||
MeshRenderer meshRenderer;
|
||||
FunctionRenderer functionRenderer;
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public LayerRenderer()
|
||||
{
|
||||
meshRenderer = new MeshRenderer();
|
||||
functionRenderer = new FunctionRenderer();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
meshRenderer.Context = Context;
|
||||
meshRenderer.RenderTarget = RenderTarget;
|
||||
|
||||
functionRenderer.Context = Context;
|
||||
functionRenderer.RenderTarget = RenderTarget;
|
||||
|
||||
// 0 = mesh (filled)
|
||||
// 1 = mesh (wireframe)
|
||||
// 2 = polygon
|
||||
// 3 = points
|
||||
// 4 = voronoi overlay
|
||||
// 5 = vector field
|
||||
// 6 = contour lines
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var layer in this.Context.RenderLayers)
|
||||
{
|
||||
if (!layer.IsEmpty() && layer.IsEnabled)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
RenderFilledMesh(layer);
|
||||
break;
|
||||
case 1:
|
||||
RenderMesh(layer);
|
||||
break;
|
||||
case 2:
|
||||
RenderPolygon(layer);
|
||||
break;
|
||||
case 3:
|
||||
RenderPoints(layer);
|
||||
break;
|
||||
case 4:
|
||||
RenderVoronoi(layer);
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderFilledMesh(IRenderLayer layer)
|
||||
{
|
||||
if (layer.Partition != null)
|
||||
{
|
||||
meshRenderer.RenderElements(layer.Points.Data, layer.Indices.Data, 3, layer.Partition.Data);
|
||||
}
|
||||
else if (layer.Colors != null)
|
||||
{
|
||||
functionRenderer.Render(layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMesh(IRenderLayer layer)
|
||||
{
|
||||
if (layer.Indices.Size == 3)
|
||||
{
|
||||
meshRenderer.RenderElements(layer.Points.Data, layer.Indices.Data, 3, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, Context.ColorManager.Line);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderPolygon(IRenderLayer layer)
|
||||
{
|
||||
meshRenderer.RenderSegments(layer.Points.Data, layer.Indices.Data, Context.ColorManager.Segment);
|
||||
}
|
||||
|
||||
private void RenderPoints(IRenderLayer layer)
|
||||
{
|
||||
meshRenderer.RenderPoints(layer.Points.Data, layer.Points.Size, layer.Count);
|
||||
}
|
||||
|
||||
private void RenderVoronoi(IRenderLayer layer)
|
||||
{
|
||||
if (RenderManager.VORONOI_DEBUG)
|
||||
{
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, Pens.Purple);
|
||||
meshRenderer.RenderPoints(layer.Points.Data, layer.Points.Size, 0, layer.Count, Brushes.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, Context.ColorManager.VoronoiLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class LayerRenderer : IRenderer
|
||||
{
|
||||
MeshRenderer meshRenderer;
|
||||
FunctionRenderer functionRenderer;
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public LayerRenderer()
|
||||
{
|
||||
meshRenderer = new MeshRenderer();
|
||||
functionRenderer = new FunctionRenderer();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
meshRenderer.Context = Context;
|
||||
meshRenderer.RenderTarget = RenderTarget;
|
||||
|
||||
functionRenderer.Context = Context;
|
||||
functionRenderer.RenderTarget = RenderTarget;
|
||||
|
||||
// 0 = mesh (filled)
|
||||
// 1 = mesh (wireframe)
|
||||
// 2 = polygon
|
||||
// 3 = points
|
||||
// 4 = voronoi overlay
|
||||
// 5 = vector field
|
||||
// 6 = contour lines
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var layer in this.Context.RenderLayers)
|
||||
{
|
||||
if (!layer.IsEmpty() && layer.IsEnabled)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
RenderFilledMesh(layer);
|
||||
break;
|
||||
case 1:
|
||||
RenderMesh(layer);
|
||||
break;
|
||||
case 2:
|
||||
RenderPolygon(layer);
|
||||
break;
|
||||
case 3:
|
||||
RenderPoints(layer);
|
||||
break;
|
||||
case 4:
|
||||
RenderVoronoi(layer);
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderFilledMesh(IRenderLayer layer)
|
||||
{
|
||||
if (layer.Partition != null)
|
||||
{
|
||||
meshRenderer.RenderElements(layer.Points.Data, layer.Indices.Data, 3, layer.Partition.Data);
|
||||
}
|
||||
else if (layer.Colors != null)
|
||||
{
|
||||
functionRenderer.Render(layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMesh(IRenderLayer layer)
|
||||
{
|
||||
if (layer.Indices.Size == 3)
|
||||
{
|
||||
meshRenderer.RenderElements(layer.Points.Data, layer.Indices.Data, 3, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var pen = new Pen(Context.ColorManager.Line);
|
||||
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, pen);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderPolygon(IRenderLayer layer)
|
||||
{
|
||||
using var pen = new Pen(Context.ColorManager.Segment);
|
||||
|
||||
meshRenderer.RenderSegments(layer.Points.Data, layer.Indices.Data, pen);
|
||||
}
|
||||
|
||||
private void RenderPoints(IRenderLayer layer)
|
||||
{
|
||||
meshRenderer.RenderPoints(layer.Points.Data, layer.Points.Size, layer.Count);
|
||||
}
|
||||
|
||||
private void RenderVoronoi(IRenderLayer layer)
|
||||
{
|
||||
if (RenderManager.VORONOI_DEBUG)
|
||||
{
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, Pens.Purple);
|
||||
meshRenderer.RenderPoints(layer.Points.Data, layer.Points.Size, 0, layer.Count, Brushes.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var pen = new Pen(Context.ColorManager.VoronoiLine);
|
||||
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, pen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+175
-173
@@ -1,173 +1,175 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="MeshRenderer.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.GDI.Native;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh.
|
||||
/// </summary>
|
||||
public class MeshRenderer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
|
||||
/// </summary>
|
||||
public MeshRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public void RenderPoints(float[] points, int size, int limit = 0)
|
||||
{
|
||||
int n = points.Length / size;
|
||||
int m = limit > 0 ? limit : n;
|
||||
|
||||
// Draw unchanged points
|
||||
RenderPoints(points, size, 0, m, Context.ColorManager.Point);
|
||||
|
||||
// Draw new (Steiner) points
|
||||
if (limit > 0)
|
||||
{
|
||||
RenderPoints(points, size, m, n, Context.ColorManager.SteinerPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderPoints(float[] points, int size, int start, int end, Brush brush)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int i, k, n = points.Length / size;
|
||||
PointF p = new PointF();
|
||||
|
||||
// Render points
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
k = size * i;
|
||||
|
||||
p.X = points[k];
|
||||
p.Y = points[k + 1];
|
||||
|
||||
if (zoom.Viewport.Contains(p))
|
||||
{
|
||||
zoom.WorldToScreen(ref p);
|
||||
g.FillEllipse(brush, p.X - 1.5f, p.Y - 1.5f, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderSegments(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
RenderLines(points, indices, pen);
|
||||
}
|
||||
|
||||
public void RenderEdges(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
RenderLines(points, indices, pen);
|
||||
}
|
||||
|
||||
public void RenderElements(float[] points, int[] indices, int size, int[] partition)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int n = indices.Length / size;
|
||||
int k0, k1, k2;
|
||||
|
||||
var tri = new PointF[size];
|
||||
|
||||
bool filled = partition != null;
|
||||
|
||||
var brushes = filled ? Context.ColorManager.GetBrushDictionary() : null;
|
||||
|
||||
// TODO: remove hardcoded color
|
||||
var pen = new Pen(Color.FromArgb(20, 20, 20));
|
||||
|
||||
// Draw triangles
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * indices[3 * i];
|
||||
k1 = 2 * indices[3 * i + 1];
|
||||
k2 = 2 * indices[3 * i + 2];
|
||||
|
||||
tri[0].X = points[k0];
|
||||
tri[0].Y = points[k0 + 1];
|
||||
|
||||
tri[1].X = points[k1];
|
||||
tri[1].Y = points[k1 + 1];
|
||||
|
||||
tri[2].X = points[k2];
|
||||
tri[2].Y = points[k2 + 1];
|
||||
|
||||
if (zoom.Viewport.Intersects(tri[0], tri[1], tri[2]))
|
||||
{
|
||||
zoom.WorldToScreen(ref tri[0]);
|
||||
zoom.WorldToScreen(ref tri[1]);
|
||||
zoom.WorldToScreen(ref tri[2]);
|
||||
|
||||
if (filled)
|
||||
{
|
||||
var b = brushes[partition[i]];
|
||||
|
||||
if (b.Color.A > 0)
|
||||
{
|
||||
g.FillPolygon(b, tri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g.DrawPolygon(pen, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pen.Dispose();
|
||||
|
||||
if (filled)
|
||||
{
|
||||
Context.ColorManager.Dispose(brushes);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderLines(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int n = indices.Length / 2;
|
||||
int k0, k1;
|
||||
|
||||
PointF p0 = new PointF();
|
||||
PointF p1 = new PointF();
|
||||
|
||||
// Draw edges
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * indices[2 * i];
|
||||
k1 = 2 * indices[2 * i + 1];
|
||||
|
||||
p0.X = points[k0];
|
||||
p0.Y = points[k0 + 1];
|
||||
|
||||
p1.X = points[k1];
|
||||
p1.Y = points[k1 + 1];
|
||||
|
||||
if (zoom.Viewport.Intersects(p0, p1))
|
||||
{
|
||||
zoom.WorldToScreen(ref p0);
|
||||
zoom.WorldToScreen(ref p1);
|
||||
|
||||
g.DrawLine(pen, p0, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="MeshRenderer.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh.
|
||||
/// </summary>
|
||||
public class MeshRenderer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
|
||||
/// </summary>
|
||||
public MeshRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public void RenderPoints(float[] points, int size, int limit = 0)
|
||||
{
|
||||
int n = points.Length / size;
|
||||
int m = limit > 0 ? limit : n;
|
||||
|
||||
using var Point = new SolidBrush(Context.ColorManager.Point);
|
||||
using var SteinerPoint = new SolidBrush(Context.ColorManager.SteinerPoint);
|
||||
|
||||
// Draw unchanged points
|
||||
RenderPoints(points, size, 0, m, Point);
|
||||
|
||||
// Draw new (Steiner) points
|
||||
if (limit > 0)
|
||||
{
|
||||
RenderPoints(points, size, m, n, SteinerPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderPoints(float[] points, int size, int start, int end, Brush brush)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int i, k, n = points.Length / size;
|
||||
PointF p = new PointF();
|
||||
|
||||
// Render points
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
k = size * i;
|
||||
|
||||
p.X = points[k];
|
||||
p.Y = points[k + 1];
|
||||
|
||||
if (zoom.Viewport.Contains(p))
|
||||
{
|
||||
zoom.NdcToScreen(ref p);
|
||||
g.FillEllipse(brush, p.X - 1.5f, p.Y - 1.5f, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderSegments(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
RenderLines(points, indices, pen);
|
||||
}
|
||||
|
||||
public void RenderEdges(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
RenderLines(points, indices, pen);
|
||||
}
|
||||
|
||||
public void RenderElements(float[] points, int[] indices, int size, int[] partition)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int n = indices.Length / size;
|
||||
int k0, k1, k2;
|
||||
|
||||
var tri = new PointF[size];
|
||||
|
||||
bool filled = partition != null;
|
||||
|
||||
var brushes = filled ? Helper.GetBrushDictionary(Context.ColorManager.ColorDictionary) : null;
|
||||
|
||||
// TODO: remove hard-coded color
|
||||
var pen = new Pen(Color.FromArgb(20, 20, 20));
|
||||
|
||||
// Draw triangles
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * indices[3 * i];
|
||||
k1 = 2 * indices[3 * i + 1];
|
||||
k2 = 2 * indices[3 * i + 2];
|
||||
|
||||
tri[0].X = points[k0];
|
||||
tri[0].Y = points[k0 + 1];
|
||||
|
||||
tri[1].X = points[k1];
|
||||
tri[1].Y = points[k1 + 1];
|
||||
|
||||
tri[2].X = points[k2];
|
||||
tri[2].Y = points[k2 + 1];
|
||||
|
||||
if (zoom.Viewport.Intersects(tri[0], tri[1], tri[2]))
|
||||
{
|
||||
zoom.NdcToScreen(ref tri[0]);
|
||||
zoom.NdcToScreen(ref tri[1]);
|
||||
zoom.NdcToScreen(ref tri[2]);
|
||||
|
||||
if (filled)
|
||||
{
|
||||
var b = brushes[partition[i]];
|
||||
|
||||
if (b.Color.A > 0)
|
||||
{
|
||||
g.FillPolygon(b, tri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g.DrawPolygon(pen, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pen.Dispose();
|
||||
|
||||
if (filled)
|
||||
{
|
||||
Helper.Dispose(brushes);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderLines(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int n = indices.Length / 2;
|
||||
int k0, k1;
|
||||
|
||||
PointF p0 = new PointF();
|
||||
PointF p1 = new PointF();
|
||||
|
||||
// Draw edges
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * indices[2 * i];
|
||||
k1 = 2 * indices[2 * i + 1];
|
||||
|
||||
p0.X = points[k0];
|
||||
p0.Y = points[k0 + 1];
|
||||
|
||||
p1.X = points[k1];
|
||||
p1.Y = points[k1 + 1];
|
||||
|
||||
if (zoom.Viewport.Intersects(p0, p1))
|
||||
{
|
||||
zoom.NdcToScreen(ref p0);
|
||||
zoom.NdcToScreen(ref p1);
|
||||
|
||||
g.DrawLine(pen, p0, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
-35
@@ -1,35 +1,35 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies gradient fill mode
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum GradientFillMode : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// In this mode, two endpoints describe a rectangle. The rectangle is defined
|
||||
/// to have a constant color (specified by the TRIVERTEX structure) for the
|
||||
/// left and right edges. GDI interpolates the color from the left to right
|
||||
/// edge and fills the interior
|
||||
/// </summary>
|
||||
GRADIENT_FILL_RECT_H = 0,
|
||||
/// <summary>
|
||||
/// In this mode, two endpoints describe a rectangle. The rectangle is
|
||||
/// defined to have a constant color (specified by the TRIVERTEX structure)
|
||||
/// for the top and bottom edges. GDI interpolates the color from the top
|
||||
/// to bottom edge and fills the interior
|
||||
/// </summary>
|
||||
GRADIENT_FILL_RECT_V = 1,
|
||||
/// <summary>
|
||||
/// In this mode, an array of TRIVERTEX structures is passed to GDI
|
||||
/// along with a list of array indexes that describe separate triangles.
|
||||
/// GDI performs linear interpolation between triangle vertices and fills
|
||||
/// the interior. Drawing is done directly in 24- and 32-bpp modes.
|
||||
/// Dithering is performed in 16-, 8-, 4-, and 1-bpp mode
|
||||
/// </summary>
|
||||
GRADIENT_FILL_TRIANGLE = 2
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies gradient fill mode
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum GradientFillMode : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// In this mode, two endpoints describe a rectangle. The rectangle is defined
|
||||
/// to have a constant color (specified by the TRIVERTEX structure) for the
|
||||
/// left and right edges. GDI interpolates the color from the left to right
|
||||
/// edge and fills the interior
|
||||
/// </summary>
|
||||
GRADIENT_FILL_RECT_H = 0,
|
||||
/// <summary>
|
||||
/// In this mode, two endpoints describe a rectangle. The rectangle is
|
||||
/// defined to have a constant color (specified by the TRIVERTEX structure)
|
||||
/// for the top and bottom edges. GDI interpolates the color from the top
|
||||
/// to bottom edge and fills the interior
|
||||
/// </summary>
|
||||
GRADIENT_FILL_RECT_V = 1,
|
||||
/// <summary>
|
||||
/// In this mode, an array of TRIVERTEX structures is passed to GDI
|
||||
/// along with a list of array indexes that describe separate triangles.
|
||||
/// GDI performs linear interpolation between triangle vertices and fills
|
||||
/// the interior. Drawing is done directly in 24- and 32-bpp modes.
|
||||
/// Dithering is performed in 16-, 8-, 4-, and 1-bpp mode
|
||||
/// </summary>
|
||||
GRADIENT_FILL_TRIANGLE = 2
|
||||
}
|
||||
}
|
||||
+28
-28
@@ -1,28 +1,28 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The GRADIENT_RECT structure specifies the index of two vertices in the
|
||||
/// pVertex array in the GradientFill function. These two vertices form the
|
||||
/// upper-left and lower-right boundaries of a rectangle.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144958.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct GradientRect
|
||||
{
|
||||
/// <summary>
|
||||
/// The upper-left corner of a rectangle.
|
||||
/// </summary>
|
||||
public uint UpperLeft;
|
||||
|
||||
/// <summary>
|
||||
/// The lower-right corner of a rectangle.
|
||||
/// </summary>
|
||||
public uint LowerRight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The GRADIENT_RECT structure specifies the index of two vertices in the
|
||||
/// pVertex array in the GradientFill function. These two vertices form the
|
||||
/// upper-left and lower-right boundaries of a rectangle.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144958.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct GradientRect
|
||||
{
|
||||
/// <summary>
|
||||
/// The upper-left corner of a rectangle.
|
||||
/// </summary>
|
||||
public uint UpperLeft;
|
||||
|
||||
/// <summary>
|
||||
/// The lower-right corner of a rectangle.
|
||||
/// </summary>
|
||||
public uint LowerRight;
|
||||
}
|
||||
|
||||
}
|
||||
+32
-32
@@ -1,32 +1,32 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The GRADIENT_TRIANGLE structure specifies the index of three
|
||||
/// vertices in the pVertex array in the GradientFill function.
|
||||
/// These three vertices form one triangle
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144959.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct GradientTriangle
|
||||
{
|
||||
/// <summary>
|
||||
/// The first point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex1;
|
||||
|
||||
/// <summary>
|
||||
/// The second point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex2;
|
||||
|
||||
/// <summary>
|
||||
/// The third point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex3;
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The GRADIENT_TRIANGLE structure specifies the index of three
|
||||
/// vertices in the pVertex array in the GradientFill function.
|
||||
/// These three vertices form one triangle
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144959.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct GradientTriangle
|
||||
{
|
||||
/// <summary>
|
||||
/// The first point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex1;
|
||||
|
||||
/// <summary>
|
||||
/// The second point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex2;
|
||||
|
||||
/// <summary>
|
||||
/// The third point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex3;
|
||||
}
|
||||
}
|
||||
+89
-89
@@ -1,90 +1,90 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// PInvoke signatures for GradientFill methods.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Minimum requirements: Windows 2000 Professional
|
||||
///
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144957.aspx
|
||||
/// </remarks>
|
||||
internal static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device contex</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">Array of elements</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, uint[] pMesh, uint nMesh,
|
||||
GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device contex</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">Array of GRADIENT_TRIANGLE structures in triangle mode</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientTriangle[] pMesh,
|
||||
uint nMesh, GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device contex</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">an array of GRADIENT_RECT structures in rectangle mode</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientRect[] pMesh,
|
||||
uint nMesh, GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
#region Nested type: Native
|
||||
|
||||
internal class Native
|
||||
{
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, uint[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, GradientRect[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, GradientTriangle[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// PInvoke signatures for GradientFill methods.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Minimum requirements: Windows 2000 Professional
|
||||
///
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144957.aspx
|
||||
/// </remarks>
|
||||
internal static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device context</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">Array of elements</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, uint[] pMesh, uint nMesh,
|
||||
GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device context</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">Array of GRADIENT_TRIANGLE structures in triangle mode</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientTriangle[] pMesh,
|
||||
uint nMesh, GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device context</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">an array of GRADIENT_RECT structures in rectangle mode</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientRect[] pMesh,
|
||||
uint nMesh, GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
#region Nested type: Native
|
||||
|
||||
internal class Native
|
||||
{
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, uint[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, GradientRect[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, GradientTriangle[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+45
-45
@@ -1,45 +1,45 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The TRIVERTEX structure contains color information and position information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145142.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct TriVertex
|
||||
{
|
||||
/// <summary>
|
||||
/// The x-coordinate, in logical units, of the upper-left corner of the rectangle
|
||||
/// </summary>
|
||||
public int x;
|
||||
|
||||
/// <summary>
|
||||
/// The y-coordinate, in logical units, of the upper-left corner of the rectangle
|
||||
/// </summary>
|
||||
public int y;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Red;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Green;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Blue;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Alpha;
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The TRIVERTEX structure contains color information and position information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145142.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct TriVertex
|
||||
{
|
||||
/// <summary>
|
||||
/// The x-coordinate, in logical units, of the upper-left corner of the rectangle
|
||||
/// </summary>
|
||||
public int x;
|
||||
|
||||
/// <summary>
|
||||
/// The y-coordinate, in logical units, of the upper-left corner of the rectangle
|
||||
/// </summary>
|
||||
public int y;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Red;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Green;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Blue;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Alpha;
|
||||
}
|
||||
}
|
||||
+251
-252
@@ -1,252 +1,251 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="RendererControl.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh using GDI.
|
||||
/// </summary>
|
||||
public class RenderControl : Control, IRenderControl
|
||||
{
|
||||
// Rendering stuff
|
||||
private BufferedGraphics buffer;
|
||||
private BufferedGraphicsContext context;
|
||||
|
||||
//ColorManager renderColors;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
string coordinate = String.Empty;
|
||||
|
||||
Timer timer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenderControl" /> class.
|
||||
/// </summary>
|
||||
public RenderControl()
|
||||
{
|
||||
//this.SetStyle(ControlStyles.UserPaint, true);
|
||||
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
|
||||
//this.SetStyle(ControlStyles.Selectable, true);
|
||||
this.SetStyle(ControlStyles.ResizeRedraw, true);
|
||||
|
||||
//renderColors = ColorManager.Default();
|
||||
|
||||
this.BackColor = Color.Black;
|
||||
|
||||
context = BufferedGraphicsManager.Current;// new BufferedGraphicsContext();
|
||||
|
||||
timer = new Timer();
|
||||
timer.Interval = 3000;
|
||||
timer.Tick += (sender, e) =>
|
||||
{
|
||||
timer.Stop();
|
||||
coordinate = String.Empty;
|
||||
this.Invalidate();
|
||||
};
|
||||
}
|
||||
|
||||
public IRenderer Renderer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the graphics buffer (should be called in the forms load event).
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
//zoom.Initialize(this.ClientRectangle);
|
||||
InitializeBuffer();
|
||||
|
||||
initialized = true;
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update graphics buffer and zoom after a resize.
|
||||
/// </summary>
|
||||
public void HandleResize()
|
||||
{
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
zoom.Resize(this.ClientRectangle);
|
||||
InitializeBuffer();
|
||||
}
|
||||
|
||||
private void InitializeBuffer()
|
||||
{
|
||||
if (this.Width > 0 && this.Height > 0)
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
if (this.ClientRectangle == buffer.Graphics.VisibleClipBounds)
|
||||
{
|
||||
this.Invalidate();
|
||||
|
||||
// Bounds didn't change. Probably we just restored the
|
||||
// window from minimized state.
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Dispose();
|
||||
}
|
||||
|
||||
//buffer = context.Allocate(Graphics.FromHwnd(this.Handle), this.ClientRectangle);
|
||||
buffer = context.Allocate(this.CreateGraphics(), this.ClientRectangle);
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
coordinate = String.Empty;
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var g = buffer.Graphics;
|
||||
var renderer = this.Renderer as LayerRenderer;
|
||||
|
||||
g.Clear(renderer.Context.ColorManager.Background);
|
||||
|
||||
if (!initialized || renderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
#region Protected overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Render();
|
||||
|
||||
if (!String.IsNullOrEmpty(coordinate) && Renderer.Context.HasData)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
g.DrawString(coordinate, this.Font, Brushes.White, 10, 10);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
// Do nothing
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaintBackground(pevent);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (zoom.Zoom(e.Delta, (float)e.X / Width, (float)e.Y / Height))
|
||||
{
|
||||
// Redraw
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e)
|
||||
{
|
||||
// We need to manually set the focus to get proper handling of
|
||||
// the KeyUp and MouseWheel events.
|
||||
this.Focus();
|
||||
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (e.Button == MouseButtons.Middle)
|
||||
{
|
||||
zoom.Reset();
|
||||
this.Render();
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
PointF c = new PointF((float)e.X / Width, (float)e.Y / Height);
|
||||
zoom.ScreenToWorld(ref c);
|
||||
coordinate = String.Format(NumberFormatInfo.InvariantInfo,
|
||||
"X:{0} Y:{1}", c.X, c.Y);
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
bool redraw = false;
|
||||
|
||||
if (e.KeyCode == Keys.Up)
|
||||
{
|
||||
redraw = zoom.Translate(0, 1);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Down)
|
||||
{
|
||||
redraw = zoom.Translate(0, -1);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Left)
|
||||
{
|
||||
redraw = zoom.Translate(-1, 0);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Right)
|
||||
{
|
||||
redraw = zoom.Translate(1, 0);
|
||||
}
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="RendererControl.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh using GDI.
|
||||
/// </summary>
|
||||
public class RenderControl : Control, IRenderControl
|
||||
{
|
||||
// Rendering stuff
|
||||
private BufferedGraphics buffer;
|
||||
private BufferedGraphicsContext context;
|
||||
|
||||
//ColorManager renderColors;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
string coordinate = string.Empty;
|
||||
|
||||
Timer timer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenderControl" /> class.
|
||||
/// </summary>
|
||||
public RenderControl()
|
||||
{
|
||||
//this.SetStyle(ControlStyles.UserPaint, true);
|
||||
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
|
||||
//this.SetStyle(ControlStyles.Selectable, true);
|
||||
this.SetStyle(ControlStyles.ResizeRedraw, true);
|
||||
|
||||
//renderColors = ColorManager.Default();
|
||||
|
||||
this.BackColor = Color.Black;
|
||||
|
||||
context = BufferedGraphicsManager.Current;// new BufferedGraphicsContext();
|
||||
|
||||
timer = new Timer();
|
||||
timer.Interval = 3000;
|
||||
timer.Tick += (sender, e) =>
|
||||
{
|
||||
timer.Stop();
|
||||
coordinate = string.Empty;
|
||||
this.Invalidate();
|
||||
};
|
||||
}
|
||||
|
||||
public IRenderer Renderer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the graphics buffer (should be called in the forms load event).
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
//zoom.Initialize(this.ClientRectangle);
|
||||
InitializeBuffer();
|
||||
|
||||
initialized = true;
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update graphics buffer and zoom after a resize.
|
||||
/// </summary>
|
||||
public void HandleResize()
|
||||
{
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
zoom.Resize(this.ClientRectangle);
|
||||
InitializeBuffer();
|
||||
}
|
||||
|
||||
private void InitializeBuffer()
|
||||
{
|
||||
if (this.Width > 0 && this.Height > 0)
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
if (this.ClientRectangle == buffer.Graphics.VisibleClipBounds)
|
||||
{
|
||||
this.Invalidate();
|
||||
|
||||
// Bounds didn't change. Probably we just restored the
|
||||
// window from minimized state.
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Dispose();
|
||||
}
|
||||
|
||||
//buffer = context.Allocate(Graphics.FromHwnd(this.Handle), this.ClientRectangle);
|
||||
buffer = context.Allocate(this.CreateGraphics(), this.ClientRectangle);
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
coordinate = string.Empty;
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var g = buffer.Graphics;
|
||||
var renderer = this.Renderer as LayerRenderer;
|
||||
|
||||
g.Clear(renderer.Context.ColorManager.Background);
|
||||
|
||||
if (!initialized || renderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
#region Protected overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Render();
|
||||
|
||||
if (!string.IsNullOrEmpty(coordinate) && Renderer.Context.HasData)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
TextRenderer.DrawText(g, coordinate, Font, new Point(10, 10), Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
// Do nothing
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaintBackground(pevent);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (zoom.Zoom(e.Delta, (float)e.X / Width, (float)e.Y / Height))
|
||||
{
|
||||
// Redraw
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e)
|
||||
{
|
||||
// We need to manually set the focus to get proper handling of
|
||||
// the KeyUp and MouseWheel events.
|
||||
this.Focus();
|
||||
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (e.Button == MouseButtons.Middle)
|
||||
{
|
||||
zoom.Reset();
|
||||
this.Render();
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
PointF c = new PointF((float)e.X / Width, (float)e.Y / Height);
|
||||
zoom.ScreenToWorld(c, out double x, out double y);
|
||||
coordinate = string.Format(NumberFormatInfo.InvariantInfo,
|
||||
"X:{0} Y:{1}", x, y);
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
bool redraw = false;
|
||||
|
||||
if (e.KeyCode == Keys.Up)
|
||||
{
|
||||
redraw = zoom.Translate(0, 1);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Down)
|
||||
{
|
||||
redraw = zoom.Translate(0, -1);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Left)
|
||||
{
|
||||
redraw = zoom.Translate(-1, 0);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Right)
|
||||
{
|
||||
redraw = zoom.Translate(1, 0);
|
||||
}
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<RootNamespace>TriangleNet.Rendering.GDI</RootNamespace>
|
||||
<AssemblyName>Triangle.Rendering.GDI</AssemblyName>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj" />
|
||||
<ProjectReference Include="..\Triangle.Rendering\Triangle.Rendering.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public abstract class BufferBase<T> : IBuffer<T> where T : struct
|
||||
{
|
||||
protected T[] data;
|
||||
protected int size;
|
||||
|
||||
public BufferBase(int capacity, int size)
|
||||
: this(new T[capacity], size)
|
||||
{
|
||||
}
|
||||
|
||||
public BufferBase(T[] data, int size)
|
||||
{
|
||||
this.data = data;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T[] Data => data;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count => data == null ? 0 : data.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int Size { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract BufferTarget Target { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class ColorBuffer : BufferBase<Color>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorBuffer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The buffer capacity.</param>
|
||||
/// <param name="size">The size of one element in the buffer (i.e. 2 for 2D points)</param>
|
||||
public ColorBuffer(int capacity, int size)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorBuffer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The buffer data.</param>
|
||||
/// <param name="size">The size of one element in the buffer (i.e. 2 for 2D points)</param>
|
||||
public ColorBuffer(Color[] data, int size)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int Size => 1;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override BufferTarget Target => BufferTarget.ColorBuffer;
|
||||
}
|
||||
}
|
||||
+34
-34
@@ -1,34 +1,34 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public enum BufferTarget : byte
|
||||
{
|
||||
ColorBuffer,
|
||||
IndexBuffer,
|
||||
VertexBuffer
|
||||
}
|
||||
|
||||
public interface IBuffer<T> where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the contents of the buffer.
|
||||
/// </summary>
|
||||
T[] Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the buffer.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of one element in the buffer (i.e. 2 for 2D points
|
||||
/// or 3 for triangles).
|
||||
/// </summary>
|
||||
int Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer target (vertices or indices).
|
||||
/// </summary>
|
||||
BufferTarget Target { get; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public enum BufferTarget : byte
|
||||
{
|
||||
ColorBuffer,
|
||||
IndexBuffer,
|
||||
VertexBuffer
|
||||
}
|
||||
|
||||
public interface IBuffer<T> where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the contents of the buffer.
|
||||
/// </summary>
|
||||
T[] Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the buffer.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of one element in the buffer (i.e. 2 for 2D points
|
||||
/// or 3 for triangles).
|
||||
/// </summary>
|
||||
int Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer target (vertices or indices).
|
||||
/// </summary>
|
||||
BufferTarget Target { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public class IndexBuffer : BufferBase<int>
|
||||
{
|
||||
#region Static methods
|
||||
|
||||
public static IBuffer<int> Create(IEnumerable<IEdge> edges, int size)
|
||||
{
|
||||
var buffer = new IndexBuffer(size * edges.Count(), size);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var e in edges)
|
||||
{
|
||||
data[size * i + 0] = e.P0;
|
||||
data[size * i + 1] = e.P1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static IBuffer<int> Create(ICollection<Triangle> elements, int size)
|
||||
{
|
||||
var buffer = new IndexBuffer(size * elements.Count, size);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var e in elements)
|
||||
{
|
||||
data[size * i + 0] = e.GetVertexID(0);
|
||||
data[size * i + 1] = e.GetVertexID(1);
|
||||
data[size * i + 2] = e.GetVertexID(2);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IndexBuffer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The buffer capacity.</param>
|
||||
/// <param name="size">The size of one element in the buffer (i.e. 2 for 2D points)</param>
|
||||
public IndexBuffer(int capacity, int size)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IndexBuffer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The buffer data.</param>
|
||||
/// <param name="size">The size of one element in the buffer (i.e. 2 for 2D points)</param>
|
||||
public IndexBuffer(int[] data, int size)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int Size => size;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override BufferTarget Target => BufferTarget.IndexBuffer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public class VertexBuffer : BufferBase<float>
|
||||
{
|
||||
#region Static methods
|
||||
|
||||
/// <summary>
|
||||
/// Create a vertex buffer from given point collection.
|
||||
/// </summary>
|
||||
/// <param name="points">The points to render.</param>
|
||||
/// <returns>Returns the vertex buffer.</returns>
|
||||
public static IBuffer<float> Create(ICollection<Point> points)
|
||||
{
|
||||
return Create(points, new Rectangle(0d, 0d, 1d, 1d));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a normalized vertex buffer from given point collection.
|
||||
/// </summary>
|
||||
/// <param name="points">The points to render.</param>
|
||||
/// <param name="bounds">The bounding box used for normalization.</param>
|
||||
/// <returns>Returns a buffer of normalized coordinates.</returns>
|
||||
public static IBuffer<float> Create(ICollection<Point> points, Rectangle bounds)
|
||||
{
|
||||
var buffer = new VertexBuffer(2 * points.Count);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
double dx = bounds.X;
|
||||
double dy = bounds.Y;
|
||||
|
||||
double scale = 1.0 / Math.Max(bounds.Width, bounds.Height);
|
||||
|
||||
int i = 0;
|
||||
|
||||
double x, y;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
x = (p.X - dx) * scale;
|
||||
y = (p.Y - dy) * scale;
|
||||
|
||||
data[2 * i] = (float)x;
|
||||
data[2 * i + 1] = (float)y;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a vertex buffer from given point collection.
|
||||
/// </summary>
|
||||
/// <param name="points">The points to render.</param>
|
||||
/// <returns>Returns the vertex buffer.</returns>
|
||||
public static IBuffer<float> Create(ICollection<Vertex> points)
|
||||
{
|
||||
return Create(points, new Rectangle(0d, 0d, 1d, 1d));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a normalized vertex buffer from given vertex collection.
|
||||
/// </summary>
|
||||
/// <param name="points">The vertices to render.</param>
|
||||
/// <param name="bounds">The bounding box used for normalization.</param>
|
||||
/// <returns>Returns a buffer of normalized coordinates.</returns>
|
||||
public static IBuffer<float> Create(ICollection<Vertex> points, Rectangle bounds)
|
||||
{
|
||||
var buffer = new VertexBuffer(2 * points.Count);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
double dx = bounds.X;
|
||||
double dy = bounds.Y;
|
||||
|
||||
double scale = 1.0 / Math.Max(bounds.Width, bounds.Height);
|
||||
|
||||
int i = 0;
|
||||
|
||||
double x, y;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
x = (p.X - dx) * scale;
|
||||
y = (p.Y - dy) * scale;
|
||||
|
||||
data[2 * i] = (float)x;
|
||||
data[2 * i + 1] = (float)y;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexBuffer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The buffer capacity.</param>
|
||||
/// <param name="size">The size of one element in the buffer (i.e. 2 for 2D points)</param>
|
||||
public VertexBuffer(int capacity, int size = 2)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexBuffer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The buffer data.</param>
|
||||
/// <param name="size">The size of one element in the buffer (i.e. 2 for 2D points)</param>
|
||||
public VertexBuffer(float[] data, int size = 2)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int Size => size;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override BufferTarget Target => BufferTarget.VertexBuffer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
public class ColorManager
|
||||
{
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public Color Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for points.
|
||||
/// </summary>
|
||||
public Color Point { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for steiner points.
|
||||
/// </summary>
|
||||
public Color SteinerPoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for mesh edges.
|
||||
/// </summary>
|
||||
public Color Line { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for mesh segments.
|
||||
/// </summary>
|
||||
public Color Segment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for Voronoi edges.
|
||||
/// </summary>
|
||||
public Color VoronoiLine { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a dictionary which maps region ids (or partition indices) to a color.
|
||||
/// </summary>
|
||||
public Dictionary<int, Color> ColorDictionary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a color map used for function plotting.
|
||||
/// </summary>
|
||||
public ColorMap ColorMap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="ColorManager"/> class with default (dark) color scheme.
|
||||
/// </summary>
|
||||
public static ColorManager Default()
|
||||
{
|
||||
var colors = new ColorManager();
|
||||
|
||||
colors.Background = Color.FromArgb(0, 0, 0);
|
||||
colors.Point = Color.Green;
|
||||
colors.SteinerPoint = Color.Peru;
|
||||
colors.Line = Color.FromArgb(30, 30, 30);
|
||||
colors.Segment = Color.DarkBlue;
|
||||
colors.VoronoiLine = Color.FromArgb(40, 50, 60);
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
public void CreateColorDictionary(int length)
|
||||
{
|
||||
var keys = new int[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
keys[i] = i;
|
||||
}
|
||||
|
||||
CreateColorDictionary(keys);
|
||||
}
|
||||
|
||||
public void CreateColorDictionary(IEnumerable<int> keys)
|
||||
{
|
||||
this.ColorDictionary = new Dictionary<int, Color>();
|
||||
|
||||
int i = 0, n = regionColors.Length;
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
this.ColorDictionary.Add(key, regionColors[i]);
|
||||
|
||||
i = (i + 1) % n;
|
||||
}
|
||||
}
|
||||
|
||||
// Change or add as many colors as you like...
|
||||
private static Color[] regionColors = {
|
||||
Color.Transparent,
|
||||
Color.FromArgb(200, 0, 255, 0),
|
||||
Color.FromArgb(200, 255, 0, 0),
|
||||
Color.FromArgb(200, 0, 0, 255),
|
||||
Color.FromArgb(200, 0, 255, 255),
|
||||
Color.FromArgb(200, 255, 255, 0),
|
||||
Color.FromArgb(200, 255, 0, 255),
|
||||
Color.FromArgb(200, 127, 0, 255),
|
||||
Color.FromArgb(200, 0, 127, 255)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
public interface IRenderContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the color manager.
|
||||
/// </summary>
|
||||
ColorManager ColorManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="IRenderLayer"/>s.
|
||||
/// </summary>
|
||||
IList<IRenderLayer> RenderLayers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Projection"/>.
|
||||
/// </summary>
|
||||
Projection Zoom { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IMesh"/>.
|
||||
/// </summary>
|
||||
IMesh Mesh { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the context has data to render.
|
||||
/// </summary>
|
||||
bool HasData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Add polygon data.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
void Add(IPolygon data);
|
||||
|
||||
/// <summary>
|
||||
/// Add mesh data.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="reset"></param>
|
||||
void Add(IMesh data, bool reset);
|
||||
|
||||
/// <summary>
|
||||
/// Add edge data (used for Voronoi).
|
||||
/// </summary>
|
||||
/// <param name="points"></param>
|
||||
/// <param name="edges"></param>
|
||||
/// <param name="reset"></param>
|
||||
void Add(ICollection<Point> points, IEnumerable<IEdge> edges, bool reset);
|
||||
|
||||
/// <summary>
|
||||
/// Add mesh function values <c>z=f(x,y)</c>.
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
void Add(float[] values);
|
||||
|
||||
/// <summary>
|
||||
/// Add mesh partitioning data.
|
||||
/// </summary>
|
||||
/// <param name="partition"></param>
|
||||
void Add(int[] partition);
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable a layer for rendering.
|
||||
/// </summary>
|
||||
/// <param name="layer">The layer index.</param>
|
||||
/// <param name="enabled">If true, enable layer, otherwise disable.</param>
|
||||
/// <remarks>
|
||||
/// 0 = mesh (filled)
|
||||
/// 1 = mesh (wireframe)
|
||||
/// 2 = polygon
|
||||
/// 3 = points
|
||||
/// 4 = voronoi overlay
|
||||
/// 5 = vector field
|
||||
/// 6 = contour lines
|
||||
/// </remarks>
|
||||
void Enable(int layer, bool enabled);
|
||||
|
||||
/// <summary>
|
||||
/// Clear data from all layers.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
}
|
||||
+26
-26
@@ -1,26 +1,26 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="IMeshRenderer.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </summary>
|
||||
public interface IRenderControl
|
||||
{
|
||||
IRenderer Renderer { get; set; }
|
||||
Rectangle ClientRectangle { get; }
|
||||
|
||||
void Initialize();
|
||||
void Refresh();
|
||||
|
||||
void HandleResize();
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="IMeshRenderer.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </summary>
|
||||
public interface IRenderControl
|
||||
{
|
||||
IRenderer Renderer { get; set; }
|
||||
|
||||
Rectangle ClientRectangle { get; }
|
||||
|
||||
void Initialize();
|
||||
|
||||
void Refresh();
|
||||
|
||||
void HandleResize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for managing the data of a render layer.
|
||||
/// </summary>
|
||||
public interface IRenderLayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the number of points in the point buffer.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the points buffer.
|
||||
/// </summary>
|
||||
IBuffer<float> Points { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the indices buffer.
|
||||
/// </summary>
|
||||
IBuffer<int> Indices { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the layer is enabled.
|
||||
/// </summary>
|
||||
bool IsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this layer contains data to render.
|
||||
/// </summary>
|
||||
/// <returns>Returns true, if the points buffer contains data.</returns>
|
||||
bool IsEmpty();
|
||||
|
||||
/// <summary>
|
||||
/// Resets this layer to an empty state.
|
||||
/// </summary>
|
||||
/// <param name="clear">If true, all buffers will be set to <c>null</c>.</param>
|
||||
void Reset(bool clear);
|
||||
|
||||
void SetPoints(IBuffer<float> buffer, bool reset = true);
|
||||
|
||||
void SetIndices(IBuffer<int> buffer);
|
||||
|
||||
#region Attached data (mesh partitioning and heat map rendering)
|
||||
|
||||
// TODO: better put attached data into a subclass?
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mesh partition.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Triangle <c>i</c> given by indices <c>[3 * i, 3 * i + 1, 3 * i + 2]</c>
|
||||
/// belongs to <c>Partition[i]</c>.
|
||||
/// </remarks>
|
||||
IBuffer<int> Partition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color attached to a point in the points buffer.
|
||||
/// </summary>
|
||||
IBuffer<Color> Colors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attach function values <c>z=f(x,y)</c> for all points <c>(x,y)</c> in the point buffer.
|
||||
/// </summary>
|
||||
/// <param name="values">The function values.</param>
|
||||
/// <param name="colormap">The color map.</param>
|
||||
void AttachLayerData(float[] values, ColorMap colormap);
|
||||
|
||||
/// <summary>
|
||||
/// Attach partitioning data to each triangle in the index buffer.
|
||||
/// </summary>
|
||||
/// <param name="partition">The mesh partition.</param>
|
||||
void AttachLayerData(int[] partition);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -1,10 +1,10 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
public interface IRenderer
|
||||
{
|
||||
IRenderContext Context { get; set; }
|
||||
|
||||
void Render();
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
public interface IRenderer
|
||||
{
|
||||
IRenderContext Context { get; set; }
|
||||
|
||||
void Render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Projection.cs" company="">
|
||||
// Triangle.NET Copyright (c) 2012-2022 Christian Woltering
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using TRectangle = Geometry.Rectangle;
|
||||
|
||||
/// <summary>
|
||||
/// Manages a world to screen transformation (2D orthographic projection).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The projection implementation is actually not world-to-screen, but NDC-to-screen
|
||||
/// (Normalized-Device-Coordinates). NDC here is - in contrast for example to OpenGL, the
|
||||
/// transformation of world coordinates to a unit rectangle with origin (0,0) and a max
|
||||
/// side length 1 (the width/height ratio is preserved). It's a simple translate-scale
|
||||
/// transform, which is automatically applied in <c>VertexBuffer.Create(points, bounds)</c>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Since the upper-left corner of the display is usually the screen coordinate origin
|
||||
/// (0,0), the projection will automatically invert the y-axis.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Projection
|
||||
{
|
||||
// The original mesh bounds (needed for screen-to-world projection).
|
||||
TRectangle world_;
|
||||
|
||||
// Precomputed scaling factor for normalized coordinates.
|
||||
double scale_;
|
||||
|
||||
// The screen dimensions.
|
||||
Rectangle screen;
|
||||
|
||||
// The original mesh and the viewport in normalized coordinates.
|
||||
RectangleF world, viewport;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current viewport (normalized coordinates).
|
||||
/// </summary>
|
||||
public RectangleF Viewport => viewport;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zoom level.
|
||||
/// </summary>
|
||||
public int Level { get; private set; }
|
||||
|
||||
private const int MAX_ZOOM = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Projection"/> class.
|
||||
/// </summary>
|
||||
/// <param name="screen">The current screen (viewport) dimensions.</param>
|
||||
public Projection(Rectangle screen)
|
||||
{
|
||||
this.screen = screen;
|
||||
|
||||
world = viewport = new RectangleF(screen.X, screen.Y, screen.Width, screen.Height);
|
||||
|
||||
world_ = new TRectangle();
|
||||
scale_ = 0;
|
||||
|
||||
Level = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the projection.
|
||||
/// </summary>
|
||||
/// <param name="world">The world that should be transformed to screen coordinates.</param>
|
||||
public void Initialize(TRectangle world)
|
||||
{
|
||||
Level = 1;
|
||||
|
||||
// Bounding box of original (non-normalized) coordinates.
|
||||
world_ = world;
|
||||
|
||||
// Scaling factor for normalized coordinates.
|
||||
scale_ = Math.Max(world.Width, world.Height);
|
||||
|
||||
// Dimensions in normalized coordinates.
|
||||
float ww = (float)(world.Width / scale_);
|
||||
float wh = (float)(world.Height / scale_);
|
||||
|
||||
// Add a margin so there's some space around the screen borders.
|
||||
float margin = (ww < wh) ? wh * 0.05f : ww * 0.05f;
|
||||
|
||||
int sw = screen.Width;
|
||||
int sh = screen.Height;
|
||||
|
||||
float wRatio = ww / wh;
|
||||
float sRatio = sw / (float)sh;
|
||||
|
||||
float scale = (sRatio < wRatio) ? (ww + margin) / sw : (wh + margin) / sh;
|
||||
|
||||
// Center in normalized coordinates (left = bottom = 0)
|
||||
float centerX = ww / 2;
|
||||
float centerY = wh / 2;
|
||||
|
||||
// Get the initial viewport (complete mesh centered on the screen)
|
||||
this.world = viewport = new RectangleF(
|
||||
centerX - sw * scale / 2,
|
||||
centerY - sh * scale / 2,
|
||||
sw * scale,
|
||||
sh * scale);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle resize of the screen (viewport).
|
||||
/// </summary>
|
||||
/// <param name="newScreen">The new screen (viewport) dimensions.</param>
|
||||
public void Resize(Rectangle newScreen)
|
||||
{
|
||||
// The viewport has to be updated, but we want to keep
|
||||
// the scaling and the center.
|
||||
|
||||
// Get the screen scaling.
|
||||
float scaleX = newScreen.Width / (float)screen.Width;
|
||||
float scaleY = newScreen.Height / (float)screen.Height;
|
||||
|
||||
screen = newScreen;
|
||||
|
||||
var view = viewport;
|
||||
|
||||
// Center of the viewport
|
||||
float centerX = (view.Left + view.Right) / 2;
|
||||
float centerY = (view.Bottom + view.Top) / 2;
|
||||
|
||||
// The new viewport dimensions.
|
||||
float width = view.Width * scaleX;
|
||||
float height = view.Height * scaleY;
|
||||
|
||||
viewport = new RectangleF(
|
||||
centerX - width / 2,
|
||||
centerY - height / 2,
|
||||
width, height);
|
||||
|
||||
// Do the same for the world:
|
||||
centerX = (world.Left + world.Right) / 2;
|
||||
centerY = (world.Bottom + world.Top) / 2;
|
||||
|
||||
width = world.Width * scaleX;
|
||||
height = world.Height * scaleY;
|
||||
|
||||
world = new RectangleF(
|
||||
centerX - width / 2,
|
||||
centerY - height / 2,
|
||||
width, height);
|
||||
}
|
||||
|
||||
public bool Translate(int dx, int dy)
|
||||
{
|
||||
if (Level == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var view = viewport;
|
||||
|
||||
float x = view.X + dx * view.Width / 4;
|
||||
float y = view.Y + dy * view.Height / 4;
|
||||
|
||||
viewport = new RectangleF(x, y, view.Width, view.Height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom in or out of the viewport.
|
||||
/// </summary>
|
||||
/// <param name="amount">Zoom amount.</param>
|
||||
/// <param name="focusX">Relative x point position (in [0..1] range).</param>
|
||||
/// <param name="focusY">Relative y point position (in [0..1] range).</param>
|
||||
public bool Zoom(int amount, float focusX, float focusY)
|
||||
{
|
||||
float width, height;
|
||||
|
||||
// Invert y coordinate.
|
||||
focusY = 1 - focusY;
|
||||
|
||||
if (amount > 0) // Zoom in
|
||||
{
|
||||
Level++;
|
||||
|
||||
if (Level > MAX_ZOOM)
|
||||
{
|
||||
Level = MAX_ZOOM;
|
||||
return false;
|
||||
}
|
||||
|
||||
width = viewport.Width / 1.1f;
|
||||
height = viewport.Height / 1.1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Level--;
|
||||
|
||||
if (Level < 1)
|
||||
{
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
width = viewport.Width * 1.1f;
|
||||
height = viewport.Height * 1.1f;
|
||||
}
|
||||
|
||||
// Current focus on viewport
|
||||
float x = viewport.X + viewport.Width * focusX;
|
||||
float y = viewport.Y + viewport.Height * focusY;
|
||||
|
||||
// New left and top positions
|
||||
x = x - width * focusX;
|
||||
y = y - height * focusY;
|
||||
|
||||
// Check if outside of world
|
||||
if (x < world.X)
|
||||
{
|
||||
x = world.X;
|
||||
}
|
||||
else if (x + width > world.Right)
|
||||
{
|
||||
x = world.Right - width;
|
||||
}
|
||||
|
||||
if (y < world.Y)
|
||||
{
|
||||
y = world.Y;
|
||||
}
|
||||
else if (y + height > world.Bottom)
|
||||
{
|
||||
y = world.Bottom - height;
|
||||
}
|
||||
|
||||
// Set new viewport
|
||||
viewport = new RectangleF(x, y, width, height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the zoom to initial state.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
viewport = world;
|
||||
Level = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Project a normalized device coordinate to screen coordinates.
|
||||
/// </summary>
|
||||
/// <param name="pt">Input normalized device coordinate, output screen coordinate.</param>
|
||||
public void NdcToScreen(ref PointF pt)
|
||||
{
|
||||
pt.X = (pt.X - viewport.X) / viewport.Width * screen.Width;
|
||||
pt.Y = (1 - (pt.Y - viewport.Y) / viewport.Height) * screen.Height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Project a screen coordinate to world coordinates.
|
||||
/// </summary>
|
||||
/// <param name="pt">Normalized position on screen (both coordinates in [0..1] range).</param>
|
||||
/// <param name="x">The world x-coordinate.</param>
|
||||
/// <param name="y">The world y-coordinate.</param>
|
||||
public void ScreenToWorld(PointF pt, out double x, out double y)
|
||||
{
|
||||
// Position in normalized coordinates.
|
||||
var nx = viewport.X + viewport.Width * pt.X;
|
||||
var ny = viewport.Y + viewport.Height * (1 - pt.Y);
|
||||
|
||||
// Translate and scale to world coordinates.
|
||||
x = world_.X + nx * scale_;
|
||||
y = world_.Y + ny * scale_;
|
||||
}
|
||||
}
|
||||
}
|
||||
+160
-162
@@ -1,162 +1,160 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Voronoi.Legacy;
|
||||
|
||||
/// <summary>
|
||||
/// The RenderContext class brings all the rendering parts together.
|
||||
/// </summary>
|
||||
public class RenderContext : IRenderContext
|
||||
{
|
||||
private ColorManager colorManager;
|
||||
private BoundingBox bounds;
|
||||
private Projection zoom;
|
||||
private IMesh mesh;
|
||||
|
||||
private List<IRenderLayer> renderLayers;
|
||||
|
||||
public RenderContext(Projection zoom, ColorManager colorManager)
|
||||
{
|
||||
bounds = new BoundingBox();
|
||||
|
||||
renderLayers = new List<IRenderLayer>(6);
|
||||
|
||||
renderLayers.Add(new RenderLayer()); // 0 = mesh (filled)
|
||||
renderLayers.Add(new RenderLayer()); // 1 = mesh (wireframe)
|
||||
renderLayers.Add(new RenderLayer()); // 2 = polygon
|
||||
renderLayers.Add(new RenderLayer()); // 3 = points
|
||||
renderLayers.Add(new RenderLayer()); // 4 = voronoi overlay
|
||||
renderLayers.Add(new RenderLayer()); // 5 = vector field
|
||||
renderLayers.Add(new RenderLayer()); // 6 = contour lines
|
||||
|
||||
RenderLayers[1].IsEnabled = true;
|
||||
RenderLayers[2].IsEnabled = true;
|
||||
RenderLayers[3].IsEnabled = true;
|
||||
|
||||
this.zoom = zoom;
|
||||
this.colorManager = colorManager;
|
||||
}
|
||||
|
||||
public ColorManager ColorManager
|
||||
{
|
||||
get { return colorManager; }
|
||||
}
|
||||
|
||||
public BoundingBox Bounds
|
||||
{
|
||||
get { return bounds; }
|
||||
}
|
||||
|
||||
public IList<IRenderLayer> RenderLayers
|
||||
{
|
||||
get { return renderLayers; }
|
||||
}
|
||||
|
||||
public Projection Zoom
|
||||
{
|
||||
get { return zoom; }
|
||||
}
|
||||
|
||||
public IMesh Mesh
|
||||
{
|
||||
get { return mesh; }
|
||||
}
|
||||
|
||||
public bool HasData
|
||||
{
|
||||
get
|
||||
{
|
||||
return renderLayers.Any(layer => !layer.IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(IPolygon data)
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(true);
|
||||
}
|
||||
|
||||
// Always clear voronoi layer.
|
||||
RenderLayers[4].Reset(true);
|
||||
|
||||
int i = 0;
|
||||
|
||||
// Ensure linear numbering of polygon vertices.
|
||||
foreach (var p in data.Points)
|
||||
{
|
||||
p.ID = i++;
|
||||
}
|
||||
|
||||
this.bounds = RenderLayers[2].SetPoints(data);
|
||||
this.zoom.Initialize(bounds);
|
||||
|
||||
RenderLayers[2].SetPolygon(data);
|
||||
RenderLayers[3].SetPoints(RenderLayers[2].Points);
|
||||
}
|
||||
|
||||
public void Add(IMesh data, bool reset)
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(reset);
|
||||
}
|
||||
|
||||
// Always clear voronoi layer.
|
||||
RenderLayers[4].Reset(true);
|
||||
|
||||
// Save reference to mesh.
|
||||
this.mesh = data;
|
||||
|
||||
this.bounds = RenderLayers[1].SetPoints(data);
|
||||
this.zoom.Initialize(bounds);
|
||||
|
||||
RenderLayers[1].SetMesh(data, false);
|
||||
|
||||
RenderLayers[2].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[2].SetPolygon(data);
|
||||
|
||||
RenderLayers[3].SetPoints(RenderLayers[1].Points);
|
||||
}
|
||||
|
||||
public void Add(ICollection<Point> points, IEnumerable<IEdge> edges, bool reset)
|
||||
{
|
||||
RenderLayers[4].SetPoints(points);
|
||||
RenderLayers[4].SetMesh(edges);
|
||||
RenderLayers[4].IsEnabled = true;
|
||||
}
|
||||
|
||||
public void Add(float[] data)
|
||||
{
|
||||
// Add function values for filled mesh.
|
||||
RenderLayers[0].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[0].SetMesh(this.mesh, true);
|
||||
RenderLayers[0].AttachLayerData(data, colorManager.ColorMap);
|
||||
|
||||
RenderLayers[0].IsEnabled = true;
|
||||
}
|
||||
|
||||
public void Add(int[] data)
|
||||
{
|
||||
// Add partition data for filled mesh.
|
||||
RenderLayers[0].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[0].SetMesh(this.mesh, true);
|
||||
RenderLayers[0].AttachLayerData(data);
|
||||
|
||||
RenderLayers[0].IsEnabled = true;
|
||||
}
|
||||
|
||||
public void Enable(int layer, bool enabled)
|
||||
{
|
||||
renderLayers[layer].IsEnabled = enabled;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
|
||||
/// <summary>
|
||||
/// The RenderContext class brings all the rendering parts together.
|
||||
/// </summary>
|
||||
public class RenderContext : IRenderContext
|
||||
{
|
||||
private ColorManager colorManager;
|
||||
private Projection zoom;
|
||||
private Rectangle bounds;
|
||||
private IMesh mesh;
|
||||
|
||||
private List<IRenderLayer> renderLayers;
|
||||
|
||||
public RenderContext(Projection zoom, ColorManager colorManager)
|
||||
{
|
||||
renderLayers = new List<IRenderLayer>(6);
|
||||
|
||||
renderLayers.Add(new RenderLayer()); // 0 = mesh (filled)
|
||||
renderLayers.Add(new RenderLayer()); // 1 = mesh (wireframe)
|
||||
renderLayers.Add(new RenderLayer()); // 2 = polygon
|
||||
renderLayers.Add(new RenderLayer()); // 3 = points
|
||||
renderLayers.Add(new RenderLayer()); // 4 = voronoi overlay
|
||||
renderLayers.Add(new RenderLayer()); // 5 = vector field
|
||||
renderLayers.Add(new RenderLayer()); // 6 = contour lines
|
||||
|
||||
RenderLayers[1].IsEnabled = true;
|
||||
RenderLayers[2].IsEnabled = true;
|
||||
RenderLayers[3].IsEnabled = true;
|
||||
|
||||
this.zoom = zoom;
|
||||
this.colorManager = colorManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ColorManager ColorManager => colorManager;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IList<IRenderLayer> RenderLayers => renderLayers;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Projection Zoom => zoom;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMesh Mesh => mesh;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasData => renderLayers.Any(layer => !layer.IsEmpty());
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(IPolygon data)
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(true);
|
||||
}
|
||||
|
||||
// Always clear Voronoi layer.
|
||||
RenderLayers[4].Reset(true);
|
||||
|
||||
int i = 0;
|
||||
|
||||
// Ensure linear numbering of polygon vertices.
|
||||
foreach (var p in data.Points)
|
||||
{
|
||||
p.ID = i++;
|
||||
}
|
||||
|
||||
bounds = data.Bounds();
|
||||
|
||||
zoom.Initialize(bounds);
|
||||
|
||||
RenderLayers[2].SetPoints(VertexBuffer.Create(data.Points, bounds));
|
||||
RenderLayers[2].SetIndices(IndexBuffer.Create(data.Segments, 2));
|
||||
|
||||
RenderLayers[3].SetPoints(RenderLayers[2].Points);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(IMesh data, bool reset)
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(reset);
|
||||
}
|
||||
|
||||
// Always clear voronoi layer.
|
||||
RenderLayers[4].Reset(true);
|
||||
|
||||
// Save reference to mesh.
|
||||
mesh = data;
|
||||
bounds = data.Bounds;
|
||||
|
||||
// Ensure linear numbering of vertices.
|
||||
mesh.Renumber();
|
||||
|
||||
zoom.Initialize(bounds);
|
||||
|
||||
RenderLayers[1].SetPoints(VertexBuffer.Create(data.Vertices, bounds));
|
||||
RenderLayers[1].SetIndices(IndexBuffer.Create(data.Edges, 2));
|
||||
|
||||
RenderLayers[2].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[2].SetIndices(IndexBuffer.Create(data.Segments, 2));
|
||||
|
||||
RenderLayers[3].SetPoints(RenderLayers[1].Points, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(ICollection<Point> points, IEnumerable<IEdge> edges, bool reset)
|
||||
{
|
||||
RenderLayers[4].SetPoints(VertexBuffer.Create(points, bounds));
|
||||
RenderLayers[4].SetIndices(IndexBuffer.Create(edges, 2));
|
||||
RenderLayers[4].IsEnabled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(float[] data)
|
||||
{
|
||||
// Add function values for filled mesh.
|
||||
RenderLayers[0].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[0].SetIndices(IndexBuffer.Create(mesh.Triangles, 3));
|
||||
RenderLayers[0].AttachLayerData(data, colorManager.ColorMap);
|
||||
|
||||
RenderLayers[0].IsEnabled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(int[] data)
|
||||
{
|
||||
// Add partition data for filled mesh.
|
||||
RenderLayers[0].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[0].SetIndices(IndexBuffer.Create(mesh.Triangles, 3));
|
||||
RenderLayers[0].AttachLayerData(data);
|
||||
|
||||
RenderLayers[0].IsEnabled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Enable(int layer, bool enabled)
|
||||
{
|
||||
renderLayers[layer].IsEnabled = enabled;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
public class RenderLayer : IRenderLayer
|
||||
{
|
||||
int count;
|
||||
|
||||
protected IBuffer<float> points;
|
||||
protected IBuffer<int> indices;
|
||||
|
||||
protected IBuffer<int> partition;
|
||||
protected IBuffer<Color> colors;
|
||||
|
||||
public RenderLayer()
|
||||
{
|
||||
this.IsEnabled = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBuffer<float> Points => points;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBuffer<int> Indices => indices;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBuffer<int> Partition => partition;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBuffer<Color> Colors => colors;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return (points == null || points.Count == 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Reset(bool clear)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
count = 0;
|
||||
points = null;
|
||||
}
|
||||
|
||||
indices = null;
|
||||
partition = null;
|
||||
colors = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPoints(IBuffer<float> buffer, bool reset = true)
|
||||
{
|
||||
if (!reset && points != null && points.Count < buffer.Count)
|
||||
{
|
||||
// NOTE: we keep the old size to be able to render new Steiner
|
||||
// points in a different color than existing points.
|
||||
count = points.Count / points.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = buffer.Count / buffer.Size;
|
||||
}
|
||||
|
||||
points = buffer;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetIndices(IBuffer<int> buffer)
|
||||
{
|
||||
indices = buffer;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AttachLayerData(float[] values, ColorMap colormap)
|
||||
{
|
||||
int length = values.Length;
|
||||
|
||||
double min = double.MaxValue;
|
||||
double max = double.MinValue;
|
||||
|
||||
// Find min and max of given values.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (values[i] < min)
|
||||
{
|
||||
min = values[i];
|
||||
}
|
||||
|
||||
if (values[i] > max)
|
||||
{
|
||||
max = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
var colorData = new Color[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
colorData[i] = colormap.GetColor(values[i], min, max);
|
||||
}
|
||||
|
||||
colors = new ColorBuffer(colorData, 1);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AttachLayerData(int[] partition)
|
||||
{
|
||||
this.partition = new IndexBuffer(partition, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+115
-132
@@ -1,132 +1,115 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.GDI;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
public class RenderManager
|
||||
{
|
||||
// TODO: delete
|
||||
public static bool VORONOI_DEBUG = false;
|
||||
|
||||
IRenderControl control;
|
||||
IRenderContext context;
|
||||
IRenderer renderer;
|
||||
Projection zoom;
|
||||
|
||||
public IRenderControl Control
|
||||
{
|
||||
get { return control; }
|
||||
}
|
||||
|
||||
public IRenderContext Context
|
||||
{
|
||||
get { return context; }
|
||||
}
|
||||
|
||||
public RenderManager()
|
||||
{
|
||||
}
|
||||
|
||||
public RenderManager(IRenderControl control)
|
||||
{
|
||||
Initialize(control);
|
||||
}
|
||||
|
||||
public RenderManager(IRenderControl control, IRenderer renderer)
|
||||
{
|
||||
Initialize(control, renderer);
|
||||
}
|
||||
|
||||
public void Initialize(IRenderControl control)
|
||||
{
|
||||
Initialize(control, new LayerRenderer());
|
||||
}
|
||||
|
||||
public void Initialize(IRenderControl control, IRenderer renderer)
|
||||
{
|
||||
this.zoom = new Projection(control.ClientRectangle);
|
||||
|
||||
this.context = new RenderContext(zoom, ColorManager.Default());
|
||||
|
||||
this.renderer = renderer;
|
||||
this.renderer.Context = context;
|
||||
|
||||
this.control = control;
|
||||
this.control.Initialize();
|
||||
this.control.Renderer = renderer;
|
||||
}
|
||||
|
||||
public bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
out IRenderControl control)
|
||||
{
|
||||
if (!ReflectionHelper.TryCreateControl(assemblyName, dependencies, out control))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return control is Control;
|
||||
}
|
||||
|
||||
public void Resize()
|
||||
{
|
||||
control.HandleResize();
|
||||
}
|
||||
|
||||
public void Enable(int layer, bool enabled)
|
||||
{
|
||||
context.Enable(layer, enabled);
|
||||
|
||||
control.Refresh();
|
||||
}
|
||||
|
||||
public void Set(IPolygon data, bool refresh = true)
|
||||
{
|
||||
context.Add(data);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(IMesh data, bool reset, bool refresh = true)
|
||||
{
|
||||
context.Add(data, reset);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set data for Voronoi layer.
|
||||
/// </summary>
|
||||
public void Set(ICollection<Point> points, IEnumerable<IEdge> edges, bool reset, bool refresh = true)
|
||||
{
|
||||
context.Add(points, edges, reset);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float[] values)
|
||||
{
|
||||
context.Add(values);
|
||||
control.Refresh();
|
||||
}
|
||||
|
||||
public void Update(int[] partition)
|
||||
{
|
||||
context.Add(partition);
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
public class RenderManager
|
||||
{
|
||||
// TODO: delete
|
||||
public static bool VORONOI_DEBUG = false;
|
||||
|
||||
IRenderControl control;
|
||||
IRenderContext context;
|
||||
IRenderer renderer;
|
||||
Projection zoom;
|
||||
|
||||
public IRenderControl Control => control;
|
||||
|
||||
public IRenderContext Context => context;
|
||||
|
||||
public RenderManager()
|
||||
{
|
||||
}
|
||||
|
||||
public RenderManager(IRenderControl control, IRenderer renderer)
|
||||
{
|
||||
Initialize(control, renderer);
|
||||
}
|
||||
|
||||
public void Initialize(IRenderControl control, IRenderer renderer)
|
||||
{
|
||||
this.zoom = new Projection(control.ClientRectangle);
|
||||
|
||||
this.context = new RenderContext(zoom, ColorManager.Default());
|
||||
|
||||
this.renderer = renderer;
|
||||
this.renderer.Context = context;
|
||||
|
||||
this.control = control;
|
||||
this.control.Initialize();
|
||||
this.control.Renderer = renderer;
|
||||
}
|
||||
|
||||
public bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
out IRenderControl control)
|
||||
{
|
||||
return ReflectionHelper.TryCreateControl(assemblyName, dependencies, out control);
|
||||
}
|
||||
|
||||
public void Resize()
|
||||
{
|
||||
control.HandleResize();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
context.Clear();
|
||||
control.Refresh();
|
||||
}
|
||||
|
||||
public void Enable(int layer, bool enabled)
|
||||
{
|
||||
context.Enable(layer, enabled);
|
||||
|
||||
control.Refresh();
|
||||
}
|
||||
|
||||
public void Set(IPolygon data, bool refresh = true)
|
||||
{
|
||||
context.Add(data);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(IMesh data, bool reset, bool refresh = true)
|
||||
{
|
||||
context.Add(data, reset);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set data for Voronoi layer.
|
||||
/// </summary>
|
||||
public void Set(ICollection<Point> points, IEnumerable<IEdge> edges, bool reset, bool refresh = true)
|
||||
{
|
||||
context.Add(points, edges, reset);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float[] values)
|
||||
{
|
||||
context.Add(values);
|
||||
control.Refresh();
|
||||
}
|
||||
|
||||
public void Update(int[] partition)
|
||||
{
|
||||
context.Add(partition);
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
+208
-208
@@ -1,208 +1,208 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
public class EpsDocument : IDisposable
|
||||
{
|
||||
// Constant to convert from millimeters to PostScript units (1/72th inch).
|
||||
private const double UNITS_PER_MM = 72.0 / 25.4;
|
||||
|
||||
private FormattingStreamWriter _w;
|
||||
private PageSize _size;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the document name.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default point size (default = 1).
|
||||
/// </summary>
|
||||
public int DefaultPointSize { get; set; }
|
||||
|
||||
public EpsDocument(string filename, PageSize pageSize)
|
||||
: this(File.Create(filename), pageSize)
|
||||
{
|
||||
Name = Path.GetFileName(filename);
|
||||
}
|
||||
|
||||
public EpsDocument(Stream stream, PageSize pageSize)
|
||||
{
|
||||
_w = new FormattingStreamWriter(stream);
|
||||
_w.NewLine = "\n";
|
||||
|
||||
_size = pageSize;
|
||||
|
||||
DefaultPointSize = 1;
|
||||
}
|
||||
|
||||
public void AddComment(string comment, int line = 1)
|
||||
{
|
||||
for (int i = 0; i < line; i++)
|
||||
{
|
||||
_w.WriteLine("%");
|
||||
}
|
||||
|
||||
var t = comment.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries );
|
||||
|
||||
for (int i = 0; i < t.Length; i++)
|
||||
{
|
||||
_w.WriteLine("% " + t[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < line; i++)
|
||||
{
|
||||
_w.WriteLine("%");
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawPoint(Point p)
|
||||
{
|
||||
_w.WriteLine("{0} {1} P", p.X, p.Y);
|
||||
}
|
||||
|
||||
public void DrawLine(Point p1, Point p2)
|
||||
{
|
||||
_w.WriteLine("{0} {1} {2} {3} L", p1.X, p1.Y, p2.X, p2.Y);
|
||||
}
|
||||
|
||||
public void DrawRectangle(Rectangle rect)
|
||||
{
|
||||
_w.WriteLine("newpath");
|
||||
_w.WriteLine(" {0} {1} moveto", rect.X, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Y);
|
||||
_w.WriteLine("stroke");
|
||||
|
||||
}
|
||||
|
||||
public void SetClip(Rectangle rect)
|
||||
{
|
||||
_w.WriteLine("newpath");
|
||||
_w.WriteLine(" {0} {1} moveto", rect.X, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Y);
|
||||
_w.WriteLine("clip newpath");
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
_w.WriteLine("{0:0.###} {1:0.###} {2:0.###} setrgbcolor",
|
||||
((float)color.R) / 255f,
|
||||
((float)color.G) / 255f,
|
||||
((float)color.B) / 255f);
|
||||
}
|
||||
|
||||
public void SetStroke(float width)
|
||||
{
|
||||
_w.WriteLine("{0:0.###} setlinewidth", width);
|
||||
}
|
||||
|
||||
public void SetStroke(float width, Color color)
|
||||
{
|
||||
SetColor(color);
|
||||
SetStroke(width);
|
||||
}
|
||||
|
||||
public void WriteHeader()
|
||||
{
|
||||
var x = _size.X; // * UNITS_PER_MM
|
||||
var y = _size.Y;
|
||||
var right = _size.Right;
|
||||
var bottom = _size.Bottom;
|
||||
|
||||
// Write document header.
|
||||
|
||||
_w.WriteLine("%!PS-Adobe-3.0 EPSF-3.0");
|
||||
_w.WriteLine("%%Creator: Triangle.NET");
|
||||
_w.WriteLine("%%Title: {0}", Name);
|
||||
_w.WriteLine("%%Pages: 1");
|
||||
_w.WriteLine("%%BoundingBox: {0} {1} {2} {3}", (int)x, (int)y, (int)right, (int)bottom);
|
||||
_w.WriteLine("%%HiResBoundingBox: {0:0.#####} {1:0.#####} {2:0.#####} {3:0.#####}", x, y, right, bottom);
|
||||
_w.WriteLine("%%Document-Fonts: Times-Roman");
|
||||
_w.WriteLine("%%LanguageLevel: 3");
|
||||
_w.WriteLine("%%EndComments");
|
||||
_w.WriteLine("%%Page: 1 1");
|
||||
_w.WriteLine("save");
|
||||
|
||||
// Define points.
|
||||
_w.WriteLine("% Define points.");
|
||||
_w.WriteLine("/P {");
|
||||
_w.WriteLine("2 dict begin");
|
||||
_w.WriteLine("/y exch def");
|
||||
_w.WriteLine("/x exch def");
|
||||
_w.WriteLine("gsave");
|
||||
_w.WriteLine("newpath x y {0} 0 360 arc fill", DefaultPointSize);
|
||||
_w.WriteLine("grestore");
|
||||
_w.WriteLine("end");
|
||||
_w.WriteLine("} def");
|
||||
|
||||
// Define lines.
|
||||
_w.WriteLine("% Define lines.");
|
||||
_w.WriteLine("/L {");
|
||||
_w.WriteLine("2 dict begin");
|
||||
_w.WriteLine("/y2 exch def");
|
||||
_w.WriteLine("/x2 exch def");
|
||||
_w.WriteLine("/y1 exch def");
|
||||
_w.WriteLine("/x1 exch def");
|
||||
_w.WriteLine("gsave");
|
||||
_w.WriteLine("newpath x1 y1 moveto x2 y2 lineto stroke");
|
||||
_w.WriteLine("grestore");
|
||||
_w.WriteLine("end");
|
||||
_w.WriteLine("} def");
|
||||
}
|
||||
|
||||
private void Close()
|
||||
{
|
||||
_w.WriteLine("%");
|
||||
_w.WriteLine("restore showpage");
|
||||
_w.WriteLine("%%Trailer");
|
||||
_w.WriteLine("%%EOF");
|
||||
}
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
// Has Dispose already been called?
|
||||
bool disposed = false;
|
||||
|
||||
// Public implementation of Dispose pattern callable by consumers.
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Protected implementation of Dispose pattern.
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
Close();
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_w.Dispose();
|
||||
_w = null;
|
||||
}
|
||||
|
||||
// Free any unmanaged objects here.
|
||||
//
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
~EpsDocument()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
public class EpsDocument : IDisposable
|
||||
{
|
||||
// Constant to convert from millimeters to PostScript units (1/72th inch).
|
||||
private const double UNITS_PER_MM = 72.0 / 25.4;
|
||||
|
||||
private FormattingStreamWriter _w;
|
||||
private PageSize _size;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the document name.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default point size (default = 1).
|
||||
/// </summary>
|
||||
public int DefaultPointSize { get; set; }
|
||||
|
||||
public EpsDocument(string filename, PageSize pageSize)
|
||||
: this(File.Create(filename), pageSize)
|
||||
{
|
||||
Name = Path.GetFileName(filename);
|
||||
}
|
||||
|
||||
public EpsDocument(Stream stream, PageSize pageSize)
|
||||
{
|
||||
_w = new FormattingStreamWriter(stream);
|
||||
_w.NewLine = "\n";
|
||||
|
||||
_size = pageSize;
|
||||
|
||||
DefaultPointSize = 1;
|
||||
}
|
||||
|
||||
public void AddComment(string comment, int line = 1)
|
||||
{
|
||||
for (int i = 0; i < line; i++)
|
||||
{
|
||||
_w.WriteLine("%");
|
||||
}
|
||||
|
||||
var t = comment.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries );
|
||||
|
||||
for (int i = 0; i < t.Length; i++)
|
||||
{
|
||||
_w.WriteLine("% " + t[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < line; i++)
|
||||
{
|
||||
_w.WriteLine("%");
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawPoint(Point p)
|
||||
{
|
||||
_w.WriteLine("{0} {1} P", p.X, p.Y);
|
||||
}
|
||||
|
||||
public void DrawLine(Point p1, Point p2)
|
||||
{
|
||||
_w.WriteLine("{0} {1} {2} {3} L", p1.X, p1.Y, p2.X, p2.Y);
|
||||
}
|
||||
|
||||
public void DrawRectangle(Rectangle rect)
|
||||
{
|
||||
_w.WriteLine("newpath");
|
||||
_w.WriteLine(" {0} {1} moveto", rect.X, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Y);
|
||||
_w.WriteLine("stroke");
|
||||
|
||||
}
|
||||
|
||||
public void SetClip(Rectangle rect)
|
||||
{
|
||||
_w.WriteLine("newpath");
|
||||
_w.WriteLine(" {0} {1} moveto", rect.X, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Y);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Bottom);
|
||||
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Y);
|
||||
_w.WriteLine("clip newpath");
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
{
|
||||
_w.WriteLine("{0:0.###} {1:0.###} {2:0.###} setrgbcolor",
|
||||
((float)color.R) / 255f,
|
||||
((float)color.G) / 255f,
|
||||
((float)color.B) / 255f);
|
||||
}
|
||||
|
||||
public void SetStroke(float width)
|
||||
{
|
||||
_w.WriteLine("{0:0.###} setlinewidth", width);
|
||||
}
|
||||
|
||||
public void SetStroke(float width, Color color)
|
||||
{
|
||||
SetColor(color);
|
||||
SetStroke(width);
|
||||
}
|
||||
|
||||
public void WriteHeader()
|
||||
{
|
||||
var x = _size.X; // * UNITS_PER_MM
|
||||
var y = _size.Y;
|
||||
var right = _size.Right;
|
||||
var bottom = _size.Bottom;
|
||||
|
||||
// Write document header.
|
||||
|
||||
_w.WriteLine("%!PS-Adobe-3.0 EPSF-3.0");
|
||||
_w.WriteLine("%%Creator: Triangle.NET");
|
||||
_w.WriteLine("%%Title: {0}", Name);
|
||||
_w.WriteLine("%%Pages: 1");
|
||||
_w.WriteLine("%%BoundingBox: {0} {1} {2} {3}", (int)x, (int)y, (int)right, (int)bottom);
|
||||
_w.WriteLine("%%HiResBoundingBox: {0:0.#####} {1:0.#####} {2:0.#####} {3:0.#####}", x, y, right, bottom);
|
||||
_w.WriteLine("%%Document-Fonts: Times-Roman");
|
||||
_w.WriteLine("%%LanguageLevel: 3");
|
||||
_w.WriteLine("%%EndComments");
|
||||
_w.WriteLine("%%Page: 1 1");
|
||||
_w.WriteLine("save");
|
||||
|
||||
// Define points.
|
||||
_w.WriteLine("% Define points.");
|
||||
_w.WriteLine("/P {");
|
||||
_w.WriteLine("2 dict begin");
|
||||
_w.WriteLine("/y exch def");
|
||||
_w.WriteLine("/x exch def");
|
||||
_w.WriteLine("gsave");
|
||||
_w.WriteLine("newpath x y {0} 0 360 arc fill", DefaultPointSize);
|
||||
_w.WriteLine("grestore");
|
||||
_w.WriteLine("end");
|
||||
_w.WriteLine("} def");
|
||||
|
||||
// Define lines.
|
||||
_w.WriteLine("% Define lines.");
|
||||
_w.WriteLine("/L {");
|
||||
_w.WriteLine("2 dict begin");
|
||||
_w.WriteLine("/y2 exch def");
|
||||
_w.WriteLine("/x2 exch def");
|
||||
_w.WriteLine("/y1 exch def");
|
||||
_w.WriteLine("/x1 exch def");
|
||||
_w.WriteLine("gsave");
|
||||
_w.WriteLine("newpath x1 y1 moveto x2 y2 lineto stroke");
|
||||
_w.WriteLine("grestore");
|
||||
_w.WriteLine("end");
|
||||
_w.WriteLine("} def");
|
||||
}
|
||||
|
||||
private void Close()
|
||||
{
|
||||
_w.WriteLine("%");
|
||||
_w.WriteLine("restore showpage");
|
||||
_w.WriteLine("%%Trailer");
|
||||
_w.WriteLine("%%EOF");
|
||||
}
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
// Has Dispose already been called?
|
||||
bool disposed = false;
|
||||
|
||||
// Public implementation of Dispose pattern callable by consumers.
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Protected implementation of Dispose pattern.
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
Close();
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_w.Dispose();
|
||||
_w = null;
|
||||
}
|
||||
|
||||
// Free any unmanaged objects here.
|
||||
//
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
~EpsDocument()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+157
-157
@@ -1,157 +1,157 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="EpsImage.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// Original Matlab code by John Burkardt, Florida State University
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
using Color = System.Drawing.Color;
|
||||
using IntPoint = System.Drawing.Point;
|
||||
using IntRectangle = System.Drawing.Rectangle;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a mesh to an EPS file.
|
||||
/// </summary>
|
||||
public class EpsImage
|
||||
{
|
||||
// EPS page metrics
|
||||
PageSize ps = new PageSize(36, 126, 576, 666);
|
||||
PageSize clip = new PageSize(18, 108, 594, 684);
|
||||
|
||||
// Mesh metrics
|
||||
double x_max, x_min;
|
||||
double y_max, y_min;
|
||||
|
||||
// TODO: use color manager
|
||||
private static Color ColorPoints = Color.FromArgb(0, 100, 0);
|
||||
private static Color ColorLines = Color.FromArgb(150, 150, 150);
|
||||
private static Color ColorSegments = Color.FromArgb(70, 130, 180);
|
||||
private static Color ColorBorder = Color.FromArgb(230, 230, 230);
|
||||
|
||||
/// <summary>
|
||||
/// Export the mesh to EPS format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="filename">The EPS filename.</param>
|
||||
/// <param name="width">The desired width of the image (currently ignored).</param>
|
||||
public void Export(Mesh mesh, string filename, int width)
|
||||
{
|
||||
// Check file name
|
||||
if (String.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
filename = String.Format("mesh-{0}.eps", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
if (!filename.EndsWith(".eps"))
|
||||
{
|
||||
filename = Path.ChangeExtension(filename, ".eps");
|
||||
}
|
||||
|
||||
UpdateMetrics(mesh.Bounds);
|
||||
|
||||
using (var eps = new EpsDocument(filename, ps))
|
||||
{
|
||||
int n = mesh.Vertices.Count;
|
||||
|
||||
// Size of the points.
|
||||
eps.DefaultPointSize = (n < 100) ? 3 : ((n < 500) ? 2 : 1);
|
||||
|
||||
eps.WriteHeader();
|
||||
|
||||
// Draw a gray border around the page.
|
||||
eps.SetColor(ColorBorder);
|
||||
eps.DrawRectangle(GetRectangle(ps));
|
||||
|
||||
// Define a clipping polygon.
|
||||
eps.SetClip(GetRectangle(clip));
|
||||
|
||||
// Draw edges.
|
||||
eps.AddComment("Draw edges.");
|
||||
eps.SetStroke(0.4f, ColorLines);
|
||||
|
||||
foreach (var e in EdgeIterator.EnumerateEdges(mesh))
|
||||
{
|
||||
eps.DrawLine(Transform(e.GetVertex(0)), Transform(e.GetVertex(1)));
|
||||
}
|
||||
|
||||
// Draw Segments.
|
||||
eps.AddComment("Draw Segments.");
|
||||
eps.SetStroke(0.8f, ColorSegments);
|
||||
|
||||
foreach (var s in mesh.Segments)
|
||||
{
|
||||
eps.DrawLine(Transform(s.GetVertex(0)), Transform(s.GetVertex(1)));
|
||||
}
|
||||
|
||||
// Draw points.
|
||||
eps.AddComment("Draw points.");
|
||||
eps.SetColor(ColorPoints);
|
||||
|
||||
foreach (var node in mesh.Vertices)
|
||||
{
|
||||
eps.DrawPoint(Transform(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IntRectangle GetRectangle(PageSize size)
|
||||
{
|
||||
return new IntRectangle((int)size.X, (int)size.Y, (int)size.Width, (int)size.Height);
|
||||
}
|
||||
|
||||
private IntPoint Transform(Point p)
|
||||
{
|
||||
return Transform(p.X, p.Y);
|
||||
}
|
||||
|
||||
private IntPoint Transform(double x, double y)
|
||||
{
|
||||
return new IntPoint(
|
||||
(int)Math.Floor(((x_max - x) * ps.X + (x - x_min) * ps.Right) / (x_max - x_min)),
|
||||
(int)Math.Floor(((y_max - y) * ps.Y + (y - y_min) * ps.Bottom) / (y_max - y_min))
|
||||
);
|
||||
}
|
||||
|
||||
private void UpdateMetrics(Rectangle bounds)
|
||||
{
|
||||
x_max = bounds.Right;
|
||||
x_min = bounds.Left;
|
||||
y_max = bounds.Top;
|
||||
y_min = bounds.Bottom;
|
||||
|
||||
// Enlarge width 5% on each side
|
||||
double x_scale = x_max - x_min;
|
||||
x_max = x_max + 0.05 * x_scale;
|
||||
x_min = x_min - 0.05 * x_scale;
|
||||
x_scale = x_max - x_min;
|
||||
|
||||
// Enlarge height 5% on each side
|
||||
double y_scale = y_max - y_min;
|
||||
y_max = y_max + 0.05 * y_scale;
|
||||
y_min = y_min - 0.05 * y_scale;
|
||||
y_scale = y_max - y_min;
|
||||
|
||||
if (x_scale < y_scale)
|
||||
{
|
||||
int delta = (int)Math.Round((ps.Right - ps.X) * (y_scale - x_scale) / (2.0 * y_scale));
|
||||
|
||||
ps.Expand(-delta, 0);
|
||||
clip.Expand(-delta, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int delta = (int)Math.Round((ps.Bottom - ps.Y) * (x_scale - y_scale) / (2.0 * x_scale));
|
||||
|
||||
ps.Expand(0, -delta);
|
||||
clip.Expand(0, -delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="EpsImage.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// Original Matlab code by John Burkardt, Florida State University
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using Color = System.Drawing.Color;
|
||||
using IntPoint = System.Drawing.Point;
|
||||
using IntRectangle = System.Drawing.Rectangle;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a mesh to an EPS file.
|
||||
/// </summary>
|
||||
public class EpsImage
|
||||
{
|
||||
// EPS page metrics
|
||||
PageSize ps = new PageSize(36, 126, 576, 666);
|
||||
PageSize clip = new PageSize(18, 108, 594, 684);
|
||||
|
||||
// Mesh metrics
|
||||
double x_max, x_min;
|
||||
double y_max, y_min;
|
||||
|
||||
// TODO: use color manager
|
||||
private static Color ColorPoints = Color.FromArgb(0, 100, 0);
|
||||
private static Color ColorLines = Color.FromArgb(150, 150, 150);
|
||||
private static Color ColorSegments = Color.FromArgb(70, 130, 180);
|
||||
private static Color ColorBorder = Color.FromArgb(230, 230, 230);
|
||||
|
||||
/// <summary>
|
||||
/// Export the mesh to EPS format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="filename">The EPS filename.</param>
|
||||
/// <param name="width">The desired width of the image (currently ignored).</param>
|
||||
public void Export(Mesh mesh, string filename, int width)
|
||||
{
|
||||
// Check file name
|
||||
if (String.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
filename = String.Format("mesh-{0}.eps", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
if (!filename.EndsWith(".eps"))
|
||||
{
|
||||
filename = Path.ChangeExtension(filename, ".eps");
|
||||
}
|
||||
|
||||
UpdateMetrics(mesh.Bounds);
|
||||
|
||||
using (var eps = new EpsDocument(filename, ps))
|
||||
{
|
||||
int n = mesh.Vertices.Count;
|
||||
|
||||
// Size of the points.
|
||||
eps.DefaultPointSize = (n < 100) ? 3 : ((n < 500) ? 2 : 1);
|
||||
|
||||
eps.WriteHeader();
|
||||
|
||||
// Draw a gray border around the page.
|
||||
eps.SetColor(ColorBorder);
|
||||
eps.DrawRectangle(GetRectangle(ps));
|
||||
|
||||
// Define a clipping polygon.
|
||||
eps.SetClip(GetRectangle(clip));
|
||||
|
||||
// Draw edges.
|
||||
eps.AddComment("Draw edges.");
|
||||
eps.SetStroke(0.4f, ColorLines);
|
||||
|
||||
foreach (var e in EdgeIterator.EnumerateEdges(mesh))
|
||||
{
|
||||
eps.DrawLine(Transform(e.GetVertex(0)), Transform(e.GetVertex(1)));
|
||||
}
|
||||
|
||||
// Draw Segments.
|
||||
eps.AddComment("Draw Segments.");
|
||||
eps.SetStroke(0.8f, ColorSegments);
|
||||
|
||||
foreach (var s in mesh.Segments)
|
||||
{
|
||||
eps.DrawLine(Transform(s.GetVertex(0)), Transform(s.GetVertex(1)));
|
||||
}
|
||||
|
||||
// Draw points.
|
||||
eps.AddComment("Draw points.");
|
||||
eps.SetColor(ColorPoints);
|
||||
|
||||
foreach (var node in mesh.Vertices)
|
||||
{
|
||||
eps.DrawPoint(Transform(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IntRectangle GetRectangle(PageSize size)
|
||||
{
|
||||
return new IntRectangle((int)size.X, (int)size.Y, (int)size.Width, (int)size.Height);
|
||||
}
|
||||
|
||||
private IntPoint Transform(Point p)
|
||||
{
|
||||
return Transform(p.X, p.Y);
|
||||
}
|
||||
|
||||
private IntPoint Transform(double x, double y)
|
||||
{
|
||||
return new IntPoint(
|
||||
(int)Math.Floor(((x_max - x) * ps.X + (x - x_min) * ps.Right) / (x_max - x_min)),
|
||||
(int)Math.Floor(((y_max - y) * ps.Y + (y - y_min) * ps.Bottom) / (y_max - y_min))
|
||||
);
|
||||
}
|
||||
|
||||
private void UpdateMetrics(Rectangle bounds)
|
||||
{
|
||||
x_max = bounds.Right;
|
||||
x_min = bounds.Left;
|
||||
y_max = bounds.Top;
|
||||
y_min = bounds.Bottom;
|
||||
|
||||
// Enlarge width 5% on each side
|
||||
double x_scale = x_max - x_min;
|
||||
x_max = x_max + 0.05 * x_scale;
|
||||
x_min = x_min - 0.05 * x_scale;
|
||||
x_scale = x_max - x_min;
|
||||
|
||||
// Enlarge height 5% on each side
|
||||
double y_scale = y_max - y_min;
|
||||
y_max = y_max + 0.05 * y_scale;
|
||||
y_min = y_min - 0.05 * y_scale;
|
||||
y_scale = y_max - y_min;
|
||||
|
||||
if (x_scale < y_scale)
|
||||
{
|
||||
int delta = (int)Math.Round((ps.Right - ps.X) * (y_scale - x_scale) / (2.0 * y_scale));
|
||||
|
||||
ps.Expand(-delta, 0);
|
||||
clip.Expand(-delta, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int delta = (int)Math.Round((ps.Bottom - ps.Y) * (x_scale - y_scale) / (2.0 * x_scale));
|
||||
|
||||
ps.Expand(0, -delta);
|
||||
clip.Expand(0, -delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
-73
@@ -1,73 +1,67 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// From http://stackoverflow.com/questions/12011789/streamwriter-and-iformatprovider
|
||||
/// </remarks>
|
||||
public class FormattingStreamWriter : StreamWriter
|
||||
{
|
||||
private readonly IFormatProvider formatProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified file
|
||||
/// by using the default encoding and buffer size.
|
||||
/// </summary>
|
||||
/// <param name="path">The complete file path to write to.</param>
|
||||
public FormattingStreamWriter(string path)
|
||||
: this(path, CultureInfo.InvariantCulture)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified stream
|
||||
/// by using UTF-8 encoding and the default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write to.</param>
|
||||
public FormattingStreamWriter(Stream stream)
|
||||
: this(stream, CultureInfo.InvariantCulture)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified file
|
||||
/// by using the default encoding and buffer size.
|
||||
/// </summary>
|
||||
/// <param name="path">The complete file path to write to.</param>
|
||||
/// <param name="formatProvider">The format provider.</param>
|
||||
public FormattingStreamWriter(string path, IFormatProvider formatProvider)
|
||||
: base(path)
|
||||
{
|
||||
this.formatProvider = formatProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified stream
|
||||
/// by using UTF-8 encoding and the default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write to.</param>
|
||||
/// <param name="formatProvider">The format provider.</param>
|
||||
public FormattingStreamWriter(Stream stream, IFormatProvider formatProvider)
|
||||
: base(stream)
|
||||
{
|
||||
this.formatProvider = formatProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an object that controls formatting.
|
||||
/// </summary>
|
||||
public override IFormatProvider FormatProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.formatProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="StreamWriter"/> class allowing to specify the <see cref="IFormatProvider"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// From http://stackoverflow.com/questions/12011789/streamwriter-and-iformatprovider
|
||||
/// </remarks>
|
||||
public class FormattingStreamWriter : StreamWriter
|
||||
{
|
||||
private readonly IFormatProvider formatProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified file
|
||||
/// by using the default encoding and buffer size.
|
||||
/// </summary>
|
||||
/// <param name="path">The complete file path to write to.</param>
|
||||
public FormattingStreamWriter(string path)
|
||||
: this(path, CultureInfo.InvariantCulture)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified stream
|
||||
/// by using UTF-8 encoding and the default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write to.</param>
|
||||
public FormattingStreamWriter(Stream stream)
|
||||
: this(stream, CultureInfo.InvariantCulture)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified file
|
||||
/// by using the default encoding and buffer size.
|
||||
/// </summary>
|
||||
/// <param name="path">The complete file path to write to.</param>
|
||||
/// <param name="formatProvider">The format provider.</param>
|
||||
public FormattingStreamWriter(string path, IFormatProvider formatProvider)
|
||||
: base(path)
|
||||
{
|
||||
this.formatProvider = formatProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the StreamWriter class for the specified stream
|
||||
/// by using UTF-8 encoding and the default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write to.</param>
|
||||
/// <param name="formatProvider">The format provider.</param>
|
||||
public FormattingStreamWriter(Stream stream, IFormatProvider formatProvider)
|
||||
: base(stream)
|
||||
{
|
||||
this.formatProvider = formatProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an object that controls formatting.
|
||||
/// </summary>
|
||||
public override IFormatProvider FormatProvider => formatProvider;
|
||||
}
|
||||
}
|
||||
+81
-81
@@ -1,81 +1,81 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Page size in millimeters.
|
||||
/// </summary>
|
||||
public struct PageSize
|
||||
{
|
||||
private const float MM_PER_INCH = 2.54f;
|
||||
|
||||
public static readonly PageSize A3 = new PageSize(297.0f, 420.0f);
|
||||
public static readonly PageSize A4 = new PageSize(210.0f, 297.0f);
|
||||
public static readonly PageSize A5 = new PageSize(148.0f, 210.0f);
|
||||
public static readonly PageSize LETTER = new PageSize(8.5f * MM_PER_INCH, 11.0f * MM_PER_INCH);
|
||||
public static readonly PageSize LEGAL = new PageSize(8.5f * MM_PER_INCH, 14.0f * MM_PER_INCH);
|
||||
|
||||
private float left;
|
||||
private float top;
|
||||
private float right;
|
||||
private float bottom;
|
||||
|
||||
public float X
|
||||
{
|
||||
get { return left; }
|
||||
}
|
||||
|
||||
public float Y
|
||||
{
|
||||
get { return top; }
|
||||
}
|
||||
|
||||
public float Width
|
||||
{
|
||||
get { return right - left; }
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get { return bottom - top; }
|
||||
}
|
||||
|
||||
public float Right
|
||||
{
|
||||
get { return right; }
|
||||
}
|
||||
|
||||
public float Bottom
|
||||
{
|
||||
get { return bottom; }
|
||||
}
|
||||
|
||||
public PageSize(float left, float top, float right, float bottom)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public PageSize(float width, float height)
|
||||
: this(0.0f, 0.0f, width, height)
|
||||
{
|
||||
}
|
||||
|
||||
public PageSize(Rectangle size)
|
||||
: this(size.Left, size.Right, size.Top, size.Bottom)
|
||||
{
|
||||
}
|
||||
|
||||
public void Expand(float dx, float dy)
|
||||
{
|
||||
left -= dx;
|
||||
top -= dy;
|
||||
|
||||
right += dx;
|
||||
bottom += dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Page size in millimeters.
|
||||
/// </summary>
|
||||
public struct PageSize
|
||||
{
|
||||
private const float MM_PER_INCH = 2.54f;
|
||||
|
||||
public static readonly PageSize A3 = new PageSize(297.0f, 420.0f);
|
||||
public static readonly PageSize A4 = new PageSize(210.0f, 297.0f);
|
||||
public static readonly PageSize A5 = new PageSize(148.0f, 210.0f);
|
||||
public static readonly PageSize LETTER = new PageSize(8.5f * MM_PER_INCH, 11.0f * MM_PER_INCH);
|
||||
public static readonly PageSize LEGAL = new PageSize(8.5f * MM_PER_INCH, 14.0f * MM_PER_INCH);
|
||||
|
||||
private float left;
|
||||
private float top;
|
||||
private float right;
|
||||
private float bottom;
|
||||
|
||||
public float X
|
||||
{
|
||||
get { return left; }
|
||||
}
|
||||
|
||||
public float Y
|
||||
{
|
||||
get { return top; }
|
||||
}
|
||||
|
||||
public float Width
|
||||
{
|
||||
get { return right - left; }
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get { return bottom - top; }
|
||||
}
|
||||
|
||||
public float Right
|
||||
{
|
||||
get { return right; }
|
||||
}
|
||||
|
||||
public float Bottom
|
||||
{
|
||||
get { return bottom; }
|
||||
}
|
||||
|
||||
public PageSize(float left, float top, float right, float bottom)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public PageSize(float width, float height)
|
||||
: this(0.0f, 0.0f, width, height)
|
||||
{
|
||||
}
|
||||
|
||||
public PageSize(Rectangle size)
|
||||
: this(size.Left, size.Right, size.Top, size.Bottom)
|
||||
{
|
||||
}
|
||||
|
||||
public void Expand(float dx, float dy)
|
||||
{
|
||||
left -= dx;
|
||||
top -= dy;
|
||||
|
||||
right += dx;
|
||||
bottom += dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
+266
-254
@@ -1,254 +1,266 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SvgImage.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a mesh to an SVG file.
|
||||
/// </summary>
|
||||
public class SvgImage
|
||||
{
|
||||
// Iterations to insert a linebreak in SVG path.
|
||||
private const int LINEBREAK_COUNT = 10;
|
||||
|
||||
float scale = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Export the mesh to SVG format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="filename">The SVG filename.</param>
|
||||
/// <param name="width">The desired width of the image.</param>
|
||||
public void Export(Mesh mesh, string filename, int width)
|
||||
{
|
||||
// Check file name
|
||||
if (String.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
filename = String.Format("mesh-{0}.svg", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
if (!filename.EndsWith(".svg"))
|
||||
{
|
||||
filename = Path.ChangeExtension(filename, ".svg");
|
||||
}
|
||||
|
||||
if (width < 200)
|
||||
{
|
||||
width = 200;
|
||||
}
|
||||
|
||||
var bounds = mesh.Bounds;
|
||||
|
||||
float margin = 0.05f * (float)bounds.Width;
|
||||
|
||||
scale = width / ((float)bounds.Width + 2 * margin);
|
||||
|
||||
int x_offset = -(int)((bounds.Left - margin) * scale);
|
||||
int y_offset = (int)((bounds.Top + margin) * scale);
|
||||
|
||||
int height = (int)((bounds.Height + 2 * margin) * scale);
|
||||
|
||||
using (var svg = new FormattingStreamWriter(filename))
|
||||
{
|
||||
svg.WriteLine("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"");
|
||||
svg.WriteLine("\twidth=\"{0}px\" height=\"{1}px\"", width, height);
|
||||
svg.WriteLine("\tviewBox=\"0 0 {0} {1}\">", width, height);
|
||||
|
||||
svg.WriteLine("<g transform=\"translate({0}, {1}) scale(1,-1)\">", x_offset, y_offset);
|
||||
|
||||
DrawTriangles(svg, mesh, false);
|
||||
//DrawEdges(svg, mesh);
|
||||
|
||||
DrawSegments(svg, mesh);
|
||||
|
||||
DrawPoints(svg, mesh, false);
|
||||
|
||||
svg.WriteLine("</g>");
|
||||
|
||||
svg.WriteLine("</svg>");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTriangles(StreamWriter svg, Mesh mesh, bool label)
|
||||
{
|
||||
svg.Write("\t<path d=\"");
|
||||
|
||||
StringBuilder labels = new StringBuilder();
|
||||
|
||||
Vertex v1, v2, v3;
|
||||
double x1, y1, x2, y2, x3, y3, xa, ya;
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var tri in mesh.Triangles)
|
||||
{
|
||||
v1 = tri.GetVertex(0);
|
||||
v2 = tri.GetVertex(1);
|
||||
v3 = tri.GetVertex(2);
|
||||
|
||||
x1 = scale * v1.X;
|
||||
y1 = scale * v1.Y;
|
||||
x2 = scale * v2.X;
|
||||
y2 = scale * v2.Y;
|
||||
x3 = scale * v3.X;
|
||||
y3 = scale * v3.Y;
|
||||
|
||||
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} {4:0.#},{5:0.#} Z ",
|
||||
x1, y1, x2, y2, x3, y3);
|
||||
|
||||
if (i % LINEBREAK_COUNT == 0)
|
||||
{
|
||||
svg.WriteLine();
|
||||
svg.Write("\t");
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (label)
|
||||
{
|
||||
xa = (x1 + x2 + x3) / 3.0;
|
||||
ya = (y1 + y2 + y3) / 3.0;
|
||||
|
||||
labels.AppendFormat("<text x=\"{0:0.#}\" y=\"{1:0.#}\">{2}</text>",
|
||||
xa, ya, tri.ID);
|
||||
labels.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
svg.WriteLine("\" style=\"stroke:#c2c2c2; fill:none; stroke-linejoin:bevel;\"/>");
|
||||
|
||||
// Label the triangles.
|
||||
if (label)
|
||||
{
|
||||
svg.WriteLine("\t<g font-family=\"Verdana\" font-size=\"11\" fill=\"black\">");
|
||||
svg.Write(labels.ToString());
|
||||
svg.WriteLine("\t<g/>");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEdges(StreamWriter svg, Mesh mesh)
|
||||
{
|
||||
svg.Write("\t<path d=\"");
|
||||
|
||||
StringBuilder labels = new StringBuilder();
|
||||
|
||||
Vertex v1, v2;
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var e in EdgeIterator.EnumerateEdges(mesh))
|
||||
{
|
||||
v1 = e.GetVertex(0);
|
||||
v2 = e.GetVertex(1);
|
||||
|
||||
x1 = scale * v1.X;
|
||||
y1 = scale * v1.Y;
|
||||
x2 = scale * v2.X;
|
||||
y2 = scale * v2.Y;
|
||||
|
||||
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} ",
|
||||
x1, y1, x2, y2);
|
||||
|
||||
if (i % LINEBREAK_COUNT == 0)
|
||||
{
|
||||
svg.WriteLine();
|
||||
svg.Write("\t");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
svg.WriteLine("\" style=\"stroke:#c2c2c2; fill:none; stroke-linejoin:bevel;\"/>");
|
||||
}
|
||||
|
||||
private void DrawSegments(StreamWriter svg, Mesh mesh)
|
||||
{
|
||||
svg.Write("\t<path d=\"");
|
||||
|
||||
StringBuilder labels = new StringBuilder();
|
||||
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var seg in mesh.Segments)
|
||||
{
|
||||
x1 = scale * seg.GetVertex(0).X;
|
||||
y1 = scale * seg.GetVertex(0).Y;
|
||||
x2 = scale * seg.GetVertex(1).X;
|
||||
y2 = scale * seg.GetVertex(1).Y;
|
||||
|
||||
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} ",
|
||||
x1, y1, x2, y2);
|
||||
|
||||
if (i % LINEBREAK_COUNT == 0)
|
||||
{
|
||||
svg.WriteLine();
|
||||
svg.Write("\t");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
svg.WriteLine("\" style=\"stroke:#4682B4; fill:none; stroke-linejoin:bevel; stroke-width:2px;\"/>");
|
||||
}
|
||||
|
||||
private void DrawPoints(StreamWriter svg, Mesh mesh, bool label)
|
||||
{
|
||||
int n = mesh.Vertices.Count;
|
||||
|
||||
float circle_size = 1.5f;
|
||||
|
||||
if (n < 100)
|
||||
{
|
||||
circle_size = 3;
|
||||
}
|
||||
else if (n < 500)
|
||||
{
|
||||
circle_size = 2;
|
||||
}
|
||||
|
||||
svg.WriteLine("\t<g style=\"fill: #006400\">");
|
||||
|
||||
double x, y;
|
||||
|
||||
StringBuilder labels = new StringBuilder();
|
||||
|
||||
foreach (var node in mesh.Vertices)
|
||||
{
|
||||
x = scale * node.X;
|
||||
y = scale * node.Y;
|
||||
|
||||
svg.WriteLine("\t\t<circle cx=\"{0:0.#}\" cy=\"{1:0.#}\" r=\"{2:0.#}\" />",
|
||||
x, y, circle_size);
|
||||
|
||||
if (label)
|
||||
{
|
||||
labels.AppendFormat("<text x=\"{0:0.#}\" y=\"{1:0.#}\">{2}</text>",
|
||||
x, y, node.ID);
|
||||
labels.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
svg.WriteLine("\t</g>");
|
||||
|
||||
// Label the nodes.
|
||||
if (label)
|
||||
{
|
||||
svg.WriteLine("\t<g font-family=\"Verdana\" font-size=\"11\" fill=\"black\">");
|
||||
svg.Write(labels.ToString());
|
||||
svg.WriteLine("\t<g/>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SvgImage.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.Text
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a mesh to an SVG file.
|
||||
/// </summary>
|
||||
public class SvgImage
|
||||
{
|
||||
// Iterations to insert a linebreak in SVG path.
|
||||
private const int LINEBREAK_COUNT = 10;
|
||||
|
||||
float scale = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Exports a mesh to SVG format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="file">The SVG filename.</param>
|
||||
/// <param name="width">The desired width (pixel) of the image.</param>
|
||||
/// <param name="regions">Enable rendering of regions.</param>
|
||||
/// <param name="points">Enable rendering of points.</param>
|
||||
public static void Save(IMesh mesh, string file = null, int width = 800,
|
||||
bool regions = false, bool points = true)
|
||||
{
|
||||
new SvgImage().Export(mesh, file, width);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export a mesh to SVG format.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The current mesh.</param>
|
||||
/// <param name="filename">The SVG filename.</param>
|
||||
/// <param name="width">The desired width of the image.</param>
|
||||
public void Export(IMesh mesh, string filename, int width)
|
||||
{
|
||||
// Check file name
|
||||
if (string.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
filename = string.Format("mesh-{0}.svg", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
|
||||
}
|
||||
|
||||
if (!filename.EndsWith(".svg"))
|
||||
{
|
||||
filename = Path.ChangeExtension(filename, ".svg");
|
||||
}
|
||||
|
||||
if (width < 200)
|
||||
{
|
||||
width = 200;
|
||||
}
|
||||
|
||||
var bounds = mesh.Bounds;
|
||||
|
||||
float margin = 0.05f * (float)bounds.Width;
|
||||
|
||||
scale = width / ((float)bounds.Width + 2 * margin);
|
||||
|
||||
int x_offset = -(int)((bounds.Left - margin) * scale);
|
||||
int y_offset = (int)((bounds.Top + margin) * scale);
|
||||
|
||||
int height = (int)((bounds.Height + 2 * margin) * scale);
|
||||
|
||||
using (var svg = new FormattingStreamWriter(filename))
|
||||
{
|
||||
svg.WriteLine("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"");
|
||||
svg.WriteLine("\twidth=\"{0}px\" height=\"{1}px\"", width, height);
|
||||
svg.WriteLine("\tviewBox=\"0 0 {0} {1}\">", width, height);
|
||||
|
||||
svg.WriteLine("<g transform=\"translate({0}, {1}) scale(1,-1)\">", x_offset, y_offset);
|
||||
|
||||
DrawTriangles(svg, mesh, false);
|
||||
//DrawEdges(svg, mesh);
|
||||
|
||||
DrawSegments(svg, mesh);
|
||||
|
||||
DrawPoints(svg, mesh, false);
|
||||
|
||||
svg.WriteLine("</g>");
|
||||
|
||||
svg.WriteLine("</svg>");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTriangles(StreamWriter svg, IMesh mesh, bool label)
|
||||
{
|
||||
svg.Write("\t<path d=\"");
|
||||
|
||||
var labels = new StringBuilder();
|
||||
|
||||
Vertex v1, v2, v3;
|
||||
double x1, y1, x2, y2, x3, y3, xa, ya;
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var tri in mesh.Triangles)
|
||||
{
|
||||
v1 = tri.GetVertex(0);
|
||||
v2 = tri.GetVertex(1);
|
||||
v3 = tri.GetVertex(2);
|
||||
|
||||
x1 = scale * v1.X;
|
||||
y1 = scale * v1.Y;
|
||||
x2 = scale * v2.X;
|
||||
y2 = scale * v2.Y;
|
||||
x3 = scale * v3.X;
|
||||
y3 = scale * v3.Y;
|
||||
|
||||
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} {4:0.#},{5:0.#} Z ",
|
||||
x1, y1, x2, y2, x3, y3);
|
||||
|
||||
if (i % LINEBREAK_COUNT == 0)
|
||||
{
|
||||
svg.WriteLine();
|
||||
svg.Write("\t");
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (label)
|
||||
{
|
||||
xa = (x1 + x2 + x3) / 3.0;
|
||||
ya = (y1 + y2 + y3) / 3.0;
|
||||
|
||||
labels.AppendFormat("<text x=\"{0:0.#}\" y=\"{1:0.#}\">{2}</text>",
|
||||
xa, ya, tri.ID);
|
||||
labels.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
svg.WriteLine("\" style=\"stroke:#c2c2c2; fill:none; stroke-linejoin:bevel;\"/>");
|
||||
|
||||
// Label the triangles.
|
||||
if (label)
|
||||
{
|
||||
svg.WriteLine("\t<g font-family=\"Verdana\" font-size=\"11\" fill=\"black\">");
|
||||
svg.Write(labels.ToString());
|
||||
svg.WriteLine("\t<g/>");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEdges(StreamWriter svg, IMesh mesh)
|
||||
{
|
||||
svg.Write("\t<path d=\"");
|
||||
|
||||
Vertex v1, v2;
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var e in EdgeIterator.EnumerateEdges(mesh))
|
||||
{
|
||||
v1 = e.GetVertex(0);
|
||||
v2 = e.GetVertex(1);
|
||||
|
||||
x1 = scale * v1.X;
|
||||
y1 = scale * v1.Y;
|
||||
x2 = scale * v2.X;
|
||||
y2 = scale * v2.Y;
|
||||
|
||||
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} ",
|
||||
x1, y1, x2, y2);
|
||||
|
||||
if (i % LINEBREAK_COUNT == 0)
|
||||
{
|
||||
svg.WriteLine();
|
||||
svg.Write("\t");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
svg.WriteLine("\" style=\"stroke:#c2c2c2; fill:none; stroke-linejoin:bevel;\"/>");
|
||||
}
|
||||
|
||||
private void DrawSegments(StreamWriter svg, IMesh mesh)
|
||||
{
|
||||
svg.Write("\t<path d=\"");
|
||||
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var seg in mesh.Segments)
|
||||
{
|
||||
x1 = scale * seg.GetVertex(0).X;
|
||||
y1 = scale * seg.GetVertex(0).Y;
|
||||
x2 = scale * seg.GetVertex(1).X;
|
||||
y2 = scale * seg.GetVertex(1).Y;
|
||||
|
||||
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} ",
|
||||
x1, y1, x2, y2);
|
||||
|
||||
if (i % LINEBREAK_COUNT == 0)
|
||||
{
|
||||
svg.WriteLine();
|
||||
svg.Write("\t");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
svg.WriteLine("\" style=\"stroke:#4682B4; fill:none; stroke-linejoin:bevel; stroke-width:2px;\"/>");
|
||||
}
|
||||
|
||||
private void DrawPoints(StreamWriter svg, IMesh mesh, bool label)
|
||||
{
|
||||
int n = mesh.Vertices.Count;
|
||||
|
||||
float circle_size = 1.5f;
|
||||
|
||||
if (n < 100)
|
||||
{
|
||||
circle_size = 3;
|
||||
}
|
||||
else if (n < 500)
|
||||
{
|
||||
circle_size = 2;
|
||||
}
|
||||
|
||||
svg.WriteLine("\t<g style=\"fill: #006400\">");
|
||||
|
||||
double x, y;
|
||||
|
||||
var labels = new StringBuilder();
|
||||
|
||||
foreach (var node in mesh.Vertices)
|
||||
{
|
||||
x = scale * node.X;
|
||||
y = scale * node.Y;
|
||||
|
||||
svg.WriteLine("\t\t<circle cx=\"{0:0.#}\" cy=\"{1:0.#}\" r=\"{2:0.#}\" />",
|
||||
x, y, circle_size);
|
||||
|
||||
if (label)
|
||||
{
|
||||
labels.AppendFormat("<text x=\"{0:0.#}\" y=\"{1:0.#}\">{2}</text>",
|
||||
x, y, node.ID);
|
||||
labels.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
svg.WriteLine("\t</g>");
|
||||
|
||||
// Label the nodes.
|
||||
if (label)
|
||||
{
|
||||
svg.WriteLine("\t<g font-family=\"Verdana\" font-size=\"11\" fill=\"black\">");
|
||||
svg.Write(labels.ToString());
|
||||
svg.WriteLine("\t<g/>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>TriangleNet.Rendering</RootNamespace>
|
||||
<AssemblyName>Triangle.Rendering</AssemblyName>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+112
-112
@@ -1,112 +1,112 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
public class ColorMap
|
||||
{
|
||||
#region Colormap definitions
|
||||
|
||||
public static ColorMap Jet(int size)
|
||||
{
|
||||
ColorMap map = new ColorMap(size);
|
||||
float v, step = 1.0f / (size - 1);
|
||||
float[] rgb = new float[3];
|
||||
|
||||
for (int i = 0; i < size; i += 1)
|
||||
{
|
||||
v = 4 * i * step;
|
||||
|
||||
rgb[0] = Math.Min(v - 1.5f, 4.5f - v);
|
||||
rgb[1] = Math.Min(v - 0.5f, 3.5f - v);
|
||||
rgb[2] = Math.Min(v + 0.5f, 2.5f - v);
|
||||
|
||||
Clamp(rgb, 0.0f, 1.0f);
|
||||
|
||||
map.colors[size - i - 1] = ColorFromRgb(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static ColorMap Hot(int size)
|
||||
{
|
||||
ColorMap map = new ColorMap(size);
|
||||
float v, step = 1.0f / (size - 1);
|
||||
float[] rgb = new float[3];
|
||||
|
||||
for (int i = 0; i < size; i += 1)
|
||||
{
|
||||
v = 2.5f * i * step;
|
||||
|
||||
rgb[0] = v;
|
||||
rgb[1] = v - 1;
|
||||
rgb[2] = 2 * v - 4;
|
||||
|
||||
Clamp(rgb, 0.0f, 1.0f);
|
||||
|
||||
map.colors[i] = ColorFromRgb(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper
|
||||
|
||||
private static Color ColorFromRgb(float r, float g, float b)
|
||||
{
|
||||
byte max = byte.MaxValue;
|
||||
|
||||
return Color.FromArgb((byte)(r * max), (byte)(g * max), (byte)(b * max));
|
||||
}
|
||||
|
||||
private static void Clamp(float[] values, float min, float max)
|
||||
{
|
||||
int n = values.Length;
|
||||
|
||||
for (int i = 0; i < n; i += 1)
|
||||
{
|
||||
values[i] = Math.Min(max, Math.Max(min, values[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private static int Clamp(int index, int max)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (index > max)
|
||||
{
|
||||
index = max;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Color[] colors;
|
||||
|
||||
private ColorMap(int size)
|
||||
{
|
||||
this.colors = new Color[size];
|
||||
}
|
||||
|
||||
public ColorMap(Color[] colors)
|
||||
{
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public Color GetColor(double value, double min, double max)
|
||||
{
|
||||
int n = this.colors.Length;
|
||||
int i = (int)Math.Floor(n * (max - value) / (max - min));
|
||||
|
||||
return this.colors[Clamp(i, n - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
public class ColorMap
|
||||
{
|
||||
#region Colormap definitions
|
||||
|
||||
public static ColorMap Jet(int size)
|
||||
{
|
||||
ColorMap map = new ColorMap(size);
|
||||
float v, step = 1.0f / (size - 1);
|
||||
float[] rgb = new float[3];
|
||||
|
||||
for (int i = 0; i < size; i += 1)
|
||||
{
|
||||
v = 4 * i * step;
|
||||
|
||||
rgb[0] = Math.Min(v - 1.5f, 4.5f - v);
|
||||
rgb[1] = Math.Min(v - 0.5f, 3.5f - v);
|
||||
rgb[2] = Math.Min(v + 0.5f, 2.5f - v);
|
||||
|
||||
Clamp(rgb, 0.0f, 1.0f);
|
||||
|
||||
map.colors[size - i - 1] = ColorFromRgb(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static ColorMap Hot(int size)
|
||||
{
|
||||
ColorMap map = new ColorMap(size);
|
||||
float v, step = 1.0f / (size - 1);
|
||||
float[] rgb = new float[3];
|
||||
|
||||
for (int i = 0; i < size; i += 1)
|
||||
{
|
||||
v = 2.5f * i * step;
|
||||
|
||||
rgb[0] = v;
|
||||
rgb[1] = v - 1;
|
||||
rgb[2] = 2 * v - 4;
|
||||
|
||||
Clamp(rgb, 0.0f, 1.0f);
|
||||
|
||||
map.colors[i] = ColorFromRgb(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper
|
||||
|
||||
private static Color ColorFromRgb(float r, float g, float b)
|
||||
{
|
||||
byte max = byte.MaxValue;
|
||||
|
||||
return Color.FromArgb((byte)(r * max), (byte)(g * max), (byte)(b * max));
|
||||
}
|
||||
|
||||
private static void Clamp(float[] values, float min, float max)
|
||||
{
|
||||
int n = values.Length;
|
||||
|
||||
for (int i = 0; i < n; i += 1)
|
||||
{
|
||||
values[i] = Math.Min(max, Math.Max(min, values[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private static int Clamp(int index, int max)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (index > max)
|
||||
{
|
||||
index = max;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Color[] colors;
|
||||
|
||||
private ColorMap(int size)
|
||||
{
|
||||
this.colors = new Color[size];
|
||||
}
|
||||
|
||||
public ColorMap(Color[] colors)
|
||||
{
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public Color GetColor(double value, double min, double max)
|
||||
{
|
||||
int n = this.colors.Length;
|
||||
int i = (int)Math.Floor(n * (max - value) / (max - min));
|
||||
|
||||
return this.colors[Clamp(i, n - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
-81
@@ -1,81 +1,81 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
internal static class ReflectionHelper
|
||||
{
|
||||
public static bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
out IRenderControl control)
|
||||
{
|
||||
return TryCreateControl(assemblyName, dependencies, null, out control);
|
||||
}
|
||||
|
||||
public static bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
string className, out IRenderControl control)
|
||||
{
|
||||
control = null;
|
||||
|
||||
if (!FilesExist(assemblyName, dependencies))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
|
||||
|
||||
// Try create render control instance.
|
||||
try
|
||||
{
|
||||
// Load the assembly into the current application domain.
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
|
||||
// Get all types implementing the IRenderControl interface.
|
||||
var type = typeof(IRenderControl);
|
||||
var matches = assembly.GetTypes().Where(s => type.IsAssignableFrom(s));
|
||||
|
||||
var match = string.IsNullOrEmpty(className) ? matches.FirstOrDefault()
|
||||
: matches.Where(s => s.Name == className).FirstOrDefault();
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
// Create an instance.
|
||||
control = (IRenderControl)Activator.CreateInstance(match);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if render control was successfully created.
|
||||
return (control != null);
|
||||
}
|
||||
|
||||
private static bool FilesExist(string assemblyName, IEnumerable<string> dependencies)
|
||||
{
|
||||
// Check if assembly exists
|
||||
if (!File.Exists(assemblyName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if dependencies exists
|
||||
if (dependencies != null)
|
||||
{
|
||||
foreach (var item in dependencies)
|
||||
{
|
||||
if (!File.Exists(item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
internal static class ReflectionHelper
|
||||
{
|
||||
public static bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
out IRenderControl control)
|
||||
{
|
||||
return TryCreateControl(assemblyName, dependencies, null, out control);
|
||||
}
|
||||
|
||||
public static bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
string className, out IRenderControl control)
|
||||
{
|
||||
control = null;
|
||||
|
||||
if (!FilesExist(assemblyName, dependencies))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
|
||||
|
||||
// Try create render control instance.
|
||||
try
|
||||
{
|
||||
// Load the assembly into the current application domain.
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
|
||||
// Get all types implementing the IRenderControl interface.
|
||||
var type = typeof(IRenderControl);
|
||||
var matches = assembly.GetTypes().Where(s => type.IsAssignableFrom(s));
|
||||
|
||||
var match = string.IsNullOrEmpty(className) ? matches.FirstOrDefault()
|
||||
: matches.Where(s => s.Name == className).FirstOrDefault();
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
// Create an instance.
|
||||
control = (IRenderControl)Activator.CreateInstance(match);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if render control was successfully created.
|
||||
return (control != null);
|
||||
}
|
||||
|
||||
private static bool FilesExist(string assemblyName, IEnumerable<string> dependencies)
|
||||
{
|
||||
// Check if assembly exists
|
||||
if (!File.Exists(assemblyName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if dependencies exists
|
||||
if (dependencies != null)
|
||||
{
|
||||
foreach (var item in dependencies)
|
||||
{
|
||||
if (!File.Exists(item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using NUnit.Framework;
|
||||
using TriangleNet.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TriangleNet.Tests.Geometry
|
||||
{
|
||||
public class ContourTest
|
||||
{
|
||||
[Test]
|
||||
public void TestFindInteriorPoint()
|
||||
{
|
||||
// The vertices that define the contour (have to be in order, obviously).
|
||||
var vertices = new Vertex[]
|
||||
{
|
||||
new Vertex(0d, 0d),
|
||||
new Vertex(1d ,0d),
|
||||
new Vertex(1d, 1d),
|
||||
new Vertex(0d, 1d),
|
||||
};
|
||||
|
||||
var contour = new Contour(vertices);
|
||||
|
||||
var p = contour.FindInteriorPoint();
|
||||
|
||||
Assert.IsTrue(p.X > 0d && p.X < 1d && p.Y > 0d && p.Y < 1d);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFindInteriorPointL()
|
||||
{
|
||||
// L-shaped contour (FindPointInPolygon() produces a test candidate
|
||||
// which lies exactly on a segment where IsPointInPolygon() returns
|
||||
// true, so IsPointOnSegment() is actually needed here).
|
||||
var points = new List<Vertex>()
|
||||
{
|
||||
new Vertex(3, 1),
|
||||
new Vertex(1, 1),
|
||||
new Vertex(1, 3),
|
||||
new Vertex(2, 3),
|
||||
new Vertex(2, 2),
|
||||
new Vertex(3, 2)
|
||||
};
|
||||
|
||||
var contour = new Contour(points);
|
||||
|
||||
var poly = new Polygon(6);
|
||||
|
||||
poly.Add(contour, true);
|
||||
|
||||
var h = poly.Holes[0];
|
||||
var p = RobustPredicates.Default;
|
||||
|
||||
int count = points.Count;
|
||||
int i = count - 1;
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
double ccw = p.CounterClockwise(points[i], h, points[j]);
|
||||
|
||||
Assert.Greater(Math.Abs(ccw), 1e-12);
|
||||
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFindInteriorPointDup()
|
||||
{
|
||||
// Rectangle contour with duplicate point.
|
||||
var points = new List<Vertex>()
|
||||
{
|
||||
new Vertex(0.0, 0.0),
|
||||
new Vertex(0.0, 1.0),
|
||||
new Vertex(2.0, 1.0),
|
||||
new Vertex(2.0, 0.5),
|
||||
new Vertex(2.0, 0.5), // duplicate
|
||||
new Vertex(2.0, 0.0)
|
||||
};
|
||||
|
||||
var contour = new Contour(points);
|
||||
|
||||
Assert.DoesNotThrow(() => contour.FindInteriorPoint());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
namespace TriangleNet.Tests
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
static class Helper
|
||||
{
|
||||
public static Contour Rectangle(double left, double top,
|
||||
double right, double bottom, int mark = 0)
|
||||
{
|
||||
var points = new List<Vertex>(4);
|
||||
|
||||
points.Add(new Vertex(left, top, mark));
|
||||
points.Add(new Vertex(right, top, mark));
|
||||
points.Add(new Vertex(right, bottom, mark));
|
||||
points.Add(new Vertex(left, bottom, mark));
|
||||
|
||||
return new Contour(points, mark, true);
|
||||
}
|
||||
|
||||
public static Triangle CreateTriangle(int id, Vertex org, Vertex dest, Vertex apex)
|
||||
{
|
||||
var t = new Triangle() { id = id, hash = id };
|
||||
|
||||
// Node ordering 'plus 1 mod 3'.
|
||||
t.vertices[0] = apex;
|
||||
t.vertices[1] = org;
|
||||
t.vertices[2] = dest;
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
|
||||
namespace TriangleNet.Tests.Meshing.Algorithm
|
||||
{
|
||||
public class TriangulatorTest
|
||||
{
|
||||
[Test]
|
||||
public void TestTriangulateIncremental()
|
||||
{
|
||||
var t = new Incremental();
|
||||
|
||||
var vertices = GetVertices();
|
||||
|
||||
var mesh = t.Triangulate(vertices, new Configuration());
|
||||
|
||||
Assert.AreEqual(6, vertices.Count);
|
||||
Assert.AreEqual(6, mesh.Vertices.Count);
|
||||
Assert.AreEqual(1, mesh.Vertices
|
||||
.Where(v => v.Type == VertexType.UndeadVertex)
|
||||
.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTriangulateSweepLine()
|
||||
{
|
||||
var t = new SweepLine();
|
||||
|
||||
var vertices = GetVertices();
|
||||
|
||||
var mesh = t.Triangulate(vertices, new Configuration());
|
||||
|
||||
Assert.AreEqual(6, vertices.Count);
|
||||
Assert.AreEqual(6, mesh.Vertices.Count);
|
||||
Assert.AreEqual(1, mesh.Vertices
|
||||
.Where(v => v.Type == VertexType.UndeadVertex)
|
||||
.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTriangulateDwyer()
|
||||
{
|
||||
var t = new Dwyer();
|
||||
|
||||
var vertices = GetVertices();
|
||||
|
||||
var mesh = t.Triangulate(vertices, new Configuration());
|
||||
|
||||
Assert.AreEqual(6, vertices.Count);
|
||||
Assert.AreEqual(6, mesh.Vertices.Count);
|
||||
Assert.AreEqual(1, mesh.Vertices
|
||||
.Where(v => v.Type == VertexType.UndeadVertex)
|
||||
.Count());
|
||||
}
|
||||
|
||||
private List<Vertex> GetVertices()
|
||||
{
|
||||
return new List<Vertex>()
|
||||
{
|
||||
new Vertex(0.0, 0.0),
|
||||
new Vertex(1.0, 0.0),
|
||||
new Vertex(1.0, 1.0),
|
||||
new Vertex(1.0, 1.0), // duplicate
|
||||
new Vertex(0.0, 1.0),
|
||||
new Vertex(0.5, 0.5)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using NUnit.Framework;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
namespace TriangleNet.Tests.Meshing.Iterators
|
||||
{
|
||||
public class RegionIteratorTest
|
||||
{
|
||||
public void TestProcessRegionProtected()
|
||||
{
|
||||
var poly = new Polygon();
|
||||
|
||||
// Outer region.
|
||||
poly.Add(Helper.Rectangle(-2d, 2d, 2d, -2d, 2));
|
||||
|
||||
// Inner region.
|
||||
poly.Add(Helper.Rectangle(-1d, 1d, 1d, -1d, 1));
|
||||
|
||||
poly.Regions.Add(new RegionPointer(0d, 0d, 1));
|
||||
|
||||
var mesh = (Mesh)poly.Triangulate();
|
||||
|
||||
var iterator = new RegionIterator(mesh);
|
||||
|
||||
var qtree = new TriangleQuadTree(mesh);
|
||||
|
||||
// Find a seeding triangle in region 1.
|
||||
var seed = (Triangle)qtree.Query(0.0, 0.0);
|
||||
|
||||
iterator.Process(seed, t => Assert.AreEqual(1, t.Label));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using NUnit.Framework;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
namespace TriangleNet.Tests
|
||||
{
|
||||
public class RobustPredicatesTest
|
||||
{
|
||||
[Test]
|
||||
public void TestCounterClockwise()
|
||||
{
|
||||
var robust = RobustPredicates.Default;
|
||||
|
||||
var a = new Point(-1d, 0d);
|
||||
var b = new Point( 0d, 1d);
|
||||
|
||||
Assert.IsTrue(robust.CounterClockwise(a, b, new Point(1d, 0d)) < 0d);
|
||||
Assert.IsTrue(robust.CounterClockwise(a, b, new Point(0d, 2d)) > 0d);
|
||||
Assert.IsTrue(robust.CounterClockwise(a, b, new Point(1d, 2d)) == 0d);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInCircle()
|
||||
{
|
||||
var robust = RobustPredicates.Default;
|
||||
|
||||
var a = new Point(-1d, 0d);
|
||||
var b = new Point(0d, 1d);
|
||||
var c = new Point(1d, 0d);
|
||||
|
||||
Assert.IsTrue(robust.InCircle(a, b, c, new Point(0d, 0.5)) < 0d);
|
||||
Assert.IsTrue(robust.InCircle(a, b, c, new Point(0d, 1.5)) > 0d);
|
||||
Assert.IsTrue(robust.InCircle(a, b, c, new Point(0d, 1d)) == 0d);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFindCircumcenter()
|
||||
{
|
||||
var robust = RobustPredicates.Default;
|
||||
|
||||
var a = new Point(-1d, 0d);
|
||||
var b = new Point(0d, 1d);
|
||||
var c = new Point(1d, 0d);
|
||||
|
||||
double xi = 0d, eta = 0d;
|
||||
|
||||
var actual = robust.FindCircumcenter(a, b, c, ref xi, ref eta);
|
||||
var expected = new Point(0d, 0d);
|
||||
|
||||
Assert.AreEqual(expected.X, actual.X);
|
||||
Assert.AreEqual(expected.Y, actual.Y);
|
||||
Assert.AreEqual(0.0, xi);
|
||||
Assert.AreEqual(0.5, eta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Smoothing;
|
||||
|
||||
namespace TriangleNet.Tests.Smoothing
|
||||
{
|
||||
public class SimpleSmootherTest
|
||||
{
|
||||
[Test]
|
||||
public void TestSmoothWithDuplicate()
|
||||
{
|
||||
var poly = GetPolygon();
|
||||
|
||||
var options = new ConstraintOptions() { ConformingDelaunay = true };
|
||||
|
||||
var quality = new QualityOptions()
|
||||
{
|
||||
MinimumAngle = 30.0
|
||||
};
|
||||
|
||||
var mesh = poly.Triangulate(options, quality);
|
||||
|
||||
Assert.AreEqual(1, mesh.Vertices
|
||||
.Where(v => v.Type == VertexType.UndeadVertex)
|
||||
.Count());
|
||||
|
||||
quality.MaximumArea = 0.2;
|
||||
|
||||
mesh.Refine(quality, true);
|
||||
|
||||
Assert.AreEqual(1, mesh.Vertices
|
||||
.Where(v => v.Type == VertexType.UndeadVertex)
|
||||
.Count());
|
||||
|
||||
var smoother = new SimpleSmoother();
|
||||
|
||||
// Smooth mesh.
|
||||
smoother.Smooth(mesh, 25);
|
||||
}
|
||||
|
||||
private Polygon GetPolygon()
|
||||
{
|
||||
var poly = new Polygon(7);
|
||||
|
||||
var p = new List<Vertex>()
|
||||
{
|
||||
new Vertex(0.0, 0.0, 1),
|
||||
new Vertex(2.0, 0.0, 1),
|
||||
new Vertex(2.0, 1.0, 1),
|
||||
new Vertex(2.0, 2.0, 1),
|
||||
new Vertex(0.0, 2.0, 1),
|
||||
new Vertex(1.5, 1.6, 1),
|
||||
new Vertex(2.0, 0.0, 1) // duplicate
|
||||
};
|
||||
|
||||
poly.Points.AddRange(p);
|
||||
|
||||
poly.Add(new Segment(p[0], p[1], 1));
|
||||
poly.Add(new Segment(p[1], p[2], 1));
|
||||
poly.Add(new Segment(p[2], p[3], 1));
|
||||
poly.Add(new Segment(p[3], p[4], 1));
|
||||
poly.Add(new Segment(p[4], p[0], 1));
|
||||
poly.Add(new Segment(p[2], p[5], 2));
|
||||
|
||||
return poly;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using NUnit.Framework;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
namespace TriangleNet.Tests.Tools
|
||||
{
|
||||
public class IntersectionHelperTest
|
||||
{
|
||||
[Test]
|
||||
public void TestIsPointOnSegment()
|
||||
{
|
||||
var a = new Vertex(1.0, 1.0);
|
||||
var b = new Vertex(2.0, 2.0);
|
||||
|
||||
// Test point = segment start point.
|
||||
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(1.0, 1.0)));
|
||||
|
||||
// Test point = segment end point.
|
||||
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0, 2.0)));
|
||||
|
||||
// Test point on segment.
|
||||
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(1.5, 1.5)));
|
||||
|
||||
// Test point collinear, but not on segment.
|
||||
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(0.0, 0.0)));
|
||||
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(3.0, 3.0)));
|
||||
|
||||
// Test point not on segment.
|
||||
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(1.5, 0.5)));
|
||||
|
||||
double eps = 1e-12;
|
||||
|
||||
// Test point collinear near endpoint, but not on segment.
|
||||
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0 + eps, 2.0 + eps)));
|
||||
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0 - eps, 2.0 + eps)));
|
||||
|
||||
// Test point collinear near endpoint on segment.
|
||||
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0 - eps, 2.0 - eps)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,496 @@
|
||||
|
||||
namespace TriangleNet.Tests
|
||||
{
|
||||
using NUnit.Framework;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
// The Otri (orientent triangle) struct is the heart of Triangle's mesh
|
||||
// datastructure. It basically represents one of the three edges of the
|
||||
// triangle by associating an orientation to the triangle object.
|
||||
//
|
||||
// For testing, a minimal example mesh is considered. It consists of
|
||||
// 6 vertices and 4 triangles.
|
||||
//
|
||||
// Vertices:
|
||||
// X [-2] [0] [2] [-1] [1] [0]
|
||||
// Y [ 0] [0] [0] [ 1] [1] [2]
|
||||
//
|
||||
// Triangles and neighbors and neighbor orientations:
|
||||
// [3 0 1] [-1 1 -1] [- 2 -]
|
||||
// [3 1 4] [ 2 3 0] [2 0 1]
|
||||
// [4 1 2] [-1 -1 1] [- - 0]
|
||||
// [5 3 4] [ 1 -1 -1] [1 - -]
|
||||
//
|
||||
// The shape is one large triangle, split into four smaller ones.
|
||||
|
||||
public class OtriTest
|
||||
{
|
||||
// The vertices of the mesh.
|
||||
Vertex[] vertices;
|
||||
|
||||
private Triangle[] CreateExampleMesh()
|
||||
{
|
||||
var triangles = new Triangle[4];
|
||||
|
||||
// Outer space triangle.
|
||||
var dummy = new Triangle() { id = -1 };
|
||||
|
||||
// Setup triangles. Keep in mind the ordering:
|
||||
//
|
||||
// The CreateTriangle method takes vertex arguments in range org-dest-apex,
|
||||
// but internally the vertices get stored in an array with ordering
|
||||
//
|
||||
// [0] = apex
|
||||
// [1] = org
|
||||
// [2] = dest
|
||||
//
|
||||
// This is because, for example, and oriented triange will return as its
|
||||
// origin (Org() method) the element at index [(orientation + 1) % 3].
|
||||
var t0 = triangles[0] = Helper.CreateTriangle(0, vertices[0], vertices[1], vertices[3]);
|
||||
var t1 = triangles[1] = Helper.CreateTriangle(1, vertices[1], vertices[4], vertices[3]);
|
||||
var t2 = triangles[2] = Helper.CreateTriangle(2, vertices[1], vertices[2], vertices[4]);
|
||||
var t3 = triangles[3] = Helper.CreateTriangle(3, vertices[3], vertices[4], vertices[5]);
|
||||
|
||||
// Setup connectivity of triangle 0.
|
||||
t0.neighbors[0].tri = dummy;
|
||||
t0.neighbors[1].tri = t1;
|
||||
t0.neighbors[1].orient = 2;
|
||||
t0.neighbors[2].tri = dummy;
|
||||
|
||||
// Setup connectivity of triangle 1.
|
||||
t1.neighbors[0].tri = t2;
|
||||
t1.neighbors[0].orient = 2;
|
||||
t1.neighbors[1].tri = t3;
|
||||
t1.neighbors[1].orient = 0;
|
||||
t1.neighbors[2].tri = t0;
|
||||
t1.neighbors[2].orient = 1;
|
||||
|
||||
// Setup connectivity of triangle 2.
|
||||
t2.neighbors[0].tri = dummy;
|
||||
t2.neighbors[1].tri = dummy;
|
||||
t2.neighbors[2].tri = t1;
|
||||
t2.neighbors[2].orient = 0;
|
||||
|
||||
// Setup connectivity of triangle 3.
|
||||
t3.neighbors[0].tri = t1;
|
||||
t3.neighbors[0].orient = 1;
|
||||
t3.neighbors[1].tri = dummy;
|
||||
t3.neighbors[2].tri = dummy;
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Initialize()
|
||||
{
|
||||
vertices = new Vertex[6];
|
||||
|
||||
vertices[0] = new Vertex(-2.0, 0.0) { id = 0 };
|
||||
vertices[1] = new Vertex( 0.0, 0.0) { id = 1 };
|
||||
vertices[2] = new Vertex( 2.0, 0.0) { id = 2 };
|
||||
vertices[3] = new Vertex(-1.0, 1.0) { id = 3 };
|
||||
vertices[4] = new Vertex( 1.0, 1.0) { id = 4 };
|
||||
vertices[5] = new Vertex( 0.0, 2.0) { id = 5 };
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOrg()
|
||||
{
|
||||
Otri t = default;
|
||||
|
||||
t.tri = Helper.CreateTriangle(0, vertices[1], vertices[4], vertices[3]);
|
||||
|
||||
t.orient = 0;
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
|
||||
t.orient = 1;
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
|
||||
t.orient = 2;
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDest()
|
||||
{
|
||||
Otri t = default;
|
||||
|
||||
t.tri = Helper.CreateTriangle(0, vertices[1], vertices[4], vertices[3]);
|
||||
|
||||
t.orient = 0;
|
||||
Assert.AreEqual(4, t.Dest().ID);
|
||||
|
||||
t.orient = 1;
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
|
||||
t.orient = 2;
|
||||
Assert.AreEqual(1, t.Dest().ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApex()
|
||||
{
|
||||
Otri t = default;
|
||||
|
||||
t.tri = Helper.CreateTriangle(0, vertices[1], vertices[4], vertices[3]);
|
||||
|
||||
t.orient = 0;
|
||||
Assert.AreEqual(3, t.Apex().ID);
|
||||
|
||||
t.orient = 1;
|
||||
Assert.AreEqual(1, t.Apex().ID);
|
||||
|
||||
t.orient = 2;
|
||||
Assert.AreEqual(4, t.Apex().ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSym()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
Otri s = default;
|
||||
|
||||
// The center triangle.
|
||||
t.tri = triangles[1];
|
||||
|
||||
t.orient = 0;
|
||||
t.Sym(ref s);
|
||||
Assert.AreEqual(2, s.tri.ID);
|
||||
|
||||
t.orient = 1;
|
||||
t.Sym(ref s);
|
||||
Assert.AreEqual(3, s.tri.ID);
|
||||
|
||||
t.orient = 2;
|
||||
t.Sym(ref s);
|
||||
Assert.AreEqual(0, s.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLnext()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// The center triangle.
|
||||
t.tri = triangles[1];
|
||||
t.orient = 0;
|
||||
|
||||
t.Lnext();
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
|
||||
t.Lnext();
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
|
||||
t.Lnext();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLprev()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// The center triangle.
|
||||
t.tri = triangles[1];
|
||||
t.orient = 0;
|
||||
|
||||
t.Lprev();
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
|
||||
t.Lprev();
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
|
||||
t.Lprev();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnext()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// Start with the bottom right triangle.
|
||||
t.tri = triangles[2];
|
||||
|
||||
// Start with edge 1 -> 2.
|
||||
t.orient = 0;
|
||||
|
||||
// Make sure we're on the correct edge.
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(2, t.Dest().ID);
|
||||
|
||||
t.Onext();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(4, t.Dest().ID);
|
||||
Assert.AreEqual(1, t.tri.ID);
|
||||
|
||||
t.Onext();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
Assert.AreEqual(0, t.tri.ID);
|
||||
|
||||
// Out of mesh.
|
||||
t.Onext();
|
||||
Assert.AreEqual(-1, t.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOprev()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// Start with the bottom left triangle.
|
||||
t.tri = triangles[0];
|
||||
|
||||
// Start with edge 1 -> 3.
|
||||
t.orient = 1;
|
||||
|
||||
// Make sure we're on the correct edge.
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
|
||||
t.Oprev();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(4, t.Dest().ID);
|
||||
Assert.AreEqual(1, t.tri.ID);
|
||||
|
||||
t.Oprev();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(2, t.Dest().ID);
|
||||
Assert.AreEqual(2, t.tri.ID);
|
||||
|
||||
// Out of mesh.
|
||||
t.Oprev();
|
||||
Assert.AreEqual(-1, t.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDnext()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// Start with the bottom left triangle.
|
||||
t.tri = triangles[0];
|
||||
|
||||
// Start with edge 1 -> 3.
|
||||
t.orient = 1;
|
||||
|
||||
// Make sure we're on the correct edge.
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
|
||||
t.Dnext();
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
Assert.AreEqual(1, t.tri.ID);
|
||||
|
||||
t.Dnext();
|
||||
Assert.AreEqual(5, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
Assert.AreEqual(3, t.tri.ID);
|
||||
|
||||
// Out of mesh.
|
||||
t.Dnext();
|
||||
Assert.AreEqual(-1, t.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDprev()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// Start with the top triangle.
|
||||
t.tri = triangles[3];
|
||||
|
||||
// Start with edge 5 -> 3.
|
||||
t.orient = 2;
|
||||
|
||||
// Make sure we're on the correct edge.
|
||||
Assert.AreEqual(5, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
|
||||
t.Dprev();
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
Assert.AreEqual(1, t.tri.ID);
|
||||
|
||||
t.Dprev();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
Assert.AreEqual(0, t.tri.ID);
|
||||
|
||||
// Out of mesh.
|
||||
t.Dprev();
|
||||
Assert.AreEqual(-1, t.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRnext()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// Start with the bottom left triangle.
|
||||
t.tri = triangles[0];
|
||||
|
||||
// Start with edge 1 -> 3.
|
||||
t.orient = 1;
|
||||
|
||||
// Make sure we're on the correct edge.
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
|
||||
t.Rnext();
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
Assert.AreEqual(1, t.Dest().ID);
|
||||
Assert.AreEqual(2, t.tri.ID);
|
||||
|
||||
t.Rnext();
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
Assert.AreEqual(4, t.Dest().ID);
|
||||
Assert.AreEqual(3, t.tri.ID);
|
||||
|
||||
// Back where we started.
|
||||
t.Rnext();
|
||||
Assert.AreEqual(0, t.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRprev()
|
||||
{
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri t = default;
|
||||
|
||||
// Start with the top triangle.
|
||||
t.tri = triangles[3];
|
||||
|
||||
// Start with edge 3 -> 4.
|
||||
t.orient = 0;
|
||||
|
||||
// Make sure we're on the correct edge.
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
Assert.AreEqual(4, t.Dest().ID);
|
||||
|
||||
t.Rprev();
|
||||
Assert.AreEqual(4, t.Org().ID);
|
||||
Assert.AreEqual(1, t.Dest().ID);
|
||||
Assert.AreEqual(2, t.tri.ID);
|
||||
|
||||
t.Rprev();
|
||||
Assert.AreEqual(1, t.Org().ID);
|
||||
Assert.AreEqual(3, t.Dest().ID);
|
||||
Assert.AreEqual(0, t.tri.ID);
|
||||
|
||||
// Back where we started.
|
||||
t.Rprev();
|
||||
Assert.AreEqual(3, t.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBond()
|
||||
{
|
||||
Otri s = default;
|
||||
Otri t = default;
|
||||
|
||||
Otri tmp = default;
|
||||
|
||||
s.tri = Helper.CreateTriangle(0, vertices[0], vertices[1], vertices[3]);
|
||||
t.tri = Helper.CreateTriangle(1, vertices[1], vertices[4], vertices[3]);
|
||||
|
||||
s.orient = 1; // Edge 1 -> 3.
|
||||
t.orient = 2; // Edge 3 -> 1.
|
||||
|
||||
// Make sure we're on the correct edges.
|
||||
Assert.AreEqual(1, s.Org().ID);
|
||||
Assert.AreEqual(3, s.Dest().ID);
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
Assert.AreEqual(1, t.Dest().ID);
|
||||
|
||||
// Check that the triangles don't have neighbors.
|
||||
s.Sym(ref tmp);
|
||||
//Assert.AreEqual(-1, tmp.tri.ID);
|
||||
Assert.IsNull(tmp.tri);
|
||||
t.Sym(ref tmp);
|
||||
//Assert.AreEqual(-1, tmp.tri.ID);
|
||||
Assert.IsNull(tmp.tri);
|
||||
|
||||
// Bond the two triangles.
|
||||
s.Bond(ref t);
|
||||
|
||||
// Check that neighbors are properly set.
|
||||
s.Sym(ref tmp);
|
||||
Assert.AreEqual(1, tmp.tri.ID);
|
||||
t.Sym(ref tmp);
|
||||
Assert.AreEqual(0, tmp.tri.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDissolve()
|
||||
{
|
||||
// Outer space triangle.
|
||||
var dummy = new Triangle() { id = -1 };
|
||||
|
||||
var triangles = CreateExampleMesh();
|
||||
|
||||
Otri s = default;
|
||||
Otri t = default;
|
||||
|
||||
Otri tmp = default;
|
||||
|
||||
// The bottom left triangle with edge 1 -> 3.
|
||||
s.tri = triangles[0];
|
||||
s.orient = 1;
|
||||
|
||||
// The center triangle with edge 3 -> 1.
|
||||
t.tri = triangles[1];
|
||||
t.orient = 2;
|
||||
|
||||
// Make sure we're on the correct edges.
|
||||
Assert.AreEqual(1, s.Org().ID);
|
||||
Assert.AreEqual(3, s.Dest().ID);
|
||||
Assert.AreEqual(3, t.Org().ID);
|
||||
Assert.AreEqual(1, t.Dest().ID);
|
||||
|
||||
// Check that neighbors are properly set.
|
||||
s.Sym(ref tmp);
|
||||
Assert.AreEqual(1, tmp.tri.ID);
|
||||
t.Sym(ref tmp);
|
||||
Assert.AreEqual(0, tmp.tri.ID);
|
||||
|
||||
// Now dissolve the bond from one side.
|
||||
s.Dissolve(dummy);
|
||||
|
||||
// Check neighbors.
|
||||
s.Sym(ref tmp);
|
||||
Assert.AreEqual(-1, tmp.tri.ID);
|
||||
t.Sym(ref tmp);
|
||||
Assert.AreEqual(0, tmp.tri.ID);
|
||||
|
||||
// And dissolve the bond from the other side.
|
||||
t.Dissolve(dummy);
|
||||
|
||||
// Check neighbors.
|
||||
s.Sym(ref tmp);
|
||||
Assert.AreEqual(-1, tmp.tri.ID);
|
||||
t.Sym(ref tmp);
|
||||
Assert.AreEqual(-1, tmp.tri.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>TriangleNet.Tests</RootNamespace>
|
||||
<AssemblyName>Triangle.Tests</AssemblyName>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="nunit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32126.317
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Triangle.Viewer", "Triangle.Viewer\Triangle.Viewer.csproj", "{336AAF8A-5316-4303-9E73-5E38BD0B28AF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Triangle.Rendering", "Triangle.Rendering\Triangle.Rendering.csproj", "{41022E0E-BD0F-439E-BC3A-AABB1B43471B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Triangle.Rendering.GDI", "Triangle.Rendering.GDI\Triangle.Rendering.GDI.csproj", "{D535E102-92B4-4F92-B284-A7170AE00CD6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Debug|x64.Build.0 = Debug|x64
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|x64.ActiveCfg = Release|x64
|
||||
{336AAF8A-5316-4303-9E73-5E38BD0B28AF}.Release|x64.Build.0 = Release|x64
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|x64.Build.0 = Debug|x64
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|x64.ActiveCfg = Release|x64
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|x64.Build.0 = Release|x64
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Debug|x64.Build.0 = Debug|x64
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Release|x64.ActiveCfg = Release|x64
|
||||
{D535E102-92B4-4F92-B284-A7170AE00CD6}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {90F4F9E9-43D6-4A3D-91D5-B2DF113E13AE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+207
-207
@@ -1,207 +1,207 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="AngleHistogram.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Displays an angle histogram.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The angle histogram is divided into two parts: the minimum angles
|
||||
/// on the left side (0 to 60 degrees) and the maximum angles on the
|
||||
/// right (60 to 180 degrees).
|
||||
/// </remarks>
|
||||
public class AngleHistogram : Control
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
int[] maxAngles;
|
||||
int[] minAngles;
|
||||
|
||||
Brush fillBlue1 = new SolidBrush(Color.FromArgb(60, 100, 140));
|
||||
Brush fillBlue2 = new SolidBrush(Color.FromArgb(110, 150, 200));
|
||||
|
||||
Brush textBack = new SolidBrush(Color.FromArgb(72, 0, 0, 0));
|
||||
|
||||
// The maximum number of angles
|
||||
int maxAngleCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AngleHistogram" /> control.
|
||||
/// </summary>
|
||||
public AngleHistogram()
|
||||
{
|
||||
this.BackColor = ColorScheme.ColorGray78;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the histogram data and invalidates the control.
|
||||
/// </summary>
|
||||
public void SetData(int[] dataMin, int[] dataMax)
|
||||
{
|
||||
maxAngleCount = 0;
|
||||
|
||||
this.minAngles = dataMin;
|
||||
this.maxAngles = dataMax;
|
||||
|
||||
ParseData(dataMin);
|
||||
ParseData(dataMax);
|
||||
|
||||
if (maxAngleCount == 0)
|
||||
{
|
||||
this.maxAngles = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
private void ParseData(int[] data)
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] > maxAngleCount)
|
||||
{
|
||||
maxAngleCount = data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int padding = 1;
|
||||
int paddingBottom = 0;
|
||||
int paddingTop = 15;
|
||||
|
||||
private void DrawHistogram(Graphics g, int offset, int left, int size, int[] data, Brush brush, Brush brushTop)
|
||||
{
|
||||
int count = maxAngleCount;
|
||||
int totalHeight = this.Height - paddingBottom - paddingTop;
|
||||
|
||||
int n = offset == 0 ? data.Length / 3 : data.Length;
|
||||
float value = 0;
|
||||
|
||||
for (int i = offset; i < n; i++)
|
||||
{
|
||||
if (data[i] > 0)
|
||||
{
|
||||
// Scale to control height
|
||||
value = totalHeight * data[i] / count;
|
||||
|
||||
// Fill bar
|
||||
g.FillRectangle(brush,
|
||||
left + i * size, this.Height - paddingBottom - value,
|
||||
size - 1, value);
|
||||
|
||||
// Draw top of bar (just a little effect ...)
|
||||
if (value > 2)
|
||||
{
|
||||
g.FillRectangle(brushTop,
|
||||
left + i * size, this.Height - paddingBottom - value,
|
||||
size - 1, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the labels on the bottom.
|
||||
/// </summary>
|
||||
private void DrawStrings(Graphics g, SizeF fSize, int size, int middle)
|
||||
{
|
||||
int fHeight = (int)(fSize.Height + 2);
|
||||
g.FillRectangle(textBack, 0, this.Height - fHeight, this.Width, fHeight);
|
||||
|
||||
g.DrawString("0", this.Font, Brushes.White, padding, this.Height - fSize.Height - 1);
|
||||
g.DrawString("60", this.Font, Brushes.White,
|
||||
this.minAngles.Length * size / 3.0f - 2 * fSize.Width,
|
||||
this.Height - fSize.Height - 1);
|
||||
|
||||
g.DrawString("60", this.Font, Brushes.White, middle, this.Height - fSize.Height - 1);
|
||||
g.DrawString("180", this.Font, Brushes.White,
|
||||
this.Width - 3 * fSize.Width,
|
||||
this.Height - fSize.Height - 1);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
|
||||
g.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
|
||||
|
||||
if (this.minAngles == null || this.maxAngles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SizeF fSize = g.MeasureString("0", this.Font, this.Width);
|
||||
|
||||
int n = this.minAngles.Length;
|
||||
|
||||
// Hack --- TODO: Change stats class
|
||||
if (n != this.maxAngles.Length)
|
||||
{
|
||||
n = this.minAngles.Length + this.maxAngles.Length;
|
||||
}
|
||||
|
||||
// Each bar takes up this space
|
||||
int size = (this.Width - 2 * padding) / (n + 1);
|
||||
|
||||
// Make pixel align
|
||||
int middle = this.Width - padding - n * size;
|
||||
|
||||
DrawHistogram(g, 0, padding, size, this.minAngles, Brushes.DarkGreen, Brushes.Green);
|
||||
DrawHistogram(g, n / 3, middle, size, this.maxAngles, fillBlue1, fillBlue2);
|
||||
|
||||
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
DrawStrings(g, fSize, size, middle + n / 3 * size);
|
||||
}
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="AngleHistogram.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// Displays an angle histogram.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The angle histogram is divided into two parts: the minimum angles
|
||||
/// on the left side (0 to 60 degrees) and the maximum angles on the
|
||||
/// right (60 to 180 degrees).
|
||||
/// </remarks>
|
||||
public class AngleHistogram : Control
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
int[] maxAngles;
|
||||
int[] minAngles;
|
||||
|
||||
Brush fillBlue1 = new SolidBrush(Color.FromArgb(60, 100, 140));
|
||||
Brush fillBlue2 = new SolidBrush(Color.FromArgb(110, 150, 200));
|
||||
|
||||
Brush textBack = new SolidBrush(Color.FromArgb(72, 0, 0, 0));
|
||||
|
||||
// The maximum number of angles
|
||||
int maxAngleCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AngleHistogram" /> control.
|
||||
/// </summary>
|
||||
public AngleHistogram()
|
||||
{
|
||||
BackColor = ColorScheme.ColorGray78;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the histogram data and invalidates the control.
|
||||
/// </summary>
|
||||
public void SetData(int[] dataMin, int[] dataMax)
|
||||
{
|
||||
maxAngleCount = 0;
|
||||
|
||||
minAngles = dataMin;
|
||||
maxAngles = dataMax;
|
||||
|
||||
ParseData(dataMin);
|
||||
ParseData(dataMax);
|
||||
|
||||
if (maxAngleCount == 0)
|
||||
{
|
||||
maxAngles = null;
|
||||
return;
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private void ParseData(int[] data)
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] > maxAngleCount)
|
||||
{
|
||||
maxAngleCount = data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int padding = 1;
|
||||
int paddingBottom = 0;
|
||||
int paddingTop = 15;
|
||||
|
||||
private void DrawHistogram(Graphics g, int offset, int left, int size, int[] data, Brush brush, Brush brushTop)
|
||||
{
|
||||
int count = maxAngleCount;
|
||||
int totalHeight = Height - paddingBottom - paddingTop;
|
||||
|
||||
int n = offset == 0 ? data.Length / 3 : data.Length;
|
||||
|
||||
for (int i = offset; i < n; i++)
|
||||
{
|
||||
if (data[i] > 0)
|
||||
{
|
||||
// Scale to control height
|
||||
float value = totalHeight * data[i] / count;
|
||||
|
||||
// Fill bar
|
||||
g.FillRectangle(brush,
|
||||
left + i * size, Height - paddingBottom - value,
|
||||
size - 1, value);
|
||||
|
||||
// Draw top of bar (just a little effect ...)
|
||||
if (value > 2)
|
||||
{
|
||||
g.FillRectangle(brushTop,
|
||||
left + i * size, Height - paddingBottom - value,
|
||||
size - 1, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the labels on the bottom.
|
||||
/// </summary>
|
||||
private void DrawStrings(Graphics g, SizeF fSize, int size, int middle)
|
||||
{
|
||||
int fHeight = (int)(fSize.Height + 2);
|
||||
|
||||
g.FillRectangle(textBack, 0, Height - fHeight, Width, fHeight);
|
||||
|
||||
var p = new Point(0, Height - (int)fSize.Height - 1);
|
||||
|
||||
p.X = padding;
|
||||
TextRenderer.DrawText(g, "0", Font, p, Color.White);
|
||||
|
||||
p.X = (int)(minAngles.Length * size / 3.0f - 2 * fSize.Width);
|
||||
TextRenderer.DrawText(g, "60", Font, p, Color.White);
|
||||
|
||||
p.X = middle;
|
||||
TextRenderer.DrawText(g, "60", Font, p, Color.White);
|
||||
|
||||
p.X = (int)(Width - 3 * fSize.Width);
|
||||
TextRenderer.DrawText(g, "180", Font, p, Color.White);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
|
||||
g.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
|
||||
|
||||
if (minAngles == null || maxAngles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int n = minAngles.Length;
|
||||
|
||||
// Hack --- TODO: Change stats class
|
||||
if (n != maxAngles.Length)
|
||||
{
|
||||
n = minAngles.Length + maxAngles.Length;
|
||||
}
|
||||
|
||||
// Each bar takes up this space
|
||||
int size = (Width - 2 * padding) / (n + 1);
|
||||
|
||||
// Make pixel align
|
||||
int middle = Width - padding - n * size;
|
||||
|
||||
DrawHistogram(g, 0, padding, size, minAngles, Brushes.DarkGreen, Brushes.Green);
|
||||
DrawHistogram(g, n / 3, middle, size, maxAngles, fillBlue1, fillBlue2);
|
||||
|
||||
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
SizeF fSize = g.MeasureString("0", Font, Width);
|
||||
|
||||
DrawStrings(g, fSize, size, middle + n / 3 * size);
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
-38
@@ -1,38 +1,34 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ColorScheme.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Dark user interface color scheme.
|
||||
/// </summary>
|
||||
public static class ColorScheme
|
||||
{
|
||||
public static Color ColorGray13 = Color.FromArgb(13, 13, 13);
|
||||
public static Color ColorGray46 = Color.FromArgb(46, 46, 46);
|
||||
public static Color ColorGray64 = Color.FromArgb(64, 64, 64);
|
||||
public static Color ColorGray68 = Color.FromArgb(68, 68, 68);
|
||||
public static Color ColorGray78 = Color.FromArgb(78, 78, 78);
|
||||
public static Color ColorGray89 = Color.FromArgb(89, 89, 89);
|
||||
public static Color ColorGray98 = Color.FromArgb(98, 98, 98);
|
||||
public static Color ColorGray107 = Color.FromArgb(107, 107, 107);
|
||||
public static Color ColorGray110 = Color.FromArgb(110, 110, 110);
|
||||
public static Color ColorGray122 = Color.FromArgb(122, 122, 122);
|
||||
|
||||
public static Brush BrushGray68 = new SolidBrush(ColorGray68);
|
||||
public static Brush BrushGray78 = new SolidBrush(ColorGray78);
|
||||
|
||||
// Linear gradient horizontal
|
||||
public static Brush SliderBorderBrush = new SolidBrush(ColorGray46);
|
||||
public static Brush SliderFillBrush = new SolidBrush(ColorGray89);
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ColorScheme.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Dark user interface color scheme.
|
||||
/// </summary>
|
||||
public static class ColorScheme
|
||||
{
|
||||
public static Color ColorGray13 = Color.FromArgb(13, 13, 13);
|
||||
public static Color ColorGray46 = Color.FromArgb(46, 46, 46);
|
||||
public static Color ColorGray64 = Color.FromArgb(64, 64, 64);
|
||||
public static Color ColorGray68 = Color.FromArgb(68, 68, 68);
|
||||
public static Color ColorGray78 = Color.FromArgb(78, 78, 78);
|
||||
public static Color ColorGray89 = Color.FromArgb(89, 89, 89);
|
||||
public static Color ColorGray98 = Color.FromArgb(98, 98, 98);
|
||||
public static Color ColorGray107 = Color.FromArgb(107, 107, 107);
|
||||
public static Color ColorGray110 = Color.FromArgb(110, 110, 110);
|
||||
public static Color ColorGray122 = Color.FromArgb(122, 122, 122);
|
||||
|
||||
public static Brush BrushGray68 = new SolidBrush(ColorGray68);
|
||||
public static Brush BrushGray78 = new SolidBrush(ColorGray78);
|
||||
|
||||
// Linear gradient horizontal
|
||||
public static Brush SliderBorderBrush = new SolidBrush(ColorGray46);
|
||||
public static Brush SliderFillBrush = new SolidBrush(ColorGray89);
|
||||
}
|
||||
}
|
||||
+185
-189
@@ -1,190 +1,186 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="DarkButton.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public class DarkButton : Button
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
enum eButtonState { Normal, MouseOver, Down }
|
||||
eButtonState m_State = eButtonState.Normal;
|
||||
|
||||
// Make sure the control is invalidated when the text is changed.
|
||||
public override string Text
|
||||
{
|
||||
get { return base.Text; }
|
||||
set { base.Text = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DarkButton" /> control.
|
||||
/// </summary>
|
||||
public DarkButton()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#region Control overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
float down = 0.0f;
|
||||
|
||||
// Colors and brushes
|
||||
Pen brushBorder = null;
|
||||
LinearGradientMode mode = LinearGradientMode.Vertical;
|
||||
LinearGradientBrush brushOuter = null;
|
||||
LinearGradientBrush brushInner = null;
|
||||
|
||||
Rectangle newRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
|
||||
Color text_color = Color.White;
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
if (base.Focused)
|
||||
brushBorder = new Pen(Color.FromArgb(24, 24, 24), 1f);
|
||||
else
|
||||
brushBorder = new Pen(Color.FromArgb(56, 56, 56), 1f);
|
||||
|
||||
switch (m_State)
|
||||
{
|
||||
case eButtonState.Normal:
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(123, 123, 123), Color.FromArgb(77, 77, 77), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(104, 104, 104), Color.FromArgb(71, 71, 71), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
break;
|
||||
|
||||
case eButtonState.MouseOver:
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(140, 140, 140), Color.FromArgb(87, 87, 87), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(118, 118, 118), Color.FromArgb(81, 81, 81), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
break;
|
||||
|
||||
case eButtonState.Down:
|
||||
down = 1.0f;
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(108, 108, 108), Color.FromArgb(68, 68, 68), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(92, 92, 92), Color.FromArgb(62, 62, 62), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
text_color = Color.FromArgb(110, 110, 110);
|
||||
brushBorder = new Pen(Color.FromArgb(48, 48, 48), 1f);
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(82, 82, 82), Color.FromArgb(67, 67, 67), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(76, 76, 76), Color.FromArgb(65, 65, 65), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
}
|
||||
|
||||
|
||||
string largetext = this.Text;
|
||||
|
||||
SizeF szL = e.Graphics.MeasureString(this.Text, base.Font, this.Width);
|
||||
if (Enabled)
|
||||
{
|
||||
e.Graphics.DrawString(largetext, base.Font, Brushes.Black,
|
||||
new RectangleF(new PointF((this.Width - szL.Width) / 2, (this.Height - szL.Height) / 2 + 1 + down), szL));
|
||||
}
|
||||
e.Graphics.DrawString(largetext, base.Font, new SolidBrush(text_color),
|
||||
new RectangleF(new PointF((this.Width - szL.Width) / 2, (this.Height - szL.Height) / 2 + down), szL));
|
||||
|
||||
brushOuter.Dispose();
|
||||
brushInner.Dispose();
|
||||
brushBorder.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Normal;
|
||||
this.Invalidate();
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Down;
|
||||
this.Invalidate();
|
||||
base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="DarkButton.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public class DarkButton : Button
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
enum eButtonState { Normal, MouseOver, Down }
|
||||
eButtonState m_State = eButtonState.Normal;
|
||||
|
||||
// Make sure the control is invalidated when the text is changed.
|
||||
public override string Text
|
||||
{
|
||||
get { return base.Text; }
|
||||
set { base.Text = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DarkButton" /> control.
|
||||
/// </summary>
|
||||
public DarkButton()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#region Control overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
float down = 0.0f;
|
||||
|
||||
// Colors and brushes
|
||||
Pen brushBorder = null;
|
||||
LinearGradientMode mode = LinearGradientMode.Vertical;
|
||||
LinearGradientBrush brushOuter = null;
|
||||
LinearGradientBrush brushInner = null;
|
||||
|
||||
Rectangle newRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
|
||||
Color text_color = Color.White;
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
if (base.Focused)
|
||||
brushBorder = new Pen(Color.FromArgb(24, 24, 24), 1f);
|
||||
else
|
||||
brushBorder = new Pen(Color.FromArgb(56, 56, 56), 1f);
|
||||
|
||||
switch (m_State)
|
||||
{
|
||||
case eButtonState.Normal:
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(123, 123, 123), Color.FromArgb(77, 77, 77), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(104, 104, 104), Color.FromArgb(71, 71, 71), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
break;
|
||||
|
||||
case eButtonState.MouseOver:
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(140, 140, 140), Color.FromArgb(87, 87, 87), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(118, 118, 118), Color.FromArgb(81, 81, 81), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
break;
|
||||
|
||||
case eButtonState.Down:
|
||||
down = 1.0f;
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(108, 108, 108), Color.FromArgb(68, 68, 68), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(92, 92, 92), Color.FromArgb(62, 62, 62), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
text_color = Color.FromArgb(110, 110, 110);
|
||||
brushBorder = new Pen(Color.FromArgb(48, 48, 48), 1f);
|
||||
brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(82, 82, 82), Color.FromArgb(67, 67, 67), mode);
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(76, 76, 76), Color.FromArgb(65, 65, 65), mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
newRect.Inflate(-1, -1);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
newRect.Inflate(1, 1);
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
}
|
||||
|
||||
|
||||
string largetext = this.Text;
|
||||
|
||||
SizeF szL = e.Graphics.MeasureString(this.Text, base.Font, this.Width);
|
||||
if (Enabled)
|
||||
{
|
||||
e.Graphics.DrawString(largetext, base.Font, Brushes.Black,
|
||||
new RectangleF(new PointF((this.Width - szL.Width) / 2, (this.Height - szL.Height) / 2 + 1 + down), szL));
|
||||
}
|
||||
e.Graphics.DrawString(largetext, base.Font, new SolidBrush(text_color),
|
||||
new RectangleF(new PointF((this.Width - szL.Width) / 2, (this.Height - szL.Height) / 2 + down), szL));
|
||||
|
||||
brushOuter.Dispose();
|
||||
brushInner.Dispose();
|
||||
brushBorder.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Normal;
|
||||
this.Invalidate();
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Down;
|
||||
this.Invalidate();
|
||||
base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+237
-239
@@ -1,239 +1,237 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="DarkCheckBox.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Dark checkbox control.
|
||||
/// </summary>
|
||||
public class DarkCheckBox : ButtonBase
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
enum eButtonState { Normal, MouseOver, Down }
|
||||
eButtonState m_State = eButtonState.Normal;
|
||||
|
||||
// Make sure the control is invalidated when the text is changed.
|
||||
public override string Text
|
||||
{
|
||||
get { return base.Text; }
|
||||
set { base.Text = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
int boxSize = 13;
|
||||
|
||||
bool isChecked = false;
|
||||
public bool Checked
|
||||
{
|
||||
get { return isChecked; }
|
||||
set { isChecked = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DarkCheckBox" /> control.
|
||||
/// </summary>
|
||||
public DarkCheckBox()
|
||||
{
|
||||
this.BackColor = Color.FromArgb(76, 76, 76);
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void DrawText(Graphics g, Color forecolor, Point location)
|
||||
{
|
||||
if (this.UseCompatibleTextRendering)
|
||||
{
|
||||
//using (StringFormat stringFormat = this.CreateStringFormat())
|
||||
{
|
||||
if (this.Enabled)
|
||||
{
|
||||
g.DrawString(this.Text, base.Font, new SolidBrush(forecolor), location.X, location.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.DrawString(this.Text, base.Font, new SolidBrush(forecolor), location.X, location.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//TextFormatFlags textFormatFlags = this.CreateTextFormatFlags();
|
||||
if (this.Enabled)
|
||||
{
|
||||
TextRenderer.DrawText((IDeviceContext)g, this.Text, this.Font, location, forecolor);
|
||||
}
|
||||
else
|
||||
{
|
||||
//forecolor = TextRenderer.DisabledTextColor(this.BackColor);
|
||||
TextRenderer.DrawText((IDeviceContext)g, this.Text, this.Font, location, forecolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Control overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
//base.OnPaint(e);
|
||||
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
|
||||
|
||||
Pen checkMark = new Pen(Color.White, 1.8f);
|
||||
checkMark.StartCap = LineCap.Round;
|
||||
checkMark.EndCap = LineCap.Round;
|
||||
|
||||
// Colors and brushes
|
||||
Pen brushBorder = null;
|
||||
LinearGradientMode mode = LinearGradientMode.Vertical;
|
||||
LinearGradientBrush brushOuter = null;
|
||||
LinearGradientBrush brushInner = null;
|
||||
|
||||
int y = (this.Height - boxSize) / 2;
|
||||
|
||||
Rectangle newRect = new Rectangle(1, y, boxSize, boxSize);
|
||||
Color text_color = Color.White;
|
||||
|
||||
brushOuter = new LinearGradientBrush(newRect, ColorScheme.ColorGray107, ColorScheme.ColorGray110, mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
|
||||
newRect = new Rectangle(2, y + 1, boxSize - 3, boxSize - 3);
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
if (base.Focused)
|
||||
brushBorder = new Pen(Color.FromArgb(60, 60, 60), 1f);
|
||||
else
|
||||
brushBorder = new Pen(Color.FromArgb(38, 38, 38), 1f);
|
||||
|
||||
switch (m_State)
|
||||
{
|
||||
case eButtonState.Normal:
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(111, 111, 111), Color.FromArgb(80, 80, 80), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
break;
|
||||
|
||||
case eButtonState.MouseOver:
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(118, 118, 118), Color.FromArgb(81, 81, 81), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
break;
|
||||
|
||||
case eButtonState.Down:
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(92, 92, 92), Color.FromArgb(62, 62, 62), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
break;
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(76, 76, 76), Color.FromArgb(65, 65, 65), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
|
||||
brushBorder = new Pen(Color.FromArgb(48, 48, 48), 1f);
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
|
||||
text_color = Color.FromArgb(160, 160, 160);
|
||||
checkMark.Color = Color.FromArgb(180, 180, 180);
|
||||
}
|
||||
|
||||
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
SizeF szL = e.Graphics.MeasureString(this.Text, base.Font, this.Width);
|
||||
DrawText(e.Graphics, text_color, new Point(boxSize + 4, (int)((this.Height - szL.Height) / 2) + 1));
|
||||
|
||||
if (this.isChecked)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
e.Graphics.DrawLine(checkMark, 4, newRect.Bottom - boxSize / 2, newRect.Left + boxSize / 2.5f, newRect.Bottom - 2);
|
||||
e.Graphics.DrawLine(checkMark, newRect.Left + boxSize / 2.6f, newRect.Bottom - 2, newRect.Right, newRect.Top);
|
||||
}
|
||||
|
||||
if (brushOuter != null) brushOuter.Dispose();
|
||||
if (brushInner != null) brushInner.Dispose();
|
||||
if (brushBorder != null) brushBorder.Dispose();
|
||||
if (checkMark != null) checkMark.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Normal;
|
||||
this.Invalidate();
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Down;
|
||||
this.Invalidate();
|
||||
base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override void OnClick(EventArgs e)
|
||||
{
|
||||
this.isChecked = !this.isChecked;
|
||||
this.Invalidate();
|
||||
base.OnClick(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="DarkCheckBox.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// Dark checkbox control.
|
||||
/// </summary>
|
||||
public class DarkCheckBox : ButtonBase
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
enum eButtonState { Normal, MouseOver, Down }
|
||||
eButtonState m_State = eButtonState.Normal;
|
||||
|
||||
// Make sure the control is invalidated when the text is changed.
|
||||
public override string Text
|
||||
{
|
||||
get { return base.Text; }
|
||||
set { base.Text = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
int boxSize = 13;
|
||||
|
||||
bool isChecked = false;
|
||||
public bool Checked
|
||||
{
|
||||
get { return isChecked; }
|
||||
set { isChecked = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DarkCheckBox" /> control.
|
||||
/// </summary>
|
||||
public DarkCheckBox()
|
||||
{
|
||||
this.BackColor = Color.FromArgb(76, 76, 76);
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void DrawText(Graphics g, Color forecolor, Point location)
|
||||
{
|
||||
if (this.UseCompatibleTextRendering)
|
||||
{
|
||||
//using (StringFormat stringFormat = this.CreateStringFormat())
|
||||
{
|
||||
if (this.Enabled)
|
||||
{
|
||||
g.DrawString(this.Text, base.Font, new SolidBrush(forecolor), location.X, location.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.DrawString(this.Text, base.Font, new SolidBrush(forecolor), location.X, location.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//TextFormatFlags textFormatFlags = this.CreateTextFormatFlags();
|
||||
if (this.Enabled)
|
||||
{
|
||||
TextRenderer.DrawText((IDeviceContext)g, this.Text, this.Font, location, forecolor);
|
||||
}
|
||||
else
|
||||
{
|
||||
//forecolor = TextRenderer.DisabledTextColor(this.BackColor);
|
||||
TextRenderer.DrawText((IDeviceContext)g, this.Text, this.Font, location, forecolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Control overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
//base.OnPaint(e);
|
||||
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
|
||||
|
||||
Pen checkMark = new Pen(Color.White, 1.8f);
|
||||
checkMark.StartCap = LineCap.Round;
|
||||
checkMark.EndCap = LineCap.Round;
|
||||
|
||||
// Colors and brushes
|
||||
Pen brushBorder = null;
|
||||
LinearGradientMode mode = LinearGradientMode.Vertical;
|
||||
LinearGradientBrush brushOuter = null;
|
||||
LinearGradientBrush brushInner = null;
|
||||
|
||||
int y = (this.Height - boxSize) / 2;
|
||||
|
||||
Rectangle newRect = new Rectangle(1, y, boxSize, boxSize);
|
||||
Color text_color = Color.White;
|
||||
|
||||
brushOuter = new LinearGradientBrush(newRect, ColorScheme.ColorGray107, ColorScheme.ColorGray110, mode);
|
||||
e.Graphics.FillRectangle(brushOuter, newRect);
|
||||
|
||||
newRect = new Rectangle(2, y + 1, boxSize - 3, boxSize - 3);
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
if (base.Focused)
|
||||
brushBorder = new Pen(Color.FromArgb(60, 60, 60), 1f);
|
||||
else
|
||||
brushBorder = new Pen(Color.FromArgb(38, 38, 38), 1f);
|
||||
|
||||
switch (m_State)
|
||||
{
|
||||
case eButtonState.Normal:
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(111, 111, 111), Color.FromArgb(80, 80, 80), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
break;
|
||||
|
||||
case eButtonState.MouseOver:
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(118, 118, 118), Color.FromArgb(81, 81, 81), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
break;
|
||||
|
||||
case eButtonState.Down:
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(92, 92, 92), Color.FromArgb(62, 62, 62), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
break;
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
brushInner = new LinearGradientBrush(newRect, Color.FromArgb(76, 76, 76), Color.FromArgb(65, 65, 65), mode);
|
||||
e.Graphics.FillRectangle(brushInner, newRect);
|
||||
|
||||
brushBorder = new Pen(Color.FromArgb(48, 48, 48), 1f);
|
||||
e.Graphics.DrawRectangle(brushBorder, newRect);
|
||||
|
||||
text_color = Color.FromArgb(160, 160, 160);
|
||||
checkMark.Color = Color.FromArgb(180, 180, 180);
|
||||
}
|
||||
|
||||
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
|
||||
SizeF szL = e.Graphics.MeasureString(this.Text, base.Font, this.Width);
|
||||
DrawText(e.Graphics, text_color, new Point(boxSize + 4, (int)((this.Height - szL.Height) / 2) + 1));
|
||||
|
||||
if (this.isChecked)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
e.Graphics.DrawLine(checkMark, 4, newRect.Bottom - boxSize / 2, newRect.Left + boxSize / 2.5f, newRect.Bottom - 2);
|
||||
e.Graphics.DrawLine(checkMark, newRect.Left + boxSize / 2.6f, newRect.Bottom - 2, newRect.Right, newRect.Top);
|
||||
}
|
||||
|
||||
if (brushOuter != null) brushOuter.Dispose();
|
||||
if (brushInner != null) brushInner.Dispose();
|
||||
if (brushBorder != null) brushBorder.Dispose();
|
||||
if (checkMark != null) checkMark.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Normal;
|
||||
this.Invalidate();
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(System.EventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.MouseOver;
|
||||
this.Invalidate();
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
|
||||
{
|
||||
m_State = eButtonState.Down;
|
||||
this.Invalidate();
|
||||
base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override void OnClick(EventArgs e)
|
||||
{
|
||||
this.isChecked = !this.isChecked;
|
||||
this.Invalidate();
|
||||
base.OnClick(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user