Add func: export image

This commit is contained in:
2018-12-26 15:55:33 +08:00
parent 92dfcc241b
commit 2aa5e38035
7 changed files with 374 additions and 130 deletions

View File

@ -38,6 +38,7 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
@ -57,9 +58,11 @@
</ApplicationDefinition>
<Compile Include="Course.cs" />
<Compile Include="General.cs" />
<Compile Include="ImageExport.cs" />
<Compile Include="Simulation.xaml.cs">
<DependentUpon>Simulation.xaml</DependentUpon>
</Compile>
<Compile Include="SimulationCore.cs" />
<Compile Include="SimulationItem.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace HFUTCourseSimulation {
public static class ImageExport {
public static readonly int WeekHeaderHeight = 50;
public static readonly int BodyCellWidth = 150;
public static readonly int BodyCellHeight = 80;
public static readonly int HeaderCellHeight = 40;
public static readonly int LeftCellWidth = 25;
public static readonly int Blank = 20;
static Dictionary<int, string> weekDict = new Dictionary<int, string>() {
{0, "星期一"},
{1, "星期二"},
{2, "星期三"},
{3, "星期四"},
{4, "星期五"},
{5, "星期六"},
{6, "星期日"}
};
public static bool Export(DateTime startDate, int weekCount, string file) {
var simuCore = new SimulationCore(startDate, weekCount);
simuCore.Generate();
if (simuCore.ErrorList.Count != 0) return false;
//define size
int weekPerLine = (int)Math.Sqrt(weekCount) + 1;
var weekWidth = (Blank + LeftCellWidth + 7 * BodyCellWidth);
var weekHeight = (Blank + WeekHeaderHeight + HeaderCellHeight + 11 * BodyCellHeight);
var img = new Bitmap(Blank + weekPerLine * weekWidth, Blank + (weekCount / weekPerLine + (weekCount % weekPerLine == 0 ? 0 : 1)) * weekHeight);
var graphics = Graphics.FromImage(img);
//declare graphics value
var headerBrush = new SolidBrush(Color.Gray);
var textBrush = new SolidBrush(Color.Black);
Brush cellBrush;
var textFont = new Font("Arial", 12);
var textMargin = graphics.MeasureString("测试字符", textFont).Height;
//output each week
for (int i = 0; i < weekCount; i++) {
//generate week data
var weekData = simuCore.Render(i + 1);
//get start position
var top = Blank + (i / weekPerLine) * weekHeight;
var left = Blank + (i % weekPerLine) * weekWidth;
graphics.TranslateTransform(left, top);
//draw week head
graphics.DrawString($"教学周:{weekData.WeekIndex}", textFont, textBrush, 0, 0);
//move transform
graphics.TranslateTransform(0, WeekHeaderHeight);
//draw header
graphics.FillRectangle(headerBrush, 0, 0, weekWidth, HeaderCellHeight);
graphics.FillRectangle(headerBrush, 0, 0, LeftCellWidth, weekHeight - WeekHeaderHeight);
//draw header text
for (int j = 0; j < 7; j++) {
graphics.DrawString(weekDict[j], textFont, textBrush, LeftCellWidth + j * BodyCellWidth, 0);
graphics.DrawString(weekData.WeekDate[j], textFont, textBrush, LeftCellWidth + j * BodyCellWidth, textMargin);
}
//draw left text
for (int j = 0; j < 11; j++) {
graphics.DrawString((j + 1).ToString(), textFont, textBrush, 0, HeaderCellHeight + j * BodyCellHeight);
}
//move transform
graphics.TranslateTransform(LeftCellWidth, HeaderCellHeight);
foreach(var courses in weekData.CourseList) {
var cellx = courses.Start.week - 1;
var celly = courses.Start.index - 1;
//background
cellBrush = new SolidBrush(courses.BkColor.ConvertWPFColor());
graphics.FillRectangle(cellBrush, cellx * BodyCellWidth, celly * BodyCellHeight, BodyCellWidth, BodyCellHeight * courses.Span);
//draw text
var rect = new RectangleF(cellx * BodyCellWidth, celly * BodyCellHeight, BodyCellWidth, celly * BodyCellHeight);
graphics.DrawString(courses.Name, textFont, textBrush, rect);
var thisTextMargin = graphics.MeasureString(courses.Name, textFont, BodyCellWidth).Height;
graphics.DrawString(courses.Desc, textFont, textBrush, cellx * BodyCellWidth, celly * BodyCellHeight + textMargin);
}
//reset
graphics.TranslateTransform(-LeftCellWidth, -HeaderCellHeight);
graphics.TranslateTransform(0, -WeekHeaderHeight);
graphics.TranslateTransform(-left, -top);
}
System.IO.File.Delete(file);
img.Save(file, ImageFormat.Png);
img.Dispose();
return true;
}
}
public static class WPFColorConvert {
public static System.Drawing.Color ConvertWPFColor(this System.Windows.Media.Color c) {
return System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B);
}
}
}

