| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- import { Injectable } from '@angular/core';
- import { Observable, forkJoin, of } from 'rxjs';
- import { map, catchError } from 'rxjs/operators';
- import {
- RequirementMapping,
- SceneTemplate,
- MappingResult,
- ColorMappingParams,
- SpaceMappingParams,
- MaterialMappingParams
- } from '../models/requirement-mapping.interface';
- import { SceneGenerationService } from './scene-generation.service';
- import { ParameterMappingService } from './parameter-mapping.service';
- @Injectable({
- providedIn: 'root'
- })
- export class RequirementMappingService {
- constructor(
- private sceneGenerationService: SceneGenerationService,
- private parameterMappingService: ParameterMappingService
- ) {}
- /**
- * 根据分析结果生成完整的需求映射
- * @param analysisResult 分析结果
- * @param preferredSceneType 首选场景类型(可选)
- */
- generateRequirementMapping(
- analysisResult: any,
- preferredSceneType?: SceneTemplate
- ): Observable<RequirementMapping> {
-
- // 确定场景类型
- const sceneType = preferredSceneType || this.determineOptimalSceneType(analysisResult);
-
- // 并行执行场景生成和参数映射
- return forkJoin({
- sceneGeneration: this.sceneGenerationService.generateSceneFromAnalysis(analysisResult, sceneType),
- parameterMapping: this.parameterMappingService.mapAllParameters(analysisResult)
- }).pipe(
- map(({ sceneGeneration, parameterMapping }) => {
- const requirementMapping: RequirementMapping = {
- sceneGeneration: {
- baseScene: sceneType,
- parameters: sceneGeneration.generatedParams!,
- atmospherePreview: sceneGeneration.previewUrl || this.generateDefaultPreview(sceneType)
- },
- parameterMapping: {
- colorParams: parameterMapping.colorParams,
- spaceParams: parameterMapping.spaceParams,
- materialParams: parameterMapping.materialParams
- }
- };
- return requirementMapping;
- }),
- catchError(error => {
- console.error('需求映射生成失败:', error);
- return of(this.getDefaultRequirementMapping());
- })
- );
- }
- /**
- * 生成多个场景选项供用户选择
- * @param analysisResult 分析结果
- * @param sceneCount 生成场景数量
- */
- generateMultipleSceneOptions(
- analysisResult: any,
- sceneCount: number = 3
- ): Observable<RequirementMapping[]> {
-
- const recommendedScenes = this.getRecommendedScenes(analysisResult, sceneCount);
-
- const mappingObservables = recommendedScenes.map(sceneType =>
- this.generateRequirementMapping(analysisResult, sceneType)
- );
- return forkJoin(mappingObservables).pipe(
- catchError(error => {
- console.error('多场景生成失败:', error);
- return of([this.getDefaultRequirementMapping()]);
- })
- );
- }
- /**
- * 更新现有需求映射的参数
- * @param currentMapping 当前映射
- * @param updatedParams 更新的参数
- */
- updateRequirementMapping(
- currentMapping: RequirementMapping,
- updatedParams: Partial<RequirementMapping>
- ): Observable<RequirementMapping> {
-
- try {
- const updatedMapping: RequirementMapping = {
- sceneGeneration: {
- ...currentMapping.sceneGeneration,
- ...updatedParams.sceneGeneration
- },
- parameterMapping: {
- ...currentMapping.parameterMapping,
- ...updatedParams.parameterMapping
- }
- };
- // 如果场景参数发生变化,重新生成预览图
- if (updatedParams.sceneGeneration?.parameters) {
- updatedMapping.sceneGeneration.atmospherePreview =
- this.generateAtmospherePreview(
- updatedMapping.sceneGeneration.parameters,
- updatedMapping.sceneGeneration.baseScene
- );
- }
- return of(updatedMapping);
- } catch (error) {
- console.error('需求映射更新失败:', error);
- return of(currentMapping);
- }
- }
- /**
- * 验证需求映射的完整性和合理性
- * @param mapping 需求映射
- */
- validateRequirementMapping(mapping: RequirementMapping): Observable<{
- isValid: boolean;
- issues: string[];
- suggestions: string[];
- }> {
-
- const issues: string[] = [];
- const suggestions: string[] = [];
- try {
- // 验证场景生成部分
- if (!mapping.sceneGeneration.baseScene) {
- issues.push('缺少基础场景模板');
- }
- if (!mapping.sceneGeneration.parameters) {
- issues.push('缺少场景参数');
- } else {
- // 验证场景参数的合理性
- const params = mapping.sceneGeneration.parameters;
-
- if (params.lighting.primaryLight.intensity < 0 || params.lighting.primaryLight.intensity > 100) {
- issues.push('主光源强度超出合理范围 (0-100)');
- }
- if (params.lighting.primaryLight.temperature < 1000 || params.lighting.primaryLight.temperature > 10000) {
- issues.push('色温值超出合理范围 (1000-10000K)');
- }
- if (params.composition.depth < 0 || params.composition.depth > 100) {
- issues.push('景深值超出合理范围 (0-100)');
- }
- }
- // 验证参数映射部分
- if (!mapping.parameterMapping.colorParams.primaryColors.length) {
- issues.push('缺少主要颜色定义');
- }
- if (!mapping.parameterMapping.spaceParams.layout.zones.length) {
- issues.push('缺少空间功能区域定义');
- }
- if (!mapping.parameterMapping.materialParams.surfaceMaterials.length) {
- issues.push('缺少主要材质定义');
- }
- // 生成优化建议
- if (mapping.parameterMapping.colorParams.saturation > 80) {
- suggestions.push('考虑降低色彩饱和度以获得更舒适的视觉效果');
- }
- if (mapping.parameterMapping.materialParams.textureScale > 80) {
- suggestions.push('高复杂度纹理可能影响渲染性能,建议适当简化');
- }
- const totalZoneArea = mapping.parameterMapping.spaceParams.layout.zones
- .reduce((sum: number, zone: any) => sum + zone.area, 0);
- if (totalZoneArea > 100) {
- suggestions.push('功能区域总面积超过100%,建议重新分配');
- }
- return of({
- isValid: issues.length === 0,
- issues,
- suggestions
- });
- } catch (error) {
- return of({
- isValid: false,
- issues: ['验证过程中发生错误'],
- suggestions: []
- });
- }
- }
- /**
- * 导出需求映射为配置文件
- * @param mapping 需求映射
- * @param format 导出格式
- */
- exportRequirementMapping(
- mapping: RequirementMapping,
- format: 'json' | 'yaml' | 'xml' = 'json'
- ): Observable<string> {
-
- try {
- let exportContent: string;
- switch (format) {
- case 'json':
- exportContent = JSON.stringify(mapping, null, 2);
- break;
- case 'yaml':
- exportContent = this.convertToYaml(mapping);
- break;
- case 'xml':
- exportContent = this.convertToXml(mapping);
- break;
- default:
- exportContent = JSON.stringify(mapping, null, 2);
- }
- return of(exportContent);
- } catch (error) {
- console.error('导出需求映射失败:', error);
- return of('');
- }
- }
- // ==================== 私有辅助方法 ====================
- /**
- * 确定最优场景类型
- */
- private determineOptimalSceneType(analysisResult: any): SceneTemplate {
- // 基于分析结果推断最适合的场景类型
-
- // 检查物体识别结果
- if (analysisResult.formAnalysis?.objectRecognition) {
- const objects = analysisResult.formAnalysis.objectRecognition.identifiedObjects || [];
-
- // 卧室相关物品
- if (objects.some((obj: any) => ['bed', 'pillow', 'nightstand'].includes(obj.category))) {
- return analysisResult.enhancedColorAnalysis?.colorPsychology?.primaryMood === 'calm'
- ? SceneTemplate.BEDROOM_MINIMAL
- : SceneTemplate.BEDROOM_COZY;
- }
-
- // 客厅相关物品
- if (objects.some((obj: any) => ['sofa', 'coffee table', 'tv'].includes(obj.category))) {
- return analysisResult.formAnalysis?.overallAssessment?.styleComplexity > 60
- ? SceneTemplate.LIVING_ROOM_CLASSIC
- : SceneTemplate.LIVING_ROOM_MODERN;
- }
-
- // 厨房相关物品
- if (objects.some((obj: any) => ['stove', 'refrigerator', 'sink'].includes(obj.category))) {
- return SceneTemplate.KITCHEN_CONTEMPORARY;
- }
-
- // 浴室相关物品
- if (objects.some((obj: any) => ['toilet', 'shower', 'bathtub'].includes(obj.category))) {
- return SceneTemplate.BATHROOM_LUXURY;
- }
- }
- // 基于色彩和风格分析
- if (analysisResult.enhancedColorAnalysis?.colorPsychology) {
- const mood = analysisResult.enhancedColorAnalysis.colorPsychology.primaryMood;
- switch (mood) {
- case 'sophisticated':
- case 'luxurious':
- return SceneTemplate.LIVING_ROOM_CLASSIC;
- case 'calm':
- case 'minimal':
- return SceneTemplate.BEDROOM_MINIMAL;
- case 'energetic':
- case 'modern':
- return SceneTemplate.LIVING_ROOM_MODERN;
- default:
- return SceneTemplate.LIVING_ROOM_MODERN;
- }
- }
- // 默认返回现代客厅
- return SceneTemplate.LIVING_ROOM_MODERN;
- }
- /**
- * 获取推荐场景列表
- */
- private getRecommendedScenes(analysisResult: any, count: number): SceneTemplate[] {
- const primaryScene = this.determineOptimalSceneType(analysisResult);
- const allScenes = Object.values(SceneTemplate);
-
- // 确保主推荐场景在第一位
- const recommendedScenes = [primaryScene];
-
- // 添加其他相关场景
- const otherScenes = allScenes.filter(scene => scene !== primaryScene);
-
- // 基于分析结果的相似度排序其他场景
- const sortedOtherScenes = this.sortScenesBySimilarity(otherScenes, analysisResult);
-
- // 取前 count-1 个场景
- recommendedScenes.push(...sortedOtherScenes.slice(0, count - 1));
-
- return recommendedScenes;
- }
- /**
- * 根据相似度排序场景
- */
- private sortScenesBySimilarity(scenes: SceneTemplate[], analysisResult: any): SceneTemplate[] {
- // 简化的相似度计算,实际项目中可以实现更复杂的算法
- return scenes.sort((a, b) => {
- const scoreA = this.calculateSceneSimilarityScore(a, analysisResult);
- const scoreB = this.calculateSceneSimilarityScore(b, analysisResult);
- return scoreB - scoreA;
- });
- }
- /**
- * 计算场景相似度分数
- */
- private calculateSceneSimilarityScore(scene: SceneTemplate, analysisResult: any): number {
- let score = 0;
-
- // 基于色彩心理学匹配
- if (analysisResult.enhancedColorAnalysis?.colorPsychology) {
- const mood = analysisResult.enhancedColorAnalysis.colorPsychology.primaryMood;
-
- const moodSceneMap: {[key: string]: SceneTemplate[]} = {
- 'calm': [SceneTemplate.BEDROOM_MINIMAL, SceneTemplate.BATHROOM_MINIMAL],
- 'sophisticated': [SceneTemplate.LIVING_ROOM_CLASSIC, SceneTemplate.OFFICE_TRADITIONAL],
- 'modern': [SceneTemplate.LIVING_ROOM_MODERN, SceneTemplate.KITCHEN_CONTEMPORARY],
- 'cozy': [SceneTemplate.BEDROOM_COZY, SceneTemplate.DINING_CASUAL]
- };
-
- if (moodSceneMap[mood]?.includes(scene)) {
- score += 30;
- }
- }
-
- // 基于材质匹配
- if (analysisResult.textureAnalysis?.materialClassification) {
- const primaryMaterial = analysisResult.textureAnalysis.materialClassification.primaryMaterial?.category;
-
- const materialSceneMap: {[key: string]: SceneTemplate[]} = {
- 'wood': [SceneTemplate.LIVING_ROOM_CLASSIC, SceneTemplate.BEDROOM_COZY],
- 'metal': [SceneTemplate.KITCHEN_CONTEMPORARY, SceneTemplate.OFFICE_MODERN],
- 'ceramic': [SceneTemplate.BATHROOM_LUXURY, SceneTemplate.KITCHEN_CONTEMPORARY],
- 'fabric': [SceneTemplate.BEDROOM_COZY, SceneTemplate.LIVING_ROOM_CLASSIC]
- };
-
- if (materialSceneMap[primaryMaterial]?.includes(scene)) {
- score += 20;
- }
- }
-
- return score;
- }
- /**
- * 生成氛围感预览图
- */
- private generateAtmospherePreview(params: any, sceneType: SceneTemplate): string {
- // 这里应该调用实际的预览图生成服务
- // 目前返回模拟的URL
- const baseUrl = document.baseURI+'/assets/previews/atmosphere/';
- const sceneId = sceneType.toString();
- const timestamp = Date.now();
- return `${baseUrl}${sceneId}_${timestamp}.jpg`;
- }
- /**
- * 生成默认预览图
- */
- private generateDefaultPreview(sceneType: SceneTemplate): string {
- return document.baseURI+`/assets/previews/default/${sceneType}.jpg`;
- }
- /**
- * 获取默认需求映射
- */
- private getDefaultRequirementMapping(): RequirementMapping {
- return {
- sceneGeneration: {
- baseScene: SceneTemplate.LIVING_ROOM_MODERN,
- parameters: this.sceneGenerationService.getSceneTemplate(SceneTemplate.LIVING_ROOM_MODERN),
- atmospherePreview: this.generateDefaultPreview(SceneTemplate.LIVING_ROOM_MODERN)
- },
- parameterMapping: {
- colorParams: {
- primaryColors: [
- { originalColor: '#FFFFFF', mappedColor: '#FFFFFF', weight: 40, usage: 'primary' },
- { originalColor: '#F5F5F5', mappedColor: '#F5F5F5', weight: 30, usage: 'secondary' },
- { originalColor: '#E0E0E0', mappedColor: '#E0E0E0', weight: 30, usage: 'background' }
- ],
- colorHarmony: 'monochromatic',
- saturation: 50,
- brightness: 70,
- contrast: 50,
- temperature: 'neutral'
- },
- spaceParams: {
- dimensions: { width: 400, height: 280, depth: 400, unit: 'meter' },
- layout: {
- type: 'open',
- flow: 'linear',
- zones: []
- },
- scale: {
- furniture: 50,
- ceiling: 60,
- openness: 70
- }
- },
- materialParams: {
- surfaceMaterials: [],
- textureScale: 50,
- reflectivity: 30,
- roughness: 40,
- metallic: 10
- }
- }
- };
- }
- /**
- * 转换为YAML格式
- */
- private convertToYaml(mapping: RequirementMapping): string {
- // 简化的YAML转换,实际项目中建议使用专门的YAML库
- return `# 需求映射配置文件
- sceneGeneration:
- baseScene: "${mapping.sceneGeneration.baseScene}"
- atmospherePreview: "${mapping.sceneGeneration.atmospherePreview}"
- parameters:
- lighting:
- primaryLight:
- type: "${mapping.sceneGeneration.parameters.lighting.primaryLight.type}"
- intensity: ${mapping.sceneGeneration.parameters.lighting.primaryLight.intensity}
- temperature: ${mapping.sceneGeneration.parameters.lighting.primaryLight.temperature}
- direction: "${mapping.sceneGeneration.parameters.lighting.primaryLight.direction}"
- # ... 其他参数
- parameterMapping:
- colorParams:
- primaryColors: [${mapping.parameterMapping.colorParams.primaryColors.map(c => `"${c}"`).join(', ')}]
- colorHarmony: "${mapping.parameterMapping.colorParams.colorHarmony}"
- saturation: ${mapping.parameterMapping.colorParams.saturation}
- brightness: ${mapping.parameterMapping.colorParams.brightness}
- # ... 其他映射参数`;
- }
- /**
- * 转换为XML格式
- */
- private convertToXml(mapping: RequirementMapping): string {
- // 简化的XML转换
- return `<?xml version="1.0" encoding="UTF-8"?>
- <RequirementMapping>
- <SceneGeneration>
- <BaseScene>${mapping.sceneGeneration.baseScene}</BaseScene>
- <AtmospherePreview>${mapping.sceneGeneration.atmospherePreview}</AtmospherePreview>
- <!-- 参数配置 -->
- </SceneGeneration>
- <ParameterMapping>
- <ColorParams>
- <PrimaryColors>${mapping.parameterMapping.colorParams.primaryColors.join(',')}</PrimaryColors>
- <ColorHarmony>${mapping.parameterMapping.colorParams.colorHarmony}</ColorHarmony>
- <SaturationLevel>${mapping.parameterMapping.colorParams.saturation}</SaturationLevel>
- <BrightnessLevel>${mapping.parameterMapping.colorParams.brightness}</BrightnessLevel>
- </ColorParams>
- <!-- 其他映射参数 -->
- </ParameterMapping>
- </RequirementMapping>`;
- }
- }
|