-- This solution uses option b). Note that this solution needs an adjustment of relation Square2blockOfCirlce.
transformation r4_b(source : Shapes, target : Shapes) {
	
	top relation ArrowSource2ArrowSource {
		
		enforce domain source sourceArrow : Shapes::Arrow {
			source = sourceArrowSource : Shapes::Shape {
			}
		};
		
		enforce domain target targetArrow : Shapes::Arrow {
			source = targetArrowSource : Shapes::Shape {
			}
		};
		
		when {
			Source2Target(sourceArrow, targetArrow);
			Source2Target(sourceArrowSource, targetArrowSource);
		}
		
	}
	
	top relation ArrowTarget2ArrowTarget {
		
		enforce domain source sourceArrow : Shapes::Arrow {
			target = sourceArrowTarget : Shapes::Shape {
			}
		};
		
		enforce domain target targetArrow : Shapes::Arrow {
			target = targetArrowTarget : Shapes::Shape {
			}
		};
		
		when {
			Source2Target(sourceArrow, targetArrow);
			Source2Target(sourceArrowTarget, targetArrowTarget);
		}
		
	}
	
	top relation ModelElementName2ModelElementName {
		
		varName : String;
		
		enforce domain source sourceModelElement : Shapes::ModelElement {
			name = varName
		};
		
		enforce domain target targetModelElement : Shapes::ModelElement {
			name = varName
		};
		
		when {
			Source2Target(sourceModelElement, targetModelElement);
		}
		
	}
	
	top relation ModelElementblock2ModelElementblock {
		
		enforce domain source sourceModelElement : Shapes::ModelElement {
			block = sourceblock : Shapes::Block {
			}
		};
		
		enforce domain target targetModelElement : Shapes::ModelElement {
			block = targetblock : Shapes::Block {
			}
		};
				
		when {
			if Square2blockOfCirlce(sourceModelElement,targetModelElement) then true else Source2Target(sourceModelElement, targetModelElement) endif;
			-- Note that you cannot use the following condition instead of the preceding condition:
			--       Source2Target(sourceModelElement, targetModelElement) or Square2blockOfCirlce(sourceModelElement,targetModelElement);
			-- ... since if Source2Target binds variable targetModelElement, it will not be bound by Square2blockOfCirlce, but this is required for squares
			-- Also the following expression has the same problem: 
			--       Square2blockOfCirlce(sourceModelElement, targetModelElement) or Source2Target(sourceModelElement,targetModelElement);
			-- ... since you cannot rely on an execution order of the OCL expression when relation calls are involved
			
			Source2Target(sourceblock, targetblock);
		}
		
	}
	
	top relation Source2Target {
		
		enforce domain source s : Shapes::ModelElement {
		};
		
		enforce domain target t : Shapes::ModelElement {
		};
		
		when {
			MapBlock(s, t) or MapRootBlock(s, t) or MapCircle(s, t) or MapTriangle(s, t) or MapSquare(s, t) or MapArrow(s, t);
		}
		
	}
	
	top relation MapRootBlock {
		
		enforce domain source s : Shapes::RootBlock {
		};
		
		enforce domain target t : Shapes::RootBlock {
		};
		
	}
	
	top relation MapBlock {
		
		enforce domain source s : Shapes::Block {
		};
		
		enforce domain target t : Shapes::Block {
		};
		
		when {
			not MapRootBlock(s, t);
		}
		
	}
	
	top relation MapCircle {
		
		enforce domain source s : Shapes::Circle {
		};
		
		enforce domain target t : Shapes::Circle {
		};
		
	}
	
	top relation MapTriangle {
		
		enforce domain source s : Shapes::Triangle {
		};
		
		enforce domain target t : Shapes::Triangle {
		};
		
	}
	
	top relation MapSquare {
		
		enforce domain source s : Shapes::Square {
		};
		
		enforce domain target containedCircle : Shapes::Circle {
			block = t : Shapes::Block {
				name = 'generated block'
			}			
		};
		
		where {
			Square2blockOfCirlce(s,t);
		}
		
	}
	
	relation Square2blockOfCirlce {
		
		enforce domain source s : Shapes::Square { };
		
		enforce domain target t : Shapes::Block { };
		
	}	
	
	top relation MapArrow {
		
		enforce domain source s : Shapes::Arrow {
		};
		
		enforce domain target t : Shapes::Arrow {
		};
		
	}
	
}