View File

@ -15,11 +15,16 @@
<MenuItem x:Name="uiMenuSave" Header="保存" Click="uiMenuSave_Click"/>
<MenuItem x:Name="uiMenuClose" Header="关闭" Click="uiMenuClose_Click"/>
</MenuItem>
<MenuItem x:Name="uiMenuSimulation" Header="模拟" Click="uiMenuSimulation_Click"/>
<MenuItem Header="输出">
<MenuItem x:Name="uiMenuSimulation" Header="实时模拟" Click="uiMenuSimulation_Click"/>
<MenuItem x:Name="uiMenuExport" Header="导出为图片" Click="uiMenuExport_Click"/>
</MenuItem>
<MenuItem x:Name="uiMenuAbout" Header="关于" Click="uiMenuAbout_Click"/>
</Menu>
<TabControl Margin="0,20,0,0">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="打开或新建一个课表文件" FontSize="20" Opacity="0.5"/>
<TabControl x:Name="uiMainTab" Margin="0,20,0,0">
<TabItem Header="通用设置">
<StackPanel Orientation="Vertical">
<TextBlock Text="起始周日期(教学第一周星期一的日期)" Margin="10,10,10,5"/>

View File

@ -35,7 +35,10 @@ namespace HFUTCourseSimulation {
uiMenuSave.IsEnabled = false;
uiMenuClose.IsEnabled = false;
uiMenuSimulation.IsEnabled = false;
uiMenuExport.IsEnabled = false;
uiMainTab.Visibility = Visibility.Collapsed;
/*
uiCourseBtnAdd.IsEnabled = false;
uiCourseBtnDelete.IsEnabled = false;
uiCourseBtnUpdate.IsEnabled = false;
@ -56,6 +59,7 @@ namespace HFUTCourseSimulation {
uiCoursesList.IsEnabled = false;
uiScheduleList.IsEnabled = false;
*/
} else {
//no file
uiMenuNew.IsEnabled = false;
@ -63,7 +67,10 @@ namespace HFUTCourseSimulation {
uiMenuSave.IsEnabled = true;
uiMenuClose.IsEnabled = true;
uiMenuSimulation.IsEnabled = true;
uiMenuExport.IsEnabled = true;
uiMainTab.Visibility = Visibility.Visible;
/*
uiCourseBtnAdd.IsEnabled = true;
uiCourseBtnDelete.IsEnabled = true;
uiCourseBtnUpdate.IsEnabled = true;
@ -84,6 +91,7 @@ namespace HFUTCourseSimulation {
uiCoursesList.IsEnabled = true;
uiScheduleList.IsEnabled = true;
*/
}
}
@ -149,6 +157,32 @@ namespace HFUTCourseSimulation {
win.ShowDialog();
}
private void uiMenuExport_Click(object sender, RoutedEventArgs e) {
//convert data
int weekCount;
DateTime originDate;
try {
originDate = DateTime.Parse(General.GeneralSheet.StartDate);
weekCount = General.GeneralSheet.WeekCount;
} catch (Exception) {
MessageBox.Show("周数或日期转换错误,无法输出", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
return;
}
//open file
var sp = new Microsoft.Win32.SaveFileDialog();
sp.RestoreDirectory = true;
sp.Filter = "图片文件(*.png)|*.png|所有文件(*.*)|*.*";
var status = sp.ShowDialog();
if (!(status.HasValue && status.Value)) return;
var getFile = sp.FileName;
//export
var res = ImageExport.Export(originDate, weekCount, getFile);
if (!res) MessageBox.Show("当前课程安排存在冲突,请通过实时预览消除所有错误后才能使用此功能来导出为图片", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
else MessageBox.Show("导出成功", "关于", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
}
private void uiMenuAbout_Click(object sender, RoutedEventArgs e) {
MessageBox.Show("本程序为开源程序。" + Environment.NewLine + "开源地址https://gitee.com/yyc12345/HFUTCourseSimulation" + Environment.NewLine +
"本程序旨在为各位选课的同学提供一个用于查验课程冲突以及查看课表的功能。如果您想参与开发提交PullRequest即可欢迎您的加入。", "关于", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);

View File

@ -17,6 +17,9 @@ namespace HFUTCourseSimulation {
/// Simulation.xaml 的交互逻辑
/// </summary>
public partial class Simulation : Window {
SimulationCore simulationKernel;
public Simulation() {
InitializeComponent();
@ -44,152 +47,55 @@ namespace HFUTCourseSimulation {
return;
}
Generate();
simulationKernel = new SimulationCore(originDate, weekCount);
simulationKernel.Generate();
//refresh error list
this.uiArrangeError.Items.Clear();
foreach (var item in errorList) {
foreach (var item in simulationKernel.ErrorList) {
this.uiArrangeError.Items.Add(item);
}
currentWeek = 1;
Render();
this.RenderGrid(simulationKernel.Render(currentWeek));
}
Dictionary<Vector3, SimulationItem> itemDict = new Dictionary<Vector3, SimulationItem>();
List<string> errorList = new List<string>();
List<Grid> uiList = new List<Grid>();
DateTime originDate;
int weekCount;
int currentWeek;
int weekCount;
DateTime originDate;
void Generate() {
foreach (var item in General.GeneralSheet.Courses) {
foreach (var inner in item.Schedule) {
var weekRes = GetArrange(inner.Week);
var dayRes = GetArrange(inner.Day);
var indexRes = GetArrange(inner.Index);
void RenderGrid(RenderWeek weekRes) {
//set date
uiWeek.Text = weekRes.WeekIndex.ToString();
uiWeek1.Text = weekRes.WeekDate[0];
uiWeek2.Text = weekRes.WeekDate[1];
uiWeek3.Text = weekRes.WeekDate[2];
uiWeek4.Text = weekRes.WeekDate[3];
uiWeek5.Text = weekRes.WeekDate[4];
uiWeek6.Text = weekRes.WeekDate[5];
uiWeek7.Text = weekRes.WeekDate[6];
foreach (var weekItem in weekRes) {
foreach (var dayItem in dayRes) {
foreach (var indexItem in indexRes) {
var vectorCache = new Vector3(weekItem, dayItem, indexItem);
if (this.itemDict.Keys.Contains(vectorCache)) {
errorList.Add($"课程冲突:无法将{item.Name}安排到 {weekItem}周,星期{dayItem},第{indexItem}节。因为此处已被{itemDict[vectorCache].Name}占据");
} else {
itemDict.Add(vectorCache, new SimulationItem() { Name = item.Name, Desc = item.Description });
}
}
}
}
}
}
}
List<int> GetArrange(string str) {
var res = new List<int>();
try {
if (str.Contains('-')) {
var strSp = str.Split('-');
int start = int.Parse(strSp[0]), end = int.Parse(strSp[1]);
for (int i = start; i <= end; i++) {
res.Add(i);
}
} else if (str.Contains(',')) {
var strSp = str.Split(',');
foreach (var item in strSp) {
res.Add(int.Parse(item));
}
} else {
res.Add(int.Parse(str));
}
} catch (Exception) {
errorList.Add("解析错误:" + str);
}
return res;
}
void Render() {
//remove all old grid
this.uiArrangeGrid.Children.Clear();
uiList.Clear();
//update date
//comput start date
uiWeek.Text = currentWeek.ToString();
var pointer = originDate;
pointer = pointer.AddDays(7 * (currentWeek - 1));
uiWeek1.Text = $"{pointer.Month}/{pointer.Day}";
pointer = pointer.AddDays(1);
uiWeek2.Text = $"{pointer.Month}/{pointer.Day}";
pointer = pointer.AddDays(1);
uiWeek3.Text = $"{pointer.Month}/{pointer.Day}";
pointer = pointer.AddDays(1);
uiWeek4.Text = $"{pointer.Month}/{pointer.Day}";
pointer = pointer.AddDays(1);
uiWeek5.Text = $"{pointer.Month}/{pointer.Day}";
pointer = pointer.AddDays(1);
uiWeek6.Text = $"{pointer.Month}/{pointer.Day}";
pointer = pointer.AddDays(1);
uiWeek7.Text = $"{pointer.Month}/{pointer.Day}";
//create grid
var query = (from item in itemDict.Keys
where item.teachingweek == currentWeek
select item).ToList();
while (query.Count != 0) {
var core = query[0];
var data = itemDict[core];
int length = 1;
//check below
if (core.index != 1 && query.Contains(core + new Vector3(0, 0, -1))) {
if (itemDict[core + new Vector3(0, 0, -1)].Name == data.Name) {
//if below have. jump this->move this to the end
query.RemoveAt(0);
query.Add(core);
continue;
}
}
//check follow
while (true) {
if (query.Contains(core + new Vector3(0, 0, length)) && itemDict[core + new Vector3(0, 0, length)].Name == data.Name) {
query.Remove(core + new Vector3(0, 0, length));
length++;
} else break;
}
//create
//generate new
foreach (var item in weekRes.CourseList) {
var warp = new Border();
warp.Background = new SolidColorBrush(Colors.LightBlue);
warp.Background = new SolidColorBrush(item.BkColor);
warp.CornerRadius = new CornerRadius(5);
Grid.SetRowSpan(warp, length);
Grid.SetRowSpan(warp, item.Span);
var nGrid = new Grid();
nGrid.ToolTip = data.Desc;
nGrid.ToolTip = item.Desc;
var courseName = new TextBlock();
courseName.VerticalAlignment = VerticalAlignment.Center;
courseName.Text = data.Name;
courseName.Text = item.Name;
nGrid.Children.Add(courseName);
warp.Child = nGrid;
Grid.SetRow(warp, core.index - 1);
Grid.SetColumn(warp, core.week - 1);
Grid.SetRow(warp, item.Start.index - 1);
Grid.SetColumn(warp, item.Start.week - 1);
this.uiArrangeGrid.Children.Add(warp);
//remove first item
query.RemoveAt(0);
}
foreach (var item in query) {
}
}
private void uiBtnPre_Click(object sender, RoutedEventArgs e) {
@ -199,7 +105,7 @@ namespace HFUTCourseSimulation {
}
currentWeek--;
Render();
this.RenderGrid(simulationKernel.Render(currentWeek));
}
private void uiBtnNext_Click(object sender, RoutedEventArgs e) {
@ -209,7 +115,7 @@ namespace HFUTCourseSimulation {
}
currentWeek++;
Render();
this.RenderGrid(simulationKernel.Render(currentWeek));
}
private void uiArrangeError_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
@ -218,7 +124,7 @@ namespace HFUTCourseSimulation {
return;
}
MessageBox.Show(errorList[this.uiArrangeError.SelectedIndex], "错误详情", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
MessageBox.Show(this.simulationKernel.ErrorList[this.uiArrangeError.SelectedIndex], "错误详情", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
}
}
}

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace HFUTCourseSimulation {
public class SimulationCore {
public SimulationCore(DateTime startDate, int weekCount) {
this.weekCount = weekCount;
this.originDate = startDate;
}
Dictionary<Vector3, SimulationItem> itemDict = new Dictionary<Vector3, SimulationItem>();
public List<string> ErrorList { get; } = new List<string>();
//List<Grid> uiList = new List<Grid>();
DateTime originDate;
int weekCount;
//int currentWeek;
public void Generate() {
//pre-generate
foreach (var item in General.GeneralSheet.Courses) {
foreach (var inner in item.Schedule) {
var weekRes = GetArrange(inner.Week);
var dayRes = GetArrange(inner.Day);
var indexRes = GetArrange(inner.Index);
foreach (var weekItem in weekRes) {
foreach (var dayItem in dayRes) {
foreach (var indexItem in indexRes) {
var vectorCache = new Vector3(weekItem, dayItem, indexItem);
if (this.itemDict.Keys.Contains(vectorCache)) {
ErrorList.Add($"课程冲突:无法将{item.Name}安排到 {weekItem}周,星期{dayItem},第{indexItem}节。因为此处已被{itemDict[vectorCache].Name}占据");
} else {
itemDict.Add(vectorCache, new SimulationItem() { Name = item.Name, Desc = item.Description, BkColor = Colors.LightBlue });
}
}
}
}
}
}
}
List<int> GetArrange(string str) {
var res = new List<int>();
try {
if (str.Contains('-')) {
var strSp = str.Split('-');
int start = int.Parse(strSp[0]), end = int.Parse(strSp[1]);
for (int i = start; i <= end; i++) {
res.Add(i);
}
} else if (str.Contains(',')) {
var strSp = str.Split(',');
foreach (var item in strSp) {
res.Add(int.Parse(item));
}
} else {
res.Add(int.Parse(str));
}
} catch (Exception) {
ErrorList.Add("解析错误:" + str);
}
return res;
}
public RenderWeek Render(int currentWeek) {
//remove all old grid
var result = new RenderWeek();
result.WeekDate = new List<string>();
//update date
//comput start date
result.WeekIndex = currentWeek;
var pointer = originDate;
pointer = pointer.AddDays(7 * (currentWeek - 1));
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
pointer = pointer.AddDays(1);
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
pointer = pointer.AddDays(1);
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
pointer = pointer.AddDays(1);
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
pointer = pointer.AddDays(1);
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
pointer = pointer.AddDays(1);
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
pointer = pointer.AddDays(1);
result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
result.CourseList = new List<SimulationRenderItem>();
//create grid
var query = (from item in itemDict.Keys
where item.teachingweek == currentWeek
select item).ToList();
while (query.Count != 0) {
var core = query[0];
var data = itemDict[core];
int length = 1;
//check below
if (core.index != 1 && query.Contains(core + new Vector3(0, 0, -1))) {
if (itemDict[core + new Vector3(0, 0, -1)].Name == data.Name) {
//if below have. jump this->move this to the end
query.RemoveAt(0);
query.Add(core);
continue;
}
}
//check follow
while (true) {
if (query.Contains(core + new Vector3(0, 0, length)) && itemDict[core + new Vector3(0, 0, length)].Name == data.Name) {
query.Remove(core + new Vector3(0, 0, length));
length++;
} else break;
}
//create
result.CourseList.Add(new SimulationRenderItem() { Name = data.Name, Desc = data.Desc, BkColor = data.BkColor, Start = core, Span = length });
/*
var warp = new Border();
warp.Background = new SolidColorBrush(Colors.LightBlue);
warp.CornerRadius = new CornerRadius(5);
Grid.SetRowSpan(warp, length);
var nGrid = new Grid();
nGrid.ToolTip = data.Desc;
var courseName = new TextBlock();
courseName.VerticalAlignment = VerticalAlignment.Center;
courseName.Text = data.Name;
nGrid.Children.Add(courseName);
warp.Child = nGrid;
Grid.SetRow(warp, core.index - 1);
Grid.SetColumn(warp, core.week - 1);
this.uiArrangeGrid.Children.Add(warp);
*/
//remove first item
query.RemoveAt(0);
}
return result;
}
}
}

View File

@ -3,11 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace HFUTCourseSimulation {
public class SimulationItem {
public string Name { get; set; }
public string Desc { get; set; }
public Color BkColor { get; set; }
}
public struct Vector3 {
@ -37,4 +40,17 @@ namespace HFUTCourseSimulation {
return (Vector3)obj == this;
}
}
//===========================================================================
public class RenderWeek {
public int WeekIndex { get; set; }
public List<string> WeekDate { get; set; }
public List<SimulationRenderItem> CourseList { get; set; }
}
public class SimulationRenderItem : SimulationItem {
public Vector3 Start { get; set; }
public int Span { get; set; }
}
}