4 changed files with 364 additions and 247 deletions
@ -0,0 +1,169 @@
@@ -0,0 +1,169 @@
|
||||
import 'package:excel/excel.dart'; |
||||
|
||||
class RelationshipCalculatorService { |
||||
final Map<String, bool> _columnRedStates = {}; |
||||
final List<List<String>> _aspects = []; // Stores [conjunction, opposition, square] for each row |
||||
|
||||
static const List<String> zodiacColumns = [ |
||||
'日', |
||||
'月', |
||||
'水', |
||||
'金', |
||||
'火', |
||||
'木', |
||||
'土', |
||||
'天', |
||||
'海', |
||||
'冥', |
||||
'南', |
||||
'北', |
||||
'孛', |
||||
'凯', |
||||
]; |
||||
|
||||
void processEntireSheet(Sheet sheet) { |
||||
_columnRedStates.clear(); |
||||
_aspects.clear(); |
||||
|
||||
for (var rowIndex = 0; rowIndex < sheet.maxRows; rowIndex++) { |
||||
final row = sheet.rows[rowIndex]; |
||||
if (row.isEmpty) continue; |
||||
|
||||
// 跳过所有第一个单元格值为"Date"的行 |
||||
if (row.first?.value?.toString().startsWith('Date') == true) { |
||||
continue; |
||||
} |
||||
|
||||
_processZodiacColumns(rowIndex, row); |
||||
_calculateCoordinateRelationships(row); |
||||
} |
||||
|
||||
// Add aspect markers to the last three rows |
||||
_addAspectMarkers(sheet); |
||||
} |
||||
|
||||
void _processZodiacColumns(int rowIndex, List<Data?> row) { |
||||
for (int i = 0; i < zodiacColumns.length; i++) { |
||||
final columnTitle = zodiacColumns[i]; |
||||
final dataColumnIndex = 4 + (i * 2) + 1; |
||||
|
||||
if (dataColumnIndex >= row.length) continue; |
||||
|
||||
final cell = row[dataColumnIndex]; |
||||
if (cell == null) continue; |
||||
|
||||
final cellValue = cell.value?.toString() ?? ''; |
||||
|
||||
if (cellValue.contains('R')) { |
||||
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.red); |
||||
_columnRedStates[columnTitle] = true; |
||||
} else if (cellValue.contains('D')) { |
||||
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.black); |
||||
_columnRedStates[columnTitle] = false; |
||||
} else if (_columnRedStates[columnTitle] == true) { |
||||
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.red); |
||||
} else { |
||||
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.black); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void _calculateCoordinateRelationships(List<Data?> row) { |
||||
List<int> positionsInMinutes = []; |
||||
List<String> planets = []; |
||||
|
||||
// Extract positions for all planets in minutes |
||||
for (int i = 0; i < zodiacColumns.length; i++) { |
||||
final dataColumnIndex = 4 + (i * 2) + 1; |
||||
if (dataColumnIndex >= row.length) continue; |
||||
|
||||
final cell = row[dataColumnIndex]; |
||||
if (cell == null) continue; |
||||
|
||||
final cellValue = cell.value?.toString() ?? ''; |
||||
final cleanedValue = cellValue.replaceAll(RegExp(r'[RD]'), ''); |
||||
if (cleanedValue.isEmpty) continue; |
||||
|
||||
try { |
||||
final parts = cleanedValue.split('°'); |
||||
if (parts.length != 2) continue; |
||||
|
||||
final degrees = int.parse(parts[0]); |
||||
final minutesPart = parts[1].split('\''); |
||||
final minutes = minutesPart.isNotEmpty ? int.parse(minutesPart[0]) : 0; |
||||
|
||||
positionsInMinutes.add(degrees * 60 + minutes); |
||||
planets.add(zodiacColumns[i]); |
||||
} catch (e) { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
// Calculate aspects |
||||
List<String> conjunctions = []; |
||||
List<String> oppositions = []; |
||||
List<String> squares = []; |
||||
|
||||
for (int i = 0; i < positionsInMinutes.length; i++) { |
||||
for (int j = i + 1; j < positionsInMinutes.length; j++) { |
||||
final diff = (positionsInMinutes[i] - positionsInMinutes[j]).abs(); |
||||
final circularDiff = diff > 10800 ? 21600 - diff : diff; // 360° = 21600 minutes |
||||
|
||||
// Check for conjunction (<60 minutes or 120°±30 minutes) |
||||
if (circularDiff < 60 || (circularDiff >= 7170 && circularDiff <= 7290)) { |
||||
// 119°30' to 120°29' |
||||
|
||||
if (planets[i] == '南' && planets[j] == '北') { |
||||
// 南北合不用显示 |
||||
} else { |
||||
conjunctions.add('${planets[i]}${planets[j]}合'); |
||||
} |
||||
} |
||||
// Check for square (90°±30 minutes) |
||||
else if (circularDiff >= 5370 && circularDiff <= 5490) { |
||||
// 89°30' to 90°29' |
||||
squares.add('${planets[i]}${planets[j]}刑'); |
||||
} |
||||
// Check for opposition (180°±30 minutes) |
||||
else if (circularDiff >= 10770 && circularDiff <= 10890) { |
||||
// 179°30' to 180°29' |
||||
oppositions.add('${planets[i]}${planets[j]}冲'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
_aspects.add([conjunctions.join(', '), oppositions.join(', '), squares.join(', ')]); |
||||
} |
||||
|
||||
void _addAspectMarkers(Sheet sheet) { |
||||
if (_aspects.isEmpty) return; |
||||
|
||||
// 确定要在哪三列添加数据(最后三列) |
||||
final firstAspectCol = sheet.maxColumns - 3; |
||||
final secondAspectCol = sheet.maxColumns - 2; |
||||
final thirdAspectCol = sheet.maxColumns - 1; |
||||
|
||||
for (int rowIndex = 0; rowIndex < sheet.maxRows; rowIndex++) { |
||||
final row = sheet.rows[rowIndex]; |
||||
if (row.isEmpty || row.first?.value?.toString().startsWith('Date') == true) { |
||||
continue; |
||||
} |
||||
|
||||
// 获取当前行对应的aspect数据 |
||||
int dataIndex = rowIndex - 1; // 假设第一行是标题行 |
||||
if (dataIndex >= 0 && dataIndex < _aspects.length) { |
||||
final aspects = _aspects[dataIndex]; |
||||
|
||||
_setCellValue(sheet, firstAspectCol, rowIndex, aspects[0]); |
||||
_setCellValue(sheet, secondAspectCol, rowIndex, aspects[1]); |
||||
_setCellValue(sheet, thirdAspectCol, rowIndex, aspects[2]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 辅助方法:正确设置单元格值 |
||||
void _setCellValue(Sheet sheet, int col, int row, String value) { |
||||
final cell = sheet.cell(CellIndex.indexByColumnRow(columnIndex: col, rowIndex: row)); |
||||
cell.value = TextCellValue(value); // 使用TextCellValue包装字符串 |
||||
} |
||||
} |
Loading…
Reference in new issue