FreeCAD
FreeCAD copied to clipboard
Using the scaling with `App.Vector(-1,-1,-1)` to mirror objects deforms the appearance of the object.
Is there an existing issue for this?
- [x] I have searched the existing issues
Problem description
Using the scaling with App.Vector(-1, -1, -1) to mirror objects deforms the appearance of the object.
The object on the left was mirrored to the left, and the colors were messed up.
Discussion: https://forum.freecad.org/viewtopic.php?p=818394#p818394
Full version info
0.21, 1.0, 1.1-dev
Subproject(s) affected?
Core
Anything else?
No response
Code of Conduct
- [x] I agree to follow this project's Code of Conduct
This is probably due to due to inverted normals. Scaling with -1 should in general be avoided in 3d applications.
Do you know a way to fix this after the mirror happens?
You are basically turning it inside out. Why do you need to mirror fasteners instead of just placing them at the right places?
I am not mirroring fasteners; I am mirroring objects, and fasteners are one of them. I have an object in one location, I have a plane, and then I am mirroring the object based on this plane. But I am not doing this. This is a feature of a Workbench. It does not behave nicely, so I am trying to understand how I can fix it so it does not produce this issue.
Scaling is the wrong way to place objects. I've done it myself and felt pretty smart about a hack like that in the past, but it always comes and bites me in the butt with threads reversing and normals pointing the wrong direction.
I would argue that scaling with negative values are undefined at best and would be good to throw an exception when the user tries to do it.
It would be good if you file this as a bug in that workbench.
Scaling is the wrong way to place objects.
I see.
It would be good if you file this as a bug in that workbench.
I did. But I am trying to fix it myself somehow.
Someone in the Freecad Forum (link in the first message of the post, above) mentioned it could be a bug, so I reported it here.
They mentioned this, and I agree.
Yes, from my perspective. If you are scaling an object, this should not change the position of the light source. Even if that scaling is negative, the programmer should account for this. If they cannot, or refuse to, then they should disallow negative scaling all together.
But other one said that:
The mirroring has no impact on the light source. The light source is part of the viewer logic and objects of a document don't change anything there.
The problem is basically a mathematical thing because using the scale factor of -1 for all coordinates one ends up with a 3x3 transformation matrix with the determinant of -1. This means that the orientation of the object is changed and surface normals do not point to the outside but to the inside.
The effect is that the rendering shows the observed behaviour.
It seems that enabling the backlight in the settings can "improve" the visual quality of the resulting object. However, I am not sure this is the right fix.
No, the right fix is to avoid scaling using negative numbers.
This approach works on 0.21.3, but in 1.1 the back light is already enabled.
No, the right fix is to avoid scaling using negative numbers.
Do you have an idea to help me fixing this?
So we're holding it wrong? Scaling with negative numbers IS mirroring. If FreeCAD messes up the normals, that's a bug that should be fixed.
Hi, Mirroring a component with Scale = -1 was working some time ago [1]. I don't know the details but it is a useful feature of LinkPart [2]. I was using it in an assembly but now the behaviour has changed: not only changes colour but it doesn't really mirror the component any more. See screencast below. All components has been inserted with the integrated assembly's "insert" tool. It works properly with appimage 39708 (see the second screencast) but it wasn't working with appimage 41127 (~March 2025).
If not, what is the correct way to obtain a mirrored part, @hyarion ? The issue is described here and here and they are still unsolved.
[1] https://github.com/FreeCAD/FreeCAD/issues/14623 [2] https://forum.freecad.org/viewtopic.php?style=3&p=555675#p555675
Not working with appimage 41213: https://github.com/user-attachments/assets/43450e25-1475-46a5-9a89-46853af8a296
Example files: issue 20464 Mirroring.zip
Working in appimage 39708: https://github.com/user-attachments/assets/e6d73a1e-3627-4218-a612-c57c70a9ea16
OS: Devuan GNU/Linux 5 (daedalus) (XFCE/xfce/xcb) Architecture: x86_64 Version: 1.1.0dev.41213 (Git) Conda AppImage Build date: 2025/04/09 15:48:15 Build type: Release Branch: main Hash: f258a2639cd8acd45cb101b7f34e90e603d91696 Python 3.11.11, Qt 6.7.3, Coin 4.0.3, Vtk 9.3.1, IfcOpenShell 0.8.1, OCC 7.8.1 Locale: Catalan/Spain (ca_ES) Stylesheet/Theme/QtStyle: FreeCAD Light.qss/FreeCAD Light/ Logical DPI/Physical DPI/Pixel Ratio: 96/93.8695/1.07292
PS: now I think that maybe I have to open a new issue for this, as it is related with the integrated assembly, and not (only) with Mod: Part and (only) with Topic: Color. Let me know, @hyarion , and I will do it.
If not, what is the correct way to obtain a mirrored part, @hyarion ?
Yes this is a problem and I don't know a good way to do it currently:
- Part_Mirror would be one way, but that doesn't support mirroring App_Part
- Subshape binder + PartDesign_Mirrored would be another way, but PD_Mirrored doesn't support replacing original, only adding.
So I think your problem is a new issue: There's currently no way to mirror a part (that I know about) and this isn't only for assembly, another usecase would be when you want to create two similar mirrored parts, then there's no way I can find to do that.
Not a new issue because it is already reported:
The issue is described here and here and they are still unsolved.
But, what about the possibility to use Scale = -1 that was working at least until March? (I don't have more appimages in between 39708 and 41127. I think it is the same or part of this original issue that has reported leoheck.
@leoheck , can you chech if, apart from the color, the mirroring works on your side? Please, test it with a non-symmetrical component. If that is the case, maybe you could update the title and the description.
@MiqCG there are some assymetric objects reported on the following link. They mirror as expected except by the color.
https://github.com/Zolko-123/FreeCAD_Assembly4/issues/552
If you follow the link above you can see that on previous versions of Freecad, enabling the background light in the settings used to fix this problem. But now, on 1.1 this is already on however the issue still persists.
@MiqCG do you need an appimage? I have these saved:
FreeCAD_weekly-builds-41213-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-41138-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-41127-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40971-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40655-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40444-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40408-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-38553-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-36438-2024-03-15-conda-Linux-x86_64-py310.AppImage
I have downloaded your file but it involves Assembly4. This part that you are mirroring don't have a different form when mirrored and when not. On the other hand, we are using a different approach to mirror an object. Am I messing up talking about scale = -1 in here? How is App.Vector(-1,-1,-1) applied?
I have made more tests: if I link the Original_Arm.FCStd of my example to another file (without Assembly container) the issue arises too:
- open the Original_Arm file
- open a new file and save the file
- link the object to the new file with
Make link - apply scale = -1 in the properties panel (the mirrored part appears)
- transforming (moving) the object make disappear the mirroring and the object turns blackSo, it is not exclusive of the integrated assembly WB.
@leoheck , can you download my example files and test the mirroring as described? Depending on the result, I will ask you for appimages to find the moment the problem arouse.
FYI the Link double-side rendering is checked here:
https://github.com/FreeCAD/FreeCAD/blob/e990b456b9db3952cf785cb38619622415b13dca/src/Gui/ViewProviderLink.cpp#L1848-L1864
@MiqCG Asm4 does this (I removed some irrelevant parts)
class makeMirrorArray(makeExpressionArray):
def _setupProperties(self, obj):
obj.Count = 2
obj.setExpression('Scaler', '1 - 2 * (Index % 2)')
obj.setExpression('.Placer.Base', '.Placer.Rotation * minvert(.AxisPlacement) * .SourceObject.Placement.Base * -2 * (Index % 2)')
obj.setExpression('.Placer.Rotation.Angle', '180 * (Index % 2)')
class ExpressionArray(LinkArray):
# do the calculation of the elements Placements
def execute(self, obj):
""" The placement is calculated relative to the axis placement
Without Axis the Array is relative to the internal Z axis of the SourceObject."""
sObj = obj.SourceObject
# we only deal with objects that are in a parent container because we'll put the array there
parent = sObj.getParentGeoFeatureGroup()
if obj.Axis:
obj.AxisPlacement = findAxisPlacement(*obj.Axis)
else:
obj.AxisPlacement = obj.SourceObject.Placement
pmt1 = obj.AxisPlacement.inverse() * sObj.Placement
placementList = []
scaleList = []
expDict = dict(obj.ExpressionEngine)
evalList = _evalOrder(expDict)
# calculate placement of each element
for i in range(obj.Count):
obj.Index = i
for pn in evalList:
ps = 'obj.'+pn.lstrip('.')
nv = type(eval(ps))(obj.evalExpression(expDict[pn]))
o,a = ps.rsplit('.',1)
if a == 'Angle' and type(eval(o)) == App.Rotation:
nv = radians(nv)
# must set entire rotation axis at once.
# Related discussion: https://forum.freecad.org/viewtopic.php?t=73898
if o.endswith('.Axis') and a in 'xyz':
axv = eval(o.replace('.Axis','.RawAxis'))
setattr(axv, a, nv)
exec(o + ' = axv')
continue
exec(ps + ' = nv')
placementList.append(obj.AxisPlacement * obj.Placer * pmt1)
s = obj.Scaler
scaleList.append(App.Vector(s, s, s)) #<---------------------- This is (-1, -1, -1) when obj.Scaler = -1
# Resetting Index to 1 because we get more useful preview results
# in the expression editor
obj.Index = 1
if obj.ShowElement:
for i in range(obj.Count):
el = obj.ElementList[i]
el.NoTouch = True
el.Placement = placementList[i]
el.ScaleVector = scaleList[i]
el.setPropertyStatus('Placement', 'ReadOnly')
el.setPropertyStatus('ScaleVector', 'ReadOnly')
el.setPropertyStatus('Scale', 'ReadOnly')
el.NoTouch = False
else:
obj.PlacementList = placementList
obj.ScaleList = scaleList
return
But I confirm that your example @MiqCG reproduces the issue.
Check here:
https://github.com/user-attachments/assets/507ab1f3-2d43-4855-a8b1-c8d38a0cd072
Sorry but I don't have enough programming skills to fully understand what the code that you sent really does.
Thanks for the testing. I will open another issue with this problem to not distort yours.
Can you give me access to some of this appimages? FreeCAD_weekly-builds-40971-conda-Linux-x86_64-py311.AppImage FreeCAD_weekly-builds-40655-conda-Linux-x86_64-py311.AppImage FreeCAD_weekly-builds-40444-conda-Linux-x86_64-py311.AppImage FreeCAD_weekly-builds-40408-conda-Linux-x86_64-py311.AppImage
We can make it one by one, beginning with the oldest one. I just want to find the moment, to ease the finding of the problematic code change.
New issue created: https://github.com/FreeCAD/FreeCAD/issues/20776 Thanks and sorry for the inconvenience.
@MiqCG, I think it is the same problem.
I am putting my AppImages here. https://www.dropbox.com/scl/fo/kk8ffuxc15ioj5l2b9r32/ABUUCxxigx1nlgVQMaPhdG8?rlkey=60qkhu7fwaxlh0m5p6jeaeonx&dl=0
It will take some time to upload them, but these are all the files you will find there
FreeCAD_weekly-builds-36438-2024-03-15-conda-Linux-x86_64-py310.AppImage
FreeCAD_weekly-builds-38553-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40408-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40444-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40655-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-40971-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-41127-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-41138-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-41213-conda-Linux-x86_64-py311.AppImage
FreeCAD_weekly-builds-41232-conda-Linux-x86_64-py311.AppImage
soft bump
The related issue here https://github.com/FreeCAD/FreeCAD/issues/20776#issuecomment-2993799518 has been fixed. However, this one has not been resolved yet. Something else has broken the color of the mirrored object when using Asm4, but I don’t know what yet.
https://github.com/FreeCAD/FreeCAD/issues/22170#comment-composer-heading